From 62521dc0f7707bdec548b21fb49398f0541ee9bb Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Tue, 9 Jun 2015 09:14:58 +0100 Subject: [PATCH] Imported Upstream version 0.5.2-426-gc5ad4e4~dfsg1 --- .gitattributes | 19 + .travis.yml | 19 + INSTALLME | 26 +- Makefile | 130 +- README | 5 +- applications/Makefile | 18 +- applications/dashcast/Makefile | 1 + applications/dashcast/audio_data.h | 2 +- applications/dashcast/audio_decoder.c | 21 +- applications/dashcast/audio_encoder.c | 11 +- applications/dashcast/audio_muxer.c | 42 +- applications/dashcast/audio_muxer.h | 3 + applications/dashcast/cmd_data.c | 73 +- applications/dashcast/cmd_data.h | 1 + applications/dashcast/controler.c | 111 +- applications/dashcast/dashcast.c | 17 +- applications/dashcast/task.c | 4 +- applications/dashcast/video_data.c | 3 +- applications/dashcast/video_data.h | 7 +- applications/dashcast/video_decoder.c | 52 +- applications/dashcast/video_decoder.h | 3 +- applications/dashcast/video_encoder.c | 31 +- applications/dashcast/video_encoder.h | 2 +- applications/dashcast/video_muxer.c | 138 +- applications/dashcast/video_muxer.h | 12 +- applications/dashcast/video_scaler.c | 34 +- applications/dashcast/video_scaler.h | 1 + applications/generators/MPEG4/MPEG4Gen.dsp | 196 +- applications/generators/MPEG4/MPEG4Gen.dsw | 58 +- applications/generators/MPEG4/main.c | 18 +- applications/generators/SVG/SVGGen.dsp | 252 +- applications/generators/SVG/SVGGen.dsw | 58 +- applications/generators/SVG/html.c | 4 +- applications/generators/SVG/laser.c | 2 +- applications/generators/SVG/main.c | 4 +- applications/generators/X3D/X3DGen.dsp | 196 +- applications/generators/X3D/X3DGen.dsw | 58 +- applications/generators/X3D/main.c | 12 +- applications/m3u82mpd/m3u82mpd.vcproj | 366 +- applications/m3u82mpd/main.c | 4 +- applications/mp42avi/main.c | 18 +- applications/mp42ts/Makefile | 4 +- applications/mp42ts/main.c | 206 +- applications/mp4box/Makefile | 9 +- applications/mp4box/filedump.c | 457 +- applications/mp4box/fileimport.c | 405 +- applications/mp4box/live.c | 24 +- applications/mp4box/main.c | 1109 +- applications/mp4box/wrapper.c | 4 +- applications/mp4client/Makefile | 5 + applications/mp4client/carbon_events.c | 109 + applications/mp4client/extract.c | 475 +- applications/mp4client/main.c | 881 +- applications/mp4client/mp4client.rc | 144 +- applications/testapps/bmp4demux/bmp4demux.sln | 40 +- .../testapps/bmp4demux/bmp4demux.vcxproj | 379 +- .../bmp4demux/bmp4demux.vcxproj.filters | 269 +- applications/testapps/bmp4demux/build.sh | 2 +- .../testapps/broadcaster/broadcaster.c | 8 +- .../testapps/broadcaster/broadcaster.dsp | 292 +- .../testapps/broadcaster/sdp_generator.c | 4 +- applications/testapps/dmbrs/dmbrs.dsp | 180 +- applications/testapps/dmbrs/main.c | 20 +- applications/testapps/fmp4demux/build.sh | 2 +- applications/testapps/fmp4demux/fmp4demux.sln | 40 +- .../testapps/fmp4demux/fmp4demux.vcxproj | 377 +- .../fmp4demux/fmp4demux.vcxproj.filters | 275 +- applications/testapps/fmp4demux/main.c | 10 +- applications/testapps/hevcbench/defbench.h | 222 +- .../testapps/hevcbench/hevcbench.vcxproj | 522 +- applications/testapps/hevcbench/main.c | 1715 ++-- applications/testapps/largefile/largefile.dsp | 204 +- applications/testapps/largefile/largefile.dsw | 88 +- .../testapps/loadcompare/LoadCompare.dsp | 224 +- .../testapps/loadcompare/loadcompare.c | 16 +- applications/testapps/mp42ts/mp42ts.vcproj | 434 +- applications/testapps/mpedemux/main.c | 2 +- applications/testapps/mpedemux/mpedemux.dsp | 180 +- applications/testapps/mpeg2ts/main.c | 10 +- applications/testapps/mpeg2ts/mpeg2ts.dsp | 200 +- applications/testapps/segmp4demux/build.sh | 2 +- .../testapps/segmp4demux/segmp4demux.sln | 40 +- .../testapps/segmp4demux/segmp4demux.vcxproj | 379 +- .../segmp4demux/segmp4demux.vcxproj.filters | 269 +- applications/testapps/svg2bifs/svg2bifs.dsp | 180 +- applications/ts2hds/f4m.c | 12 +- applications/ts2hds/main.c | 41 +- applications/udptsseg/main.c | 10 +- applications/udptsseg/udptsseg.dsp | 188 +- applications/udptsseg/udptsseg.vcproj | 426 +- .../release/install/archive.bat | 25 +- .../release/install/build_installer.bat | 77 +- .../release/install/readme.txt | 12 +- configure | 764 +- doc/INSTALL.w32 | 2 +- doc/configuration.html | 1778 ++-- extra_lib/include/DTAPI.h | 7232 +++++++++++++ .../ffmpeg_android/libavcodec/avcodec.h | 5959 ++++++----- .../include/ffmpeg_android/libavcodec/avfft.h | 236 + .../ffmpeg_android/libavcodec/dv_profile.h | 160 + .../include/ffmpeg_android/libavcodec/dxva2.h | 186 + .../ffmpeg_android/libavcodec/old_codec_ids.h | 794 ++ .../include/ffmpeg_android/libavcodec/vaapi.h | 346 + .../include/ffmpeg_android/libavcodec/vda.h | 426 + .../include/ffmpeg_android/libavcodec/vdpau.h | 430 + .../ffmpeg_android/libavcodec/version.h | 364 + .../include/ffmpeg_android/libavcodec/xvmc.h | 340 + .../ffmpeg_android/libavformat/avformat.h | 2711 +++-- .../include/ffmpeg_android/libavformat/avio.h | 744 +- .../ffmpeg_android/libavformat/version.h | 170 + .../ffmpeg_android/libavutil/adler32.h | 110 + .../include/ffmpeg_android/libavutil/aes.h | 130 + .../ffmpeg_android/libavutil/attributes.h | 83 +- .../ffmpeg_android/libavutil/audio_fifo.h | 306 + .../ffmpeg_android/libavutil/audioconvert.h | 12 + .../ffmpeg_android/libavutil/avassert.h | 132 + .../ffmpeg_android/libavutil/avconfig.h | 2 + .../ffmpeg_android/libavutil/avstring.h | 728 ++ .../include/ffmpeg_android/libavutil/avutil.h | 319 +- .../include/ffmpeg_android/libavutil/base64.h | 134 + .../ffmpeg_android/libavutil/blowfish.h | 154 + .../include/ffmpeg_android/libavutil/bprint.h | 432 + .../include/ffmpeg_android/libavutil/bswap.h | 218 + .../include/ffmpeg_android/libavutil/buffer.h | 548 + .../ffmpeg_android/libavutil/channel_layout.h | 444 + .../include/ffmpeg_android/libavutil/common.h | 360 +- .../include/ffmpeg_android/libavutil/cpu.h | 232 + .../include/ffmpeg_android/libavutil/crc.h | 172 + .../include/ffmpeg_android/libavutil/dict.h | 356 + .../ffmpeg_android/libavutil/display.h | 172 + .../ffmpeg_android/libavutil/downmix_info.h | 230 + .../include/ffmpeg_android/libavutil/error.h | 91 +- .../include/ffmpeg_android/libavutil/eval.h | 226 + .../ffmpeg_android/libavutil/ffversion.h | 8 + .../include/ffmpeg_android/libavutil/fifo.h | 316 + .../include/ffmpeg_android/libavutil/file.h | 132 + .../include/ffmpeg_android/libavutil/frame.h | 1518 +++ .../include/ffmpeg_android/libavutil/hash.h | 224 + .../include/ffmpeg_android/libavutil/hmac.h | 198 + .../ffmpeg_android/libavutil/imgutils.h | 426 + .../ffmpeg_android/libavutil/intfloat.h | 154 + .../libavutil/intfloat_readwrite.h | 16 +- .../ffmpeg_android/libavutil/intreadwrite.h | 1258 +++ .../include/ffmpeg_android/libavutil/lfg.h | 124 + .../include/ffmpeg_android/libavutil/log.h | 271 +- .../include/ffmpeg_android/libavutil/lzo.h | 132 + .../include/ffmpeg_android/libavutil/macros.h | 96 + .../ffmpeg_android/libavutil/mathematics.h | 82 +- .../include/ffmpeg_android/libavutil/md5.h | 162 + .../include/ffmpeg_android/libavutil/mem.h | 310 +- .../ffmpeg_android/libavutil/motion_vector.h | 100 + .../ffmpeg_android/libavutil/murmur3.h | 64 + .../ffmpeg_android/libavutil/old_pix_fmts.h | 354 + .../include/ffmpeg_android/libavutil/opt.h | 1718 ++++ .../ffmpeg_android/libavutil/parseutils.h | 374 + .../ffmpeg_android/libavutil/pixdesc.h | 718 ++ .../ffmpeg_android/libavutil/pixelutils.h | 104 + .../include/ffmpeg_android/libavutil/pixfmt.h | 566 +- .../ffmpeg_android/libavutil/random_seed.h | 86 + .../ffmpeg_android/libavutil/rational.h | 63 +- .../ffmpeg_android/libavutil/replaygain.h | 102 + .../include/ffmpeg_android/libavutil/ripemd.h | 150 + .../ffmpeg_android/libavutil/samplefmt.h | 558 + .../include/ffmpeg_android/libavutil/sha.h | 148 + .../include/ffmpeg_android/libavutil/sha512.h | 150 + .../ffmpeg_android/libavutil/stereo3d.h | 304 + .../ffmpeg_android/libavutil/threadmessage.h | 182 + .../include/ffmpeg_android/libavutil/time.h | 112 + .../ffmpeg_android/libavutil/timecode.h | 280 + .../ffmpeg_android/libavutil/timestamp.h | 156 + .../ffmpeg_android/libavutil/version.h | 310 + .../include/ffmpeg_android/libavutil/xtea.h | 128 + .../ffmpeg_android/libswscale/swscale.h | 169 +- .../ffmpeg_android/libswscale/version.h | 118 + extra_lib/include/js/jscpucfg.h | 108 +- extra_lib/include/js/jstypes.h | 2 +- extra_lib/include/openHevcWrapper.h | 10 +- fixEOL.sh | 12 - generate_installer.bat | 194 +- gui/extensions/H2B2VS/H2B2VS.png | Bin 0 -> 22850 bytes gui/extensions/H2B2VS/h2b2vs.js | 392 + gui/extensions/H2B2VS/init.js | 16 + gui/extensions/H2B2VS/logo_hd.png | Bin 0 -> 16123 bytes gui/extensions/H2B2VS/logo_uhd.png | Bin 0 -> 50515 bytes .../player}/applications-multimedia.svg | 0 gui/extensions/player/fileopen.js | 242 + gui/extensions/player/init.js | 15 + gui/extensions/player/player.js | 1436 +++ gui/extensions/player/playlist.js | 327 + gui/extensions/player/stats.js | 606 ++ gui/extensions/widget_manager/init.js | 1854 ++-- gui/gui.bt | 30 +- gui/gui.js | 1475 +-- gui/gui_old.js | 14 +- gui/gwlib.js | 5390 ++++++---- gui/icons/add.svg | 12 + gui/icons/app.svg | 35 + gui/icons/applications-internet.svg | 622 -- gui/icons/applications-system.svg | 247 - gui/icons/audio-volume-high.svg | 643 -- gui/icons/audio-volume-low.svg | 641 -- gui/icons/audio-volume-medium.svg | 646 -- gui/icons/audio-volume-muted.svg | 991 -- gui/icons/audio-x-generic.svg | 180 - gui/icons/audio.svg | 19 + gui/icons/audio_full.svg | 26 + gui/icons/audio_mute.svg | 12 + gui/icons/battery-caution.svg | 625 -- gui/icons/camera-photo.svg | 681 -- gui/icons/camera-video.svg | 1257 --- gui/icons/check.svg | 11 + gui/icons/close.svg | 16 + gui/icons/cross.svg | 13 + gui/icons/dialog-error.svg | 316 - gui/icons/dialog-information.svg | 1145 --- gui/icons/dialog-warning.svg | 359 - gui/icons/document-new.svg | 448 - gui/icons/document-print-preview.svg | 701 -- gui/icons/document-print.svg | 530 - gui/icons/document-save-as.svg | 661 -- gui/icons/document-save.svg | 617 -- gui/icons/down.svg | 9 + gui/icons/edit-find.svg | 750 -- gui/icons/emblem-symbolic-link.svg | 246 - gui/icons/emblem-unreadable.svg | 357 - gui/icons/expand.svg | 26 + gui/icons/face-surprise.svg | 254 - gui/icons/file.svg | 10 + gui/icons/film.svg | 27 + gui/icons/folder-open.svg | 482 - gui/icons/folder.svg | 435 +- gui/icons/go-bottom.svg | 225 - gui/icons/go-down.svg | 199 - gui/icons/go-first.svg | 203 - gui/icons/go-home.svg | 441 - gui/icons/go-jump.svg | 203 - gui/icons/go-last.svg | 203 - gui/icons/go-next.svg | 191 - gui/icons/go-previous.svg | 852 -- gui/icons/go-top.svg | 972 -- gui/icons/go-up.svg | 195 - gui/icons/harddrive.svg | 14 + gui/icons/heart.svg | 8 + gui/icons/home.svg | 11 + gui/icons/image-missing.svg | 318 - gui/icons/image.svg | 14 + gui/icons/info.svg | 14 + gui/icons/laptop.svg | 16 + gui/icons/left.svg | 9 + gui/icons/left_arrow.svg | 374 - gui/icons/list-add.svg | 434 - gui/icons/list-remove.svg | 422 - gui/icons/list.svg | 20 + gui/icons/live.svg | 21 + gui/icons/media-eject.svg | 439 - gui/icons/media-playback-pause.svg | 630 -- gui/icons/media-playback-start.svg | 308 - gui/icons/media-playback-stop.svg | 640 -- gui/icons/media-record.svg | 326 - gui/icons/media-seek-backward.svg | 363 - gui/icons/media-seek-forward.svg | 370 - gui/icons/media-skip-backward.svg | 1014 -- gui/icons/media-skip-forward.svg | 1002 -- gui/icons/media_next.svg | 12 + gui/icons/media_prev.svg | 12 + gui/icons/monitor.svg | 11 + gui/icons/more.svg | 9 + gui/icons/musical.svg | 14 + gui/icons/navigation.svg | 17 + gui/icons/network.svg | 27 + gui/icons/next.svg | 11 + gui/icons/osmo.svg | 26 + gui/icons/overflowing.svg | 30 + gui/icons/pause.svg | 12 + gui/icons/pl_next.svg | 16 + gui/icons/pl_prev.svg | 16 + gui/icons/play.svg | 10 + gui/icons/play_loop.svg | 16 + gui/icons/play_shuffle.svg | 17 + gui/icons/play_single.svg | 12 + gui/icons/power.svg | 14 + .../preferences-desktop-remote-desktop.svg | 1479 --- gui/icons/preferences-system-windows.svg | 386 - gui/icons/previous.svg | 11 + gui/icons/process-stop.svg | 334 - gui/icons/remove.svg | 10 + gui/icons/resize.svg | 14 + gui/icons/rewind.svg | 11 + gui/icons/right.svg | 9 + gui/icons/right_arrow.svg | 383 - gui/icons/seek_forward.svg | 11 + gui/icons/shrink.svg | 55 + gui/icons/sort.svg | 25 + gui/icons/speed.svg | 26 + gui/icons/star.svg | 11 + gui/icons/stop.svg | 10 + gui/icons/stop2.svg | 10 + gui/icons/tennis_ball.svg | 71 - gui/icons/tennis_black.svg | 50 - gui/icons/tennis_racket.svg | 64 - gui/icons/tennis_racket_color.svg | 68 - gui/icons/trash.svg | 16 + gui/icons/tray.svg | 14 + gui/icons/tv.svg | 21 + gui/icons/up.svg | 9 + gui/icons/user-trash.svg | 487 - gui/icons/video-display.svg | 487 - gui/icons/video-x-generic.svg | 318 - gui/icons/view-fullscreen.svg | 520 - gui/icons/world.svg | 64 + gui/iphone_wm_gui.js | 12 +- gui/webvtt-renderer.js | 562 +- include/gpac/avparse.h | 11 + include/gpac/bifs.h | 2 + include/gpac/bitstream.h | 6 +- include/gpac/cache.h | 6 +- include/gpac/color.h | 21 +- include/gpac/compositor.h | 10 +- include/gpac/configuration.h | 151 +- include/gpac/constants.h | 23 +- include/gpac/dash.h | 132 +- include/gpac/download.h | 32 +- include/gpac/events.h | 6 +- include/gpac/events_constants.h | 15 +- include/gpac/html5_mse.h | 4 + include/gpac/ietf.h | 9 +- include/gpac/internal/bifs_dev.h | 2 + include/gpac/internal/compositor_dev.h | 53 +- include/gpac/internal/dvb_mpe_dev.h | 8 +- include/gpac/internal/isomedia_dev.h | 138 +- include/gpac/internal/laser_dev.h | 1 + include/gpac/internal/m3u8.h | 183 +- include/gpac/internal/media_dev.h | 5 +- include/gpac/internal/mesh.h | 2 +- include/gpac/internal/mpd.h | 66 +- include/gpac/internal/scenegraph_dev.h | 27 +- include/gpac/internal/smjs_api.h | 60 +- include/gpac/internal/swf_dev.h | 12 +- include/gpac/internal/terminal_dev.h | 160 +- include/gpac/iso639.h | 533 +- include/gpac/isomedia.h | 157 +- include/gpac/{math.h => maths.h} | 2 +- include/gpac/media_tools.h | 48 +- include/gpac/mediaobject.h | 20 +- include/gpac/module.h | 77 +- include/gpac/modules/audio_out.h | 2 +- include/gpac/modules/codec.h | 10 +- include/gpac/modules/service.h | 94 +- include/gpac/modules/video_out.h | 4 +- include/gpac/mpeg4_odf.h | 13 +- include/gpac/mpegts.h | 59 +- include/gpac/network.h | 47 + include/gpac/options.h | 6 + include/gpac/path2d.h | 4 +- include/gpac/scene_manager.h | 23 +- include/gpac/scenegraph.h | 3 +- include/gpac/scenegraph_svg.h | 5 +- include/gpac/scenegraph_vrml.h | 14 +- include/gpac/setup.h | 25 +- include/gpac/sync_layer.h | 7 + include/gpac/term_info.h | 9 +- include/gpac/terminal.h | 14 +- include/gpac/thread.h | 8 +- include/gpac/token.h | 8 +- include/gpac/tools.h | 70 +- include/gpac/unicode.h | 4 +- include/gpac/user.h | 18 +- include/gpac/version.h | 10 +- include/gpac/webvtt.h | 6 +- include/gpac/xml.h | 16 + include/win32/inttypes.h | 38 +- mkdmg.sh | 42 +- modules/Makefile | 2 +- modules/aac_in/Makefile | 4 +- modules/aac_in/aac_in.c | 46 +- modules/aac_in/faad_dec.c | 10 +- modules/ac3_in/Makefile | 2 +- modules/ac3_in/ac3_in.c | 36 +- modules/alsa/Makefile | 2 +- modules/alsa/alsa.c | 2 +- modules/amr_dec/Makefile | 2 +- modules/amr_dec/amr_dec.c | 2 +- modules/amr_dec/amr_in.c | 16 +- modules/amr_float_dec/Makefile | 2 +- modules/amr_float_dec/amr_api.h | 68 +- modules/amr_float_dec/amr_float_dec.c | 2 +- modules/audio_filter/Makefile | 2 +- modules/audio_filter/audio_filter.c | 4 +- modules/avcap/Makefile | 2 +- modules/avcap/avcap.cpp | 2 +- modules/bifs_dec/Makefile | 4 +- modules/bifs_dec/bifs_dec.c | 2 +- modules/ctx_load/Makefile | 4 +- modules/ctx_load/ctx_load.c | 44 +- modules/dektec_out/Makefile | 58 + modules/dektec_out/dektec_video.cpp | 361 + modules/demo_is/Makefile | 2 +- modules/demo_is/demo_is.c | 2 +- modules/directfb_out/Makefile | 2 +- modules/directfb_out/directfb_out.c | 2 +- modules/droid_audio/droidaudio.c | 2 +- modules/droid_cam/droid_cam.c | 2 +- modules/droid_mpegv/droid_mpegv.c | 2 +- modules/droid_out/droid_vout-bitmap.c | 2 +- modules/droid_out/droid_vout.c | 43 +- modules/dummy_in/Makefile | 4 +- modules/dummy_in/dummy_in.c | 14 +- modules/dx_hw/Makefile | 2 +- modules/dx_hw/copy_pixels.c | 4 +- modules/dx_hw/dx_2d.c | 5 +- modules/dx_hw/dx_audio.c | 6 +- modules/dx_hw/dx_hw.h | 7 +- modules/dx_hw/dx_video.c | 114 +- modules/dx_hw/dx_window.c | 44 +- modules/epoc_hw/epoc_vout.cpp | 18 +- modules/ffmpeg_in/Makefile | 2 +- modules/ffmpeg_in/ffmpeg_decode.c | 51 +- modules/ffmpeg_in/ffmpeg_demux.c | 118 +- modules/ffmpeg_in/ffmpeg_in.h | 4 +- modules/ffmpeg_in/ffmpeg_load.c | 2 +- modules/freenect/Makefile | 2 +- modules/freenect/freenect.c | 2 +- modules/ft_font/Makefile | 4 +- modules/ft_font/ft_font.c | 155 +- modules/gapi/gapi.cpp | 26 +- modules/gapi/gapi.h | 4 +- modules/gdip_raster/gdip_font.cpp | 2 +- modules/gpac_js/Makefile | 2 +- modules/gpac_js/gpac_js.c | 1591 ++- modules/hyb_in/Makefile | 4 +- modules/hyb_in/hyb_in.c | 2 +- modules/img_in/Makefile | 4 +- modules/img_in/img_dec.c | 2 +- modules/img_in/img_in.c | 22 +- modules/ios_cam/ios_cam.c | 4 +- modules/ios_mpegv/ios_mpegv.c | 2 +- modules/ismacryp/Makefile | 4 +- modules/ismacryp/isma_ea.c | 43 +- modules/isom_in/Makefile | 4 +- modules/isom_in/isom_cache.c | 8 +- modules/isom_in/isom_in.h | 15 +- modules/isom_in/load.c | 11 +- modules/isom_in/read.c | 63 +- modules/isom_in/read_ch.c | 299 +- modules/jack/Makefile | 2 +- modules/jack/jack.c | 2 +- modules/laser_dec/Makefile | 4 +- modules/laser_dec/laser_dec.c | 2 +- modules/libplayer/Makefile | 2 +- modules/libplayer/libplayer.c | 2 +- modules/mp3_in/Makefile | 4 +- modules/mp3_in/mad_dec.c | 1 - modules/mp3_in/mp3_in.c | 40 +- modules/mpd_in/Makefile | 4 +- modules/mpd_in/mpd_in.c | 514 +- modules/mpegts_in/Makefile | 4 +- modules/mpegts_in/mpegts_in.c | 296 +- modules/mse_in/Makefile | 4 +- modules/mse_in/mse_in.c | 15 +- modules/odf_dec/Makefile | 4 +- modules/odf_dec/odf_dec.c | 4 +- modules/ogg/Makefile | 2 +- modules/ogg/ogg_in.c | 20 +- modules/ogg/ogg_load.c | 2 +- modules/opencv_is/Makefile | 2 +- modules/opencv_is/opencv_is.c | 2 +- modules/openhevc_dec/Makefile | 2 +- modules/openhevc_dec/openhevc_dec.c | 55 +- modules/opensvc_dec/Makefile | 2 +- modules/opensvc_dec/opensvc_dec.c | 5 +- modules/osd/Makefile | 2 +- modules/osd/osd.c | 9 +- modules/oss_audio/Makefile | 4 +- modules/oss_audio/oss.c | 2 +- modules/platinum/GPACFileMediaServer.cpp | 9 +- modules/platinum/GPACFileMediaServer.h | 5 +- modules/platinum/GPACMediaRenderer.h | 4 +- modules/platinum/GPACPlatinum.cpp | 20 +- modules/platinum/Makefile | 2 +- modules/pulseaudio/Makefile | 2 +- modules/pulseaudio/pulseaudio.c | 2 +- modules/raw_out/Makefile | 4 +- modules/raw_out/raw_video.c | 2 +- modules/redirect_av/Makefile | 2 +- modules/redirect_av/ffmpeg_ts_muxer.c | 4 +- modules/redirect_av/redirect_av.c | 6 +- modules/redirect_av/ts_muxer.h | 2 +- modules/rtp_in/Makefile | 4 +- modules/rtp_in/rtp_in.c | 6 +- modules/rtp_in/rtp_in.h | 4 + modules/rtp_in/rtp_stream.c | 43 +- modules/rtp_in/sdp_fetch.c | 10 +- modules/rtp_in/sdp_load.c | 4 +- modules/rvc_dec/Makefile | 2 +- modules/rvc_dec/rvc_dec.c | 8 +- modules/saf_in/Makefile | 4 +- modules/saf_in/saf_in.c | 12 +- modules/sdl_out/Makefile | 2 +- modules/sdl_out/sdl_out.c | 2 +- modules/sdl_out/sdl_out.h | 17 +- modules/sdl_out/video.c | 557 +- modules/soft_raster/Makefile | 4 +- modules/soft_raster/ftgrays.c | 10 +- modules/soft_raster/raster_argb.c | 7 + modules/soft_raster/raster_load.c | 2 +- modules/svg_in/Makefile | 4 +- modules/svg_in/svg_in.c | 16 +- modules/timedtext/Makefile | 4 +- modules/timedtext/timedtext_dec.c | 4 +- modules/ui_rec/Makefile | 2 +- modules/ui_rec/ui_rec.c | 8 +- modules/validator/Makefile | 49 + modules/validator/README.TXT | 90 +- modules/validator/validator.c | 164 +- modules/vtt_in/Makefile | 4 +- modules/vtt_in/vtt_dec.c | 20 +- modules/vtt_in/vtt_in.c | 21 +- modules/wav_out/Makefile | 2 +- modules/wav_out/wav_out.c | 2 +- modules/widgetman/Makefile | 2 +- modules/widgetman/unzip.c | 14 +- modules/widgetman/unzip.h | 2 +- modules/widgetman/wgt_load.c | 12 +- modules/widgetman/wgt_load_base.js | 4 +- modules/widgetman/widgetman.c | 26 +- modules/wiiis/Makefile | 2 +- modules/wiiis/wiiis.c | 2 +- modules/x11_out/Makefile | 4 +- modules/x11_out/x11_out.c | 19 +- modules/x11_out/x11_out.h | 2 +- modules/xvid_dec/Makefile | 2 +- modules/xvid_dec/xvid_dec.c | 2 +- modules/xvid_dec/xvid_dec_wce.cpp | 2 +- packagers/win32_64/nsis/gpac_installer.nsi | 1918 ++-- regression_tests/auxiliary_files/logo.bt | 252 +- regression_tests/auxiliary_files/subtitle.srt | 2 +- .../bifs/bifs-cachetexture_cache.bt | 180 +- .../bifs/bifs-cachetexture_nocache.bt | 114 +- regression_tests/bifs/bifs-environmenttest.bt | 258 +- regression_tests/bifs/bifs-keynavigator.bt | 440 +- .../bifs/bifs-misc-hc-proto-events.bt | 57 + regression_tests/bifs/bifs-storage.bt | 130 +- ...ifs-timeline-mediasensor-segment-switch.bt | 2 +- .../bifs/bifs-timeline-mediasensor-segment.bt | 2 +- .../bifs/bifs-timeline-mediasensor.bt | 2 +- .../html5_video/basic_arraybuffer.js | 40 +- regression_tests/html5_video/basic_audio.svg | 22 +- .../html5_video/basic_mediasource.js | 48 +- .../html5_video/basic_sourcebuffer.js | 104 +- regression_tests/html5_video/basic_url.js | 50 +- regression_tests/html5_video/basic_video.js | 160 +- regression_tests/html5_video/gpac-mse.js | 716 +- regression_tests/html5_video/video.svg | 58 +- regression_tests/html5_video/xhr.svg | 6 +- regression_tests/ttml/ebu-ttd_sample.ttml | 39 + .../ttml/ebu-ttd_sample_invalid_ns.ttml | 28 + .../ttml/ebu-ttd_sample_span.ttml | 29 + .../ttml/ebu-ttd_timing_contiguous.ttml | 30 + .../ttml/ebu-ttd_timing_non-contiguous.ttml | 30 + .../ttml/ebu-ttd_timing_overlapping_fail.ttml | 29 + regression_tests/webvtt/counter.vtt | 9004 ++++++++--------- regression_tests/webvtt/simple.vtt | 62 +- regression_tests/xmlin4/anim.swf | Bin 0 -> 6913 bytes regression_tests/xmlin4/ebu-ttd_sample.ttml | 39 + regression_tests/xmlin4/first.xml | 3 + regression_tests/xmlin4/input.txt | 13 + regression_tests/xmlin4/input.xml | 5 + regression_tests/xmlin4/last.xml | 3 + .../xmlin4/meta-mett-no-mime.nhml | 8 + .../xmlin4/meta-mett-xml-header.nhml | 6 + regression_tests/xmlin4/meta-mett-xml.nhml | 6 + regression_tests/xmlin4/meta-mett.nhml | 8 + .../xmlin4/meta-metx-no-namespace.nhml | 6 + regression_tests/xmlin4/meta-metx.nhml | 6 + regression_tests/xmlin4/run_one_test.sh | 21 + regression_tests/xmlin4/run_tests.sh | 59 + regression_tests/xmlin4/second.xml | 3 + .../xmlin4/subt-sbtt-no-mime.nhml | 6 + regression_tests/xmlin4/subt-sbtt.nhml | 6 + .../xmlin4/subt-stpp-no-namespace.nhml | 6 + regression_tests/xmlin4/subt-stpp.nhml | 6 + regression_tests/xmlin4/text-stxt-header.nhml | 7 + .../xmlin4/text-stxt-no-mime.nhml | 8 + regression_tests/xmlin4/text-stxt.nhml | 8 + src/Makefile | 32 +- src/bifs/bifs_codec.c | 32 +- src/bifs/bifs_node_tables.c | 78 - src/bifs/com_dec.c | 52 +- src/bifs/com_enc.c | 18 +- src/bifs/conditional.c | 2 +- src/bifs/field_decode.c | 44 +- src/bifs/field_encode.c | 61 +- src/bifs/memory_decoder.c | 16 +- src/bifs/quantize.c | 10 +- src/bifs/script_enc.c | 75 +- src/bifs/unquantize.c | 1 + src/compositor/audio_input.c | 95 +- src/compositor/audio_mixer.c | 30 +- src/compositor/audio_render.c | 155 +- src/compositor/compositor.c | 264 +- src/compositor/compositor_2d.c | 466 +- src/compositor/drawable.c | 124 +- src/compositor/events.c | 274 +- src/compositor/gl_inc.h | 17 +- src/compositor/hardcoded_protos.c | 92 + src/compositor/mesh.c | 2 +- src/compositor/mpeg4_audio.c | 70 +- src/compositor/mpeg4_background2d.c | 31 +- src/compositor/mpeg4_bitmap.c | 10 +- src/compositor/mpeg4_composite.c | 73 +- src/compositor/mpeg4_geometry_2d.c | 4 +- src/compositor/mpeg4_grouping.c | 23 +- src/compositor/mpeg4_layer_3d.c | 4 +- src/compositor/mpeg4_layout.c | 4 - src/compositor/mpeg4_lighting.c | 34 +- src/compositor/mpeg4_text.c | 4 + src/compositor/mpeg4_textures.c | 89 +- src/compositor/nodes_stacks.h | 1 + src/compositor/offscreen_cache.c | 4 +- src/compositor/svg_filters.c | 2 +- src/compositor/svg_media.c | 67 +- src/compositor/svg_text.c | 2 +- src/compositor/texturing.c | 23 +- src/compositor/texturing_gl.c | 69 +- src/compositor/visual_manager.c | 2 +- src/compositor/visual_manager.h | 15 +- src/compositor/visual_manager_2d.c | 6 +- src/compositor/visual_manager_2d.h | 1 + src/compositor/visual_manager_2d_draw.c | 22 +- src/compositor/visual_manager_3d.c | 20 +- src/compositor/visual_manager_3d.h | 4 +- src/compositor/visual_manager_3d_gl.c | 588 +- src/export.cpp | 139 +- src/ietf/rtcp.c | 2 +- src/ietf/rtp.c | 24 +- src/ietf/rtp_depacketizer.c | 11 +- src/ietf/rtp_packetizer.c | 2 +- src/ietf/rtp_pck_mpeg4.c | 2 +- src/ietf/rtp_streamer.c | 14 +- src/ietf/rtsp_session.c | 4 +- src/ietf/sdp.c | 3 + src/isomedia/avc_ext.c | 133 +- src/isomedia/box_code_3gpp.c | 14 - src/isomedia/box_code_adobe.c | 7 +- src/isomedia/box_code_base.c | 690 +- src/isomedia/box_code_drm.c | 10 + src/isomedia/box_code_meta.c | 2 +- src/isomedia/box_dump.c | 424 +- src/isomedia/box_funcs.c | 117 +- src/isomedia/data_map.c | 50 +- src/isomedia/drm_sample.c | 2 +- src/isomedia/isom_intern.c | 7 + src/isomedia/isom_read.c | 285 +- src/isomedia/isom_store.c | 26 +- src/isomedia/isom_write.c | 496 +- src/isomedia/media.c | 50 +- src/isomedia/media_odf.c | 2 +- src/isomedia/meta.c | 36 +- src/isomedia/movie_fragments.c | 145 +- src/isomedia/sample_descs.c | 524 +- src/isomedia/stbl_read.c | 22 +- src/isomedia/stbl_write.c | 34 +- src/isomedia/track.c | 29 +- src/isomedia/ttml.c | 243 +- src/isomedia/tx3g.c | 6 +- src/laser/lsr_dec.c | 1 - src/laser/lsr_enc.c | 363 +- src/mcrypt/g_crypt.c | 16 +- src/media_tools/av_parsers.c | 271 +- src/media_tools/avilib.c | 104 +- src/media_tools/dash_client.c | 2340 +++-- src/media_tools/dash_segmenter.c | 2185 ++-- src/media_tools/dsmcc.c | 4 +- src/media_tools/dvb_mpe.c | 30 +- src/media_tools/filestreamer.c | 20 +- src/media_tools/html5_mse.c | 7 +- src/media_tools/img.c | 29 +- src/media_tools/ismacryp.c | 115 +- src/media_tools/isom_hinter.c | 22 +- src/media_tools/isom_tools.c | 108 +- src/media_tools/m2ts_mux.c | 59 +- src/media_tools/m3u8.c | 1304 ++- src/media_tools/media_export.c | 543 +- src/media_tools/media_import.c | 1381 ++- src/media_tools/mpd.c | 1524 ++- src/media_tools/mpeg2_ps.c | 24 +- src/media_tools/mpegts.c | 980 +- src/media_tools/text_import.c | 730 +- src/media_tools/webvtt.c | 265 +- src/odf/desc_private.c | 9 +- src/odf/ipmpx_parse.c | 12 +- src/odf/odf_code.c | 7 +- src/odf/odf_parse.c | 16 +- src/scene_manager/encode_isom.c | 39 +- src/scene_manager/loader_bt.c | 56 +- src/scene_manager/loader_isom.c | 4 +- src/scene_manager/loader_qt.c | 4 +- src/scene_manager/loader_svg.c | 24 +- src/scene_manager/loader_xmt.c | 19 +- src/scene_manager/scene_dump.c | 38 +- src/scene_manager/scene_engine.c | 16 +- src/scene_manager/scene_manager.c | 10 +- src/scene_manager/swf_bifs.c | 18 +- src/scene_manager/swf_parse.c | 46 +- src/scene_manager/swf_svg.c | 38 +- src/scene_manager/text_to_bifs.c | 16 +- src/scenegraph/base_scenegraph.c | 27 +- src/scenegraph/commands.c | 7 +- src/scenegraph/dom_events.c | 2 +- src/scenegraph/dom_smjs.c | 59 +- src/scenegraph/svg_attributes.c | 215 +- src/scenegraph/svg_smjs.c | 16 +- src/scenegraph/vrml_proto.c | 34 +- src/scenegraph/vrml_route.c | 47 + src/scenegraph/vrml_smjs.c | 881 +- src/scenegraph/vrml_tools.c | 8 +- src/scenegraph/webvtt_smjs.c | 5 +- src/scenegraph/xml_ns.c | 18 +- src/terminal/channel.c | 297 +- src/terminal/clock.c | 91 +- src/terminal/decoder.c | 302 +- src/terminal/media_control.c | 111 +- src/terminal/media_control.h | 4 +- src/terminal/media_manager.c | 59 +- src/terminal/media_memory.c | 44 +- src/terminal/media_memory.h | 10 +- src/terminal/media_object.c | 388 +- src/terminal/media_sensor.c | 20 +- src/terminal/mpeg4_inline.c | 21 +- src/terminal/network_service.c | 135 +- src/terminal/object_browser.c | 85 +- src/terminal/object_manager.c | 291 +- src/terminal/scene.c | 767 +- src/terminal/terminal.c | 275 +- src/utils/alloc.c | 76 +- src/utils/base_encoding.c | 6 +- src/utils/bitstream.c | 36 +- src/utils/cache.c | 86 +- src/utils/color.c | 211 +- src/utils/configfile.c | 18 +- src/utils/downloader.c | 771 +- src/utils/error.c | 566 +- src/utils/gzio.cpp | 4 +- src/utils/math.c | 2 +- src/utils/module.c | 38 +- src/utils/os_config_init.c | 173 +- src/utils/os_divers.c | 824 +- src/utils/os_file.c | 681 ++ src/utils/os_net.c | 127 +- src/utils/os_thread.c | 60 +- src/utils/path2d.c | 4 +- src/utils/sha1.c | 18 +- src/utils/symbian_os.cpp | 18 +- src/utils/token.c | 2 +- src/utils/url.c | 15 +- src/utils/xml_parser.c | 348 +- src/utils/zutil.c | 1 + version.bat | 40 +- 758 files changed, 83431 insertions(+), 62999 deletions(-) create mode 100644 .gitattributes create mode 100644 .travis.yml create mode 100644 applications/mp4client/carbon_events.c create mode 100644 extra_lib/include/DTAPI.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/avfft.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/dv_profile.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/dxva2.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/old_codec_ids.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/vaapi.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/vda.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/vdpau.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/version.h create mode 100644 extra_lib/include/ffmpeg_android/libavcodec/xvmc.h create mode 100644 extra_lib/include/ffmpeg_android/libavformat/version.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/adler32.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/aes.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/audio_fifo.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/audioconvert.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/avassert.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/avstring.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/base64.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/blowfish.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/bprint.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/bswap.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/buffer.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/channel_layout.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/cpu.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/crc.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/dict.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/display.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/downmix_info.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/eval.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/ffversion.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/fifo.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/file.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/frame.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/hash.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/hmac.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/imgutils.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/intfloat.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/intreadwrite.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/lfg.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/lzo.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/macros.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/md5.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/motion_vector.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/murmur3.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/old_pix_fmts.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/opt.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/parseutils.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/pixdesc.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/pixelutils.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/random_seed.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/replaygain.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/ripemd.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/samplefmt.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/sha.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/sha512.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/stereo3d.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/threadmessage.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/time.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/timecode.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/timestamp.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/version.h create mode 100644 extra_lib/include/ffmpeg_android/libavutil/xtea.h create mode 100644 extra_lib/include/ffmpeg_android/libswscale/version.h delete mode 100644 fixEOL.sh create mode 100644 gui/extensions/H2B2VS/H2B2VS.png create mode 100644 gui/extensions/H2B2VS/h2b2vs.js create mode 100644 gui/extensions/H2B2VS/init.js create mode 100644 gui/extensions/H2B2VS/logo_hd.png create mode 100644 gui/extensions/H2B2VS/logo_uhd.png rename gui/{icons => extensions/player}/applications-multimedia.svg (100%) create mode 100644 gui/extensions/player/fileopen.js create mode 100644 gui/extensions/player/init.js create mode 100644 gui/extensions/player/player.js create mode 100644 gui/extensions/player/playlist.js create mode 100644 gui/extensions/player/stats.js create mode 100644 gui/icons/add.svg create mode 100644 gui/icons/app.svg delete mode 100644 gui/icons/applications-internet.svg delete mode 100644 gui/icons/applications-system.svg delete mode 100644 gui/icons/audio-volume-high.svg delete mode 100644 gui/icons/audio-volume-low.svg delete mode 100644 gui/icons/audio-volume-medium.svg delete mode 100644 gui/icons/audio-volume-muted.svg delete mode 100644 gui/icons/audio-x-generic.svg create mode 100644 gui/icons/audio.svg create mode 100644 gui/icons/audio_full.svg create mode 100644 gui/icons/audio_mute.svg delete mode 100644 gui/icons/battery-caution.svg delete mode 100644 gui/icons/camera-photo.svg delete mode 100644 gui/icons/camera-video.svg create mode 100644 gui/icons/check.svg create mode 100644 gui/icons/close.svg create mode 100644 gui/icons/cross.svg delete mode 100644 gui/icons/dialog-error.svg delete mode 100644 gui/icons/dialog-information.svg delete mode 100644 gui/icons/dialog-warning.svg delete mode 100644 gui/icons/document-new.svg delete mode 100644 gui/icons/document-print-preview.svg delete mode 100644 gui/icons/document-print.svg delete mode 100644 gui/icons/document-save-as.svg delete mode 100644 gui/icons/document-save.svg create mode 100644 gui/icons/down.svg delete mode 100644 gui/icons/edit-find.svg delete mode 100644 gui/icons/emblem-symbolic-link.svg delete mode 100644 gui/icons/emblem-unreadable.svg create mode 100644 gui/icons/expand.svg delete mode 100644 gui/icons/face-surprise.svg create mode 100644 gui/icons/file.svg create mode 100644 gui/icons/film.svg delete mode 100644 gui/icons/folder-open.svg delete mode 100644 gui/icons/go-bottom.svg delete mode 100644 gui/icons/go-down.svg delete mode 100644 gui/icons/go-first.svg delete mode 100644 gui/icons/go-home.svg delete mode 100644 gui/icons/go-jump.svg delete mode 100644 gui/icons/go-last.svg delete mode 100644 gui/icons/go-next.svg delete mode 100644 gui/icons/go-previous.svg delete mode 100644 gui/icons/go-top.svg delete mode 100644 gui/icons/go-up.svg create mode 100644 gui/icons/harddrive.svg create mode 100644 gui/icons/heart.svg create mode 100644 gui/icons/home.svg delete mode 100644 gui/icons/image-missing.svg create mode 100644 gui/icons/image.svg create mode 100644 gui/icons/info.svg create mode 100644 gui/icons/laptop.svg create mode 100644 gui/icons/left.svg delete mode 100644 gui/icons/left_arrow.svg delete mode 100644 gui/icons/list-add.svg delete mode 100644 gui/icons/list-remove.svg create mode 100644 gui/icons/list.svg create mode 100644 gui/icons/live.svg delete mode 100644 gui/icons/media-eject.svg delete mode 100644 gui/icons/media-playback-pause.svg delete mode 100644 gui/icons/media-playback-start.svg delete mode 100644 gui/icons/media-playback-stop.svg delete mode 100644 gui/icons/media-record.svg delete mode 100644 gui/icons/media-seek-backward.svg delete mode 100644 gui/icons/media-seek-forward.svg delete mode 100644 gui/icons/media-skip-backward.svg delete mode 100644 gui/icons/media-skip-forward.svg create mode 100644 gui/icons/media_next.svg create mode 100644 gui/icons/media_prev.svg create mode 100644 gui/icons/monitor.svg create mode 100644 gui/icons/more.svg create mode 100644 gui/icons/musical.svg create mode 100644 gui/icons/navigation.svg create mode 100644 gui/icons/network.svg create mode 100644 gui/icons/next.svg create mode 100644 gui/icons/osmo.svg create mode 100644 gui/icons/overflowing.svg create mode 100644 gui/icons/pause.svg create mode 100644 gui/icons/pl_next.svg create mode 100644 gui/icons/pl_prev.svg create mode 100644 gui/icons/play.svg create mode 100644 gui/icons/play_loop.svg create mode 100644 gui/icons/play_shuffle.svg create mode 100644 gui/icons/play_single.svg create mode 100644 gui/icons/power.svg delete mode 100644 gui/icons/preferences-desktop-remote-desktop.svg delete mode 100644 gui/icons/preferences-system-windows.svg create mode 100644 gui/icons/previous.svg delete mode 100644 gui/icons/process-stop.svg create mode 100644 gui/icons/remove.svg create mode 100644 gui/icons/resize.svg create mode 100644 gui/icons/rewind.svg create mode 100644 gui/icons/right.svg delete mode 100644 gui/icons/right_arrow.svg create mode 100644 gui/icons/seek_forward.svg create mode 100644 gui/icons/shrink.svg create mode 100644 gui/icons/sort.svg create mode 100644 gui/icons/speed.svg create mode 100644 gui/icons/star.svg create mode 100644 gui/icons/stop.svg create mode 100644 gui/icons/stop2.svg delete mode 100644 gui/icons/tennis_ball.svg delete mode 100644 gui/icons/tennis_black.svg delete mode 100644 gui/icons/tennis_racket.svg delete mode 100644 gui/icons/tennis_racket_color.svg create mode 100644 gui/icons/trash.svg create mode 100644 gui/icons/tray.svg create mode 100644 gui/icons/tv.svg create mode 100644 gui/icons/up.svg delete mode 100644 gui/icons/user-trash.svg delete mode 100644 gui/icons/video-display.svg delete mode 100644 gui/icons/video-x-generic.svg delete mode 100644 gui/icons/view-fullscreen.svg create mode 100644 gui/icons/world.svg rename include/gpac/{math.h => maths.h} (99%) create mode 100644 modules/dektec_out/Makefile create mode 100644 modules/dektec_out/dektec_video.cpp create mode 100644 modules/validator/Makefile create mode 100644 regression_tests/bifs/bifs-misc-hc-proto-events.bt create mode 100644 regression_tests/ttml/ebu-ttd_sample.ttml create mode 100644 regression_tests/ttml/ebu-ttd_sample_invalid_ns.ttml create mode 100644 regression_tests/ttml/ebu-ttd_sample_span.ttml create mode 100644 regression_tests/ttml/ebu-ttd_timing_contiguous.ttml create mode 100644 regression_tests/ttml/ebu-ttd_timing_non-contiguous.ttml create mode 100644 regression_tests/ttml/ebu-ttd_timing_overlapping_fail.ttml create mode 100644 regression_tests/xmlin4/anim.swf create mode 100644 regression_tests/xmlin4/ebu-ttd_sample.ttml create mode 100644 regression_tests/xmlin4/first.xml create mode 100644 regression_tests/xmlin4/input.txt create mode 100644 regression_tests/xmlin4/input.xml create mode 100644 regression_tests/xmlin4/last.xml create mode 100644 regression_tests/xmlin4/meta-mett-no-mime.nhml create mode 100644 regression_tests/xmlin4/meta-mett-xml-header.nhml create mode 100644 regression_tests/xmlin4/meta-mett-xml.nhml create mode 100644 regression_tests/xmlin4/meta-mett.nhml create mode 100644 regression_tests/xmlin4/meta-metx-no-namespace.nhml create mode 100644 regression_tests/xmlin4/meta-metx.nhml create mode 100644 regression_tests/xmlin4/run_one_test.sh create mode 100644 regression_tests/xmlin4/run_tests.sh create mode 100644 regression_tests/xmlin4/second.xml create mode 100644 regression_tests/xmlin4/subt-sbtt-no-mime.nhml create mode 100644 regression_tests/xmlin4/subt-sbtt.nhml create mode 100644 regression_tests/xmlin4/subt-stpp-no-namespace.nhml create mode 100644 regression_tests/xmlin4/subt-stpp.nhml create mode 100644 regression_tests/xmlin4/text-stxt-header.nhml create mode 100644 regression_tests/xmlin4/text-stxt-no-mime.nhml create mode 100644 regression_tests/xmlin4/text-stxt.nhml create mode 100644 src/utils/os_file.c diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f8c796f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,19 @@ +* text=auto + +*.c text +*.cpp text +*.h text +*.ttx text +Makefile text + +#unix +*.sh text eol=lf +configure text eol=lf + +#windows +*.bat text eol=crlf +*.sln text eol=crlf +*.vcproj text eol=crlf +*.vcxproj text eol=crlf +*.dsp text eol=crlf +*.dsw text eol=crlf diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1f2675f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: c +compiler: gcc +before_install: + - sudo apt-get update -qq +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 +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 diff --git a/INSTALLME b/INSTALLME index d648cae..d6d61b0 100644 --- a/INSTALLME +++ b/INSTALLME @@ -1,13 +1,15 @@ -Installation instructions for latest GPAC svn version and GPAC release 0.5.0 - May 2012: +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 Android, follow the instructions in gpac/build/android/README -For WindowsMobile platform, get the latest package of gpac extra libs available on GPAC svn: -http://gpac.svn.sourceforge.net/viewvc/gpac/trunk/gpac_extra_libs/gpac_extra_libs.zip -and follow the instructions in gpac/doc/INSTALL.wCE +(WindowsMobile platform i sno 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/ +and follow the instructions in gpac/doc/INSTALL.wCE @@ -21,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 is gpac_extra_libs available at sourceforge: -http://gpac.svn.sourceforge.net/viewvc/gpac/trunk/gpac_extra_libs/gpac_extra_libs.zip?view=log + 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/ 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. @@ -40,18 +42,24 @@ http://gpac.svn.sourceforge.net/viewvc/gpac/trunk/gpac_extra_libs/gpac_extra_lib * Installing GPAC -/!\ GPAC won't compile if the 'svnversion' command (shipped with every Subversion package) is not in your path /!\ +/!\ GPAC won't compile if the 'git' command is not in your path /!\ + +!! WARNING !! +The following instructions may not be completely up to data +You should use online instructions which may be more up-to-date: +http://gpac.io/2011/04/18/command-line-gpac-compiling-on-windows-x86-using-free-microsoft-visual-c/ -!!OUTDATED - please see online instructions instead!! Detailed instruction for Win32 MSVC Compilation are available in gpac/doc/INSTALL.w32 Detailed instruction for WinCE eVC Compilation are available in gpac/doc/INSTALL.wCE -s + Detailed instruction for GCC Compilation are available in gpac/doc/INSTALL.gcc Detailed instruction for GCC cross-compilation for familiar+GPE systems are available in gpac/doc/INSTALL.gpe Detailed instruction for GCCE/Symbian cross-compilation for Symbian v9.1 systems are available in gpac/doc/INSTALL.symbian + +Detailed instruction for iOS Compilation are available in gpac/build/xcode/README_IOS.txt * Configuring GPAC diff --git a/Makefile b/Makefile index 77f440e..62b7850 100644 --- a/Makefile +++ b/Makefile @@ -8,21 +8,24 @@ vpath %.c $(SRC_PATH) all: version $(MAKE) -C src all $(MAKE) -C applications all +ifneq ($(MP4BOX_STATIC),yes) $(MAKE) -C modules all +endif -SVNREV_PATH:=$(SRC_PATH)/include/gpac/revision.h +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") version: - @if [ -d $(SRC_PATH)/".svn" ]; then \ - if which svnversion >/dev/null; then \ - echo "#define GPAC_SVN_REVISION \"$(shell svnversion $(SRC_PATH) )\"" > $(SVNREV_PATH).new ; \ - if ! diff -q $(SVNREV_PATH) $(SVNREV_PATH).new >/dev/null ; then \ - mv $(SVNREV_PATH).new $(SVNREV_PATH) ; \ - fi ; \ - fi \ + @if [ -d $(SRC_PATH)/".git" ]; then \ + echo "#define GPAC_GIT_REVISION \"$(VERSION)-$(BRANCH)\"" > $(GITREV_PATH).new; \ + if ! diff -q $(GITREV_PATH) $(GITREV_PATH).new >/dev/null ; then \ + mv $(GITREV_PATH).new $(GITREV_PATH); \ + fi; \ else \ - echo "No SVN Version found" ; \ - fi \ + echo "No GIT Version found" ; \ + fi lib: version $(MAKE) -C src all @@ -38,7 +41,7 @@ mods: instmoz: $(MAKE) -C applications/osmozilla install - + depend: $(MAKE) -C src dep $(MAKE) -C applications dep @@ -55,6 +58,21 @@ distclean: $(MAKE) -C modules distclean rm -f config.mak config.h +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 + dep: depend # tar release (use 'make -k tar' on a checkouted tree) @@ -71,24 +89,31 @@ install: ifeq ($(DISABLE_ISOFF), no) ifeq ($(CONFIG_LINUX), yes) ifneq ($(CONFIG_FFMPEG), no) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/DashCast "$(DESTDIR)$(prefix)/bin" + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/DashCast$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" endif endif endif ifeq ($(DISABLE_ISOFF), no) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Box "$(DESTDIR)$(prefix)/bin" + $(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 "$(DESTDIR)$(prefix)/bin" + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Client$(EXE_SUFFIX) "$(DESTDIR)$(prefix)/bin" +endif endif if [ -d $(DESTDIR)$(prefix)/$(libdir)/pkgconfig ] ; then \ $(INSTALL) $(INSTFLAGS) -m 644 gpac.pc "$(DESTDIR)$(prefix)/$(libdir)/pkgconfig" ; \ fi $(INSTALL) -d "$(DESTDIR)$(moddir)" - $(INSTALL) bin/gcc/*.$(DYN_LIB_SUFFIX) "$(DESTDIR)$(moddir)" - rm -f $(DESTDIR)$(moddir)/libgpac.$(DYN_LIB_SUFFIX) - rm -f $(DESTDIR)$(moddir)/nposmozilla.$(DYN_LIB_SUFFIX) +ifneq ($(MP4BOX_STATIC),yes) + $(INSTALL) bin/gcc/*$(DYN_LIB_SUFFIX) "$(DESTDIR)$(moddir)" + rm -f $(DESTDIR)$(moddir)/libgpac$(DYN_LIB_SUFFIX) + rm -f $(DESTDIR)$(moddir)/nposmozilla$(DYN_LIB_SUFFIX) $(MAKE) installdylib +endif $(INSTALL) -d "$(DESTDIR)$(mandir)" $(INSTALL) -d "$(DESTDIR)$(mandir)/man1"; if [ -d doc ] ; then \ @@ -107,16 +132,50 @@ endif $(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/*.svn" ; \ + rm -rf "$(DESTDIR)$(prefix)/share/gpac/gui/extensions/*.git" ; \ fi +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) +endif +ifneq ($(MP4BOX_STATIC),yes) +ifeq ($(DISABLE_PLAYER), no) + ln -sf $(BUILD_PATH)/bin/gcc/MP4Client$(EXE_SUFFIX) $(DESTDIR)$(prefix)/bin/MP4Client$(EXE_SUFFIX) +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) + ln -sf $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_MAJOR) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX) +else + ln -s $(BUILD_PATH)/bin/gcc/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) + ln -sf $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so.$(VERSION_MAJOR) + ln -sf $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so +ifeq ($(DESTDIR)$(prefix),$(prefix)) + ldconfig || true +endif +endif + uninstall: $(MAKE) -C applications uninstall rm -rf $(DESTDIR)$(moddir) rm -rf $(DESTDIR)$(prefix)/$(libdir)/libgpac* +ifeq ($(CONFIG_WIN32),yes) + rm -rf "$(DESTDIR)$(prefix)/bin/libgpac*" +endif rm -rf $(DESTDIR)$(prefix)/$(libdir)/pkgconfig/gpac.pc rm -rf $(DESTDIR)$(prefix)/bin/MP4Box rm -rf $(DESTDIR)$(prefix)/bin/MP4Client + rm -rf $(DESTDIR)$(prefix)/bin/MP42TS rm -rf $(DESTDIR)$(prefix)/bin/DashCast rm -rf $(DESTDIR)$(mandir)/man1/mp4box.1 rm -rf $(DESTDIR)$(mandir)/man1/mp4client.1 @@ -125,24 +184,27 @@ uninstall: rm -rf $(DESTDIR)$(prefix)/include/gpac installdylib: +ifneq ($(MP4BOX_STATIC),yes) ifeq ($(CONFIG_WIN32),yes) - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll $(prefix)/$(libdir) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll.a $(DESTDIR)$(prefix)/$(libdir) + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.dll $(DESTDIR)$(prefix)/bin else ifeq ($(DEBUGBUILD),no) - $(STRIP) bin/gcc/libgpac.$(DYN_LIB_SUFFIX) + $(STRIP) bin/gcc/libgpac$(DYN_LIB_SUFFIX) endif ifeq ($(CONFIG_DARWIN),yes) - $(INSTALL) -m 755 bin/gcc/libgpac.$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(VERSION).$(DYN_LIB_SUFFIX) - ln -sf libgpac.$(VERSION).$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(DYN_LIB_SUFFIX) + $(INSTALL) -m 755 bin/gcc/libgpac$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(VERSION)$(DYN_LIB_SUFFIX) + ln -sf libgpac.$(VERSION)$(DYN_LIB_SUFFIX) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX) else - $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) - ln -sf libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so.$(VERSION_MAJOR) - ln -sf libgpac.$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so + $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) + ln -sf libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so.$(VERSION_MAJOR) + ln -sf libgpac$(DYN_LIB_SUFFIX).$(VERSION_SONAME) $(DESTDIR)$(prefix)/$(libdir)/libgpac.so ifeq ($(DESTDIR)$(prefix),$(prefix)) ldconfig || true endif endif endif +endif install-lib: mkdir -p "$(DESTDIR)$(prefix)/include/gpac" @@ -168,20 +230,30 @@ uninstall-lib: ifeq ($(CONFIG_DARWIN),yes) dmg: + @if [ ! -z "$(shell git diff master..origin/master)" ]; 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; \ + fi rm "bin/gcc/MP4Client" $(MAKE) -C applications/mp4client - ./mkdmg.sh + ./mkdmg.sh $(arch) endif ifeq ($(CONFIG_LINUX),yes) deb: + @if [ ! -z "$(shell git diff master..origin/master)" ]; 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; \ + fi + git checkout -- debian/changelog fakeroot debian/rules clean - sed -i "s/.DEV/.DEV-r`svnversion \"$(SRC_PATH)\"`/" debian/changelog + sed -i "s/-DEV/-DEV-rev$(VERSION)-$(BRANCH)/" debian/changelog fakeroot debian/rules configure fakeroot debian/rules binary rm -rf debian/ - svn cleanup - svn up + git checkout debian endif help: diff --git a/README b/README index ccb6ea6..1e52c00 100644 --- a/README +++ b/README @@ -11,7 +11,8 @@ 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 on sourceforge: - http://gpac.sourceforge.net +For more information, visit the GPAC website: + http://gpac.io + diff --git a/applications/Makefile b/applications/Makefile index da358cb..e60a811 100644 --- a/applications/Makefile +++ b/applications/Makefile @@ -2,13 +2,21 @@ include ../config.mak APPDIRS= +ifeq ($(MP4BOX_STATIC),yes) +APPDIRS+=mp4box +else + ifeq ($(DISABLE_PLAYER), no) APPDIRS+=mp4client endif - ifeq ($(DISABLE_ISOFF), no) APPDIRS+=mp4box +ifeq ($(DISABLE_M2TS_MUX), no) +APPDIRS+=mp42ts +endif + +ifneq ($(CONFIG_WIN32), yes) ifneq ($(CONFIG_FFMPEG), no) ifneq ($(DISABLE_CORE_TOOLS), yes) ifneq ($(DISABLE_AV_PARSERS), yes) @@ -16,9 +24,9 @@ APPDIRS+=dashcast endif endif endif -ifeq ($(DISABLE_M2TS_MUX), no) -APPDIRS+=mp42ts endif + + endif V4STUDIODIR= @@ -36,11 +44,13 @@ ifeq ($(USE_WXWIDGETS), yes) #INSTDIRS+=osmo4_wx endif +#MP4BOX_STATIC +endif + ALLDIRS=$(APPDIRS) all: apps - apps: set -e; for i in $(APPDIRS) ; do $(MAKE) -C $$i all; done diff --git a/applications/dashcast/Makefile b/applications/dashcast/Makefile index 0b2bb02..89eeeda 100644 --- a/applications/dashcast/Makefile +++ b/applications/dashcast/Makefile @@ -29,6 +29,7 @@ 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 diff --git a/applications/dashcast/audio_data.h b/applications/dashcast/audio_data.h index 2c78c3e..c2b4e35 100644 --- a/applications/dashcast/audio_data.h +++ b/applications/dashcast/audio_data.h @@ -85,7 +85,7 @@ typedef struct { /* audio codec */ char codec[GF_MAX_PATH]; /* custom parameter to be passed directly to the encoder - free it once you're done */ - char *custom; + char custom[GF_MAX_PATH]; /* used for source switching */ char source_id[GF_MAX_PATH]; diff --git a/applications/dashcast/audio_decoder.c b/applications/dashcast/audio_decoder.c index 76a84c8..b5fc1bf 100644 --- a/applications/dashcast/audio_decoder.c +++ b/applications/dashcast/audio_decoder.c @@ -147,15 +147,16 @@ static int resample_audio(AudioInputFile *audio_input_file, AudioInputData *audi *num_planes_out = av_sample_fmt_is_planar(DC_AUDIO_SAMPLE_FORMAT) ? DC_AUDIO_NUM_CHANNELS : 1; *output = (uint8_t**)av_malloc(*num_planes_out*sizeof(uint8_t*)); for (i=0; i<*num_planes_out; i++) { - *output[i] = (uint8_t*)av_malloc(DC_AUDIO_MAX_CHUNCK_SIZE); //FIXME: fix using size below av_samples_get_buffer_size() + (*output) [i] = (uint8_t*)av_malloc(DC_AUDIO_MAX_CHUNCK_SIZE); //FIXME: fix using size below av_samples_get_buffer_size() } - if (avresample_convert(audio_input_file->aresampler, *output, DC_AUDIO_MAX_CHUNCK_SIZE, audio_input_data->aframe->nb_samples, audio_input_data->aframe->extended_data, audio_input_data->aframe->linesize[0], audio_input_data->aframe->nb_samples) < 0) { + i = avresample_convert(audio_input_file->aresampler, *output, DC_AUDIO_MAX_CHUNCK_SIZE, audio_input_data->aframe->nb_samples, audio_input_data->aframe->extended_data, audio_input_data->aframe->linesize[0], audio_input_data->aframe->nb_samples); + if (i < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not resample audio frame. Aborting.\n")); return -1; } - return 0; + return i; } #endif @@ -288,16 +289,18 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi exit(1); #else uint8_t **output; + int nb_samp; if (ensure_resampler(audio_input_file, sample_rate, num_channels, channel_layout, sample_format)) { return -1; } - if (resample_audio(audio_input_file, audio_input_data, codec_ctx, &output, &num_planes_out, num_channels, sample_format)) { + 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; - } else { - data = output; - av_samples_get_buffer_size(&data_size, num_channels, audio_input_data->aframe->nb_samples, sample_format, 0); - } + } + + av_samples_get_buffer_size(&data_size, DC_AUDIO_NUM_CHANNELS, nb_samp, DC_AUDIO_SAMPLE_FORMAT, 0); + data = output; #endif } else { /*no resampling needed: read data from the AVFrame*/ @@ -344,7 +347,7 @@ int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audi dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf); } } - + #ifdef DC_AUDIO_RESAMPLER if (resample) { int i; diff --git a/applications/dashcast/audio_encoder.c b/applications/dashcast/audio_encoder.c index f277d73..c0d6a79 100644 --- a/applications/dashcast/audio_encoder.c +++ b/applications/dashcast/audio_encoder.c @@ -54,11 +54,12 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud audio_output_file->codec_ctx->codec_id = audio_output_file->codec->id; 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 = audio_data_conf->samplerate; + audio_output_file->codec_ctx->sample_rate = DC_AUDIO_SAMPLE_RATE /*audio_data_conf->samplerate*/; + { AVRational time_base; time_base.num = 1; - time_base.den = audio_data_conf->samplerate; + time_base.den = audio_output_file->codec_ctx->sample_rate; audio_output_file->codec_ctx->time_base = time_base; } audio_output_file->codec_ctx->channels = audio_data_conf->channels; @@ -69,8 +70,6 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud #endif if (audio_data_conf->custom) { build_dict(audio_output_file->codec_ctx->priv_data, audio_data_conf->custom); - gf_free(audio_data_conf->custom); - audio_data_conf->custom = NULL; } audio_output_file->astream_idx = 0; @@ -96,7 +95,7 @@ int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *aud audio_output_file->aframe->nb_samples = audio_output_file->codec_ctx->frame_size; if (avcodec_fill_audio_frame(audio_output_file->aframe, audio_output_file->codec_ctx->channels, audio_output_file->codec_ctx->sample_fmt, - audio_output_file->adata_buf, audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * audio_output_file->codec_ctx->channels, 1) < 0) { + audio_output_file->adata_buf, audio_output_file->codec_ctx->frame_size * av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * audio_output_file->codec_ctx->channels, 1) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Fill audio frame failed\n")); return -1; } @@ -301,7 +300,7 @@ int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData * #endif return -1; } - + #ifdef DC_AUDIO_RESAMPLER if (resample) { int i; diff --git a/applications/dashcast/audio_muxer.c b/applications/dashcast/audio_muxer.c index 8ca4eae..50ae59e 100644 --- a/applications/dashcast/audio_muxer.c +++ b/applications/dashcast/audio_muxer.c @@ -26,6 +26,7 @@ #include "audio_muxer.h" #include "libavformat/avio.h" +#ifndef GPAC_DISABLE_ISOM int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename) { @@ -121,8 +122,7 @@ int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename bpsample = av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * 8; - ret = gf_isom_set_audio_info(audio_output_file->isof, track, di, - audio_codec_ctx->sample_rate, audio_output_file->codec_ctx->channels, bpsample); + ret = gf_isom_set_audio_info(audio_output_file->isof, track, di, audio_codec_ctx->sample_rate, audio_output_file->codec_ctx->channels, bpsample); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_audio_info\n", gf_error_to_string(ret))); return -1; @@ -140,7 +140,7 @@ int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename ret = gf_isom_setup_track_fragment(audio_output_file->isof, track, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0, 0); if (ret != GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_setutrack_fragment\n", gf_error_to_string(ret))); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_setup_track_fragment\n", gf_error_to_string(ret))); return -1; } @@ -176,7 +176,7 @@ int dc_gpac_audio_isom_write(AudioOutputFile *audio_output_file) audio_output_file->sample->dataLength = audio_output_file->packet.size; audio_output_file->sample->DTS = audio_output_file->dts; //audio_output_file->aframe->pts; - audio_output_file->sample->IsRAP = 1; //audio_output_file->aframe->key_frame;//audio_codec_ctx->coded_frame->key_frame; + 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); @@ -223,6 +223,10 @@ int dc_gpac_audio_isom_close(AudioOutputFile *audio_output_file) return 0; } +#endif + + + int dc_ffmpeg_audio_muxer_open(AudioOutputFile *audio_output_file, char *filename) { AVStream *audio_stream; @@ -273,7 +277,7 @@ int dc_ffmpeg_audio_muxer_open(AudioOutputFile *audio_output_file, char *filenam audio_stream->codec->bit_rate = audio_codec_ctx->bit_rate;//audio_output_file->audio_data_conf->bitrate; audio_stream->codec->sample_rate = audio_codec_ctx->sample_rate;//audio_output_file->audio_data_conf->samplerate; audio_stream->codec->channels = audio_codec_ctx->channels;//audio_output_file->audio_data_conf->channels; - assert(audio_codec_ctx->codec->sample_fmts); + assert(audio_codec_ctx->codec->sample_fmts); audio_stream->codec->sample_fmt = audio_codec_ctx->codec->sample_fmts[0]; // if (audio_output_file->av_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) @@ -353,42 +357,44 @@ int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio snprintf(name, sizeof(name), "audio encoder %s", audio_data_conf->filename); dc_consumer_init(&audio_output_file->consumer, AUDIO_CB_SIZE, name); +#ifndef GPAC_DISABLE_ISOM audio_output_file->sample = gf_isom_sample_new(); audio_output_file->isof = NULL; - audio_output_file->muxer_type = muxer_type; +#endif + audio_output_file->muxer_type = muxer_type; audio_output_file->frame_per_seg = frame_per_seg; audio_output_file->frame_per_frag = frame_per_frag; - audio_output_file->seg_marker = seg_marker; - return 0; } void dc_audio_muxer_free(AudioOutputFile *audio_output_file) { +#ifndef GPAC_DISABLE_ISOM if (audio_output_file->isof != NULL) { gf_isom_close(audio_output_file->isof); } - //gf_isom_sample_del(&audio_output_file->sample); +#endif } GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg) { - GF_Err ret; + GF_Err ret = GF_NOT_SUPPORTED; char name[GF_MAX_PATH]; switch (audio_output_file->muxer_type) { case FFMPEG_AUDIO_MUXER: snprintf(name, sizeof(name), "%s/%s_%d_ffmpeg.mp4", directory, id_name, seg); return dc_ffmpeg_audio_muxer_open(audio_output_file, name); +#ifndef GPAC_DISABLE_ISOM case GPAC_AUDIO_MUXER: snprintf(name, sizeof(name), "%s/%s_%d_gpac.mp4", directory, id_name, seg); dc_gpac_audio_moov_create(audio_output_file, name); return dc_gpac_audio_isom_open_seg(audio_output_file, NULL); case GPAC_INIT_AUDIO_MUXER: - if (seg == 0) { + if (seg == 1) { snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name); dc_gpac_audio_moov_create(audio_output_file, name); audio_output_file->first_dts = 0; @@ -396,11 +402,13 @@ GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg); ret = dc_gpac_audio_isom_open_seg(audio_output_file, name); return ret; +#endif default: - return GF_BAD_PARAM; + ret = GF_BAD_PARAM; + break; } - return GF_BAD_PARAM; + return ret; } int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb) @@ -408,6 +416,7 @@ int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb) switch (audio_output_file->muxer_type) { case FFMPEG_AUDIO_MUXER: return dc_ffmpeg_audio_muxer_write(audio_output_file); +#ifndef GPAC_DISABLE_ISOM case GPAC_AUDIO_MUXER: case GPAC_INIT_AUDIO_MUXER: if (frame_nb % audio_output_file->frame_per_frag == 0) { @@ -419,14 +428,17 @@ int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb) 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); } + //TODO - do same as video, flush based on time in case of losses if (frame_nb + 1 == audio_output_file->frame_per_seg) { return 1; } + return 0; +#endif + default: return GF_BAD_PARAM; } - return GF_BAD_PARAM; } @@ -435,11 +447,13 @@ int dc_audio_muxer_close(AudioOutputFile *audio_output_file) switch (audio_output_file->muxer_type) { case FFMPEG_AUDIO_MUXER: return dc_ffmpeg_audio_muxer_close(audio_output_file); +#ifndef GPAC_DISABLE_ISOM case GPAC_AUDIO_MUXER: dc_gpac_audio_isom_close_seg(audio_output_file); return dc_gpac_audio_isom_close(audio_output_file); case GPAC_INIT_AUDIO_MUXER: return dc_gpac_audio_isom_close_seg(audio_output_file); +#endif default: return GF_BAD_PARAM; } diff --git a/applications/dashcast/audio_muxer.h b/applications/dashcast/audio_muxer.h index 148d8c1..7c1d95e 100644 --- a/applications/dashcast/audio_muxer.h +++ b/applications/dashcast/audio_muxer.h @@ -64,8 +64,11 @@ typedef struct { AVCodec *codec; AVCodecContext *codec_ctx; +#ifndef GPAC_DISABLE_ISOM GF_ISOFile *isof; GF_ISOSample *sample; +#endif + int dts; /* The index to the audio stream in the file */ diff --git a/applications/dashcast/cmd_data.c b/applications/dashcast/cmd_data.c index 1d35e11..176369f 100644 --- a/applications/dashcast/cmd_data.c +++ b/applications/dashcast/cmd_data.c @@ -55,7 +55,7 @@ int dc_str_to_resolution(char *str, int *width, int *height) } -#define DEFAULT_VIDEO_BITRATE 400000 +#define DEFAULT_VIDEO_BITRATE 1000000 #define DEFAULT_VIDEO_FRAMERATE 25 #define DEFAULT_VIDEO_WIDTH 640 #define DEFAULT_VIDEO_HEIGHT 480 @@ -116,6 +116,9 @@ static void dc_create_configuration(CmdData *cmd_data) snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.crop_x); gf_cfg_set_key(conf, section_name, "crop_x", value); } + if (!gf_cfg_get_key(conf, section_name, "low_delay")) { + gf_cfg_set_key(conf, section_name, "low_delay", cmd_data->video_data_conf.low_delay ? "yes" : "no"); + } if (!gf_cfg_get_key(conf, section_name, "crop_y")) { if (cmd_data->video_data_conf.crop_y == -1) @@ -186,8 +189,14 @@ int dc_read_configuration(CmdData *cmd_data) video_data_conf->crop_x = opt ? atoi(opt) : 0; opt = gf_cfg_get_key(conf, section_name, "crop_y"); video_data_conf->crop_x = opt ? atoi(opt) : 0; + opt = gf_cfg_get_key(conf, section_name, "low_delay"); + video_data_conf->low_delay = (opt && !strcmp(opt, "yes")) ? 1 : 0; opt = gf_cfg_get_key(conf, section_name, "custom"); - video_data_conf->custom = opt ? gf_strdup(opt) : NULL; + if (opt) { + if (strlen(opt) >= GF_MAX_PATH) + fprintf(stderr, "Warning: video custom opt is too long. Truncating.\n"); + strncpy(video_data_conf->custom, opt, GF_MAX_PATH-1); + } gf_list_add(cmd_data->video_lst, (void *) video_data_conf); } else if (strcmp(section_type, "audio") == 0) @@ -205,7 +214,11 @@ int dc_read_configuration(CmdData *cmd_data) opt = gf_cfg_get_key(conf, section_name, "channels"); audio_data_conf->channels = opt ? atoi(opt) : DEFAULT_AUDIO_CHANNELS; opt = gf_cfg_get_key(conf, section_name, "custom"); - audio_data_conf->custom = opt ? gf_strdup(opt) : NULL; + if (opt) { + if (strlen(opt) >= GF_MAX_PATH) + fprintf(stderr, "Warning: audio custom opt is too long. Truncating.\n"); + strncpy(audio_data_conf->custom, opt, GF_MAX_PATH-1); + } gf_list_add(cmd_data->audio_lst, (void *) audio_data_conf); } else { fprintf(stderr, "Configuration file: type %s is not supported.\n", section_type); @@ -355,7 +368,6 @@ 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); - gf_free(audio_data_conf->custom); gf_list_rem_last(cmd_data->audio_lst); gf_free(audio_data_conf); } @@ -363,7 +375,6 @@ void dc_cmd_data_destroy(CmdData *cmd_data) while (gf_list_count(cmd_data->video_lst)) { VideoDataConf *video_data_conf = gf_list_last(cmd_data->video_lst); - gf_free(video_data_conf->custom); gf_list_rem_last(cmd_data->video_lst); gf_free(video_data_conf); } @@ -374,7 +385,7 @@ void dc_cmd_data_destroy(CmdData *cmd_data) gf_cfg_del(cmd_data->conf); gf_cfg_del(cmd_data->switch_conf); if (cmd_data->logfile) - fclose(cmd_data->logfile); + gf_fclose(cmd_data->logfile); dc_task_destroy(&cmd_data->task_list); @@ -395,6 +406,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) const char *command_usage = "Usage: DashCast [options]\n" + "GPAC version " GPAC_FULL_VERSION"\n" "\n" "General options:\n" " -log-file filename set output log file. Also works with -lf\n" @@ -437,7 +449,6 @@ 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" - " -gdr use Gradual Decoder Refresh feature for video encoding (h264 codec only)\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" @@ -450,7 +461,10 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) #if 0 //TODO: bind to option and params - test first how it binds to current input parameters " -vb int set the output video bitrate (in bits)\n" #endif - " -vcustom string send custom parameters directly to the audio encoder\n" + " -vcustom string send custom parameters directly to the video encoder\n" + " -gdr use Gradual Decoder Refresh feature for video encoding (h264 codec only)\n" + " -gop specify GOP size in frames - default is framerate (1 sec gop)\n" + " -low-delay specify that low delay settings should be used (no B-frames, fast encoding)\n" "* Audio encoding options:\n" " -acodec string set the output audio codec (default: aac)\n" #if 0 //TODO: bind to option and params - test first how it binds to current input parameters @@ -462,11 +476,11 @@ 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 dur:int set the fragment duration in millisecond (default value: 1000)\n" - " -seg-marker marker:str add a marker box named marker at the end of DASH segment\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" - " -ast-offset dur:int dur is the MPD availabilityStartTime shift in milliseconds (default value: 1000)\n" + " -ast-offset dur:int dur is the MPD availabilityStartTime shift in milliseconds (default value: 0)\n" " -mpd-refresh dur:int dur is the MPD minimumUpdatePeriod in seconds\n" " -time-shift dur:int dur is the MPD TimeShiftBufferDepth in seconds\n" " - the default value is 10. Specify -1 to keep all files.\n" @@ -482,6 +496,9 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) " 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" +#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" #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" @@ -508,12 +525,14 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) gf_sys_init(use_mem_track); + gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); if (use_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; i = 1; while (i < argc) { @@ -600,16 +619,18 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) fprintf(stderr, "%s", command_usage); return -1; } - strncpy(cmd_data->video_data_conf.codec, argv[i], GF_MAX_PATH); + strncpy(cmd_data->video_data_conf.codec, argv[i], GF_MAX_PATH-1); i++; } else if (strcmp(argv[i], "-vcustom") == 0) { DASHCAST_CHECK_NEXT_ARG - if (strcmp(cmd_data->video_data_conf.custom, "") != 0) { + if (strlen(cmd_data->video_data_conf.custom)) { fprintf(stderr, "Video custom has already been specified: appending\n"); fprintf(stderr, "%s", command_usage); return -1; } - strncpy(cmd_data->video_data_conf.custom, argv[i], GF_MAX_PATH); + if (strlen(argv[i]) >= GF_MAX_PATH) + fprintf(stderr, "Warning: video custom is too long. Truncating.\n"); + strncpy(cmd_data->video_data_conf.custom, argv[i], GF_MAX_PATH-1); i++; } else if (strcmp(argv[i], "-acodec") == 0) { DASHCAST_CHECK_NEXT_ARG @@ -618,16 +639,18 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) fprintf(stderr, "%s", command_usage); return -1; } - strncpy(cmd_data->audio_data_conf.codec, argv[i], GF_MAX_PATH); + strncpy(cmd_data->audio_data_conf.codec, argv[i], GF_MAX_PATH-1); i++; } else if (strcmp(argv[i], "-acustom") == 0) { DASHCAST_CHECK_NEXT_ARG - if (strcmp(cmd_data->audio_data_conf.custom, "") != 0) { + if (strlen(cmd_data->audio_data_conf.custom)) { fprintf(stderr, "Audio custom has already been specified: appending\n"); fprintf(stderr, "%s", command_usage); return -1; } - strncpy(cmd_data->audio_data_conf.custom, argv[i], GF_MAX_PATH); + if (strlen(argv[i]) >= GF_MAX_PATH) + fprintf(stderr, "Warning: audio custom is too long. Truncating.\n"); + strncpy(cmd_data->audio_data_conf.custom, argv[i], GF_MAX_PATH-1); i++; } else if (strcmp(argv[i], "-conf") == 0) { DASHCAST_CHECK_NEXT_ARG @@ -665,7 +688,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) fprintf(stderr, "%s", command_usage); return -1; } - strncpy(cmd_data->mpd_filename, argv[i], GF_MAX_PATH); + strncpy(cmd_data->mpd_filename, argv[i], GF_MAX_PATH-1); i++; } else if (strcmp(argv[i], "-seg-dur") == 0) { DASHCAST_CHECK_NEXT_ARG @@ -676,7 +699,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) } cmd_data->seg_dur = atoi(argv[i]); i++; - } else if (strcmp(argv[i], "-frag-dur") == 0) { + } else if ((strcmp(argv[i], "-frag-dur") == 0) || (strcmp(argv[i], "-frag") == 0)) { DASHCAST_CHECK_NEXT_ARG if (cmd_data->frag_dur != 0) { fprintf(stderr, "Fragment duration has already been specified.\n"); @@ -737,7 +760,10 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) fprintf(stderr, "%s", command_usage); return -1; } - strncpy(cmd_data->base_url, argv[i], GF_MAX_PATH); + strncpy(cmd_data->base_url, argv[i], GF_MAX_PATH-1); + i++; + } else if (strcmp(argv[i], "-low-delay") == 0) { + cmd_data->video_data_conf.low_delay = 1; i++; } else if (strcmp(argv[i], "-live") == 0) { cmd_data->mode = LIVE_CAMERA; @@ -775,7 +801,7 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) #endif } else if (!strcmp(argv[i], "-lf") || !strcmp(argv[i], "-log-file")) { DASHCAST_CHECK_NEXT_ARG - cmd_data->logfile = gf_f64_open(argv[i], "wt"); + cmd_data->logfile = gf_fopen(argv[i], "wt"); gf_log_set_callback(cmd_data->logfile, on_dc_log); i++; } else if (strcmp(argv[i], "-gdr") == 0) { @@ -837,6 +863,11 @@ int dc_parse_command(int argc, char **argv, CmdData *cmd_data) cmd_data->min_buffer_time = 1.0; } + 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; + } + //safety checks if (cmd_data->video_data_conf.crop_x || cmd_data->video_data_conf.crop_y) { if (cmd_data->video_data_conf.width == -1 && cmd_data->video_data_conf.height == -1) { diff --git a/applications/dashcast/cmd_data.h b/applications/dashcast/cmd_data.h index 4c706d6..73bdbf4 100644 --- a/applications/dashcast/cmd_data.h +++ b/applications/dashcast/cmd_data.h @@ -108,6 +108,7 @@ typedef struct { int insert_utc; Bool use_source_timing; + Bool use_mem_track; } CmdData; /* diff --git a/applications/dashcast/controler.c b/applications/dashcast/controler.c index cc6487a..08d5601 100644 --- a/applications/dashcast/controler.c +++ b/applications/dashcast/controler.c @@ -43,10 +43,11 @@ # error #endif +#include typedef struct { int segnum; - u64 time; + u64 utc_time, ntpts; } segtime; @@ -72,10 +73,13 @@ typedef struct { void optimize_seg_frag_dur(int *seg, int *frag) { + int min_rem; int seg_nb = *seg; int frag_nb = *frag; + if (!frag_nb) frag_nb = 1; - int min_rem = seg_nb % frag_nb; + min_rem = seg_nb % frag_nb; + if (seg_nb % (frag_nb + 1) < min_rem) { min_rem = seg_nb % (frag_nb + 1); *seg = seg_nb; @@ -150,7 +154,7 @@ static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, optimize_seg_frag_dur(&video_seg_dur, &video_frag_dur); } - f = fopen(name, "w"); + f = gf_fopen(name, "w"); //TODO: if (!f) ... // time_t t = time(NULL); @@ -183,7 +187,7 @@ static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, fprintf(f, " %s\n", cmddata->base_url); } - fprintf(f, " \n"); + fprintf(f, " \n"); if (strcmp(cmddata->audio_data_conf.filename, "") != 0) { fprintf(f, " \n"); @@ -246,11 +250,7 @@ static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, fprintf(f, "\n"); - fclose(f); - -// fprintf(stdout, "\33[34m\33[1m"); - fprintf(stdout, "MPD file generated: %s/%s\n", cmddata->out_dir, cmddata->mpd_filename); -// fprintf(stdout, "\33[0m"); + gf_fclose(f); } static u32 mpd_thread(void *params) @@ -268,7 +268,8 @@ static u32 mpd_thread(void *params) segtime main_seg_time; Bool first = GF_TRUE; main_seg_time.segnum = 0; - main_seg_time.time = 0; + main_seg_time.utc_time = 0; + main_seg_time.ntpts = 0; if (cmddata->mode == LIVE_CAMERA || cmddata->mode == LIVE_MEDIA) { while (1) { @@ -276,7 +277,7 @@ static u32 mpd_thread(void *params) time_t t; segtime seg_time; seg_time.segnum = 0; - seg_time.time = 0; + seg_time.utc_time = 0; if (cmddata->exit_signal) { break; @@ -292,7 +293,7 @@ static u32 mpd_thread(void *params) } if (cmddata->ast_offset>0) { - seg_time.time += cmddata->ast_offset; + seg_time.utc_time += cmddata->ast_offset; } if (cmddata->use_dynamic_ast) { @@ -311,18 +312,17 @@ static u32 mpd_thread(void *params) } } - //printf time at which we generate MPD - t = seg_time.time / 1000; - msecs = (u32) ( (seg_time.time - t*1000) ); + + t = (seg_time.ntpts >> 32) - GF_NTP_SEC_1900_TO_1970; + msecs = (u32) ( (seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) ); ast_time = *gmtime(&t); - strftime(availability_start_time, 64, "%Y-%m-%dT%H:%M:%S", &ast_time); - fprintf(stdout, "Generating MPD at %s.%d\n", availability_start_time, msecs); + 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); - t = main_seg_time.time / 1000; - msecs = (u32) ( (main_seg_time.time - t*1000) ); + t = (main_seg_time.ntpts >> 32) - GF_NTP_SEC_1900_TO_1970; + msecs = (u32) ( (main_seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) ); ast_time = *gmtime(&t); - sprintf(availability_start_time, "%d-%02d-%02dT%02d:%02d:%02d.%d", 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, seg_time.segnum); + 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); if (cmddata->time_shift != -1) { int ts, h, m, s; @@ -334,7 +334,7 @@ static u32 mpd_thread(void *params) snprintf(time_shift, sizeof(time_shift), "timeShiftBufferDepth=\"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, cmddata->ast_offset); + 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); } } else { @@ -484,7 +484,7 @@ Bool dasher_thread(void *params) // } // // dash_profile = cmd_data->live ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_MAIN; -// strncpy(sz_mpd, cmd_data->mpd_filename, GF_MAX_PATH); +// strncpy(sz_mpd, cmd_data->mpd_filename, GF_MAX_PATH-1); // // dash_duration = cmd_data->dash_dur ? cmd_data->dash_dur / 1000 : 1; // @@ -752,7 +752,8 @@ u32 video_encoder_thread(void *params) segtime time_at_segment_start; VideoMuxerType muxer_type = VIDEO_MUXER; VideoThreadParam *thread_params = (VideoThreadParam*)params; - + u32 sec, frac; + 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); @@ -798,12 +799,18 @@ u32 video_encoder_thread(void *params) return -1; } - if (dc_video_encoder_open(&out_file, video_data_conf, in_data->use_source_timing) < 0) { + if (dc_video_encoder_open(&out_file, video_data_conf, in_data->use_source_timing, video_scaled_data->sar) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video stream.\n")); in_data->exit_signal = 1; return -1; } + if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) { + init_mpd = GF_TRUE; + } + + + time_at_segment_start.ntpts = 0; start_utc = gf_net_get_utc(); seg_utc = 0; while (1) { @@ -811,19 +818,47 @@ u32 video_encoder_thread(void *params) //log time at segment start, because segment availabilityStartTime is computed from AST anchor + segment duration //logging at the end of the segment production will induce one segment delay time_at_segment_start.segnum = seg_nb; - time_at_segment_start.time = gf_net_get_utc(); + time_at_segment_start.utc_time = gf_net_get_utc(); + gf_net_get_ntp(&sec, &frac); + +#ifndef GPAC_DISABLE_LOG + if (gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_INFO)) { + if (time_at_segment_start.ntpts) { + u32 ref_sec, ref_frac; + Double tr, t; + ref_sec = (time_at_segment_start.ntpts>>32) & 0xFFFFFFFFULL; + ref_frac = (u32) (time_at_segment_start.ntpts & 0xFFFFFFFFULL); + tr = ref_sec * 1000.0; + tr += ref_frac*1000.0 /0xFFFFFFFF; + t = sec * 1000.0; + t += frac*1000.0 /0xFFFFFFFF; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] NTP diff since last segment start in msec is %f\n", t - tr)); + + } + } +#endif - if (dc_video_muxer_open(&out_file, in_data->out_dir, video_data_conf->filename, seg_nb) < 0) { + time_at_segment_start.ntpts = sec; + time_at_segment_start.ntpts <<= 32; + time_at_segment_start.ntpts |= frac; + + //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; + dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start)); + } + + assert(! out_file.segment_started); + + if (dc_video_muxer_open(&out_file, in_data->out_dir, video_data_conf->filename, seg_nb+1) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video file.\n")); in_data->exit_signal = 1; return -1; } // fprintf(stdout, "Header size: %d\n", ret); while (1) { -// if (seg_frame_max > 0) { -// if (frame_nb == seg_frame_max) -// break; -// } + u64 ntpts = gf_net_get_ntp_ts(); + //we have the RAP already encoded, skip coder if (loss_state == 2) { ret = 1; @@ -845,13 +880,14 @@ u32 video_encoder_thread(void *params) if (ret > 0) { int r; + /*resync at first RAP: flush current broken segment and restart next one on rap*/ if ((loss_state==1) && out_file.codec_ctx->coded_frame->key_frame) { loss_state = 2; break; } - r = dc_video_muxer_write(&out_file, frame_nb, in_data->insert_utc); + r = dc_video_muxer_write(&out_file, frame_nb, in_data->insert_utc ? ntpts : 0); if (r < 0) { quit = 1; in_data->exit_signal = 1; @@ -884,7 +920,6 @@ u32 video_encoder_thread(void *params) int seg_diff; seg_utc = gf_net_get_utc(); diff = (int) (seg_utc - start_utc); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[video_encoder] UTC diff %d - cumulated segment duration %d -> %d\n", diff, (seg_nb+1) * real_video_seg_dur, diff - (seg_nb+1) * real_video_seg_dur)); //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_video_seg_dur) { @@ -895,7 +930,7 @@ u32 video_encoder_thread(void *params) //do a rough estimate of losses to adjust timing... if (! in_data->use_source_timing) { - out_file.first_dts += out_file.codec_ctx->time_base.den; + out_file.first_dts_in_fragment += out_file.codec_ctx->time_base.den; } } //wait for RAP to cut next segment @@ -1000,7 +1035,7 @@ u32 audio_encoder_thread(void *params) frame_per_seg = (int)((audio_data_conf->samplerate / (double) audio_output_file.codec_ctx->frame_size) * (in_data->seg_dur / 1000.0)); frame_per_frag = (int)((audio_data_conf->samplerate / (double) audio_output_file.codec_ctx->frame_size) * (in_data->frag_dur / 1000.0)); optimize_seg_frag_dur(&frame_per_seg, &frame_per_frag); - + real_audio_seg_dur = (int) (frame_per_seg * (double) audio_output_file.codec_ctx->frame_size * 1000.0 / (double) audio_data_conf->samplerate); GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[audio_encoder] frame_per_seg=%d, frame_per_frag=%d, real_audio_seg_dur=%d ms\n", frame_per_seg, frame_per_frag, real_audio_seg_dur) ); @@ -1016,7 +1051,7 @@ u32 audio_encoder_thread(void *params) while (1) { frame_nb = 0; quit = 0; - if (dc_audio_muxer_open(&audio_output_file, in_data->out_dir, audio_data_conf->filename, seg_nb) < 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; return -1; @@ -1102,7 +1137,7 @@ u32 audio_encoder_thread(void *params) } 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.time = gf_net_get_utc(); + t.utc_time = gf_net_get_utc(); //time_t t = time(NULL); dc_message_queue_put(mq, &t, sizeof(t)); } @@ -1225,7 +1260,7 @@ int dc_run_controler(CmdData *in_data) } for (i=0; ivsrc) + 1; i++) { - dc_video_input_data_set_prop(&video_input_data, i, video_input_file[i]->width, video_input_file[i]->height, in_data->video_data_conf.crop_x, in_data->video_data_conf.crop_y, video_input_file[i]->pix_fmt); + dc_video_input_data_set_prop(&video_input_data, i, video_input_file[i]->width, video_input_file[i]->height, in_data->video_data_conf.crop_x, in_data->video_data_conf.crop_y, video_input_file[i]->pix_fmt, video_input_file[i]->sar); } for (i=0; isource_number = source_number; - strncpy(task->id, id_name, MAX_ID_SIZE); + strncpy(task->id, id_name, MAX_ID_SIZE-1); task->start_time_t = start; task->end_time_t = end; gf_list_add(list->tasks, task); @@ -55,7 +55,7 @@ int dc_task_get_current(TaskList *list, Task *task) for (i = 0; isize; i++) { Task *cur_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); + //strncpy(task->id, cur_task->id, MAX_ID_SIZE-1); //memcpy(&task->start_time, &cur_task->start_time, sizeof(struct tm)); //memcpy(&task->end_time, &cur_task->end_time, sizeof(struct tm)); task->source_number = cur_task->source_number; diff --git a/applications/dashcast/video_data.c b/applications/dashcast/video_data.c index 97b37df..f960d57 100644 --- a/applications/dashcast/video_data.c +++ b/applications/dashcast/video_data.c @@ -67,13 +67,14 @@ int dc_video_input_data_init(VideoInputData *video_input_data, /*int width, int return 0; } -void dc_video_input_data_set_prop(VideoInputData *video_input_data, int index, int width, int height, int crop_x, int crop_y, int pix_fmt) +void dc_video_input_data_set_prop(VideoInputData *video_input_data, int index, int width, int height, int crop_x, int crop_y, int pix_fmt, AVRational sar) { video_input_data->vprop[index].width = width; video_input_data->vprop[index].height = height; video_input_data->vprop[index].crop_x = crop_x; video_input_data->vprop[index].crop_y = crop_y; video_input_data->vprop[index].pix_fmt = pix_fmt; + video_input_data->vprop[index].sar = sar; } void dc_video_input_data_destroy(VideoInputData *video_input_data) diff --git a/applications/dashcast/video_data.h b/applications/dashcast/video_data.h index 26f3f6f..c5bc68f 100644 --- a/applications/dashcast/video_data.h +++ b/applications/dashcast/video_data.h @@ -70,7 +70,9 @@ typedef struct { /* RFC6381 codec name, only valid when VIDEO_MUXER == GPAC_INIT_VIDEO_MUXER_AVC1 */ char codec6381[GF_MAX_PATH]; /* custom parameter to be passed directly to the encoder - free it once you're done */ - char *custom; + char custom[GF_MAX_PATH]; + /*low delay is used*/ + int low_delay; /* used for source switching */ char source_id[GF_MAX_PATH]; @@ -88,6 +90,7 @@ typedef struct { int height; int crop_x, crop_y; int pix_fmt; + AVRational sar; } VideoInputProp; /* @@ -146,7 +149,7 @@ int dc_video_input_data_init(VideoInputData *video_input_data,/* int width, int /* * Set properties for a VideoInputData. */ -void dc_video_input_data_set_prop(VideoInputData *video_input_data, int index, int width, int height, int crop_x, int crop_y, int pix_fmt); +void dc_video_input_data_set_prop(VideoInputData *video_input_data, int index, int width, int height, int crop_x, int crop_y, int pix_fmt, AVRational sar); /* * Destroy a VideoInputData. diff --git a/applications/dashcast/video_decoder.c b/applications/dashcast/video_decoder.c index d0c6298..de708f9 100644 --- a/applications/dashcast/video_decoder.c +++ b/applications/dashcast/video_decoder.c @@ -153,8 +153,17 @@ int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video video_input_file->width = codec_ctx->width; video_input_file->height = codec_ctx->height; + video_input_file->sar = codec_ctx->sample_aspect_ratio; + video_input_file->pix_fmt = codec_ctx->pix_fmt; - if (video_data_conf->framerate >= 0 && codec_ctx->time_base.num) { + 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; + } + } + else if (video_data_conf->framerate >= 0 && codec_ctx->time_base.num) { video_data_conf->framerate = codec_ctx->time_base.den / codec_ctx->time_base.num; } if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { @@ -175,7 +184,7 @@ int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video } if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Invalid input framerate.\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Invalid input framerate %d (AVCTX timebase is %d/%d).\n", video_data_conf->framerate, codec_ctx->time_base.num, codec_ctx->time_base.den)); return -1; } @@ -306,30 +315,39 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide video_input_file->pts_init = 1; video_input_file->utc_at_init = gf_net_get_utc(); video_input_file->first_pts = packet.pts; - video_input_file->computed_pts = 0; + 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 } - //perform FPS re-linearisation + + //move to 0-based PTS pts = packet.pts - video_input_file->first_pts; - if (pts - video_input_file->prev_pts > video_input_file->sync_tolerance) { - u32 nb_lost=0; - while (pts > video_input_file->computed_pts) { - video_input_file->computed_pts += video_input_data->frame_duration; - nb_lost++; - } - if (nb_lost) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DashCast] Capture lost %d video frames \n", nb_lost)); + 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)); + } + + + //check for drop frames +#ifndef GPAC_DISABLE_LOG + if (0 && gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_WARNING)) { + if (pts - video_input_file->prev_pts > video_input_file->sync_tolerance) { + u32 nb_lost=0; + while (video_input_file->prev_pts + video_input_data->frame_duration + video_input_file->sync_tolerance < pts) { + video_input_file->prev_pts += video_input_data->frame_duration; + nb_lost++; + } + if (nb_lost) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DashCast] Capture lost %d video frames \n", nb_lost)); + } } } - -// fprintf(stdout, "Capture PTS %g - UTC diff %g - Computed PTS %g\n", (Double) pts / codec_ctx->time_base.den, (Double) (gf_net_get_utc() - video_input_file->utc_at_init) / 1000, (Double) video_input_file->computed_pts / codec_ctx->time_base.den); +#endif video_input_file->prev_pts = pts; - video_data_node->vframe->pts = video_input_file->computed_pts; - video_input_file->computed_pts += video_input_data->frame_duration; + video_data_node->vframe->pts = pts; } if (video_data_node->vframe->pts==AV_NOPTS_VALUE) { @@ -341,7 +359,7 @@ int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *vide } video_input_file->frame_decoded++; - GF_LOG(GF_LOG_INFO, 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\n", video_data_node->vframe->pts, gf_net_get_utc() )); // For a decode/encode process we must free this memory. //But if the input is raw and there is no need to decode then diff --git a/applications/dashcast/video_decoder.h b/applications/dashcast/video_decoder.h index 305d95f..59a6f94 100644 --- a/applications/dashcast/video_decoder.h +++ b/applications/dashcast/video_decoder.h @@ -51,13 +51,14 @@ typedef struct { int width; int height; int pix_fmt; + AVRational sar; int mode; int no_loop, nb_consumers; u32 frame_decoded; Bool pts_init; - u64 first_pts, prev_pts, computed_pts, sync_tolerance; + u64 first_pts, prev_pts, sync_tolerance; u64 utc_at_init; } VideoInputFile; diff --git a/applications/dashcast/video_encoder.c b/applications/dashcast/video_encoder.c index 784e4a4..1b07cf1 100644 --- a/applications/dashcast/video_encoder.c +++ b/applications/dashcast/video_encoder.c @@ -56,7 +56,7 @@ void build_dict(void *priv_data, const char *options) { gf_free(opt); } -int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing) +int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing, AVRational sar) { video_output_file->vbuf_size = 9 * video_data_conf->width * video_data_conf->height + 10000; video_output_file->vbuf = (uint8_t *) av_malloc(video_output_file->vbuf_size); @@ -75,8 +75,7 @@ int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *vid video_output_file->codec_ctx->bit_rate = video_data_conf->bitrate; video_output_file->codec_ctx->width = video_data_conf->width; video_output_file->codec_ctx->height = video_data_conf->height; - video_output_file->codec_ctx->sample_aspect_ratio.num = video_data_conf->width; - video_output_file->codec_ctx->sample_aspect_ratio.den = video_data_conf->height; + video_output_file->codec_ctx->sample_aspect_ratio = sar; video_output_file->codec_ctx->time_base.num = 1; video_output_file->codec_ctx->time_base.den = video_output_file->gop_size ? video_output_file->gop_size : video_data_conf->framerate; @@ -127,14 +126,16 @@ int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *vid * */ - if (video_data_conf->custom) { + if ( strlen(video_data_conf->custom) ) { build_dict(video_output_file->codec_ctx->priv_data, video_data_conf->custom); - gf_free(video_data_conf->custom); - video_data_conf->custom = NULL; - } else { + } else if (video_data_conf->low_delay) { GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video Encoder: applying default options (preset=ultrafast tune=zerolatency)\n")); + av_opt_set(video_output_file->codec_ctx->priv_data, "vprofile", "baseline", 0); av_opt_set(video_output_file->codec_ctx->priv_data, "preset", "ultrafast", 0); av_opt_set(video_output_file->codec_ctx->priv_data, "tune", "zerolatency", 0); + if (strstr(video_data_conf->codec, "264")) { + av_opt_set(video_output_file->codec_ctx->priv_data, "x264opts", "no-mbtree:sliced-threads:sync-lookahead=0", 0); + } } if (video_output_file->gdr) { @@ -191,10 +192,24 @@ int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData 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; + 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; + video_output_file->encoded_frame_size = avcodec_encode_video2(video_codec_ctx, &pkt, video_data_node->vframe, &got_packet); #endif @@ -225,7 +240,7 @@ int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData return -1; } - GF_LOG(GF_LOG_INFO, 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\n", video_output_file->rep_id, /*video_data_node->source_number, */video_data_node->vframe->pts, gf_net_get_utc() )); /* if zero size, it means the image was buffered */ // if (out_size > 0) { diff --git a/applications/dashcast/video_encoder.h b/applications/dashcast/video_encoder.h index 6bc7498..26e4cb6 100644 --- a/applications/dashcast/video_encoder.h +++ b/applications/dashcast/video_encoder.h @@ -37,7 +37,7 @@ * * @return 0 on success, -1 on failure */ -int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing); +int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing, AVRational sar); /* * Read the decoded video frames from circular buffer diff --git a/applications/dashcast/video_muxer.c b/applications/dashcast/video_muxer.c index 19facd7..7f0ae3c 100644 --- a/applications/dashcast/video_muxer.c +++ b/applications/dashcast/video_muxer.c @@ -25,6 +25,7 @@ #include "video_muxer.h" #include "libavutil/opt.h" +#include /** @@ -158,7 +159,7 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ); if (!bs) return GF_BAD_PARAM; - + memset(&hevc, 0, sizeof(HEVCState)); hevc.sps_active_idx = -1; @@ -168,7 +169,7 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s u8 nal_unit_type, temporal_id, layer_id; u64 nal_start; u32 nal_size; - + if (gf_bs_read_u32(bs) != 0x00000001) { gf_bs_del(bs); return GF_BAD_PARAM; @@ -212,7 +213,7 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s dst_cfg->constantFrameRate = hevc.vps[idx].rates[0].constand_pic_rate_idc; dst_cfg->numTemporalLayers = hevc.vps[idx].max_sub_layers; dst_cfg->temporalIdNested = hevc.vps[idx].temporal_id_nesting; - + if (!vpss) { GF_SAFEALLOC(vpss, GF_HEVCParamArray); vpss->nalus = gf_list_new(); @@ -237,13 +238,13 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s gf_free(buffer); return GF_BAD_PARAM; } - + assert(!(hevc.sps[idx].state & AVC_SPS_DECLARED)); //we don't expect multiple SPS if ((hevc.sps[idx].state & AVC_SPS_PARSED) && !(hevc.sps[idx].state & AVC_SPS_DECLARED)) { hevc.sps[idx].state |= AVC_SPS_DECLARED; hevc.sps[idx].crc = gf_crc_32(buffer, nal_size); } - + dst_cfg->configurationVersion = 1; dst_cfg->profile_space = hevc.sps[idx].ptl.profile_space; dst_cfg->tier_flag = hevc.sps[idx].ptl.tier_flag; @@ -260,7 +261,7 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s dst_cfg->chromaFormat = hevc.sps[idx].chroma_format_idc; dst_cfg->luma_bit_depth = hevc.sps[idx].bit_depth_luma; dst_cfg->chroma_bit_depth = hevc.sps[idx].bit_depth_chroma; - + if (!spss) { GF_SAFEALLOC(spss, GF_HEVCParamArray); spss->nalus = gf_list_new(); @@ -283,7 +284,7 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s gf_free(buffer); return GF_BAD_PARAM; } - + assert(hevc.pps[idx].state == 1); //we don't expect multiple PPS if (hevc.pps[idx].state == 1) { hevc.pps[idx].state = 2; @@ -323,6 +324,8 @@ static GF_Err hevc_import_ffextradata(const u8 *extradata, const u64 extradata_s #endif } +#ifndef GPAC_DISABLE_ISOM + static GF_Err dc_gpac_video_write_config(VideoOutputFile *video_output_file, u32 *di, u32 track) { GF_Err ret; if (video_output_file->codec_ctx->codec_id == CODEC_ID_H264) { @@ -442,15 +445,13 @@ int dc_gpac_video_moov_create(VideoOutputFile *video_output_file, char *filename return -1; } - //gf_isom_add_track_to_root_od(video_output_file->isof,1); - ret = gf_isom_finalize_for_fragment(video_output_file->isof, track); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret))); return -1; } - ret = gf_media_get_rfc_6381_codec_name(video_output_file->isof, track, video_output_file->video_data_conf->codec6381); + ret = gf_media_get_rfc_6381_codec_name(video_output_file->isof, track, video_output_file->video_data_conf->codec6381, GF_FALSE, GF_FALSE); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret))); return -1; @@ -467,16 +468,6 @@ int dc_gpac_video_isom_open_seg(VideoOutputFile *video_output_file, char *filena GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_start_segment\n", gf_error_to_string(ret))); return -1; } - -// ret = gf_isom_set_traf_base_media_decode_time(video_output_file->isof, 1, -// video_output_file->first_dts); -// if (ret != GF_OK) { -// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_traf_base_media_decode_time\n", gf_error_to_string(ret))); -// return -1; -// } -// -// video_output_file->first_dts += video_output_file->frame_per_segment; - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Opening new segment %s at UTC "LLU" ms\n", filename, gf_net_get_utc() )); return 0; } @@ -568,9 +559,12 @@ int dc_gpac_video_isom_close(VideoOutputFile *video_output_file) return 0; } +#endif + + int dc_raw_h264_open(VideoOutputFile *video_output_file, char *filename) { - video_output_file->file = fopen(filename, "w"); + video_output_file->file = gf_fopen(filename, "w"); return 0; } @@ -582,7 +576,7 @@ int dc_raw_h264_write(VideoOutputFile *video_output_file) int dc_raw_h264_close(VideoOutputFile *video_output_file) { - fclose(video_output_file->file); + gf_fclose(video_output_file->file); return 0; } @@ -719,8 +713,11 @@ int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video snprintf(name, sizeof(name), "video encoder %s", video_data_conf->filename); dc_consumer_init(&video_output_file->consumer, video_cb_size, name); +#ifndef GPAC_DISABLE_ISOM video_output_file->sample = gf_isom_sample_new(); video_output_file->isof = NULL; +#endif + video_output_file->muxer_type = muxer_type; video_output_file->frame_per_segment = frame_per_segment; @@ -739,12 +736,13 @@ int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video int dc_video_muxer_free(VideoOutputFile *video_output_file) { +#ifndef GPAC_DISABLE_ISOM if (video_output_file->isof != NULL) { gf_isom_close(video_output_file->isof); } gf_isom_sample_del(&video_output_file->sample); - +#endif return 0; } @@ -759,15 +757,16 @@ GF_Err dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, case RAW_VIDEO_H264: snprintf(name, sizeof(name), "%s/%s_%d.264", directory, id_name, seg); return dc_raw_h264_open(video_output_file, name); +#ifndef GPAC_DISABLE_ISOM case GPAC_VIDEO_MUXER: snprintf(name, sizeof(name), "%s/%s_%d_gpac.mp4", directory, id_name, seg); dc_gpac_video_moov_create(video_output_file, name); return dc_gpac_video_isom_open_seg(video_output_file, NULL); case GPAC_INIT_VIDEO_MUXER_AVC1: - if (seg == 0) { + if (seg == 1) { snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name); dc_gpac_video_moov_create(video_output_file, name); - video_output_file->first_dts = 0; + video_output_file->first_dts_in_fragment = 0; } snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg); return dc_gpac_video_isom_open_seg(video_output_file, name); @@ -775,10 +774,11 @@ GF_Err dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, if (seg == 0) { snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name); dc_gpac_video_moov_create(video_output_file, name); - video_output_file->first_dts = 0; + video_output_file->first_dts_in_fragment = 0; } snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg); return dc_gpac_video_isom_open_seg(video_output_file, name); +#endif default: return GF_BAD_PARAM; }; @@ -786,49 +786,53 @@ 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, Bool insert_utc) +int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 ntp_timestamp) { - u64 frame_dur; - GF_Err ret; switch (video_output_file->muxer_type) { case FFMPEG_VIDEO_MUXER: return dc_ffmpeg_video_muxer_write(video_output_file); case RAW_VIDEO_H264: return dc_raw_h264_write(video_output_file); +#ifndef GPAC_DISABLE_ISOM case GPAC_VIDEO_MUXER: case GPAC_INIT_VIDEO_MUXER_AVC1: case GPAC_INIT_VIDEO_MUXER_AVC3: if (video_output_file->use_source_timing) { + GF_Err ret; if (!video_output_file->fragment_started) { video_output_file->fragment_started = 1; ret = gf_isom_start_fragment(video_output_file->isof, 1); if (ret < 0) return -1; - video_output_file->first_dts = video_output_file->codec_ctx->coded_frame->pkt_dts; + //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); + } + + video_output_file->first_dts_in_fragment = video_output_file->codec_ctx->coded_frame->pkt_dts; if (!video_output_file->segment_started) { - u32 sec, frac; - u64 ntpts; video_output_file->pts_at_segment_start = video_output_file->codec_ctx->coded_frame->pts; video_output_file->segment_started = 1; + if (!video_output_file->nb_segments) { + video_output_file->pts_at_first_segment = video_output_file->pts_at_segment_start; + } - if (insert_utc) { - gf_net_get_ntp(&sec, &frac); - ntpts = sec; - ntpts <<= 32; - ntpts |= frac; - gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, ntpts, video_output_file->pts_at_segment_start); +#ifndef GPAC_DISABLE_LOG + if (ntp_timestamp && 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; + } 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 ); + + s32 diff_ms = ts_diff - ntp_diff; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Video Segment start NTP diff: %d ms TS diff: %d ms drift: %d ms\n", ntp_diff, ts_diff, diff_ms)); + } } +#endif } - gf_isom_set_traf_base_media_decode_time(video_output_file->isof, video_output_file->trackID, video_output_file->first_dts); - } - - //keep track of previous frame dur and use last dur as the default duration for next sample - //this works fine because we perform frame rate regulation at the capture stage - frame_dur = video_output_file->codec_ctx->coded_frame->pts - video_output_file->last_pts; - if (frame_dur && (video_output_file->frame_dur>(u32) frame_dur)) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("New frame dur detected: %d vs %d old\n", (u32) frame_dur, (u32) video_output_file->frame_dur)); - video_output_file->frame_dur = (u32)frame_dur; + gf_isom_set_traf_base_media_decode_time(video_output_file->isof, video_output_file->trackID, video_output_file->first_dts_in_fragment); } if (dc_gpac_video_isom_write(video_output_file) < 0) { @@ -837,16 +841,23 @@ int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, Bool 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 + video_output_file->frame_dur) /video_output_file->timescale >= video_output_file->frag_dur / 1000) { + 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 to disk at UTC "LLU" ms - last coded frame PTS %d\n", gf_net_get_utc(), video_output_file->codec_ctx->coded_frame->pts)); + 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)); } //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; + } +#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; } +#endif return 0; } @@ -854,44 +865,32 @@ int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, Bool gf_isom_start_fragment(video_output_file->isof, 1); if (!video_output_file->segment_started) { - u32 sec, frac; - u64 ntpts; - video_output_file->pts_at_segment_start = video_output_file->codec_ctx->coded_frame->pts; video_output_file->segment_started = 1; - if (insert_utc) { - time_t secs; - struct tm t; - gf_net_get_ntp(&sec, &frac); - ntpts = sec; - ntpts <<= 32; - ntpts |= frac; - gf_isom_set_fragment_reference_time(video_output_file->isof, video_output_file->trackID, ntpts, video_output_file->pts_at_segment_start); - - secs = sec - GF_NTP_SEC_1900_TO_1970; - t = *gmtime(&secs); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Producer reference clock: Timestamp %d matches sender NTP time %d-%02d-%02dT%02d:%02d:%02dZ (NTP frac part %u) \n", (u32) video_output_file->pts_at_segment_start, 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, (u32) frac )); - + 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); } } - gf_isom_set_traf_base_media_decode_time(video_output_file->isof, video_output_file->trackID, video_output_file->first_dts); - video_output_file->first_dts += video_output_file->frame_per_fragment; + gf_isom_set_traf_base_media_decode_time(video_output_file->isof, video_output_file->trackID, video_output_file->first_dts_in_fragment); + video_output_file->first_dts_in_fragment += video_output_file->frame_per_fragment; } dc_gpac_video_isom_write(video_output_file); if (frame_nb % video_output_file->frame_per_fragment == video_output_file->frame_per_fragment - 1) { gf_isom_flush_fragments(video_output_file->isof, 1); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Flushed fragment to disk at UTC "LLU" ms - last coded frame PTS %d\n", gf_net_get_utc(), video_output_file->codec_ctx->coded_frame->pts)); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Flushed fragment to disk at UTC "LLU" ms - last coded frame PTS "LLU"\n", gf_net_get_utc(), video_output_file->codec_ctx->coded_frame->pts)); } if (frame_nb + 1 == video_output_file->frame_per_segment) return 1; return 0; +#endif + default: return -2; } @@ -902,18 +901,21 @@ int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, Bool int dc_video_muxer_close(VideoOutputFile *video_output_file) { video_output_file->fragment_started = video_output_file->segment_started = 0; + video_output_file->nb_segments++; switch (video_output_file->muxer_type) { case FFMPEG_VIDEO_MUXER: return dc_ffmpeg_video_muxer_close(video_output_file); case RAW_VIDEO_H264: return dc_raw_h264_close(video_output_file); +#ifndef GPAC_DISABLE_ISOM case GPAC_VIDEO_MUXER: dc_gpac_video_isom_close_seg(video_output_file); return dc_gpac_video_isom_close(video_output_file); case GPAC_INIT_VIDEO_MUXER_AVC1: case GPAC_INIT_VIDEO_MUXER_AVC3: return dc_gpac_video_isom_close_seg(video_output_file); +#endif default: return -2; } diff --git a/applications/dashcast/video_muxer.h b/applications/dashcast/video_muxer.h index f869589..08ded74 100644 --- a/applications/dashcast/video_muxer.h +++ b/applications/dashcast/video_muxer.h @@ -36,7 +36,6 @@ #include "video_scaler.h" - typedef enum { FFMPEG_VIDEO_MUXER, RAW_VIDEO_H264, @@ -61,8 +60,11 @@ typedef struct { FILE *file; +#ifndef GPAC_DISABLE_ISOM GF_ISOFile *isof; GF_ISOSample *sample; +#endif + u32 trackID; /* Index of the video stream in the file */ int vstream_idx; @@ -80,7 +82,8 @@ typedef struct { int seg_dur; int frag_dur; - u64 first_dts; + u64 first_dts_in_fragment; + u64 ntp_at_first_dts; u32 seg_marker; @@ -89,10 +92,11 @@ typedef struct { Bool use_source_timing; - u64 pts_at_segment_start; + u64 pts_at_segment_start, pts_at_first_segment; u64 last_pts, last_dts; u64 frame_dur; u32 timescale; + u32 nb_segments; Bool fragment_started, segment_started; const char *rep_id; } VideoOutputFile; @@ -103,7 +107,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, Bool insert_utc); +int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, u64 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 277d95f..0135d9d 100644 --- a/applications/dashcast/video_scaler.c +++ b/applications/dashcast/video_scaler.c @@ -143,6 +143,8 @@ int dc_video_scaler_data_set_prop(VideoInputData *video_input_data, VideoScaledD video_scaled_data->vsprop[index].in_height = video_input_data->vprop[index].height - video_input_data->vprop[index].crop_y; video_scaled_data->vsprop[index].in_pix_fmt = video_input_data->vprop[index].pix_fmt; + video_scaled_data->sar = video_input_data->vprop[index].sar; + video_scaled_data->vsprop[index].sws_ctx = sws_getContext( video_scaled_data->vsprop[index].in_width, video_scaled_data->vsprop[index].in_height, @@ -164,18 +166,25 @@ int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *vid VideoScaledDataNode *video_scaled_data_node; AVFrame *src_vframe; - ret = dc_consumer_lock(&video_scaled_data->consumer, &video_input_data->circular_buf); - if (ret < 0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler got an end of buffer!\n")); - return -2; - } - + //step 1: try to lock output slot. If none available, return .... if (video_input_data->circular_buf.size > 1) dc_consumer_unlock_previous(&video_scaled_data->consumer, &video_input_data->circular_buf); - dc_producer_lock(&video_scaled_data->producer, &video_scaled_data->circular_buf); + ret = dc_producer_lock(&video_scaled_data->producer, &video_scaled_data->circular_buf); + //not ready + if (ret<0) { + return -1; + } dc_producer_unlock_previous(&video_scaled_data->producer, &video_scaled_data->circular_buf); + //step 2: lock input + ret = dc_consumer_lock(&video_scaled_data->consumer, &video_input_data->circular_buf); + if (ret < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler got an end of input tbuffer!\n")); + return -2; + } + + //step 3 - grab source and dest images video_data_node = (VideoDataNode*)dc_consumer_consume(&video_scaled_data->consumer, &video_input_data->circular_buf); video_scaled_data_node = (VideoScaledDataNode*)dc_producer_produce(&video_scaled_data->producer, &video_scaled_data->circular_buf); index = video_data_node->source_number; @@ -201,11 +210,16 @@ int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *vid src_height = video_input_data->vprop[index].height; } + //rescale the cropped frame - 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); + 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); + 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; if (video_data_node->nb_raw_frames_ref) { diff --git a/applications/dashcast/video_scaler.h b/applications/dashcast/video_scaler.h index b50b9c7..3442e59 100644 --- a/applications/dashcast/video_scaler.h +++ b/applications/dashcast/video_scaler.h @@ -51,6 +51,7 @@ typedef struct { int out_width; int out_height; int out_pix_fmt; + AVRational sar; /* scaler of the libav */ //struct SwsContext * sws_ctx; diff --git a/applications/generators/MPEG4/MPEG4Gen.dsp b/applications/generators/MPEG4/MPEG4Gen.dsp index e5a7d9c..2339ae7 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 e3bd23b..15ce429 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/main.c b/applications/generators/MPEG4/main.c index 1715182..a3f7b0e 100644 --- a/applications/generators/MPEG4/main.c +++ b/applications/generators/MPEG4/main.c @@ -229,7 +229,7 @@ FILE *BeginFile(char *name, u32 type) } } - f = fopen(sPath, "wt"); + f = gf_fopen(sPath, "wt"); fprintf(f, "%s\n", cprt); @@ -258,7 +258,7 @@ void EndFile(FILE *f, char *name, u32 type) } fprintf(f, "\n\n#endif\t\t/*_%s_H*/\n\n", name); } - fclose(f); + gf_fclose(f); } void TranslateToken(char *token) @@ -1624,7 +1624,7 @@ void generate_ndts(GF_List *NDTs, GF_List *nodes, u32 nbVersion) char szFile[100]; FILE *f; sprintf(szFile, "NdtListV%d.html", i+1); - f = fopen(szFile, "wt"); + f = gf_fopen(szFile, "wt"); fprintf(f, "\n"\ "\n"\ @@ -1684,7 +1684,7 @@ void generate_ndts(GF_List *NDTs, GF_List *nodes, u32 nbVersion) fprintf(f, "\n"); } - fclose(f); + gf_fclose(f); } } @@ -1715,7 +1715,7 @@ int main (int argc, char **argv) if (!strcmp(argv[i], "-ndt")) { generate_ndt = 1; } else if (argv[i][0]=='-') { - fskip = fopen(argv[i+1], "rt"); + fskip = gf_fopen(argv[i+1], "rt"); if (!fskip) { printf("file %s not found\n", argv[i+1]); return 0; @@ -1726,10 +1726,10 @@ int main (int argc, char **argv) nbVersion=1; while (1) { sprintf(szTempFile, "templates%u.txt", nbVersion); - nodes = fopen(szTempFile, "rt"); + nodes = gf_fopen(szTempFile, "rt"); if (!nodes) { sprintf(szTempFile, "template%u.txt", nbVersion); - nodes = fopen(szTempFile, "rt"); + nodes = gf_fopen(szTempFile, "rt"); } if (!nodes) break; @@ -1740,7 +1740,7 @@ int main (int argc, char **argv) //special case for viewport: it is present in V1 but empty if (nbVersion==1) CheckInTable("SFViewportNode", NDTs); nbVersion++; - fclose(nodes); + gf_fclose(nodes); } nbVersion--; printf("BIFS tables parsed: %d versions\n", nbVersion); @@ -1752,7 +1752,7 @@ int main (int argc, char **argv) if (fskip) { parse_profile(BNodes, fskip); - fclose(fskip); + gf_fclose(fskip); } //write the nodes def diff --git a/applications/generators/SVG/SVGGen.dsp b/applications/generators/SVG/SVGGen.dsp index c76b774..8d95fcb 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 1b31b26..170c054 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/html.c b/applications/generators/SVG/html.c index 53bf02b..6fdbbee 100644 --- a/applications/generators/SVG/html.c +++ b/applications/generators/SVG/html.c @@ -30,7 +30,7 @@ static FILE *BeginHtml() char sPath[GF_MAX_PATH]; sprintf(sPath, "C:%cUsers%cCyril%ccontent%csvg%cregression%cregression_table.html", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); - f = fopen(sPath, "wt"); + f = gf_fopen(sPath, "wt"); fprintf(f, "\n"); fprintf(f, "\n"); @@ -55,7 +55,7 @@ static void EndHtml(FILE *f) { fprintf(f, "\n"); fprintf(f, "\n"); - fclose(f); + gf_fclose(f); } /* Generates an HTML table */ diff --git a/applications/generators/SVG/laser.c b/applications/generators/SVG/laser.c index 376bef3..3fc8a31 100644 --- a/applications/generators/SVG/laser.c +++ b/applications/generators/SVG/laser.c @@ -263,5 +263,5 @@ void generate_laser_tables_da(GF_List *atts) } fprintf(output, "\treturn 1;\n}\n\n"); - fclose(output); + gf_fclose(output); } \ No newline at end of file diff --git a/applications/generators/SVG/main.c b/applications/generators/SVG/main.c index 668c701..3a393d8 100644 --- a/applications/generators/SVG/main.c +++ b/applications/generators/SVG/main.c @@ -805,7 +805,7 @@ FILE *BeginFile(u32 type) #endif } - f = fopen(sPath, "wt"); + f = gf_fopen(sPath, "wt"); fprintf(f, "%s\n", COPYRIGHT); { @@ -840,7 +840,7 @@ void EndFile(FILE *f, u32 type) } else { fprintf(f, "\n"); } - fclose(f); + gf_fclose(f); } void generateAttributes(FILE *output, GF_List *attributes, Bool inDefine) diff --git a/applications/generators/X3D/X3DGen.dsp b/applications/generators/X3D/X3DGen.dsp index 7afd243..b16b8dd 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 2aca071..2c265c5 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 ecd6a29..339819a 100644 --- a/applications/generators/X3D/main.c +++ b/applications/generators/X3D/main.c @@ -180,7 +180,7 @@ FILE *BeginFile(u32 type) sprintf(sPath, "..%c..%c..%csrc%cscenegraph%cx3d_nodes.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); } - f = fopen(sPath, "wt"); + f = gf_fopen(sPath, "wt"); fprintf(f, "%s\n", COPYRIGHT); { @@ -203,7 +203,7 @@ void EndFile(FILE *f, u32 type) fprintf(f, "#ifdef __cplusplus\n}\n#endif\n\n"); fprintf(f, "\n\n#endif\t\t/*_GF_X3D_NODES_H*/\n\n"); } - fclose(f); + gf_fclose(f); } void TranslateToken(char *token) @@ -1208,7 +1208,7 @@ int main (int argc, char **argv) X3DField *bf; u32 nb_nodes, nb_imp; - nodes = fopen("templates_X3D.txt", "rt"); + nodes = gf_fopen("templates_X3D.txt", "rt"); if (!nodes) { fprintf(stdout, "cannot open \"templates_X3D.txt\" - aborting\n"); return 0; @@ -1218,14 +1218,14 @@ int main (int argc, char **argv) NDTs = gf_list_new(); //all nodes are in the same list but we keep version info ParseTemplateFile(nodes, XNodes, NDTs); - fclose(nodes); + gf_fclose(nodes); if (argc>1) { - pf = fopen(argv[1], "rt"); + pf = gf_fopen(argv[1], "rt"); if (!pf) fprintf(stdout, "Cannot open profile file %s\n", argv[1]); else { parse_profile(XNodes, pf); - fclose(pf); + gf_fclose(pf); } } diff --git a/applications/m3u82mpd/m3u82mpd.vcproj b/applications/m3u82mpd/m3u82mpd.vcproj index 1887aca..b139419 100644 --- a/applications/m3u82mpd/m3u82mpd.vcproj +++ b/applications/m3u82mpd/m3u82mpd.vcproj @@ -1,183 +1,183 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/m3u82mpd/main.c b/applications/m3u82mpd/main.c index 5621030..2c161d5 100644 --- a/applications/m3u82mpd/main.c +++ b/applications/m3u82mpd/main.c @@ -58,7 +58,7 @@ int main(int argc, char **argv) e = parse_root_playlist(m3u8_local_name, &pl, "."); if (e != GF_OK) return -1; - fmpd = fopen(argv[2], "wt"); + fmpd = gf_fopen(argv[2], "wt"); fprintf(fmpd, "\n"); fprintf(fmpd, " \n"); @@ -111,7 +111,7 @@ int main(int argc, char **argv) } fprintf(fmpd, " \n"); fprintf(fmpd, ""); - fclose(fmpd); + gf_fclose(fmpd); variant_playlist_del(pl); if (is_local) break; gf_sleep(update_interval); diff --git a/applications/mp42avi/main.c b/applications/mp42avi/main.c index 06403bf..4b6c057 100644 --- a/applications/mp42avi/main.c +++ b/applications/mp42avi/main.c @@ -148,7 +148,7 @@ void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) sprintf(str, "%s_%d.bmp", rad_name, img_num); } - fout = fopen(str, "wb"); + fout = gf_fopen(str, "wb"); if (!fout) return; memset(&fh, 0, sizeof(fh)); @@ -184,7 +184,7 @@ void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) } } - fclose(fout); + gf_fclose(fout); } @@ -200,10 +200,10 @@ void write_raw(GF_VideoSurface *fb, char *rad_name, u32 img_num) sprintf(str, "%s_%d.raw", rad_name, img_num); } - fout = fopen(str, "wb"); + fout = gf_fopen(str, "wb"); if (!fout) return; gf_fwrite(fb->video_buffer , fb->height*fb->pitch, 1, fout); - fclose(fout); + gf_fclose(fout); } void dump_frame(BIFSVID b2v, char *conv_buf, char *out_path, u32 dump_type, avi_t *avi_out, u32 frameNum) @@ -365,9 +365,9 @@ void bifs3d_viewpoints_merger(GF_ISOFile *file, char *szConfigFile, u32 width, u for (viewpoint_index = 1; viewpoint_index <= nb_viewpoints; viewpoint_index++) { GF_SAFEALLOC(rendered_frames[viewpoint_index-1], fb.width*fb.height*3); gf_sc_set_viewpoint(b2v.sr, viewpoint_index, NULL); - gf_sc_draw_frame(b2v.sr); + gf_sc_draw_frame(b2v.sr, 0, NULL); /*needed for background2D !!*/ - gf_sc_draw_frame(b2v.sr); + gf_sc_draw_frame(b2v.sr, 0, NULL); strcpy(out_path, ""); if (out_dir) { strcat(out_path, out_dir); @@ -583,7 +583,7 @@ void bifs_to_vid(GF_ISOFile *file, char *szConfigFile, u32 width, u32 height, ch } gf_sc_set_size(b2v.sr, width, height); - gf_sc_draw_frame(b2v.sr); + gf_sc_draw_frame(b2v.sr, 0, NULL); gf_sc_get_screen_buffer(b2v.sr, &fb); width = fb.width; @@ -613,10 +613,10 @@ void bifs_to_vid(GF_ISOFile *file, char *szConfigFile, u32 width, u32 height, ch if ((frameID>=0) && (j<(u32)frameID)) continue; if ((dump_time>=0) && ((u32) dump_time>b2v.cts)) continue; /*render frame*/ - gf_sc_draw_frame(b2v.sr); + gf_sc_draw_frame(b2v.sr, 0, NULL); /*needed for background2D !!*/ if (first_dump) { - gf_sc_draw_frame(b2v.sr); + gf_sc_draw_frame(b2v.sr, 0, NULL); first_dump = 0; } diff --git a/applications/mp42ts/Makefile b/applications/mp42ts/Makefile index 3e79f20..c8b88db 100644 --- a/applications/mp42ts/Makefile +++ b/applications/mp42ts/Makefile @@ -20,10 +20,10 @@ OBJS= main.o LINKFLAGS=-L../../bin/gcc ifeq ($(CONFIG_WIN32),yes) EXE=.exe -PROG=mp42ts$(EXE) +PROG=MP42TS$(EXE) else EXT= -PROG=mp42ts +PROG=MP42TS endif LINKFLAGS+=-lgpac diff --git a/applications/mp42ts/main.c b/applications/mp42ts/main.c index b430b6b..eba445d 100644 --- a/applications/mp42ts/main.c +++ b/applications/mp42ts/main.c @@ -40,25 +40,17 @@ #include #endif -#ifdef GPAC_DISABLE_ISOM - -#error "Cannot compile MP42TS if GPAC is not built with ISO File Format support" - -#endif #ifdef GPAC_DISABLE_MPEG2TS_MUX - #error "Cannot compile MP42TS if GPAC is not built with MPEG2-TS Muxing support" - #endif - -#define UDP_BUFFER_SIZE 0x40000 - #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*/ u32 temi_url_insertion_delay = 1000; +u32 temi_offset = 0; +Bool temi_disable_loop = 0; FILE *logfile = NULL; static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) @@ -74,7 +66,7 @@ static GFINLINE void usage() "GPAC Copyright (c) Telecom ParisTech 2000-2014\n" "GPAC Configuration: " GPAC_CONFIGURATION "\n" "Features: %s\n\n", gpac_features()); - fprintf(stderr, "mp2ts [options]\n" + fprintf(stderr, "mp42ts [options]\n" "\n" "Inputs:\n" "-src filename[:OPTS] specifies an input file used for a TS service\n" @@ -110,19 +102,21 @@ static GFINLINE void usage() "-pcr-init V sets initial value V for PCR - if not set, random value is used\n" "-pcr-offset V offsets all timestamps from PCR by V, in 90kHz. Default value is computed based on input media.\n" "-psi-rate V sets PSI refresh rate V in ms (default 100ms).\n" - " * If 0, PSI data is only send once at the begining or before each IDR when -rap option is set.\n" + " * If 0, PSI data is only send once at the beginning or before each IDR when -rap option is set.\n" " * 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" "-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 N TS packets together before sending on network or writing to file\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" "-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-delay DelayMS Specifies delay between two TEMI url descriptors\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" "-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" @@ -149,7 +143,11 @@ static GFINLINE void usage() #define MAX_MUX_SRC_PROG 100 typedef struct { + +#ifndef GPAC_DISABLE_ISOM GF_ISOFile *mp4; +#endif + u32 nb_streams, pcr_idx; GF_ESInterface streams[40]; GF_Descriptor *iod; @@ -177,6 +175,7 @@ typedef struct Double last_ntp; } M2TSSource; +#ifndef GPAC_DISABLE_ISOM typedef struct { GF_ISOFile *mp4; @@ -196,8 +195,11 @@ typedef struct const char *temi_url; u32 last_temi_url; + Bool insert_temi; + Bool insert_ntp; } GF_ESIMP4; +#endif typedef struct { @@ -249,19 +251,18 @@ static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 } else { last_time = (u32) (1000*timecode/timescale); } - if (!*last_url_time || (last_time - *last_url_time + 1 >= temi_url_insertion_delay) ) { + if (temi_url && (!*last_url_time || (last_time - *last_url_time + 1 >= temi_url_insertion_delay)) ) { *last_url_time = last_time + 1; len = 0; - gf_bs_write_int(bs, 0x00, 8); + gf_bs_write_int(bs, GF_M2TS_AFDESC_LOCATION_DESCRIPTOR, 8); gf_bs_write_int(bs, len, 8); gf_bs_write_int(bs, 0, 1); //force_reload gf_bs_write_int(bs, 0, 1); //is_announcement gf_bs_write_int(bs, 0, 1); //splicing_flag - gf_bs_write_int(bs, strlen(temi_url) ? 0 : 1, 1); //external_url gf_bs_write_int(bs, 0, 1); //use_base_temi_url - gf_bs_write_int(bs, 0xFF, 3); //reserved - gf_bs_write_int(bs, 0, 8); //timeline_id + gf_bs_write_int(bs, 0xFF, 5); //reserved + gf_bs_write_int(bs, 0, 7); //timeline_id if (strlen(temi_url)) { char *url = (char *)temi_url; @@ -284,16 +285,17 @@ static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 } if (timescale || ntp) { + Bool use64 = (timecode > 0xFFFFFFFFUL) ? 1 : 0; len = 3; //3 bytes flags - if (timescale) len += 4 + ((timecode > 0xFFFFFFFFUL) ? 8 : 4); + if (timescale) len += 4 + (use64 ? 8 : 4); if (ntp) len += 8; //write timeline descriptor - gf_bs_write_int(bs, 0x01, 8); + gf_bs_write_int(bs, GF_M2TS_AFDESC_TIMELINE_DESCRIPTOR, 8); gf_bs_write_int(bs, len, 8); - gf_bs_write_int(bs, timescale ? ((timecode > 0xFFFFFFUL) ? 2 : 1) : 0, 2); //has_timestamp + gf_bs_write_int(bs, timescale ? (use64 ? 2 : 1) : 0, 2); //has_timestamp gf_bs_write_int(bs, ntp ? 1 : 0, 1); //has_ntp gf_bs_write_int(bs, 0, 1); //has_ptp gf_bs_write_int(bs, 0, 2); //has_timecode @@ -301,10 +303,10 @@ 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, 0, 8); //timeline_id + gf_bs_write_int(bs, temi_url ? 0 : 150, 8); //timeline_id if (timescale) { gf_bs_write_u32(bs, timescale); //timescale - if (timecode > 0xFFFFFFUL) + if (use64) gf_bs_write_u64(bs, timecode); //timestamp else gf_bs_write_u32(bs, (u32) timecode); //timestamp @@ -318,6 +320,8 @@ static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 return res; } +#ifndef GPAC_DISABLE_ISOM + static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) { char af_data[188]; @@ -345,8 +349,25 @@ 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->temi_url) { - pck.mpeg2_af_descriptors_size = format_af_descriptor(af_data, priv->sample->DTS + priv->sample->CTS_Offset, ifce->timescale, 0, priv->temi_url, &priv->last_temi_url); + if (priv->insert_temi) { + u64 ntp=0; + u64 tc = priv->sample->DTS + priv->sample->CTS_Offset; + if (temi_disable_loop) { + tc += priv->ts_offset; + } + + if (temi_offset) { + tc += ((u64) temi_offset) * ifce->timescale / 1000; + } + + if (priv->insert_ntp) { + u32 sec, frac; + gf_net_get_ntp(&sec, &frac); + ntp = sec; + 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 = af_data; } @@ -459,7 +480,7 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFile *mp4, u32 track_num, u32 bifs_use_pes, Bool compute_max_size) { GF_ESIMP4 *priv; - char _lan[4]; + char *_lan; GF_ESD *esd; u64 avg_rate, duration; s32 ref_count; @@ -512,11 +533,15 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi } gf_odf_desc_del((GF_Descriptor *)esd); } - gf_isom_get_media_language(mp4, track_num, _lan); - if (!strcmp(_lan, "und")) + gf_isom_get_media_language(mp4, track_num, &_lan); + if (!_lan || !strcmp(_lan, "und")) { ifce->lang = 0; - else + } else { ifce->lang = GF_4CC(_lan[0],_lan[1],_lan[2],' '); + } + if (_lan) { + gf_free(_lan); + } ifce->timescale = gf_isom_get_media_timescale(mp4, track_num); ifce->duration = gf_isom_get_media_timescale(mp4, track_num); @@ -573,7 +598,6 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi ifce->depends_on_stream = 0; } - source->max_sample_size = 0; if (compute_max_size) { u32 i; for (i=0; i < priv->sample_count; i++) { @@ -584,6 +608,8 @@ static void fill_isom_es_ifce(M2TSSource *source, GF_ESInterface *ifce, GF_ISOFi } +#endif //GPAC_DISABLE_ISOM + #ifndef GPAC_DISABLE_SENG static GF_Err seng_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) @@ -900,10 +926,12 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf } #endif /*GPAC_DISABLE_STREAMING*/ +#ifndef GPAC_DISABLE_SENG static GF_Err void_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param) { return GF_OK; } +#endif /*AAC import features*/ #ifndef GPAC_DISABLE_PLAYER @@ -1182,13 +1210,13 @@ static u32 seng_output(void *param) fprintf(stderr, "Update file modified - processing\n"); last_src_modif = mod_time; - srcf = gf_f64_open(source->bifs_src_name, "rt"); + srcf = gf_fopen(source->bifs_src_name, "rt"); if (!srcf) continue; /*checks if we have a broadcast config*/ if (!fgets(flag_buf, 200, srcf)) flag_buf[0] = '\0'; - fclose(srcf); + gf_fclose(srcf); aggregate_au = force_rap = adjust_carousel_time = discard_pending = signal_rap = signal_critical = 0; version_inc = 1; @@ -1349,19 +1377,20 @@ void fill_seng_es_ifce(GF_ESInterface *ifce, u32 i, GF_SceneEngine *seng, u32 pe } #endif -static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mpeg4_signaling, char *update, char *audio_input_ip, u16 audio_input_port, char *video_buffer, Bool force_real_time, u32 bifs_use_pes, const char *temi_url, Bool compute_max_size) +static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mpeg4_signaling, char *update, char *audio_input_ip, u16 audio_input_port, char *video_buffer, Bool force_real_time, u32 bifs_use_pes, const char *temi_url, Bool compute_max_size, Bool insert_ntp) { #ifndef GPAC_DISABLE_STREAMING GF_SDPInfo *sdp; #endif - u32 i; s64 min_offset = 0; memset(source, 0, sizeof(M2TSSource)); source->mpeg4_signaling = mpeg4_signaling; /*open ISO file*/ +#ifndef GPAC_DISABLE_ISOM if (gf_isom_probe_file(src)) { + u32 i; u32 nb_tracks; Bool has_bifs_od = 0; u32 first_audio = 0; @@ -1404,7 +1433,13 @@ 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; - ((GF_ESIMP4 *)source->streams[i].input_udta)->temi_url = temi_url; + 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")) + ((GF_ESIMP4 *)source->streams[i].input_udta)->temi_url = temi_url; + } } } break; @@ -1515,26 +1550,28 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } return 1; } +#endif + #ifndef GPAC_DISABLE_STREAMING /*open SDP file*/ if (strstr(src, ".sdp")) { GF_X_Attribute *att; char *sdp_buf; - u32 sdp_size; + u32 sdp_size, i; GF_Err e; - FILE *_sdp = fopen(src, "rt"); + FILE *_sdp = gf_fopen(src, "rt"); if (!_sdp) { fprintf(stderr, "Error opening %s - no such file\n", src); return 0; } - gf_f64_seek(_sdp, 0, SEEK_END); - sdp_size = (u32)gf_f64_tell(_sdp); - gf_f64_seek(_sdp, 0, SEEK_SET); + gf_fseek(_sdp, 0, SEEK_END); + sdp_size = (u32)gf_ftell(_sdp); + gf_fseek(_sdp, 0, SEEK_SET); sdp_buf = (char*)gf_malloc(sizeof(char)*sdp_size); memset(sdp_buf, 0, sizeof(char)*sdp_size); sdp_size = (u32) fread(sdp_buf, 1, sdp_size, _sdp); - fclose(_sdp); + gf_fclose(_sdp); sdp = gf_sdp_info_new(); e = gf_sdp_info_parse(sdp, sdp_buf, sdp_size); @@ -1592,6 +1629,7 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp #ifndef GPAC_DISABLE_SENG if (strstr(src, ".bt")) //open .bt file { + u32 i; u32 load_type=0; source->seng = gf_seng_init(source, src, load_type, NULL, (load_type == GF_SM_LOAD_DIMS) ? 1 : 0); if (!source->seng) { @@ -1733,9 +1771,9 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } else #endif { - FILE *f = fopen(src, "rt"); + FILE *f = gf_fopen(src, "rt"); if (f) { - fclose(f); + gf_fclose(f); fprintf(stderr, "Error opening %s - not a supported input media, skipping.\n", src); } else { fprintf(stderr, "Error opening %s - no such file.\n", src); @@ -1744,6 +1782,10 @@ static Bool open_source(M2TSSource *source, char *src, u32 carousel_rate, u32 mp } } +#ifdef GPAC_MEMORY_TRACKING +static Bool enable_mem_tracker = GF_FALSE; +#endif + /*macro to keep retro compatibility with '=' and spaces in parse_args*/ #define CHECK_PARAM(param) (!strnicmp(arg, param, strlen(param)) \ && ( ((arg[strlen(param)] == '=') && (next_arg = arg+strlen(param)+1)) \ @@ -1758,7 +1800,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car char** segment_dir, u32 *segment_duration, char **segment_manifest, u32 *segment_number, char **segment_http_prefix, u32 *split_rap, u32 *nb_pck_pack, u32 *pcr_ms, u32 *ttl, const char **ip_ifce, const char **temi_url, u32 *sdt_refresh_rate) { Bool rate_found=0, mpeg4_carousel_found=0, time_found=0, src_found=0, dst_found=0, audio_input_found=0, video_input_found=0, - seg_dur_found=0, seg_dir_found=0, seg_manifest_found=0, seg_number_found=0, seg_http_found=0, real_time_found=0; + seg_dur_found=0, seg_dir_found=0, seg_manifest_found=0, seg_number_found=0, seg_http_found=0, real_time_found=0, insert_ntp=0; char *arg = NULL, *next_arg = NULL, *error_msg = "no argument found"; u32 mpeg4_signaling = GF_M2TS_MPEG4_SIGNALING_NONE; Bool force_real_time = 0; @@ -1785,14 +1827,14 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car goto error; } video_input_found = 1; - f = fopen(next_arg, "rb"); + f = gf_fopen(next_arg, "rb"); if (!f) { error_msg = "video file not found: "; goto error; } - gf_f64_seek(f, 0, SEEK_END); - *video_buffer_size = (u32)gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + *video_buffer_size = (u32)gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); assert(*video_buffer_size); *video_buffer = (char*) gf_malloc(*video_buffer_size); { @@ -1800,7 +1842,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car if (read != *video_buffer_size) fprintf(stderr, "Error while reading video file, has readen %u chars instead of %u.\n", read, *video_buffer_size); } - fclose(f); + gf_fclose(f); } else if (CHECK_PARAM("-audio")) { if (audio_input_found) { error_msg = "multiple '-audio' found"; @@ -1858,6 +1900,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car } else if (!strcmp(arg, "-mem-track")) { #ifdef GPAC_MEMORY_TRACKING gf_sys_close(); + enable_mem_tracker = GF_TRUE; gf_sys_init(GF_TRUE); gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); #else @@ -1916,7 +1959,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car if (gf_log_set_tools_levels(next_arg) != GF_OK) return GF_BAD_PARAM; } else if (CHECK_PARAM("-lf")) { - logfile = gf_f64_open(next_arg, "wt"); + logfile = gf_fopen(next_arg, "wt"); gf_log_set_callback(logfile, on_gpac_log); } else if (CHECK_PARAM("-segment-dir")) { if (seg_dir_found) { @@ -1931,19 +1974,19 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car } seg_dur_found = 1; *segment_duration = atoi(next_arg); - } else if (CHECK_PARAM("-segment-manifest=")) { + } else if (CHECK_PARAM("-segment-manifest")) { if (seg_manifest_found) { goto error; } seg_manifest_found = 1; *segment_manifest = next_arg; - } else if (CHECK_PARAM("-segment-http-prefix=")) { + } else if (CHECK_PARAM("-segment-http-prefix")) { if (seg_http_found) { goto error; } seg_http_found = 1; *segment_http_prefix = next_arg; - } else if (CHECK_PARAM("-segment-number=")) { + } else if (CHECK_PARAM("-segment-number")) { if (seg_number_found) { goto error; } @@ -1961,11 +2004,13 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car } else if (CHECK_PARAM("-dst-file")) { dst_found = 1; *ts_out = gf_strdup(next_arg); - } else if (!strnicmp(arg, "-temi", 5)) { - *temi_url = ""; - if (arg[5]=='=' || arg[5]==' ') { - *temi_url = arg+6; - if (strlen(arg+6) > 150) { + } else if (CHECK_PARAM("-temi")) { + if (next_arg[0]=='-') { + *temi_url = "NOTEMIURL"; + i--; + } else { + *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; } @@ -1973,6 +2018,12 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car } else if (CHECK_PARAM("-temi-delay")) { temi_url_insertion_delay = atoi(next_arg); + } else if (CHECK_PARAM("-temi-offset")) { + temi_offset = atoi(next_arg); + } else if (!stricmp(arg, "-temi-noloop")) { + temi_disable_loop = 1; + } else if (!stricmp(arg, "-insert-ntp")) { + insert_ntp = GF_TRUE; } else if (CHECK_PARAM("-dst-udp")) { char *sep = strchr(next_arg, ':'); @@ -2028,7 +2079,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car src_args = src_args + 1; } - res = open_source(&sources[*nb_sources], next_arg, *carrousel_rate, mpeg4_signaling, *bifs_src_name, *audio_input_ip, *audio_input_port, *video_buffer, force_real_time, *bifs_use_pes, *temi_url, (*pcr_offset == (u32) -1) ? 1 : 0); + res = open_source(&sources[*nb_sources], next_arg, *carrousel_rate, mpeg4_signaling, *bifs_src_name, *audio_input_ip, *audio_input_port, *video_buffer, force_real_time, *bifs_use_pes, *temi_url, (*pcr_offset == (u32) -1) ? 1 : 0, insert_ntp); //we may have arguments @@ -2101,7 +2152,7 @@ static GF_Err write_manifest(char *manifest, char *segment_dir, u32 segment_dura sprintf(manifest_name, "%s", manifest); } - manifest_fp = fopen(tmp_manifest, "w"); + manifest_fp = gf_fopen(tmp_manifest, "w"); if (!manifest_fp) { fprintf(stderr, "Could not create m3u8 manifest file (%s)\n", tmp_manifest); return GF_BAD_PARAM; @@ -2116,7 +2167,7 @@ static GF_Err write_manifest(char *manifest, char *segment_dir, u32 segment_dura if (end) { fprintf(manifest_fp, "#EXT-X-ENDLIST\n"); } - fclose(manifest_fp); + gf_fclose(manifest_fp); if (!rename(tmp_manifest, manifest_name)) { return GF_OK; @@ -2243,16 +2294,17 @@ int main(int argc, char **argv) /* create mp42ts muxer */ /***************************/ muxer = gf_m2ts_mux_new(mux_rate, psi_refresh_rate, real_time); - if (muxer) gf_m2ts_mux_use_single_au_pes_mode(muxer, single_au_pes); + if (!muxer) { + fprintf(stderr, "Could not create the muxer. Aborting.\n"); + goto exit; + } + gf_m2ts_mux_use_single_au_pes_mode(muxer, single_au_pes); if (pcr_init_val>=0) gf_m2ts_mux_set_initial_pcr(muxer, (u64) pcr_init_val); gf_m2ts_mux_set_pcr_max_interval(muxer, pcr_ms); if (ts_out != NULL) { if (segment_duration) { - char *dot; strcpy(segment_prefix, ts_out); - dot = strrchr(segment_prefix, '.'); - dot[0] = 0; if (segment_dir) { if (strchr("\\/", segment_name[strlen(segment_name)-1])) { sprintf(segment_name, "%s%s_%d.ts", segment_dir, segment_prefix, segment_index); @@ -2273,7 +2325,7 @@ int main(int argc, char **argv) ts_output_file = stdout; is_stdout = GF_TRUE; } else { - ts_output_file = fopen(ts_out, "wb"); + ts_output_file = gf_fopen(ts_out, "wb"); is_stdout = GF_FALSE; } if (!ts_output_file) { @@ -2510,7 +2562,7 @@ call_flush: gf_fwrite(ts_pck, 1, 188 * nb_pck_in_pack, ts_output_file); if (segment_duration && (muxer->time.sec > prev_seg_time.sec + segment_duration)) { prev_seg_time = muxer->time; - fclose(ts_output_file); + gf_fclose(ts_output_file); segment_index++; if (segment_dir) { if (strchr("\\/", segment_name[strlen(segment_name)-1])) { @@ -2521,7 +2573,7 @@ call_flush: } else { sprintf(segment_name, "%s_%d.ts", segment_prefix, segment_index); } - ts_output_file = fopen(segment_name, "wb"); + ts_output_file = gf_fopen(segment_name, "wb"); if (!ts_output_file) { fprintf(stderr, "Error opening %s\n", segment_name); goto exit; @@ -2595,7 +2647,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 %d - TS time %d - avg bitrate %d\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 - avg 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(); @@ -2643,7 +2695,7 @@ exit: if (segment_duration) { write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, segment_index - segment_number, segment_index, 1); } - if (ts_output_file && !is_stdout) fclose(ts_output_file); + if (ts_output_file && !is_stdout) gf_fclose(ts_output_file); if (ts_output_udp_sk) gf_sk_del(ts_output_udp_sk); #ifndef GPAC_DISABLE_STREAMING if (ts_output_rtp) gf_rtp_del(ts_output_rtp); @@ -2672,7 +2724,10 @@ exit: } } if (sources[i].iod) gf_odf_desc_del((GF_Descriptor*)sources[i].iod); +#ifndef GPAC_DISABLE_ISOM if (sources[i].mp4) gf_isom_close(sources[i].mp4); +#endif + #ifndef GPAC_DISABLE_SENG if (sources[i].seng) { gf_seng_terminate(sources[i].seng); @@ -2686,8 +2741,15 @@ exit: if (aac_reader) AAC_Reader_del(aac_reader); #endif - if (logfile) fclose(logfile); + if (logfile) gf_fclose(logfile); gf_sys_close(); + +#ifdef GPAC_MEMORY_TRACKING + if (enable_mem_tracker && (gf_memory_size() || gf_file_handles_count() )) { + gf_memory_print(); + return 2; + } +#endif return 0; } diff --git a/applications/mp4box/Makefile b/applications/mp4box/Makefile index 320acab..fde035a 100644 --- a/applications/mp4box/Makefile +++ b/applications/mp4box/Makefile @@ -25,11 +25,13 @@ LINKFLAGS=-L../../bin/gcc -L../../extra_lib/lib/gcc ifeq ($(CONFIG_WIN32),yes) EXE=.exe PROG=MP4Box$(EXE) + ifeq ($(MP4BOX_STATIC),yes) +LINKFLAGS+=-lgpac_static $(EXTRALIBS) ifneq ($(CONFIG_ZLIB),no) LINKFLAGS+=-lz endif -LINKFLAGS+=-lgpac_static $(EXTRALIBS) + else LINKFLAGS+=-lgpac endif @@ -38,11 +40,14 @@ else EXT= PROG=MP4Box + ifeq ($(MP4BOX_STATIC),yes) + +LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) + ifneq ($(CONFIG_ZLIB),no) LINKFLAGS+=-lz endif -LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) # spidermonkey support ifeq ($(CONFIG_JS),no) diff --git a/applications/mp4box/filedump.c b/applications/mp4box/filedump.c index 1966b5e..b2ca565 100644 --- a/applications/mp4box/filedump.c +++ b/applications/mp4box/filedump.c @@ -56,7 +56,7 @@ extern u32 swf_flags; extern Float swf_flatten_angle; -extern u32 get_file_type_by_ext(char *inName); +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); @@ -66,47 +66,20 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc void PrintLanguages() { - u32 i=0; + u32 i=0, count = gf_lang_get_count(); fprintf(stderr, "Supported ISO 639 languages and codes:\n\n"); - while (GF_ISO639_Lang[i]) { - if (!GF_ISO639_Lang[i+2][0]) { - i+=3; - continue; + for (i=0; i=0) return gf_lang_get_name(idx); + return lcode; } GF_Err dump_cover_art(GF_ISOFile *file, char *inName) @@ -125,10 +98,10 @@ GF_Err dump_cover_art(GF_ISOFile *file, char *inName) } sprintf(szName, "%s.%s", inName, (tag_len>>31) ? "png" : "jpg"); - t = gf_f64_open(szName, "wb"); + t = gf_fopen(szName, "wb"); gf_fwrite(tag, tag_len & 0x7FFFFFFF, 1, t); - fclose(t); + gf_fclose(t); return GF_OK; } @@ -140,13 +113,13 @@ GF_Err set_cover_art(GF_ISOFile *file, char *inName) char *tag, *ext; FILE *t; u32 tag_len; - t = gf_f64_open(inName, "rb"); - gf_f64_seek(t, 0, SEEK_END); - tag_len = (u32) gf_f64_tell(t); - gf_f64_seek(t, 0, SEEK_SET); + t = gf_fopen(inName, "rb"); + gf_fseek(t, 0, SEEK_END); + tag_len = (u32) gf_ftell(t); + gf_fseek(t, 0, SEEK_SET); tag = gf_malloc(sizeof(char) * tag_len); tag_len = (u32) fread(tag, sizeof(char), tag_len, t); - fclose(t); + gf_fclose(t); ext = strrchr(inName, '.'); if (!stricmp(ext, ".png")) tag_len |= 0x80000000; @@ -159,13 +132,13 @@ GF_Err set_cover_art(GF_ISOFile *file, char *inName) #ifndef GPAC_DISABLE_SCENE_DUMP -GF_Err dump_file_text(char *file, char *inName, u32 dump_mode, Bool do_log) +GF_Err dump_file_text(char *file, char *inName, GF_SceneDumpFormat dump_mode, Bool do_log) { GF_Err e; GF_SceneManager *ctx; GF_SceneGraph *sg; GF_SceneLoader load; - u32 ftype; + GF_FileType ftype; gf_log_cbk prev_logs = NULL; FILE *logs = NULL; e = GF_OK; @@ -178,11 +151,12 @@ GF_Err dump_file_text(char *file, char *inName, u32 dump_mode, Bool do_log) load.swf_import_flags = swf_flags; if (dump_mode == GF_SM_DUMP_SVG) { load.swf_import_flags |= GF_SM_SWF_USE_SVG; + load.svgOutFile = inName; } load.swf_flatten_limit = swf_flatten_angle; ftype = get_file_type_by_ext(file); - if (ftype == 1) { + if (ftype == GF_FILE_TYPE_ISO_MEDIA) { load.isom = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL); if (!load.isom) { e = gf_isom_last_error(NULL); @@ -191,9 +165,7 @@ GF_Err dump_file_text(char *file, char *inName, u32 dump_mode, Bool do_log) gf_sg_del(sg); return e; } - } - /*SAF*/ - else if (ftype==6) { + } else if (ftype==GF_FILE_TYPE_LSR_SAF) { load.isom = gf_isom_open("saf_conv", GF_ISOM_WRITE_EDIT, NULL); #ifndef GPAC_DISABLE_MEDIA_IMPORT if (load.isom) @@ -216,7 +188,7 @@ GF_Err dump_file_text(char *file, char *inName, u32 dump_mode, Bool do_log) if (do_log) { char szLog[GF_MAX_PATH]; sprintf(szLog, "%s_dec.logs", inName); - logs = gf_f64_open(szLog, "wt"); + logs = gf_fopen(szLog, "wt"); gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_DEBUG); prev_logs = gf_log_set_callback(logs, scene_coding_log); @@ -227,9 +199,9 @@ GF_Err dump_file_text(char *file, char *inName, u32 dump_mode, Bool do_log) if (logs) { gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_ERROR); gf_log_set_callback(NULL, prev_logs); - fclose(logs); + gf_fclose(logs); } - if (!e) { + if (!e && dump_mode != GF_SM_DUMP_SVG) { u32 count = gf_list_count(ctx->streams); if (count) fprintf(stderr, "Scene loaded - dumping %d systems streams\n", count); @@ -414,7 +386,7 @@ void dump_scene_stats(char *file, char *inName, u32 stat_level) if (inName) { strcpy(szBuf, inName); strcat(szBuf, "_stat.xml"); - dump = gf_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); close = 1; } else { dump = stderr; @@ -495,7 +467,7 @@ exit: } else { fprintf(dump, "\n"); } - if (dump && close) fclose(dump); + if (dump && close) gf_fclose(dump); fprintf(stderr, "done\n"); } #endif /*GPAC_DISABLE_SCENE_STATS*/ @@ -771,9 +743,9 @@ void dump_isom_xml(GF_ISOFile *file, char *inName) if (inName) { strcpy(szBuf, inName); strcat(szBuf, "_info.xml"); - dump = gf_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); gf_isom_dump(file, dump); - fclose(dump); + gf_fclose(dump); } else { gf_isom_dump(file, stderr); } @@ -785,14 +757,15 @@ void dump_isom_xml(GF_ISOFile *file, char *inName) void dump_file_rtp(GF_ISOFile *file, char *inName) { - u32 i, j; + u32 i, j, size; FILE *dump; + const char *sdp; char szBuf[1024]; if (inName) { strcpy(szBuf, inName); strcat(szBuf, "_rtp.xml"); - dump = gf_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); } else { dump = stderr; } @@ -805,13 +778,16 @@ void dump_file_rtp(GF_ISOFile *file, char *inName) if (gf_isom_get_media_type(file, i+1) != GF_ISOM_MEDIA_HINT) continue; fprintf(dump, "\n", gf_isom_get_track_id(file, i+1)); + gf_isom_sdp_track_get(file, i+1, &sdp, &size); + fprintf(dump, "%s", sdp); + for (j=0; j\n"); } fprintf(dump, "\n"); - if (inName) fclose(dump); + if (inName) gf_fclose(dump); } #endif @@ -825,7 +801,7 @@ void dump_file_timestamps(GF_ISOFile *file, char *inName) if (inName) { strcpy(szBuf, inName); strcat(szBuf, "_ts.txt"); - dump = gf_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); } else { dump = stderr; } @@ -834,17 +810,21 @@ void dump_file_timestamps(GF_ISOFile *file, char *inName) for (i=0; iDTS; cts = dts + (s32) samp->CTS_Offset; - - fprintf(dump, "Sample %d\tDTS "LLD"\tCTS "LLD"\t%d\t%d\t"LLD, j+1, LLD_CAST dts, LLD_CAST cts, samp->dataLength, samp->IsRAP, 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>3), (ptr[1] & 0x7) ); #endif //GPAC_DISABLE_HEVC return; } bs = gf_bs_new(ptr, ptr_size, GF_BITSTREAM_READ); - type = ptr[0] & 0x1F; + type = gf_bs_read_u8(bs) & 0x1F; fprintf(dump, "code=\"%d\" type=\"", type); res = 0; switch (type) { case GF_AVC_NALU_NON_IDR_SLICE: res = gf_media_avc_parse_nalu(bs, ptr[0], avc); fputs("Non IDR slice", dump); - - if (res>=0) + + if (res>=0) fprintf(dump, "\" poc=\"%d", avc->s_info.poc); break; case GF_AVC_NALU_DP_A_SLICE: @@ -1035,7 +1054,7 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ case GF_AVC_NALU_IDR_SLICE: res = gf_media_avc_parse_nalu(bs, ptr[0], avc); fputs("IDR slice", dump); - if (res>=0) + if (res>=0) fprintf(dump, "\" poc=\"%d", avc->s_info.poc); break; case GF_AVC_NALU_SEI: @@ -1107,6 +1126,11 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_ break; } fputs("\"", dump); + + if (type==GF_AVC_NALU_SEI) { + dump_sei(dump, (u8 *) ptr, ptr_size, is_hevc); + } + if (res<0) fprintf(dump, " status=\"error decoding slice\""); @@ -1119,26 +1143,38 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) 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 = 0; + Bool is_hevc = GF_FALSE; AVCState avc; GF_AVCConfig *avccfg, *svccfg; GF_HEVCConfig *hevccfg, *shvccfg; GF_AVCConfigSlot *slc; - Bool is_adobe_protection = GF_FALSE; +#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); + hevccfg = gf_isom_hevc_config_get(file, track, 1); + shvccfg = gf_isom_shvc_config_get(file, track, 1); + if (!avccfg && !svccfg && !hevccfg && !shvccfg) { + 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_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); } else { dump = stderr; } - track = gf_isom_get_track_by_id(file, trackID); count = gf_isom_get_sample_count(file, track); @@ -1149,10 +1185,6 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) fprintf(dump, "\n", trackID, count, timescale); #ifndef GPAC_DISABLE_AV_PARSERS - avccfg = gf_isom_avc_config_get(file, track, 1); - svccfg = gf_isom_svc_config_get(file, track, 1); - hevccfg = gf_isom_hevc_config_get(file, track, 1); - shvccfg = gf_isom_shvc_config_get(file, track, 1); //for tile tracks the hvcC is stored in the 'tbas' track if (!hevccfg && gf_isom_get_reference_count(file, track, GF_4CC('t','b','a','s'))) { u32 tk = 0; @@ -1223,6 +1255,7 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) } #endif } + #endif fprintf(dump, " \n"); @@ -1300,7 +1333,7 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName) fprintf(dump, " \n"); fprintf(dump, "\n"); - if (inName) fclose(dump); + 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); @@ -1324,7 +1357,7 @@ void dump_file_ismacryp(GF_ISOFile *file, char *inName) if (inName) { strcpy(szBuf, inName); strcat(szBuf, "_ismacryp.xml"); - dump = gf_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); } else { dump = stderr; } @@ -1346,11 +1379,11 @@ void dump_file_ismacryp(GF_ISOFile *file, char *inName) fprintf(dump, "\n"); } fprintf(dump, "\n"); - if (inName) fclose(dump); + if (inName) gf_fclose(dump); } -void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_convert, u32 dump_type) +void dump_timed_text_track(GF_ISOFile *file, u32 trackID, char *inName, Bool is_convert, GF_TextDumpType dump_type) { FILE *dump; GF_Err e; @@ -1373,16 +1406,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) - sprintf(szBuf, "%s.%s", inName, (dump_type==2) ? "svg" : ((dump_type==1) ? "srt" : "ttxt") ) ; + sprintf(szBuf, "%s.%s", inName, ext) ; else - sprintf(szBuf, "%s_%d_text.%s", inName, trackID, (dump_type==2) ? "svg" : ((dump_type==1) ? "srt" : "ttxt") ); - dump = gf_f64_open(szBuf, "wt"); + sprintf(szBuf, "%s_%d_text.%s", inName, trackID, ext); + dump = gf_fopen(szBuf, "wt"); } else { dump = stdout; } e = gf_isom_text_dump(file, track, dump, dump_type); - if (inName) fclose(dump); + if (inName) gf_fclose(dump); if (e) fprintf(stderr, "Conversion failed (%s)\n", gf_error_to_string(e)); else fprintf(stderr, "Conversion done\n"); @@ -1405,7 +1440,7 @@ void DumpSDP(GF_ISOFile *file, char *inName) ext = strchr(szBuf, '.'); if (ext) ext[0] = 0; strcat(szBuf, "_sdp.txt"); - dump = gf_f64_open(szBuf, "wt"); + dump = gf_fopen(szBuf, "wt"); } else { dump = stderr; fprintf(dump, "* File SDP content *\n\n"); @@ -1422,7 +1457,7 @@ void DumpSDP(GF_ISOFile *file, char *inName) fprintf(dump, "%s", sdp); } fprintf(dump, "\n\n"); - if (inName) fclose(dump); + if (inName) gf_fclose(dump); } #endif @@ -1473,7 +1508,63 @@ static char *format_date(u64 time, char *szTime) return szTime; } +void print_udta(GF_ISOFile *file, u32 track_number) +{ + u32 i, count; + + count = gf_isom_get_udta_count(file, track_number); + if (!count) return; + + fprintf(stderr, "%d UDTA types: ", count); + + for (i=0; idata, slc->size, hash); + fprintf(stderr, "\t%s#%d hash: ", szName, i+1); + for (j=0; j<20; j++) fprintf(stderr, "%02X", hash[j]); + fprintf(stderr, "\n"); + } +} + #ifndef GPAC_DISABLE_HEVC void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg, HEVCState *hevc_state) { @@ -1593,14 +1699,23 @@ void dump_hevc_track_info(GF_ISOFile *file, u32 trackNum, GF_HEVCConfig *hevccfg } 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"); } + + for (k=0; kparam_array); k++) { + GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k); + if (ar->type==GF_HEVC_NALU_SEQ_PARAM) print_config_hash(ar->nalus, "SPS"); + else if (ar->type==GF_HEVC_NALU_PIC_PARAM) print_config_hash(ar->nalus, "PPS"); + else if (ar->type==GF_HEVC_NALU_VID_PARAM) print_config_hash(ar->nalus, "VPS"); + } } #endif + void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) { Float scale; @@ -1609,7 +1724,8 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) u64 time_slice, dur, size; u8 bps; GF_ESD *esd; - char sType[5], szDur[50]; + char szDur[50]; + char *lang; trackNum = gf_isom_get_track_by_id(file, trackID); if (!trackNum) { @@ -1625,14 +1741,22 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) if (gf_isom_is_track_in_root_od(file, trackNum) ) fprintf(stderr, "Track is present in Root OD\n"); if (!gf_isom_is_track_enabled(file, trackNum)) fprintf(stderr, "Track is disabled\n"); - gf_isom_get_media_language(file, trackNum, sType); - fprintf(stderr, "Media Info: Language \"%s\" - ", GetLanguage(sType) ); + gf_isom_get_media_language(file, trackNum, &lang); + fprintf(stderr, "Media Info: Language \"%s (%s)\" - ", GetLanguage(lang), lang ); + gf_free(lang); mtype = gf_isom_get_media_type(file, trackNum); fprintf(stderr, "Type \"%s:", gf_4cc_to_str(mtype)); msub_type = gf_isom_get_mpeg4_subtype(file, trackNum, 1); if (!msub_type) msub_type = gf_isom_get_media_subtype(file, trackNum, 1); fprintf(stderr, "%s\" - %d samples\n", gf_4cc_to_str(msub_type), gf_isom_get_sample_count(file, trackNum)); + count = gf_isom_get_track_kind_count(file, trackNum); + for (i = 0; i < count; i++) { + 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 (gf_isom_is_track_fragmented(file, trackID) ) { u32 frag_samples; u64 frag_duration; @@ -1652,6 +1776,8 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) fprintf(stderr, "Handler name: %s\n", handler_name); } + print_udta(file, trackNum); + if (mtype==GF_ISOM_MEDIA_VISUAL) { s32 tx, ty; u32 w, h; @@ -1738,18 +1864,23 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) fprintf(stderr, "\tAVC Info: %d SPS - %d PPS", gf_list_count(avccfg->sequenceParameterSets) , gf_list_count(avccfg->pictureParameterSets) ); fprintf(stderr, " - Profile %s @ Level %g\n", gf_avc_get_profile_name(avccfg->AVCProfileIndication), ((Double)avccfg->AVCLevelIndication)/10.0 ); fprintf(stderr, "\tNAL Unit length bits: %d\n", 8*avccfg->nal_unit_size); - slc = gf_list_get(avccfg->sequenceParameterSets, 0); - if (slc) { + for (i=0; isequenceParameterSets); i++) { + slc = gf_list_get(avccfg->sequenceParameterSets, i); gf_avc_get_sps_info(slc->data, slc->size, NULL, NULL, NULL, &par_n, &par_d); if ((par_n>0) && (par_d>0)) { u32 tw, th; 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); } + 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); } + + print_config_hash(avccfg->sequenceParameterSets, "SPS"); + print_config_hash(avccfg->pictureParameterSets, "PPS"); + gf_odf_avc_cfg_del(avccfg); } if (svccfg) { @@ -1768,6 +1899,10 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } } } + print_config_hash(svccfg->sequenceParameterSets, "SPS"); + print_config_hash(svccfg->pictureParameterSets, "PPS"); + print_config_hash(svccfg->sequenceParameterSetExtensions, "SPSEx"); + gf_odf_avc_cfg_del(svccfg); } #endif /*GPAC_DISABLE_AV_PARSERS*/ @@ -1967,7 +2102,7 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) else fprintf(stderr, "Synchronized on stream %d\n", esd->OCRESID); } else { - fprintf(stderr, "\tDecoding Buffer size %d - Average bitrate %d kbps - Max Bitrate %d kbps\n", esd->decoderConfig->bufferSizeDB, esd->decoderConfig->avgBitrate/1000, esd->decoderConfig->maxBitrate/1000); + fprintf(stderr, "\tDecoding Buffer size %d - Bitrate: avg %d - max %d kbps\n", esd->decoderConfig->bufferSizeDB, esd->decoderConfig->avgBitrate/1000, esd->decoderConfig->maxBitrate/1000); if (esd->dependsOnESID) fprintf(stderr, "\tDepends on stream %d for decoding\n", esd->dependsOnESID); else @@ -2045,11 +2180,13 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) gf_isom_get_visual_info(file, trackNum, 1, &w, &h); fprintf(stderr, "\tMotionJPEG2000 stream - Resolution %d x %d\n", w, h); } else if ((msub_type == GF_ISOM_SUBTYPE_3GP_AMR) || (msub_type == GF_ISOM_SUBTYPE_3GP_AMR_WB)) { - fprintf(stderr, "\t3GPP AMR%s stream - Sample Rate %d - %d channel(s) %d bits per samples\n", (msub_type == GF_ISOM_SUBTYPE_3GP_AMR_WB) ? " Wide Band" : "", sr, nb_ch, (u32) bps); + fprintf(stderr, "\t3GPP AMR%s stream - Sample Rate %d - %d channel(s) %d bps\n", (msub_type == GF_ISOM_SUBTYPE_3GP_AMR_WB) ? " Wide Band" : "", sr, nb_ch, (u32) bps); } else if (msub_type == GF_ISOM_SUBTYPE_3GP_EVRC) { - fprintf(stderr, "\t3GPP EVRC stream - Sample Rate %d - %d channel(s) %d bits per samples\n", sr, nb_ch, (u32) bps); + fprintf(stderr, "\t3GPP EVRC stream - Sample Rate %d - %d channel(s) %d bps\n", sr, nb_ch, (u32) bps); } else if (msub_type == GF_ISOM_SUBTYPE_3GP_QCELP) { - fprintf(stderr, "\t3GPP QCELP stream - Sample Rate %d - %d channel(s) %d bits per samples\n", sr, nb_ch, (u32) bps); + fprintf(stderr, "\t3GPP QCELP stream - Sample Rate %d - %d channel(s) %d bps\n", sr, nb_ch, (u32) bps); + } else if (msub_type == GF_ISOM_SUBTYPE_MP3) { + fprintf(stderr, "\tMPEG 1/2 Audio stream - Sample Rate %d - %d channel(s) %d bps\n", sr, nb_ch, (u32) bps); } else if (msub_type == GF_ISOM_SUBTYPE_AC3) { u32 br = 0; Bool lfe = 0; @@ -2057,7 +2194,12 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) #ifndef GPAC_DISABLE_AV_PARSERS GF_AC3Config *ac3 = gf_isom_ac3_config_get(file, trackNum, 1); if (ac3) { + int i; nb_ch = gf_ac3_get_channels(ac3->streams[0].acmod); + for (i=0; istreams[0].nb_dep_sub; ++i) { + assert(ac3->streams[0].nb_dep_sub == 1); + nb_ch += gf_ac3_get_channels(ac3->streams[0].chan_loc); + } lfe = ac3->streams[0].lfon; br = ac3->is_ec3 ? ac3->brcode : gf_ac3_get_bitrate(ac3->brcode); is_ec3 = ac3->is_ec3; @@ -2106,18 +2248,76 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) u32 w, h; s16 l; s32 tx, ty; + const char *content_encoding = NULL; + const char *mime = NULL; + const char *config = NULL; + const char *_namespace = NULL; + const char *schema_loc = NULL; + const char *auxiliary_mimes = NULL; gf_isom_get_track_layout_info(file, trackNum, &w, &h, &tx, &ty, &l); - fprintf(stderr, "Timed Text - Size %d x %d - Translation X=%d Y=%d - Layer %d\n", w, h, tx, ty, l); + if (msub_type == GF_ISOM_SUBTYPE_SBTT) { + gf_isom_stxt_get_description(file, trackNum, 1, &mime, &content_encoding, &config); + fprintf(stderr, "Textual Subtitle Stream "); + fprintf(stderr, "- mime %s", mime); + if (content_encoding != NULL) { + fprintf(stderr, " - encoding %s", content_encoding); + } + if (config != NULL) { + fprintf(stderr, " - %d bytes config", (u32) strlen(config)); + } + } else if (msub_type == GF_ISOM_SUBTYPE_STXT) { + gf_isom_stxt_get_description(file, trackNum, 1, &mime, &content_encoding, &config); + fprintf(stderr, "Simple Timed Text Stream "); + fprintf(stderr, "- mime %s", mime); + if (content_encoding != NULL) { + fprintf(stderr, " - encoding %s", content_encoding); + } + if (config != NULL) { + fprintf(stderr, " - %d bytes config", (u32) strlen(config)); + } + } else if (msub_type == GF_ISOM_SUBTYPE_STPP) { + gf_isom_xml_subtitle_get_description(file, trackNum, 1, &_namespace, &schema_loc, &auxiliary_mimes); + fprintf(stderr, "XML Subtitle Stream "); + fprintf(stderr, "- namespace %s", _namespace); + if (schema_loc != NULL) { + fprintf(stderr, " - schema-location %s", schema_loc); + } + if (auxiliary_mimes != NULL) { + fprintf(stderr, " - auxiliary-mime-types %s", auxiliary_mimes); + } + } else { + fprintf(stderr, "Unknown Text Stream"); + } + fprintf(stderr, "\n Size %d x %d - Translation X=%d Y=%d - Layer %d\n", w, h, tx, ty, l); } else if (mtype == GF_ISOM_MEDIA_META) { - Bool is_xml = 0; - const char *mime_or_namespace = NULL; const char *content_encoding = NULL; - const char *schema_loc = NULL; - gf_isom_get_timed_meta_data_info(file, trackNum, 1, &is_xml, &mime_or_namespace, &content_encoding, &schema_loc); - fprintf(stderr, "%s Metadata stream\n\t%s %s\n\tencoding %s", is_xml ? "Xml" : "Text", is_xml ? "namespace" : "mime-type", mime_or_namespace, content_encoding); - if (is_xml && schema_loc != NULL) - fprintf(stderr, "\n\tschema %s\n", schema_loc); - fprintf(stderr, "\n"); + if (msub_type == GF_ISOM_SUBTYPE_METT) { + const char *mime = NULL; + const char *config = NULL; + gf_isom_stxt_get_description(file, trackNum, 1, &mime, &content_encoding, &config); + fprintf(stderr, "Textual Metadata Stream - mime %s", mime); + if (content_encoding != NULL) { + fprintf(stderr, " - encoding %s", content_encoding); + } + if (config != NULL) { + fprintf(stderr, " - %d bytes config", (u32) strlen(config)); + } + fprintf(stderr, "\n"); + } else if (msub_type == GF_ISOM_SUBTYPE_METX) { + const char *_namespace = NULL; + const char *schema_loc = NULL; + gf_isom_get_xml_metadata_description(file, trackNum, 1, &_namespace, &schema_loc, &content_encoding); + fprintf(stderr, "XML Metadata Stream - namespace %s", _namespace); + if (content_encoding != NULL) { + fprintf(stderr, " - encoding %s", content_encoding); + } + if (schema_loc != NULL) { + fprintf(stderr, " - schema-location %s", schema_loc); + } + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "Unknown Metadata Stream\n"); + } } else { GF_GenericSampleDescription *udesc = gf_isom_get_generic_sample_description(file, trackNum, 1); if (udesc) { @@ -2141,6 +2341,12 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } } + { + char szCodec[100]; + gf_media_get_rfc_6381_codec_name(file, trackNum, szCodec, GF_FALSE, GF_FALSE); + fprintf(stderr, "\tRFC6381 Codec Parameters: %s\n", szCodec); + } + DumpMetaItem(file, 0, trackNum, "Track Meta"); gf_isom_get_track_switch_group_count(file, trackNum, &alt_group, &nb_groups); @@ -2166,6 +2372,18 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump) } } + switch (gf_isom_has_sync_points(file, trackNum)) { + case 0: + 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; + case 2: + fprintf(stderr, "\tNo sync sample found\n"); + break; + } + if (!full_dump) { fprintf(stderr, "\n"); return; @@ -2406,6 +2624,7 @@ void DumpMovieInfo(GF_ISOFile *file) } } + print_udta(file, 0); fprintf(stderr, "\n"); for (i=0; i\n"); - fclose(dumper.pes_out_nhml); - fclose(dumper.pes_out_info); + gf_fclose(dumper.pes_out_nhml); + gf_fclose(dumper.pes_out_info); } #endif - if (dumper.timestamps_info_file) fclose(dumper.timestamps_info_file); + if (dumper.timestamps_info_file) gf_fclose(dumper.timestamps_info_file); } diff --git a/applications/mp4box/fileimport.c b/applications/mp4box/fileimport.c index 39fd3ba..80bfb8f 100644 --- a/applications/mp4box/fileimport.c +++ b/applications/mp4box/fileimport.c @@ -27,13 +27,14 @@ #include #include #include +#include +#include +#include #if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_SVG) #include #endif -#ifndef GPAC_DISABLE_SMGR -#include -#endif + #ifndef GPAC_DISABLE_BIFS #include @@ -41,7 +42,6 @@ #ifndef GPAC_DISABLE_VRML #include #endif -#include #ifndef GPAC_DISABLE_ISOM_WRITE @@ -60,7 +60,6 @@ extern u32 swf_flags; extern Float swf_flatten_angle; extern Bool keep_sys_tracks; -const char *GetLanguageCode(char *lang); void scene_coding_log(void *cbk, u32 log_level, u32 log_tool, const char *fmt, va_list vlist); void convert_file_info(char *inName, u32 trackID) @@ -195,9 +194,53 @@ static void set_chapter_track(GF_ISOFile *file, u32 track, u32 chapter_ref_trak) } } +GF_Err set_file_udta(GF_ISOFile *dest, u32 tracknum, u32 udta_type, char *src, Bool is_box_array) +{ + char *data = NULL; + u32 size; + bin128 uuid; + memset(uuid, 0 , 16); + + if (!udta_type && !is_box_array) return GF_BAD_PARAM; + + if (!src) { + return gf_isom_remove_user_data(dest, tracknum, udta_type, uuid); + } + + if (!strnicmp(src, "base64", 6)) { + src += 7; + size = (u32) strlen(src); + data = gf_malloc(sizeof(char) * size); + size = gf_base64_decode(src, size, data, size); + } else { + FILE *t = gf_fopen(src, "rb"); + if (!t) return GF_IO_ERR; + fseek(t, 0, SEEK_END); + size = ftell(t); + fseek(t, 0, SEEK_SET); + data = gf_malloc(sizeof(char)*size); + if (size != fread(data, 1, size, t) ) { + gf_free(data); + gf_fclose(t); + return GF_IO_ERR; + } + gf_fclose(t); + } + + if (size && data) { + if (is_box_array) { + gf_isom_add_user_data_boxes(dest, tracknum, data, size); + } else { + gf_isom_add_user_data(dest, tracknum, udta_type, uuid, data, size); + } + gf_free(data); + } + return GF_OK; +} + GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample) { - u32 track_id, i, timescale, track, stype, profile, level, new_timescale, rescale, svc_mode, tile_mode; + u32 track_id, i, j, timescale, track, stype, profile, level, new_timescale, rescale, svc_mode, tile_mode, txt_flags; s32 par_d, par_n, prog_id, delay; s32 tw, th, tx, ty, txtw, txth, txtx, txty; Bool do_audio, do_video, do_all, disable, track_layout, text_layout, chap_ref, is_chap, is_chap_file, keep_handler, negative_cts_offset, rap_only; @@ -206,6 +249,9 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc GF_Err e; GF_MediaImporter import; char *ext, szName[1000], *handler_name, *rvc_config, *chapter_name; + GF_List *kinds; + GF_TextFlagsMode txt_mode = GF_ISOM_TEXT_FLAGS_OVERWRITE; + rvc_predefined = 0; chapter_name = NULL; new_timescale = 1; @@ -226,6 +272,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc disable = 0; chap_ref = 0; is_chap = 0; + kinds = gf_list_new(); track_layout = 0; szLan = NULL; delay = 0; @@ -235,6 +282,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc negative_cts_offset = 0; tile_mode = 0; rap_only = 0; + txt_flags = 0; tw = th = tx = ty = txtw = txth = txtx = txty = 0; par_d = par_n = -2; @@ -251,53 +299,9 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc if (ext2) ext2[0] = 0; /*all extensions for track-based importing*/ - if (!strnicmp(ext+1, "lang=", 5)) szLan = GetLanguageCode(ext+6); + if (!strnicmp(ext+1, "dur=", 4)) import.duration = (u32) (atof(ext+5) * 1000); + else if (!strnicmp(ext+1, "lang=", 5)) szLan = ext+6; else if (!strnicmp(ext+1, "delay=", 6)) delay = atoi(ext+7); - else if (!strnicmp(ext+1, "fps=", 4)) { - if (!strcmp(ext+5, "auto")) force_fps = GF_IMPORT_AUTO_FPS; - else if (strchr(ext+5, '-')) { - u32 ticks, dts_inc; - sscanf(ext+5, "%u-%u", &ticks, &dts_inc); - if (!dts_inc) dts_inc=1; - force_fps = ticks; - force_fps /= dts_inc; - } - else force_fps = atof(ext+5); - } - else if (!strnicmp(ext+1, "timescale=", 10)) { - new_timescale = atoi(ext+11); - } - else if (!strnicmp(ext+1, "rescale=", 8)) { - rescale = atoi(ext+9); - } - else if (!stricmp(ext+1, "chap")) is_chap = 1; - else if (!stricmp(ext+1, "dref")) import_flags |= GF_IMPORT_USE_DATAREF; - else if (!stricmp(ext+1, "nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; - else if (!stricmp(ext+1, "packed")) import_flags |= GF_IMPORT_FORCE_PACKED; - else if (!stricmp(ext+1, "sbr")) import_flags |= GF_IMPORT_SBR_IMPLICIT; - else if (!stricmp(ext+1, "sbrx")) import_flags |= GF_IMPORT_SBR_EXPLICIT; - else if (!stricmp(ext+1, "ovsbr")) import_flags |= GF_IMPORT_OVSBR; - else if (!stricmp(ext+1, "ps")) import_flags |= GF_IMPORT_PS_IMPLICIT; - else if (!stricmp(ext+1, "psx")) import_flags |= GF_IMPORT_PS_EXPLICIT; - else if (!stricmp(ext+1, "svc") || !stricmp(ext+1, "shvc") ) import_flags |= GF_IMPORT_SVC_EXPLICIT; - else if (!stricmp(ext+1, "nosvc") || !stricmp(ext+1, "noshvc")) import_flags |= GF_IMPORT_SVC_NONE; - else if (!stricmp(ext+1, "subsamples")) import_flags |= GF_IMPORT_SET_SUBSAMPLES; - else if (!stricmp(ext+1, "forcesync")) import_flags |= GF_IMPORT_FORCE_SYNC; - else if (!stricmp(ext+1, "rap")) rap_only = 1; - else if (!stricmp(ext+1, "mpeg4")) import_flags |= GF_IMPORT_FORCE_MPEG4; - else if (!stricmp(ext+1, "swf-global")) import.swf_flags |= GF_SM_SWF_STATIC_DICT; - else if (!stricmp(ext+1, "swf-no-ctrl")) import.swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; - else if (!stricmp(ext+1, "swf-no-text")) import.swf_flags |= GF_SM_SWF_NO_TEXT; - else if (!stricmp(ext+1, "swf-no-font")) import.swf_flags |= GF_SM_SWF_NO_FONT; - else if (!stricmp(ext+1, "swf-no-line")) import.swf_flags |= GF_SM_SWF_NO_LINE; - else if (!stricmp(ext+1, "swf-no-grad")) import.swf_flags |= GF_SM_SWF_NO_GRADIENT; - else if (!stricmp(ext+1, "swf-quad")) import.swf_flags |= GF_SM_SWF_QUAD_CURVE; - else if (!stricmp(ext+1, "swf-xlp")) import.swf_flags |= GF_SM_SWF_SCALABLE_LINE; - else if (!stricmp(ext+1, "swf-ic2d")) import.swf_flags |= GF_SM_SWF_USE_IC2D; - else if (!stricmp(ext+1, "swf-same-app")) import.swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; - else if (!strnicmp(ext+1, "swf-flatten=", 12)) import.swf_flatten_angle = (Float) atof(ext+13); - else if (!strnicmp(ext+1, "agg=", 4)) frames_per_sample = atoi(ext+5); - else if (!strnicmp(ext+1, "dur=", 4)) import.duration = (u32) (atof(ext+5) * 1000); else if (!strnicmp(ext+1, "par=", 4)) { if (!stricmp(ext+5, "none")) { par_n = par_d = -1; @@ -309,14 +313,6 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc } } else if (!strnicmp(ext+1, "name=", 5)) handler_name = gf_strdup(ext+6); - else if (!strnicmp(ext+1, "rvc=", 4)) { - if (sscanf(ext+5, "%d", &rvc_predefined) != 1) { - rvc_config = gf_strdup(ext+5); - } - } - else if (!strnicmp(ext+1, "font=", 5)) import.fontName = gf_strdup(ext+6); - else if (!strnicmp(ext+1, "size=", 5)) import.fontSize = atoi(ext+6); - else if (!strnicmp(ext+1, "fmt=", 4)) import.streamFormat = gf_strdup(ext+5); else if (!strnicmp(ext+1, "ext=", 4)) { /*extensions begin with '.'*/ if (*(ext+5) == '.') @@ -327,14 +323,66 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc strcat(import.force_ext+1, ext+5); } } + else if (!strnicmp(ext+1, "hdlr=", 5)) handler = GF_4CC(ext[6], ext[7], ext[8], ext[9]); else if (!strnicmp(ext+1, "disable", 7)) disable = 1; else if (!strnicmp(ext+1, "group=", 6)) { group = atoi(ext+7); if (!group) group = gf_isom_get_next_alternate_group_id(dest); } - else if (!strnicmp(ext+1, "hdlr=", 5)) - handler = GF_4CC(ext[6], ext[7], ext[8], ext[9]); + else if (!strnicmp(ext+1, "fps=", 4)) { + if (!strcmp(ext+5, "auto")) force_fps = GF_IMPORT_AUTO_FPS; + else if (strchr(ext+5, '-')) { + u32 ticks, dts_inc; + sscanf(ext+5, "%u-%u", &ticks, &dts_inc); + if (!dts_inc) dts_inc=1; + force_fps = ticks; + force_fps /= dts_inc; + } + else force_fps = atof(ext+5); + } + else if (!stricmp(ext+1, "rap")) rap_only = 1; + else if (!stricmp(ext+1, "trailing")) import_flags |= GF_IMPORT_KEEP_TRAILING; + else if (!strnicmp(ext+1, "agg=", 4)) frames_per_sample = atoi(ext+5); + else if (!stricmp(ext+1, "dref")) import_flags |= GF_IMPORT_USE_DATAREF; + else if (!stricmp(ext+1, "nodrop")) import_flags |= GF_IMPORT_NO_FRAME_DROP; + else if (!stricmp(ext+1, "packed")) import_flags |= GF_IMPORT_FORCE_PACKED; + else if (!stricmp(ext+1, "sbr")) import_flags |= GF_IMPORT_SBR_IMPLICIT; + else if (!stricmp(ext+1, "sbrx")) import_flags |= GF_IMPORT_SBR_EXPLICIT; + else if (!stricmp(ext+1, "ovsbr")) import_flags |= GF_IMPORT_OVSBR; + else if (!stricmp(ext+1, "ps")) import_flags |= GF_IMPORT_PS_IMPLICIT; + else if (!stricmp(ext+1, "psx")) import_flags |= GF_IMPORT_PS_EXPLICIT; + else if (!stricmp(ext+1, "mpeg4")) import_flags |= GF_IMPORT_FORCE_MPEG4; + else if (!stricmp(ext+1, "svc") || !stricmp(ext+1, "shvc") ) import_flags |= GF_IMPORT_SVC_EXPLICIT; + else if (!stricmp(ext+1, "nosvc") || !stricmp(ext+1, "noshvc")) import_flags |= GF_IMPORT_SVC_NONE; + /*split SVC layers*/ + else if (!strnicmp(ext+1, "svcmode=", 8) || !strnicmp(ext+1, "shvcmode=", 9)) { + char *mode = ext+9; + if (mode[0]=='=') mode = ext+10; + if (!stricmp(mode, "splitnox")) + svc_mode = 3; + else if (!stricmp(mode, "splitall") || !stricmp(mode, "split")) + svc_mode = 2; + else if (!stricmp(mode, "splitbase")) + svc_mode = 1; + else if (!stricmp(mode, "merged")) + svc_mode = 0; + } + else if (!stricmp(ext+1, "subsamples")) import_flags |= GF_IMPORT_SET_SUBSAMPLES; + else if (!stricmp(ext+1, "forcesync")) import_flags |= GF_IMPORT_FORCE_SYNC; + else if (!stricmp(ext+1, "xps_inband")) import_flags |= GF_IMPORT_FORCE_XPS_INBAND; + + /*force all composition offsets to be positive*/ + else if (!strnicmp(ext+1, "negctts", 7)) negative_cts_offset = 1; + else if (!strnicmp(ext+1, "stype=", 6)) { + stype = GF_4CC(ext[7], ext[8], ext[9], ext[10]); + } + else if (!stricmp(ext+1, "chap")) is_chap = 1; + else if (!strnicmp(ext+1, "chapter=", 8)) chapter_name = gf_strdup(ext+9); + else if (!strnicmp(ext+1, "chapfile=", 9)) { + chapter_name = gf_strdup(ext+10); + is_chap_file=1; + } else if (!strnicmp(ext+1, "layout=", 7)) { if ( sscanf(ext+8, "%dx%dx%dx%d", &tw, &th, &tx, &ty)==4) { track_layout = 1; @@ -343,6 +391,26 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc tx = ty = 0; } } + else if (!strnicmp(ext+1, "rescale=", 8)) { + rescale = atoi(ext+9); + } + else if (!strnicmp(ext+1, "timescale=", 10)) { + new_timescale = atoi(ext+11); + } + else if (!stricmp(ext+1, "noedit")) import_flags |= GF_IMPORT_NO_EDIT_LIST; + + + else if (!strnicmp(ext+1, "rvc=", 4)) { + if (sscanf(ext+5, "%d", &rvc_predefined) != 1) { + rvc_config = gf_strdup(ext+5); + } + } + else if (!strnicmp(ext+1, "fmt=", 4)) import.streamFormat = gf_strdup(ext+5); + else if (!strnicmp(ext+1, "profile=", 8)) profile = atoi(ext+9); + else if (!strnicmp(ext+1, "level=", 6)) level = atoi(ext+7); + + else if (!strnicmp(ext+1, "font=", 5)) import.fontName = gf_strdup(ext+6); + else if (!strnicmp(ext+1, "size=", 5)) import.fontSize = atoi(ext+6); else if (!strnicmp(ext+1, "text_layout=", 12)) { if ( sscanf(ext+13, "%dx%dx%dx%d", &txtw, &txth, &txtx, &txty)==4) { text_layout = 1; @@ -351,35 +419,55 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc txtx = txty = 0; } } - else if (!strnicmp(ext+1, "stype=", 6)) { - stype = GF_4CC(ext[7], ext[8], ext[9], ext[10]); + + else if (!stricmp(ext+1, "swf-global")) import.swf_flags |= GF_SM_SWF_STATIC_DICT; + else if (!stricmp(ext+1, "swf-no-ctrl")) import.swf_flags &= ~GF_SM_SWF_SPLIT_TIMELINE; + else if (!stricmp(ext+1, "swf-no-text")) import.swf_flags |= GF_SM_SWF_NO_TEXT; + else if (!stricmp(ext+1, "swf-no-font")) import.swf_flags |= GF_SM_SWF_NO_FONT; + else if (!stricmp(ext+1, "swf-no-line")) import.swf_flags |= GF_SM_SWF_NO_LINE; + else if (!stricmp(ext+1, "swf-no-grad")) import.swf_flags |= GF_SM_SWF_NO_GRADIENT; + else if (!stricmp(ext+1, "swf-quad")) import.swf_flags |= GF_SM_SWF_QUAD_CURVE; + else if (!stricmp(ext+1, "swf-xlp")) import.swf_flags |= GF_SM_SWF_SCALABLE_LINE; + else if (!stricmp(ext+1, "swf-ic2d")) import.swf_flags |= GF_SM_SWF_USE_IC2D; + else if (!stricmp(ext+1, "swf-same-app")) import.swf_flags |= GF_SM_SWF_REUSE_APPEARANCE; + else if (!strnicmp(ext+1, "swf-flatten=", 12)) import.swf_flatten_angle = (Float) atof(ext+13); + + else if (!strnicmp(ext+1, "kind=", 5)) { + char *kind_scheme, *kind_value; + char *kind_data = ext+6; + char *sep = strchr(kind_data, '='); + if (sep) { + *sep = 0; + } + kind_scheme = gf_strdup(kind_data); + if (sep) { + *sep = '='; + kind_value = gf_strdup(sep+1); + } else { + kind_value = NULL; + } + gf_list_add(kinds, kind_scheme); + gf_list_add(kinds, kind_value); } - else if (!strnicmp(ext+1, "profile=", 8)) profile = atoi(ext+9); - else if (!strnicmp(ext+1, "level=", 6)) level = atoi(ext+7); - else if (!strnicmp(ext+1, "chapter=", 8)) chapter_name = gf_strdup(ext+9); - else if (!strnicmp(ext+1, "chapfile=", 9)) { - chapter_name = gf_strdup(ext+10); - is_chap_file=1; + else if (!strnicmp(ext+1, "txtflags", 8)) { + if (!strnicmp(ext+1, "txtflags=", 9)) { + sscanf(ext+10, "%x", &txt_flags); + } + else if (!strnicmp(ext+1, "txtflags+=", 10)) { + sscanf(ext+11, "%x", &txt_flags); + txt_mode = GF_ISOM_TEXT_FLAGS_TOGGLE; + } + else if (!strnicmp(ext+1, "txtflags-=", 10)) { + sscanf(ext+11, "%x", &txt_flags); + txt_mode = GF_ISOM_TEXT_FLAGS_UNTOGGLE; + } } - /*force all composition offsets to be positive*/ - else if (!strnicmp(ext+1, "negctts", 7)) negative_cts_offset = 1; - /*split SVC layers*/ - else if (!strnicmp(ext+1, "svcmode=", 8) || !strnicmp(ext+1, "shvcmode=", 9)) { - char *mode = ext+9; - if (mode[0]=='=') mode = ext+10; - if (!stricmp(mode, "splitnox")) - svc_mode = 3; - else if (!stricmp(mode, "splitall") || !stricmp(mode, "split")) - svc_mode = 2; - else if (!stricmp(mode, "splitbase")) - svc_mode = 1; - else if (!stricmp(mode, "merged")) - svc_mode = 0; - } + /*EXPERIMENTAL OPTIONS NOT DOCUMENTED*/ else if (!strnicmp(ext+1, "tiles", 5)) { tile_mode = 1; } + /*unrecognized, assume name has colon in it*/ else { ext = ext2; @@ -544,6 +632,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc set_chapter_track(import.dest, i+1, chap_ref); } + for (j = 0; j < gf_list_count(kinds); j+=2) { + char *kind_scheme = (char *)gf_list_get(kinds, j); + char *kind_value = (char *)gf_list_get(kinds, j+1); + gf_isom_add_track_kind(import.dest, i+1, kind_scheme, kind_value); + } + if (profile || level) gf_media_change_pl(import.dest, i+1, profile, level); @@ -558,6 +652,11 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc if (gf_isom_get_hevc_shvc_type(import.dest, i+1, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC) check_track_for_shvc = i+1; + if (txt_flags) { + gf_isom_text_set_display_flags(import.dest, i+1, 0, txt_flags, txt_mode); + } + + if (tile_mode) { switch (gf_isom_get_media_subtype(import.dest, i+1, 1)) { case GF_ISOM_SUBTYPE_HVC1: @@ -606,7 +705,7 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc u64 to_skip = (timescale*(-delay))/1000; if (to_skip=GF_ISOM_HEVCTYPE_HEVC_SHVC) check_track_for_shvc = track; + if (txt_flags) { + gf_isom_text_set_display_flags(import.dest, track, 0, txt_flags, txt_mode); + } + if (tile_mode) { switch (gf_isom_get_media_subtype(import.dest, track, 1)) { case GF_ISOM_SUBTYPE_HVC1: @@ -755,6 +864,12 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc exit: + while (gf_list_count(kinds)) { + char *kind = (char *)gf_list_get(kinds, 0); + gf_list_rem(kinds, 0); + if (kind) gf_free(kind); + } + gf_list_del(kinds); if (handler_name) gf_free(handler_name); if (chapter_name ) gf_free(chapter_name ); if (import.fontName) gf_free(import.fontName); @@ -874,12 +989,12 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, case GF_ISOM_MEDIA_MPEGJ: case GF_ISOM_MEDIA_MPEG7: case GF_ISOM_MEDIA_FLASH: - fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by spliter - skipping\n", gf_isom_get_track_id(mp4, i+1), gf_4cc_to_str(mtype)); + fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by splitter - skipping\n", gf_isom_get_track_id(mp4, i+1), gf_4cc_to_str(mtype)); continue; default: /*for all other track types, only split if more than one sample*/ if (gf_isom_get_sample_count(mp4, i+1)==1) { - fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by spliter - skipping\n", gf_isom_get_track_id(mp4, i+1), gf_4cc_to_str(mtype)); + fprintf(stderr, "WARNING: Track ID %d (type %s) not handled by splitter - skipping\n", gf_isom_get_track_id(mp4, i+1), gf_4cc_to_str(mtype)); continue; } tks[nb_tk].can_duplicate = 1; @@ -911,7 +1026,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, nb_tk++; } if (!nb_tk) { - fprintf(stderr, "No suitable tracks found for spliting file\n"); + fprintf(stderr, "No suitable tracks found for splitting file\n"); gf_free(tks); return GF_NOT_SUPPORTED; } @@ -997,13 +1112,21 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, cur_file = 0; while (nb_tk_donedst_tk); } do_add = 1; - is_last = 0; + is_last_rap = 0; last_rap_sample_time = 0; file_split_dur = split_dur; @@ -1032,7 +1155,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, max_dts = 0; while (do_add) { Double time; - u32 nb_over; + u32 nb_over, nb_av = 0; /*perfom basic de-interleaving to make sure we're not importing too much of a given track*/ u32 nb_add = 0; /*add one sample of each track*/ @@ -1041,6 +1164,8 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, u64 dts; tki = &tks[i]; + if (!tki->can_duplicate) nb_av++; + if (tki->stop_state) continue; if (tki->last_sample==tki->sample_count) @@ -1064,9 +1189,9 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, t = (Double) (s64) dts; t /= tki->time_scale; if (tki->first_sample_done) { - if (t>max_dts) continue; + if (!all_av_done && (t>max_dts)) continue; } else { - /*here's the trick: only take care of a/v media for deinterleaving, and ad other media + /*here's the trick: only take care of a/v media for splitting, and add other media only if thir dts is less than the max AV dts found. Otherwise with some text streams we will end up importing too much video and corrupting the last sync point indication*/ if (!tki->can_duplicate && (t>max_dts)) max_dts = t; @@ -1084,10 +1209,10 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, last_rap_sample_time /= tki->time_scale; e = gf_isom_get_sample_for_media_time(mp4, tki->tk, samp->DTS+tki->firstDTS+2, &sdi, GF_ISOM_SEARCH_SYNC_FORWARD, &next_rap, &next_rap_num); if (e==GF_EOS) - is_last = 1; + is_last_rap = 1; if (next_rap) { if (!next_rap->IsRAP) - is_last = 1; + is_last_rap = 1; gf_isom_sample_del(&next_rap); } } @@ -1127,6 +1252,8 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, tki = &tks[i]; if (tki->stop_state) { nb_over++; + if (!tki->can_duplicate && (tki->last_sample==tki->sample_count) ) + nb_av--; continue; } time = (Double) (s64) tki->lastDTS; @@ -1138,8 +1265,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 = 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); @@ -1160,6 +1289,9 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, tki->first_sample_done = 0; } if (nb_over==nb_tk) do_add = 0; + + if (!nb_av) + all_av_done = GF_TRUE; } /*remove samples - first figure out smallest duration*/ @@ -1168,7 +1300,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, Double time; tki = &tks[i]; /*track done*/ - if ((tki->stop_state==2) || (!is_last && (tki->sample_count == tki->last_sample)) ) { + if ((tki->stop_state==2) || (!is_last_rap && (tki->sample_count == tki->last_sample)) ) { if (tki->has_non_raps) last_rap_sample_time = 0; time = (Double) (s64) ( gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1) - tki->firstDTS); time /= tki->time_scale; @@ -1193,14 +1325,15 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, if (adjust_split_end) { fprintf(stderr, "Adjusting chunk end time to previous random access at %02.2f sec\n", chunk_start + last_rap_sample_time); file_split_dur = last_rap_sample_time; - sprintf(szFile, "%s_%d_%d%s", szName, (u32) chunk_start, (u32) (chunk_start+file_split_dur), ext); + if (outName) strcpy(szFile, outName); + else sprintf(szFile, "%s_%d_%d%s", szName, (u32) chunk_start, (u32) (chunk_start+file_split_dur), ext); gf_isom_set_final_name(dest, szFile); } else file_split_dur = split_dur; } /*don't split if eq to copy...*/ - if (is_last && !cur_file && !chunk_start) { + if (is_last_rap && !cur_file && !chunk_start) { fprintf(stderr, "Cannot split file (Not enough sync samples, duration too large or size too big)\n"); goto err_exit; } @@ -1211,27 +1344,25 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, /*if larger than last RAP, rewind till it*/ if (last_rap_sample_time && (last_rap_sample_timedst_tk); - if (last_samp<=1) break; - dts = gf_isom_get_sample_dts(dest, tki->dst_tk, last_samp); - time = (Double) (s64) dts; + 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; - time = (Double) (s64) gf_isom_get_media_duration(dest, tki->dst_tk); - time /= tki->time_scale; + if (last_samp<=1) break; /*done*/ if (tki->last_sample==tki->sample_count) { @@ -1257,10 +1388,18 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, time /= tki->time_scale; /*re-insert prev sample*/ if (tki->can_duplicate && (time>file_split_dur) ) { + Bool was_insert = GF_FALSE; tki->last_sample--; dts = gf_isom_get_sample_dts(mp4, tki->tk, tki->last_sample+1); + if (dts < tki->firstDTS) was_insert = GF_TRUE; tki->firstDTS += (u64) (file_split_dur*tki->time_scale); - gf_isom_set_last_sample_duration(dest, tki->dst_tk, (u32) (tki->firstDTS - dts) ); + //the original, last sample added starts before the first sample in the file: we have re-inserted + //a single sample, use split duration as target duration + if (was_insert) { + gf_isom_set_last_sample_duration(dest, tki->dst_tk, (u32) (file_split_dur*tki->time_scale)); + } else { + gf_isom_set_last_sample_duration(dest, tki->dst_tk, (u32) (tki->firstDTS - dts) ); + } } else { tki->firstDTS = dts; } @@ -1291,7 +1430,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, if (gf_isom_has_time_offset(mp4, tki->tk)) { gf_isom_set_cts_packing(dest, tki->dst_tk, 0); } - if (is_last && tki->can_duplicate) { + 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)); } @@ -1351,7 +1490,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, e = gf_isom_close(dest); dest = NULL; if (e) fprintf(stderr, "Error storing file %s\n", gf_error_to_string(e)); - if (is_last || chunk_extraction) break; + if (is_last_rap || chunk_extraction) break; cur_file++; } gf_set_progress("Splitting", nb_samp, nb_samp); @@ -1650,12 +1789,21 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou /*check language code*/ else if (!skip_lang_test && (mtype==GF_ISOM_MEDIA_AUDIO)) { u32 lang_src, lang_dst; - char lang[4]; - lang[3]=0; - gf_isom_get_media_language(orig, i+1, lang); - lang_src = GF_4CC(lang[0], lang[1], lang[2], lang[3]); - gf_isom_get_media_language(dest, j+1, lang); - lang_dst = GF_4CC(lang[0], lang[1], lang[2], lang[3]); + char *lang = NULL; + gf_isom_get_media_language(orig, i+1, &lang); + if (lang) { + lang_src = GF_4CC(lang[0], lang[1], lang[2], lang[3]); + gf_free(lang); + } else { + lang_src = 0; + } + gf_isom_get_media_language(dest, j+1, &lang); + if (lang) { + lang_dst = GF_4CC(lang[0], lang[1], lang[2], lang[3]); + gf_free(lang); + } else { + lang_dst = 0; + } if (lang_dst==lang_src) { dst_tk = j+1; break; @@ -2114,6 +2262,7 @@ GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *log gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_DEBUG); prev_logs = gf_log_set_callback(logs, scene_coding_log); } + opts->src_url = in; e = gf_sm_encode_to_file(ctx, mp4, opts); if (logs) { gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_ERROR); @@ -2277,9 +2426,9 @@ GF_Err EncodeBIFSChunk(GF_SceneManager *ctx, char *bifsOutputFile, GF_Err (*AUCa e = gf_bifs_encode_au(bifsenc, sc->ESID, au->commands, &data, &data_len); if (data) { sprintf(szName, "%s%02d.bifs", szRad, j); - f = gf_f64_open(szName, "wb"); + f = gf_fopen(szName, "wb"); gf_fwrite(data, data_len, 1, f); - fclose(f); + gf_fclose(f); gf_free(data); } } @@ -2433,7 +2582,7 @@ static Bool wgt_enum_files(void *cbck, char *file_name, char *file_path, GF_File } static Bool wgt_enum_dir(void *cbck, char *file_name, char *file_path, GF_FileEnumInfo *file_info) { - if (!stricmp(file_name, "cvs") || !stricmp(file_name, ".svn")) return 0; + if (!stricmp(file_name, "cvs") || !stricmp(file_name, ".svn") || !stricmp(file_name, ".git")) return 0; gf_enum_directory(file_path, 0, wgt_enum_files, cbck, NULL); return gf_enum_directory(file_path, 1, wgt_enum_dir, cbck, NULL); } @@ -2517,7 +2666,7 @@ GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool ma for (i=0; iact_type==4) meta->act_type=5; + if (meta->act_type==META_ACTION_SET_XML) meta->act_type=META_ACTION_SET_BINARY_XML; ret = 1; } else if (!strchr(szSlot, '=')) { switch (meta->act_type) { - case 0: + case META_ACTION_SET_TYPE: if (!stricmp(szSlot, "null") || !stricmp(szSlot, "0")) meta->meta_4cc = 0; else meta->meta_4cc = GF_4CC(szSlot[0], szSlot[1], szSlot[2], szSlot[3]); ret = 1; break; - case 1: - case 4: - case 7: + case META_ACTION_ADD_ITEM: + case META_ACTION_SET_XML: + case META_ACTION_DUMP_ITEM: strcpy(meta->szPath, szSlot); ret = 1; break; - case 2: - case 3: - case 8: + case META_ACTION_REM_ITEM: + case META_ACTION_SET_PRIMARY_ITEM: + case META_ACTION_DUMP_XML: meta->item_id = atoi(szSlot); ret = 1; break; + default: + break; } } opts += strlen(szSlot); @@ -1230,12 +1278,16 @@ static Bool parse_meta_args(MetaAction *meta, u32 act_type, char *opts) #endif - +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 { - /*0: set tsel param - 1 remove tsel - 2 remove all tsel info in alternate group - 3 remove all tsel info in file*/ - u32 act_type; + TSELActionType act_type; u32 trackID; u32 refTrackID; @@ -1245,9 +1297,8 @@ typedef struct u32 switchGroupID; } TSELAction; -static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_act) +static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_act, TSELActionType act) { - u32 act; u32 refTrackID = 0; Bool has_switch_id; u32 switch_id = 0; @@ -1258,7 +1309,6 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a TSELAction *tsel_list = *__tsel_list; has_switch_id = 0; - act = tsel_list[*nb_tsel_act].act_type; if (!opts) return 0; @@ -1296,7 +1346,7 @@ static Bool parse_tsel_args(TSELAction **__tsel_list, char *opts, u32 *nb_tsel_a } } else if (!strnicmp(szSlot, "trackID=", 8) || !strchr(szSlot, '=') ) { - __tsel_list = gf_realloc(__tsel_list, sizeof(TSELAction) * (*nb_tsel_act + 1)); + *__tsel_list = gf_realloc(*__tsel_list, sizeof(TSELAction) * (*nb_tsel_act + 1)); tsel_list = *__tsel_list; tsel_act = &tsel_list[*nb_tsel_act]; @@ -1322,31 +1372,39 @@ 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); } +typedef enum { + TRAC_ACTION_REM_TRACK = 0, + TRAC_ACTION_SET_LANGUAGE = 1, + TRAC_ACTION_SET_DELAY = 2, + TRAC_ACTION_SET_KMS_URI = 3, + TRAC_ACTION_SET_PAR = 4, + TRAC_ACTION_SET_HANDLER_NAME= 5, + TRAC_ACTION_ENABLE = 6, + TRAC_ACTION_DISABLE = 7, + TRAC_ACTION_REFERENCE = 8, + TRAC_ACTION_RAW_EXTRACT = 9, + TRAC_ACTION_REM_NON_RAP = 10, + TRAC_ACTION_SET_KIND = 11, + TRAC_ACTION_REM_KIND = 12, + TRAC_ACTION_SET_ID = 13, + TRAC_ACTION_SET_UDTA = 14, +} TrackActionType; + typedef struct { - /* - 0: rem track - 1: set track language - 2: set track delay - 3: set track KMS URI - 4: set visual track PAR if possible - 5: set track handler name - 6: enables track - 7: disables track - 8: referenceTrack - 9: raw extraction - 10: remove non-rap - */ - u32 act_type; - /*track ID*/ + TrackActionType act_type; u32 trackID; - char lang[4]; + char *lang; s32 delay_ms; const char *kms; const char *hdl_name; s32 par_num, par_den; u32 dump_type, sample_num; char *out_name; + char *src_name; + u32 udta_type; + char *kind_scheme, *kind_value; + u32 newTrackID; } TrackAction; enum @@ -1366,6 +1424,12 @@ enum for (i=0; inb_rep_descs; input_index++) { \ - gf_free(dash_inputs->rep_descs[input_index]); \ - } \ - gf_free(dash_inputs->rep_descs); \ - for (input_index = 0; input_index < dash_inputs->nb_as_descs; input_index++) { \ - gf_free(dash_inputs->as_descs[input_index]); \ - } \ - gf_free(dash_inputs->as_descs); \ - for (input_index = 0; input_index < dash_inputs->nb_as_c_descs; input_index++) { \ - gf_free(dash_inputs->as_c_descs[input_index]); \ - } \ - gf_free(dash_inputs->as_c_descs); \ - for (input_index = 0; input_index < dash_inputs->nb_p_descs; input_index++) { \ - gf_free(dash_inputs->p_descs[input_index]); \ - } \ - gf_free(dash_inputs->p_descs); \ + u32 i, j; \ + 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(); \ - return __ret_code; \ + 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 = strchr(name, ':'); - if (sep && (sep[1]=='\\')) sep = strchr(sep+1, ':'); + 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, ':'); dash_inputs = gf_realloc(dash_inputs, sizeof(GF_DashSegmenterInput) * (*nb_dash_inputs + 1) ); memset(&dash_inputs[*nb_dash_inputs], 0, sizeof(GF_DashSegmenterInput) ); @@ -1415,12 +1514,14 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * 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, ":period=", 8) || - !strnicmp(sep, ":bandwidth=", 11) || - !strnicmp(sep, ":role=", 6) || - !strnicmp(sep, ":desc", 5) || - !strnicmp(sep, ":xlink=", 7)) { - break; + !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, ":xlink=", 7)) { + break; } else { sep = strchr(sep+1, ':'); } @@ -1430,7 +1531,7 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * if (!strnicmp(opts, "id=", 3)) { u32 i; - strncpy(di->representationID, opts+3, 99); + di->representationID = gf_strdup(opts+3); /* check to see if this representation Id has already been assigned */ for (i=0; i<(*nb_dash_inputs)-1; i++) { GF_DashSegmenterInput *other_di; @@ -1439,18 +1540,17 @@ 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)) { - if (strlen(opts+7) > 99) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] PeriodID cannot exceed 99 characters in MP4Box, truncating ...\n")); - } - strncpy(di->periodID, opts+7, 99); - } - else if (!strnicmp(opts, "bandwidth=", 10)) di->bandwidth = atoi(opts+10); - else if (!strnicmp(opts, "role=", 5)) strncpy(di->role, opts+5, 99); + } 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)) { - u32 *nb_descs; - char ***descs; - u32 opt_offset; + u32 *nb_descs=NULL; + char ***descs=NULL; + u32 opt_offset=0; u32 len; if (!strnicmp(opts, "desc_p=", 7)) { nb_descs = &di->nb_p_descs; @@ -1469,19 +1569,20 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * descs = &di->rep_descs; opt_offset = 9; } - (*nb_descs)++; - opts += opt_offset; - len = (u32) strlen(opts); - (*descs) = (char **)gf_realloc((*descs), (*nb_descs)*sizeof(char *)); - (*descs)[(*nb_descs)-1] = (char *)gf_malloc((len+1)*sizeof(char)); - strncpy((*descs)[(*nb_descs)-1], opts, len); - (*descs)[(*nb_descs)-1][len] = 0; - } - else if (!strnicmp(opts, "xlink=", 6)) { - if (strlen(opts+6) > 199) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] XLink cannot exceed 99 characters in MP4Box, truncating ...\n")); + if (opt_offset) { + (*nb_descs)++; + opts += opt_offset; + len = (u32) strlen(opts); + (*descs) = (char **)gf_realloc((*descs), (*nb_descs)*sizeof(char *)); + (*descs)[(*nb_descs)-1] = (char *)gf_malloc((len+1)*sizeof(char)); + strncpy((*descs)[(*nb_descs)-1], opts, len); + (*descs)[(*nb_descs)-1][len] = 0; } - strncpy(di->xlink, opts+6, 199); + + } + 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); } if (!sep) break; @@ -1490,7 +1591,11 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char * } } di->file_name = name; - if (!strlen(di->representationID)) sprintf(di->representationID, "%d", *nb_dash_inputs); + if (!di->representationID) { + char szRep[100]; + sprintf(szRep, "%d", *nb_dash_inputs); + di->representationID = gf_strdup(szRep); + } return dash_inputs; } @@ -1514,6 +1619,13 @@ static GF_Err parse_track_action_params(char *string, TrackAction *action) action->dump_type |= GF_EXPORT_WEBVTT_META_EMBEDDED; } else if (!strncmp("output=", param, 7)) { action->out_name = gf_strdup(param+7); + } else if (!strncmp("src=", param, 4)) { + action->src_name = gf_strdup(param+4); + } else if (!strncmp("box=", param, 4)) { + action->src_name = gf_strdup(param+4); + action->sample_num = 1; + } else if (!strncmp("type=", param, 4)) { + action->udta_type = GF_4CC(param[5], param[6], param[7], param[8]); } else if (action->dump_type == GF_EXPORT_RAW_SAMPLES) { action->sample_num = atoi(param); } @@ -1532,13 +1644,87 @@ static u32 create_new_track_action(char *string, TrackAction **actions, u32 *nb_ { *actions = (TrackAction *)gf_realloc(*actions, sizeof(TrackAction) * (*nb_track_act+1)); memset(&(*actions)[*nb_track_act], 0, sizeof(TrackAction) ); - (*actions)[*nb_track_act].act_type = 9; + (*actions)[*nb_track_act].act_type = TRAC_ACTION_RAW_EXTRACT; (*actions)[*nb_track_act].dump_type = dump_type; parse_track_action_params(string, &(*actions)[*nb_track_act]); (*nb_track_act)++; return dump_type; } +static GF_Err nhml_bs_to_bin(char *inName, char *outName, u32 dump_std) +{ + GF_Err e; + GF_XMLNode *root; + char *data = NULL; + u32 data_size; + + GF_DOMParser *dom = gf_xml_dom_new(); + e = gf_xml_dom_parse(dom, inName, NULL, NULL); + if (e) { + gf_xml_dom_del(dom); + fprintf(stderr, "Failed to parse XML file: %s\n", gf_error_to_string(e)); + return e; + } + root = gf_xml_dom_get_root_idx(dom, 0); + if (!root) { + gf_xml_dom_del(dom); + return GF_OK; + } + + e = gf_xml_parse_bit_sequence(root, &data, &data_size); + gf_xml_dom_del(dom); + + if (e) { + fprintf(stderr, "Failed to parse binary sequence: %s\n", gf_error_to_string(e)); + return e; + } + + if (dump_std) { + fwrite(data, 1, data_size, stdout); + } else { + FILE *t; + char szFile[GF_MAX_PATH]; + if (outName) { + strcpy(szFile, outName); + } else { + strcpy(szFile, inName); + strcat(szFile, ".bin"); + } + t = gf_fopen(szFile, "wb"); + if (!t) { + fprintf(stderr, "Failed to open file %s\n", szFile); + e = GF_IO_ERR; + } else { + if (fwrite(data, 1, data_size, t) != data_size) { + fprintf(stderr, "Failed to write output to file %s\n", szFile); + e = GF_IO_ERR; + } + gf_fclose(t); + } + } + gf_free(data); + return e; +} + + +static GF_Err hash_file(char *name, u32 dump_std) +{ + u32 i; + u8 hash[20]; + GF_Err e = gf_media_get_file_hash(name, hash); + if (e) return e; + if (dump_std==2) { + fwrite(hash, 1, 20, stdout); + } else if (dump_std==1) { + for (i=0; i<20; i++) fprintf(stdout, "%02X", hash[i]); + } + fprintf(stderr, "File hash (SHA-1): "); + for (i=0; i<20; i++) fprintf(stderr, "%02X", hash[i]); + fprintf(stderr, "\n"); + + return GF_OK; +} + static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) { FILE *logs = cbk; @@ -1562,19 +1748,27 @@ int mp4boxMain(int argc, char **argv) s32 subsegs_per_sidx; u32 *brand_add = NULL; u32 *brand_rem = NULL; - GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_INBAND; - 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, dash_dynamic, initial_moof_sn, dump_std, dump_mode, import_subtitle; + 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; +#ifndef GPAC_DISABLE_SCENE_DUMP + GF_SceneDumpFormat dump_mode; +#endif + Double mpd_live_duration = 0; Bool HintIt, needSave, FullInter, Frag, HintInter, dump_rtp, regular_iod, remove_sys_tracks, remove_hint, 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; + 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; - u32 ast_shift_sec = 1; + 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; @@ -1587,8 +1781,10 @@ int mp4boxMain(int argc, char **argv) u32 MTUSize = 1450; #endif GF_ISOFile *file; - u32 mpd_update_time = 0; + 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; @@ -1600,12 +1796,15 @@ int mp4boxMain(int argc, char **argv) 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; @@ -1616,6 +1815,7 @@ int mp4boxMain(int argc, char **argv) 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; @@ -1631,10 +1831,13 @@ int mp4boxMain(int argc, char **argv) movie_time = 0; dump_nal = 0; FullInter = HintInter = encode = do_log = old_interleave = do_saf = do_hash = verbose = 0; - dump_mode = Frag = force_ocr = remove_sys_tracks = agg_samples = remove_hint = keep_sys_tracks = remove_root_od = single_group = 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; - dash_dynamic = 0; + single_traf_per_moof = 0, /*align cat is the new default behaviour for -cat*/ align_cat = 1; subsegs_per_sidx = 0; @@ -1663,8 +1866,6 @@ int mp4boxMain(int argc, char **argv) swf_flatten_angle = 0.0f; tmpdir = NULL; - - for (i = 1; i < (u32) argc ; i++) { if (!strcmp(argv[i], "-mem-track")) { #ifdef GPAC_MEMORY_TRACKING @@ -1676,6 +1877,7 @@ int mp4boxMain(int argc, char **argv) } } + /*init libgpac*/ gf_sys_init(enable_mem_tracker); if (argc < 2) { PrintUsage(); @@ -1731,7 +1933,7 @@ int mp4boxMain(int argc, char **argv) i++; } else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { - logfile = gf_f64_open(argv[i+1], "wt"); + logfile = gf_fopen(argv[i+1], "wt"); gf_log_set_callback(logfile, on_gpac_log); i++; } @@ -1753,6 +1955,12 @@ int mp4boxMain(int argc, char **argv) grab_m2ts = argv[i+1]; i++; } + else if (!stricmp(arg, "-ifce")) { + CHECK_NEXT_ARG + grab_ifce = argv[i+1]; + i++; + } + #endif #if !defined(GPAC_DISABLE_CORE_TOOLS) else if (!stricmp(arg, "-wget")) { @@ -1870,13 +2078,13 @@ int mp4boxMain(int argc, char **argv) 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 = 1 + GF_SM_DUMP_BT; - else if (!stricmp(arg, "-xmt")) dump_mode = 1 + GF_SM_DUMP_XMTA; - else if (!stricmp(arg, "-wrl")) dump_mode = 1 + GF_SM_DUMP_VRML; - else if (!stricmp(arg, "-x3dv")) dump_mode = 1 + GF_SM_DUMP_X3D_VRML; - else if (!stricmp(arg, "-x3d")) dump_mode = 1 + GF_SM_DUMP_X3D_XML; - else if (!stricmp(arg, "-lsr")) dump_mode = 1 + GF_SM_DUMP_LASER; - else if (!stricmp(arg, "-svg")) dump_mode = 1 + GF_SM_DUMP_SVG; + 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; @@ -1887,6 +2095,23 @@ int mp4boxMain(int argc, char **argv) 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]; + } + dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]); + i++; + } + #if 0 else if (!stricmp(arg, "-conf")) { @@ -1934,8 +2159,8 @@ int mp4boxMain(int argc, char **argv) MP4BOX_EXIT_WITH_CODE(1); } #endif - if (!stricmp(arg, "-ttxt")) dump_ttxt = 1; - else dump_srt = 1; + if (!stricmp(arg, "-ttxt")) dump_ttxt = GF_TRUE; + else dump_srt = GF_TRUE; import_subtitle = 1; } else if (!stricmp(arg, "-dm2ts")) { dump_m2ts = 1; @@ -2001,6 +2226,10 @@ int mp4boxMain(int argc, char **argv) CHECK_NEXT_ARG tmpdir = argv[i+1]; i++; } + else if (!stricmp(arg, "-co64")) { + force_co64 = GF_TRUE; + open_edit = 1; + } else if (!stricmp(arg, "-write-buffer")) { CHECK_NEXT_ARG gf_isom_set_output_buffering(NULL, atoi(argv[i+1])); @@ -2071,16 +2300,26 @@ int mp4boxMain(int argc, char **argv) CHECK_NEXT_ARG if (!stricmp(argv[i+1], "no") || !stricmp(argv[i+1], "off")) bitstream_switching_mode = GF_DASH_BSMODE_NONE; else if (!stricmp(argv[i+1], "merge")) bitstream_switching_mode = GF_DASH_BSMODE_MERGED; + else if (!stricmp(argv[i+1], "multi")) bitstream_switching_mode = GF_DASH_BSMODE_MULTIPLE_ENTRIES; else if (!stricmp(argv[i+1], "single")) bitstream_switching_mode = GF_DASH_BSMODE_SINGLE; else if (!stricmp(argv[i+1], "inband")) bitstream_switching_mode = GF_DASH_BSMODE_INBAND; - else bitstream_switching_mode = GF_DASH_BSMODE_INBAND; + else { + fprintf(stderr, "\tWARNING: Unrecognized bitstream switchin mode \"%s\" - please check usage\n", argv[i+1]); + MP4BOX_EXIT_WITH_CODE(1); + } i++; } else if (!stricmp(arg, "-dynamic")) { - dash_dynamic = 1; + dash_mode = GF_DASH_DYNAMIC; + } + 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 (!strnicmp(arg, "-dash-live", 10) || !strnicmp(arg, "-ddbg-live", 10)) { - dash_dynamic = !strnicmp(arg, "-ddbg-live", 10) ? 2 : 1; + 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; @@ -2089,8 +2328,12 @@ int mp4boxMain(int argc, char **argv) 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 = atoi(argv[i+1]); + CHECK_NEXT_ARG mpd_update_time = atof(argv[i+1]); i++; } else if (!stricmp(arg, "-time-shift")) { @@ -2106,7 +2349,7 @@ int mp4boxMain(int argc, char **argv) } else if (!stricmp(arg, "-ast-offset")) { CHECK_NEXT_ARG - ast_shift_sec = (u32) atoi(argv[i+1]); + ast_offset_ms = atoi(argv[i+1]); i++; } else if (!stricmp(arg, "-moof-sn")) { @@ -2122,6 +2365,9 @@ int mp4boxMain(int argc, char **argv) else if (!stricmp(arg, "-no-frags-default")) { no_fragments_defaults = 1; } + else if (!stricmp(arg, "-single-traf")) { + single_traf_per_moof = 1; + } else if (!stricmp(arg, "-mpd-title")) { CHECK_NEXT_ARG dash_title = argv[i+1]; i++; @@ -2142,7 +2388,6 @@ int mp4boxMain(int argc, char **argv) nb_mpd_base_urls++; i++; } - else if (!stricmp(arg, "-dash-ctx")) { CHECK_NEXT_ARG dash_ctx_file = argv[i+1]; @@ -2161,15 +2406,19 @@ int mp4boxMain(int argc, char **argv) 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], "dashavc264:live")) { + 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; - no_fragments_defaults = 1; } else if (!stricmp(argv[i+1], "dashavc264:onDemand")) { dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND; - no_fragments_defaults = 1; } 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, "-profile-ext")) { + CHECK_NEXT_ARG + dash_profile_extension = argv[i+1]; + i++; } else if (!strnicmp(arg, "-url-template", 13)) { use_url_template = 1; if ((arg[13]=='=') && arg[14]) { @@ -2184,6 +2433,9 @@ int mp4boxMain(int argc, char **argv) CHECK_NEXT_ARG 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 if (!stricmp(arg, "-itags")) { CHECK_NEXT_ARG itunes_tags = argv[i+1]; i++; @@ -2210,7 +2462,7 @@ int mp4boxMain(int argc, char **argv) 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 = 10; + tracks[nb_track_act].act_type = TRAC_ACTION_REM_NON_RAP; tracks[nb_track_act].trackID = trackID; nb_track_act++; i++; @@ -2292,7 +2544,7 @@ int mp4boxMain(int argc, char **argv) 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 = 9; + 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++; @@ -2300,9 +2552,25 @@ int mp4boxMain(int argc, char **argv) #endif } else if (!stricmp(arg, "-iod")) regular_iod = 1; - else if (!stricmp(arg, "-flat")) do_flat = 1; + else if (!stricmp(arg, "-flat")) { + open_edit = 1; + do_flat = 1; + } else if (!stricmp(arg, "-keep-utc")) keep_utc = 1; else if (!stricmp(arg, "-new")) force_new = 1; + else if (!stricmp(arg, "-timescale")) { + CHECK_NEXT_ARG + timescale = atoi(argv[i+1]); + open_edit = 1; + i++; + } + else if (!stricmp(arg, "-udta")) { + CHECK_NEXT_ARG + create_new_track_action(argv[i+1], &tracks, &nb_track_act, 0); + tracks[nb_track_act-1].act_type = TRAC_ACTION_SET_UDTA; + open_edit = 1; + i++; + } else if (!stricmp(arg, "-add") || !stricmp(arg, "-import") || !stricmp(arg, "-convert")) { CHECK_NEXT_ARG if (!stricmp(arg, "-import")) fprintf(stderr, "\tWARNING: \"-import\" is deprecated - use \"-add\"\n"); @@ -2340,11 +2608,26 @@ int mp4boxMain(int argc, char **argv) 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 = 6; - else if (!stricmp(arg, "-disable")) tracks[nb_track_act].act_type = 7; - else tracks[nb_track_act].act_type = 0; + 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++; + i++; + } + else if (!stricmp(arg, "-set-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 = 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++; i++; @@ -2355,7 +2638,7 @@ int mp4boxMain(int argc, char **argv) tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); - tracks[nb_track_act].act_type = 4; + 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, '='); @@ -2386,17 +2669,16 @@ int mp4boxMain(int argc, char **argv) tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1)); memset(&tracks[nb_track_act], 0, sizeof(TrackAction) ); - tracks[nb_track_act].act_type = 1; - tracks[nb_track_act].lang[3] = 0; + 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]+1, 3); + tracks[nb_track_act].lang = gf_strdup(argv[i+1]+4); } else if (!ext) { - strncpy(tracks[nb_track_act].lang, argv[i+1], 3); + tracks[nb_track_act].lang = gf_strdup(argv[i+1]); } else { - strncpy(tracks[nb_track_act].lang, ext+1, 3); + tracks[nb_track_act].lang = gf_strdup(ext+1); ext[0] = 0; tracks[nb_track_act].trackID = atoi(szTK); ext[0] = '='; @@ -2405,6 +2687,56 @@ int mp4boxMain(int argc, char **argv) nb_track_act++; i++; } + 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; + } 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; + } + } + 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 = 1; + nb_track_act++; + i++; + } else if (!stricmp(arg, "-delay")) { char szTK[20], *ext; CHECK_NEXT_ARG @@ -2417,7 +2749,7 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "Bad format for track delay - expecting ID=DLAY got %s\n", argv[i+1]); MP4BOX_EXIT_WITH_CODE(1); } - tracks[nb_track_act].act_type = 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); @@ -2437,7 +2769,7 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "Bad format for track reference - expecting ID:XXXX:refID got %s\n", argv[i+1]); MP4BOX_EXIT_WITH_CODE(1); } - tracks[nb_track_act].act_type = 8; + tracks[nb_track_act].act_type = TRAC_ACTION_REFERENCE; ext[0] = 0; tracks[nb_track_act].trackID = atoi(szTK); ext[0] = ':'; @@ -2448,7 +2780,7 @@ int mp4boxMain(int argc, char **argv) MP4BOX_EXIT_WITH_CODE(1); } ext[0] = 0; - strncpy(tracks[nb_track_act].lang, szTK, 4); + tracks[nb_track_act].lang = gf_strdup(szTK); ext[0] = ':'; tracks[nb_track_act].delay_ms = (s32) atoi(ext+1); open_edit = 1; @@ -2467,7 +2799,7 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "Bad format for track name - expecting ID=name got %s\n", argv[i+1]); MP4BOX_EXIT_WITH_CODE(1); } - tracks[nb_track_act].act_type = 5; + 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); @@ -2522,7 +2854,7 @@ int mp4boxMain(int argc, char **argv) else if (!stricmp(arg, "-mpd")) { do_mpd = 1; CHECK_NEXT_ARG - outName = argv[i+1]; + inName = argv[i+1]; i++; } #endif @@ -2612,7 +2944,7 @@ int mp4boxMain(int argc, char **argv) strncpy(szTK, argv[i+1], 19); ext = strchr(szTK, '='); - tracks[nb_track_act].act_type = 3; + 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; @@ -2666,60 +2998,67 @@ int mp4boxMain(int argc, char **argv) /*meta*/ else if (!stricmp(arg, "-set-meta")) { metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); - parse_meta_args(&metas[nb_meta_act], 0, argv[i+1]); + parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_TYPE, argv[i+1]); nb_meta_act++; open_edit = 1; i++; } else if (!stricmp(arg, "-add-item")) { metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); - parse_meta_args(&metas[nb_meta_act], 1, argv[i+1]); + parse_meta_args(&metas[nb_meta_act], META_ACTION_ADD_ITEM, argv[i+1]); nb_meta_act++; open_edit = 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], 2, argv[i+1]); + parse_meta_args(&metas[nb_meta_act], META_ACTION_REM_ITEM, argv[i+1]); nb_meta_act++; open_edit = 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], 3, argv[i+1]); + parse_meta_args(&metas[nb_meta_act], META_ACTION_SET_PRIMARY_ITEM, argv[i+1]); nb_meta_act++; open_edit = 1; i++; } else if (!stricmp(arg, "-set-xml")) { metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); - parse_meta_args(&metas[nb_meta_act], 4, argv[i+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, "-rem-xml")) { metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); - if (parse_meta_args(&metas[nb_meta_act], 6, argv[i+1])) i++; + 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, "-dump-xml")) { metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); - parse_meta_args(&metas[nb_meta_act], 7, argv[i+1]); + parse_meta_args(&metas[nb_meta_act], META_ACTION_DUMP_XML, argv[i+1]); nb_meta_act++; i++; } else if (!stricmp(arg, "-dump-item")) { metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1)); - parse_meta_args(&metas[nb_meta_act], 8, argv[i+1]); + parse_meta_args(&metas[nb_meta_act], META_ACTION_DUMP_ITEM, argv[i+1]); nb_meta_act++; i++; } else if (!stricmp(arg, "-group-add") || !stricmp(arg, "-group-rem-track") || !stricmp(arg, "-group-rem")) { - tsel_acts[nb_tsel_acts].act_type = !stricmp(arg, "-group-rem") ? 2 : ( !stricmp(arg, "-group-rem-track") ? 1 : 0 ); - if (parse_tsel_args(&tsel_acts, argv[i+1], &nb_tsel_acts)==0) { + 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); } @@ -2727,7 +3066,7 @@ int mp4boxMain(int argc, char **argv) i++; } else if (!stricmp(arg, "-group-clean")) { - tsel_acts[nb_tsel_acts].act_type = 3; + tsel_acts[nb_tsel_acts].act_type = TSEL_ACTION_REMOVE_ALL_TSEL_IN_FILE; nb_tsel_acts++; open_edit=1; } @@ -2880,16 +3219,16 @@ int mp4boxMain(int argc, char **argv) char chunk[4096]; FILE *fin, *fout; s64 to_copy, done; - fin = gf_f64_open(raw_cat, "rb"); + fin = gf_fopen(raw_cat, "rb"); if (!fin) MP4BOX_EXIT_WITH_CODE(1); - fout = gf_f64_open(inName, "a+b"); + fout = gf_fopen(inName, "a+b"); if (!fout) { - fclose(fin); + gf_fclose(fin); MP4BOX_EXIT_WITH_CODE(1); } - gf_f64_seek(fin, 0, SEEK_END); - to_copy = gf_f64_tell(fin); - gf_f64_seek(fin, 0, SEEK_SET); + gf_fseek(fin, 0, SEEK_END); + to_copy = gf_ftell(fin); + gf_fseek(fin, 0, SEEK_SET); done = 0; while (1) { u32 nb_bytes = (u32) fread(chunk, 1, 4096, fin); @@ -2898,20 +3237,15 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "Appending file %s - %02.2f done\r", raw_cat, 100.0*done/to_copy); if (done >= to_copy) break; } - fclose(fin); - fclose(fout); + gf_fclose(fin); + gf_fclose(fout); MP4BOX_EXIT_WITH_CODE(0); } #if !defined(GPAC_DISABLE_STREAMING) if (grab_m2ts) { - return grab_live_m2ts(grab_m2ts, inName); + return grab_live_m2ts(grab_m2ts, grab_ifce, inName); } #endif - /*init libgpac*/ - if (enable_mem_tracker) { - gf_sys_close(); - gf_sys_init(enable_mem_tracker); - } if (gf_logs) { //gf_log_set_tools_levels(gf_logs); @@ -2935,7 +3269,7 @@ int mp4boxMain(int argc, char **argv) #if !defined(DISABLE_CORE_TOOLS) if (do_wget != NULL) { - e = gf_dm_wget(do_wget, inName, 0, 0); + e = gf_dm_wget(do_wget, inName, 0, 0, NULL); if (e != GF_OK) { fprintf(stderr, "Cannot retrieve %s: %s\n", do_wget, gf_error_to_string(e) ); } @@ -2945,25 +3279,25 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_MPD if (do_mpd) { - Bool remote = 0; - char *mpd_base_url = gf_strdup(inName); + Bool remote = GF_FALSE; + char *mpd_base_url = NULL; if (!strnicmp(inName, "http://", 7)) { #if !defined(GPAC_DISABLE_CORE_TOOLS) - e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0); + e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0, &mpd_base_url); if (e != GF_OK) { fprintf(stderr, "Cannot retrieve M3U8 (%s): %s\n", inName, gf_error_to_string(e)); - gf_free(mpd_base_url); + if (mpd_base_url) gf_free(mpd_base_url); MP4BOX_EXIT_WITH_CODE(1); } - inName = "tmp_main.m3u8"; - remote = 1; + remote = GF_TRUE; #else + gf_free(mpd_base_url); fprintf(stderr, "HTTP Downloader disabled in this build\n"); MP4BOX_EXIT_WITH_CODE(1); #endif } - e = gf_m3u8_to_mpd(inName, mpd_base_url, (outName ? outName : inName), 0, "video/mp2t", 1, use_url_template, NULL); - gf_free(mpd_base_url); + e = gf_m3u8_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd_base_url ? mpd_base_url : inName, (outName ? outName : inName), 0, "video/mp2t", GF_TRUE, use_url_template, NULL); + if (mpd_base_url) gf_free(mpd_base_url); if (remote) { //gf_delete_file("tmp_main.m3u8"); @@ -2984,28 +3318,40 @@ int mp4boxMain(int argc, char **argv) if (do_saf && !encode) { switch (get_file_type_by_ext(inName)) { - case 2: - case 3: - case 4: + case GF_FILE_TYPE_BT_WRL_X3DV: + case GF_FILE_TYPE_XMT_X3D: + case GF_FILE_TYPE_SVG: encode = 1; break; + case GF_FILE_TYPE_NOT_SUPPORTED: + case GF_FILE_TYPE_ISO_MEDIA: + case GF_FILE_TYPE_SWF: + case GF_FILE_TYPE_LSR_SAF: + break; } } #ifndef GPAC_DISABLE_SCENE_DUMP - if (dump_mode == 1 + GF_SM_DUMP_SVG) { + if (dump_mode == GF_SM_DUMP_SVG) { if (strstr(inName, ".srt") || strstr(inName, ".ttxt")) import_subtitle = 2; } #endif if (import_subtitle && !trackID) { + /* We import the subtitle file, + i.e. we parse it and store the content as samples of a 3GPP Timed Text track in an ISO file, + possibly for later export (e.g. when converting SRT to TTXT, ...) */ #ifndef GPAC_DISABLE_MEDIA_IMPORT GF_MediaImporter import; + /* Prepare the importer */ file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL); + if (timescale && file) gf_isom_set_timescale(file, timescale); + memset(&import, 0, sizeof(GF_MediaImporter)); import.dest = file; import.in_name = inName; + /* Start the import */ e = gf_media_import(&import); if (e) { fprintf(stderr, "Error importing %s: %s\n", inName, gf_error_to_string(e)); @@ -3013,14 +3359,20 @@ int mp4boxMain(int argc, char **argv) gf_delete_file("ttxt_convert"); MP4BOX_EXIT_WITH_CODE(1); } - strcpy(outfile, outName ? outName : inName); + /* Prepare the export */ + strcpy(outfile, inName); if (strchr(outfile, '.')) { while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0; outfile[strlen(outfile)-1] = 0; } #ifndef GPAC_DISABLE_ISOM_DUMP - dump_timed_text_track(file, gf_isom_get_track_id(file, 1), dump_std ? NULL : outfile, 1, (import_subtitle==2) ? 2 : dump_srt); + /* Start the export of the track #1, in the appropriate dump type, indicating it's a conversion */ + dump_timed_text_track(file, gf_isom_get_track_id(file, 1), + dump_std ? NULL : outfile, + GF_TRUE, + (import_subtitle==2) ? GF_TEXTDUMPTYPE_SVG : (dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT)); #endif + /* Clean the importer */ gf_isom_delete(file); gf_delete_file("ttxt_convert"); if (e) { @@ -3040,12 +3392,12 @@ int mp4boxMain(int argc, char **argv) if (force_new) { open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; } else { - FILE *test = gf_f64_open(inName, "rb"); + FILE *test = gf_fopen(inName, "rb"); if (!test) { open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; if (!outName) outName = inName; } else { - fclose(test); + gf_fclose(test); if (! gf_isom_probe_file(inName) ) { open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; if (!outName) outName = inName; @@ -3059,6 +3411,7 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) ); MP4BOX_EXIT_WITH_CODE(1); } + for (i=0; i<(u32) argc; i++) { if (!strcmp(argv[i], "-add")) { char *src = argv[i+1]; @@ -3067,7 +3420,11 @@ int mp4boxMain(int argc, char **argv) if (e) { while (src) { char *sep = strchr(src, '+'); - if (sep) sep[0] = 0; + if (sep) { + sep[0] = 0; + } else { + break; + } e = import_file(file, src, import_flags, import_fps, agg_samples); @@ -3093,8 +3450,6 @@ int mp4boxMain(int argc, char **argv) /*unless explicitly asked, remove all systems tracks*/ if (!keep_sys_tracks) remove_systems_tracks(file); needSave = 1; - /*JLF commented: if you want ISMA, just ask for it, no more auto-detect*/ -// if (!conv_type && can_convert_to_isma(file)) conv_type = GF_ISOM_CONV_TYPE_ISMA; } if (nb_cat) { @@ -3103,12 +3458,12 @@ int mp4boxMain(int argc, char **argv) if (force_new) { open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; } else { - FILE *test = gf_f64_open(inName, "rb"); + FILE *test = gf_fopen(inName, "rb"); if (!test) { open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT; if (!outName) outName = inName; } - else fclose(test); + else gf_fclose(test); } open_edit = 1; @@ -3159,7 +3514,7 @@ int mp4boxMain(int argc, char **argv) logfile[strlen(logfile)-1] = 0; } strcat(logfile, "_enc.logs"); - logs = gf_f64_open(logfile, "wt"); + logs = gf_fopen(logfile, "wt"); } strcpy(outfile, outName ? outName : inName); if (strchr(outfile, '.')) { @@ -3170,7 +3525,7 @@ int mp4boxMain(int argc, char **argv) file = gf_isom_open(outfile, GF_ISOM_WRITE_EDIT, tmpdir); opts.mediaSource = mediaSource ? mediaSource : outfile; e = EncodeFile(inName, file, &opts, logs); - if (logs) fclose(logs); + if (logs) gf_fclose(logs); if (e) goto err_exit; needSave = 1; if (do_saf) { @@ -3209,7 +3564,12 @@ int mp4boxMain(int argc, char **argv) strcpy(szMPD, outfile); strcat(szMPD, ".mpd"); - if (dash_dynamic && dash_live) + if ((dash_subduration>0) && (dash_duration > dash_subduration)) { + fprintf(stderr, "Warning: -subdur parameter (%g s) should be greater than segment duration (%g s), using segment duration instead\n", dash_subduration, dash_duration); + dash_subduration = dash_duration; + } + + if (dash_mode && dash_live) fprintf(stderr, "Live DASH-ing - press 'q' to quit, 's' to save context and quit\n"); if (!dash_ctx_file && dash_live) { @@ -3222,15 +3582,15 @@ int mp4boxMain(int argc, char **argv) } if (dash_profile==GF_DASH_PROFILE_UNKNOWN) - dash_profile = dash_dynamic ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_FULL; + dash_profile = dash_mode ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_FULL; - if (!dash_dynamic) { + if (!dash_mode) { time_shift_depth = 0; mpd_update_time = 0; } else if ((dash_profile>=GF_DASH_PROFILE_MAIN) && !use_url_template && !mpd_update_time) { /*use a default MPD update of dash_duration sec*/ - mpd_update_time = (u32) (dash_subduration ? dash_subduration : dash_duration); - fprintf(stderr, "Using default MPD refresh of %d seconds\n", mpd_update_time); + mpd_update_time = (Double) (dash_subduration ? dash_subduration : dash_duration); + fprintf(stderr, "Using default MPD refresh of %g seconds\n", mpd_update_time); } if (file && needSave) { @@ -3238,41 +3598,63 @@ int mp4boxMain(int argc, char **argv) file = NULL; del_file = GF_TRUE; } - while (!do_abort) { + while (1) { + if (do_abort>=2) { + dash_mode = GF_DASH_DYNAMIC_LAST; + } 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_dynamic, mpd_update_time, time_shift_depth, dash_subduration, min_buffer, - ast_shift_sec, dash_scale, memory_frags, initial_moof_sn, initial_tfdt, no_fragments_defaults, pssh_in_moof, samplegroups_in_traf); + 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 (do_abort) + break; + + //this happens when reading file while writing them (local playback of the live session ...) + if (dash_live && (e==GF_IO_ERR) ) { + fprintf(stderr, "Error dashing file (%s) but continuing ...\n", gf_error_to_string(e) ); + e = GF_OK; + } + if (e) break; if (dash_live) { + u32 slept = gf_sys_clock(); u32 sleep_for = gf_dasher_next_update_time(dash_ctx, mpd_update_time); - fprintf(stderr, "sleep for %d ms\n", sleep_for); + fprintf(stderr, "Next generation scheduled in %d ms\n", sleep_for); while (1) { if (gf_prompt_has_input()) { char c = (char) gf_prompt_get_char(); - if (c=='q') { + if (c=='X') { do_abort = 1; break; } - if (c=='s') { + if (c=='q') { do_abort = 2; break; } + if (c=='s') { + do_abort = 3; + break; + } } - if (dash_dynamic == 2) { + if (dash_mode == GF_DASH_DYNAMIC_DEBUG) { break; } - if (sleep_for<100) - break; - gf_sleep(100); + 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); + break; + } } } else { break; @@ -3280,12 +3662,14 @@ int mp4boxMain(int argc, char **argv) } if (dash_ctx) { - if (do_abort==2) { - char szName[1024]; - fprintf(stderr, "Enter file name to save dash context:\n"); - if (scanf("%s", szName) == 1) { - gf_cfg_set_filename(dash_ctx, szName); - gf_cfg_save(dash_ctx); + if (do_abort==3) { + if (!dash_ctx_file) { + char szName[1024]; + fprintf(stderr, "Enter file name to save dash context:\n"); + if (scanf("%s", szName) == 1) { + gf_cfg_set_filename(dash_ctx, szName); + gf_cfg_save(dash_ctx); + } } } gf_cfg_del(dash_ctx); @@ -3303,11 +3687,11 @@ int mp4boxMain(int argc, char **argv) && !(track_dump_type & GF_EXPORT_AVI_NATIVE) #endif ) { - FILE *st = gf_f64_open(inName, "rb"); + FILE *st = gf_fopen(inName, "rb"); Bool file_exists = 0; if (st) { file_exists = 1; - fclose(st); + gf_fclose(st); } switch (get_file_type_by_ext(inName)) { case 1: @@ -3341,7 +3725,7 @@ int mp4boxMain(int argc, char **argv) /*used for .saf / .lsr dump*/ case 6: #ifndef GPAC_DISABLE_SCENE_DUMP - if ((dump_mode==1+GF_SM_DUMP_LASER) || (dump_mode==1+GF_SM_DUMP_SVG)) { + if ((dump_mode==GF_SM_DUMP_LASER) || (dump_mode==GF_SM_DUMP_SVG)) { break; } #endif @@ -3350,7 +3734,11 @@ int mp4boxMain(int argc, char **argv) if (!open_edit && file_exists && !gf_isom_probe_file(inName) && track_dump_type) { } #ifndef GPAC_DISABLE_ISOM_WRITE - else if (!open_edit && file_exists /* && !gf_isom_probe_file(inName) */ && !dump_mode) { + else if (!open_edit && file_exists /* && !gf_isom_probe_file(inName) */ +#ifndef GPAC_DISABLE_SCENE_DUMP + && dump_mode == GF_SM_DUMP_NONE +#endif + ) { /*************************************************************************************************/ #ifndef GPAC_DISABLE_MEDIA_IMPORT if(dvbhdemux) @@ -3379,8 +3767,12 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_MPEG2TS dump_mpeg2_ts(inName, pes_dump, program_number); #endif -#ifndef GPAC_DISABLE_MEDIA_IMPORT + } else if (do_bin_nhml) { + nhml_bs_to_bin(inName, outName, dump_std); + } else if (do_hash) { + hash_file(inName, dump_std); } else { +#ifndef GPAC_DISABLE_MEDIA_IMPORT convert_file_info(inName, info_track_id); #endif } @@ -3449,7 +3841,7 @@ int mp4boxMain(int argc, char **argv) char szFile[1024]; for (i=0; iact_type != 9) continue; + if (tka->act_type != TRAC_ACTION_RAW_EXTRACT) continue; memset(&mdump, 0, sizeof(mdump)); mdump.in_name = inName; mdump.flags = tka->dump_type; @@ -3473,8 +3865,8 @@ int mp4boxMain(int argc, char **argv) #endif /*GPAC_DISABLE_MEDIA_EXPORT*/ #ifndef GPAC_DISABLE_SCENE_DUMP - if (dump_mode) { - e = dump_file_text(inName, dump_std ? NULL : outfile, dump_mode-1, do_log); + if (dump_mode != GF_SM_DUMP_NONE) { + e = dump_file_text(inName, dump_std ? NULL : outfile, dump_mode, do_log); if (e) goto err_exit; } #endif @@ -3497,7 +3889,7 @@ 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); + 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); #ifndef GPAC_DISABLE_ISOM_HINTING if (dump_rtp) dump_file_rtp(file, dump_std ? NULL : outfile); #endif @@ -3507,15 +3899,17 @@ int mp4boxMain(int argc, char **argv) if (dump_nal) dump_file_nal(file, dump_nal, dump_std ? NULL : outfile); if (do_hash) { - u8 hash[20]; - e = gf_media_get_file_hash(inName, hash); + e = hash_file(inName, dump_std); if (e) goto err_exit; - fprintf(stderr, "File %s hash (SHA-1): ", inName); - for (i=0; i<20; i++) fprintf(stderr, "%02X", hash[i]); - fprintf(stderr, "\n"); } + if (do_bin_nhml) { + e = nhml_bs_to_bin(inName, outName, dump_std); + if (e) goto err_exit; + } + 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_iod) { GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)gf_isom_get_root_od(file); @@ -3527,7 +3921,7 @@ int mp4boxMain(int argc, char **argv) GF_BitStream *bs = NULL; sprintf(szName, "%s.iod", outfile); - iodf = gf_f64_open(szName, "wb"); + iodf = gf_fopen(szName, "wb"); if (!iodf) { fprintf(stderr, "Cannot open destination %s\n", szName); } else { @@ -3540,7 +3934,7 @@ int mp4boxMain(int argc, char **argv) } else { fprintf(stderr, "Error writing IOD %s\n", szName); } - fclose(iodf); + gf_fclose(iodf); } gf_free(bs); } @@ -3561,7 +3955,7 @@ int mp4boxMain(int argc, char **argv) GF_MediaExporter mdump; for (i=0; iact_type != 9) continue; + if (tka->act_type != TRAC_ACTION_RAW_EXTRACT) continue; memset(&mdump, 0, sizeof(mdump)); mdump.file = file; mdump.flags = tka->dump_type; @@ -3610,13 +4004,13 @@ int mp4boxMain(int argc, char **argv) switch (meta->act_type) { #ifndef GPAC_DISABLE_ISOM_WRITE - case 0: + case META_ACTION_SET_TYPE: /*note: we don't handle file brand modification, this is an author stuff and cannot be guessed from meta type*/ e = gf_isom_set_meta_type(file, meta->root_meta, tk, meta->meta_4cc); gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO2, 1); needSave = 1; break; - case 1: + 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, @@ -3626,20 +4020,20 @@ int mp4boxMain(int argc, char **argv) meta->use_dref ? meta->szPath : NULL, NULL); needSave = 1; break; - case 2: + case META_ACTION_REM_ITEM: e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id); needSave = 1; break; - case 3: + case META_ACTION_SET_PRIMARY_ITEM: e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id); needSave = 1; break; - case 4: - case 5: - e = gf_isom_set_meta_xml(file, meta->root_meta, tk, meta->szPath, (meta->act_type==5) ? 1 : 0); + 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; break; - case 6: + 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; @@ -3647,7 +4041,7 @@ int mp4boxMain(int argc, char **argv) fprintf(stderr, "No meta box in input file\n"); } break; - case 8: + case META_ACTION_DUMP_XML: 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 { @@ -3655,13 +4049,15 @@ int mp4boxMain(int argc, char **argv) } break; #endif - case 7: + case META_ACTION_DUMP_ITEM: if (gf_isom_has_meta_xml(file, meta->root_meta, tk)) { e = gf_isom_extract_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL); } else { fprintf(stderr, "No meta box in input file\n"); } break; + default: + break; } if (e) goto err_exit; } @@ -3673,7 +4069,7 @@ int mp4boxMain(int argc, char **argv) #ifndef GPAC_DISABLE_ISOM_WRITE for (i=0; itrackID ? gf_isom_get_track_by_id(file, tka->trackID) : 0; u32 timescale = gf_isom_get_timescale(file); switch (tka->act_type) { - case 0: + case TRAC_ACTION_REM_TRACK: e = gf_isom_remove_track(file, track); if (e) { fprintf(stderr, "Error Removing track ID %d: %s\n", tka->trackID, gf_error_to_string(e)); @@ -3868,16 +4270,34 @@ int mp4boxMain(int argc, char **argv) } needSave = 1; break; - case 1: + case TRAC_ACTION_SET_LANGUAGE: for (i=0; ilang)); + e = gf_isom_set_media_language(file, i+1, tka->lang); if (e) goto err_exit; needSave = 1; } needSave = 1; break; - case 2: + case TRAC_ACTION_SET_KIND: + for (i=0; ikind_scheme, tka->kind_value); + if (e) goto err_exit; + needSave = 1; + } + needSave = 1; + break; + case TRAC_ACTION_REM_KIND: + for (i=0; ikind_scheme, tka->kind_value); + if (e) goto err_exit; + needSave = 1; + } + needSave = 1; + break; + case TRAC_ACTION_SET_DELAY: if (tka->delay_ms) { u64 tk_dur; @@ -3904,7 +4324,7 @@ int mp4boxMain(int argc, char **argv) needSave = 1; } break; - case 3: + case TRAC_ACTION_SET_KMS_URI: for (i=0; inewTrackID); + if (newTrack != 0) { + fprintf(stderr, "Error: Cannot set track id with value %d because a track already exists - ignoring", tka->newTrackID); + } else { + e = gf_isom_set_track_id(file, track, tka->newTrackID); + needSave = 1; + } + } else { + fprintf(stderr, "Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID); + } + break; + case TRAC_ACTION_SET_PAR: e = gf_media_change_par(file, track, tka->par_num, tka->par_den); needSave = 1; break; - case 5: + case TRAC_ACTION_SET_HANDLER_NAME: e = gf_isom_set_handler_name(file, track, tka->hdl_name); needSave = 1; break; - case 6: + case TRAC_ACTION_ENABLE: if (!gf_isom_is_track_enabled(file, track)) { e = gf_isom_set_track_enabled(file, track, 1); needSave = 1; } break; - case 7: + case TRAC_ACTION_DISABLE: if (gf_isom_is_track_enabled(file, track)) { e = gf_isom_set_track_enabled(file, track, 0); needSave = 1; } break; - case 8: + 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; break; - case 10: + 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; 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; + break; + default: + break; } if (e) goto err_exit; } @@ -3994,13 +4434,13 @@ int mp4boxMain(int argc, char **argv) case GF_ISOM_ITUNE_COVER_ART: { char *d, *ext; - FILE *t = gf_f64_open(val, "rb"); - gf_f64_seek(t, 0, SEEK_END); - tlen = (u32) gf_f64_tell(t); - gf_f64_seek(t, 0, SEEK_SET); + FILE *t = gf_fopen(val, "rb"); + gf_fseek(t, 0, SEEK_END); + tlen = (u32) gf_ftell(t); + gf_fseek(t, 0, SEEK_SET); d = gf_malloc(sizeof(char) * tlen); tlen = (u32) fread(d, sizeof(char), tlen, t); - fclose(t); + gf_fclose(t); ext = strrchr(val, '.'); if (!stricmp(ext, ".png")) tlen |= 0x80000000; @@ -4048,7 +4488,7 @@ int mp4boxMain(int argc, char **argv) case GF_ISOM_ITUNE_COMPILATION: { char _t[1]; - if (!stricmp(val, "yes")) _t[0] = 1; + if (val && !stricmp(val, "yes")) _t[0] = 1; else _t[0] = 0; gf_isom_apple_set_tag(file, itag, _t, 1); } @@ -4115,8 +4555,11 @@ int mp4boxMain(int argc, char **argv) needSave = 1; } else { e = gf_isom_make_interleave(file, interleaving_time); - if (!e && !old_interleave) e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_DRIFT_INTERLEAVED); + if (!e && old_interleave) e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_INTERLEAVED); } + if (force_co64) + gf_isom_force_64bit_chunk_offset(file, GF_TRUE); + if (e) goto err_exit; #if !defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_SENG) @@ -4217,6 +4660,16 @@ err_exit: if (file) gf_isom_delete(file); fprintf(stderr, "\n\tError: %s\n", gf_error_to_string(e)); MP4BOX_EXIT_WITH_CODE(1); + +exit: + +#ifdef GPAC_MEMORY_TRACKING + if (enable_mem_tracker && (gf_memory_size() || gf_file_handles_count() )) { + gf_memory_print(); + return 2; + } +#endif + return 0; } int main( int argc, char** argv ) diff --git a/applications/mp4box/wrapper.c b/applications/mp4box/wrapper.c index f26fe93..d4a22c7 100644 --- a/applications/mp4box/wrapper.c +++ b/applications/mp4box/wrapper.c @@ -57,8 +57,8 @@ JNIEXPORT void JNICALL Java_com_enst_mp4box_mp4terminal_run(JNIEnv * env, jobjec (*env)->ReleaseStringUTFChars(env, sCommand, sOriginalCommand); jniLOGV("mp4terminal::end"); - fclose(ferr); - fclose(fout); + gf_fclose(ferr); + gf_fclose(fout); } char ** ConvertCommandLine( const char* sCommand, int* iNbArg ) diff --git a/applications/mp4client/Makefile b/applications/mp4client/Makefile index b699020..6aff667 100644 --- a/applications/mp4client/Makefile +++ b/applications/mp4client/Makefile @@ -31,6 +31,11 @@ EXT= PROG=MP4Client endif +ifeq ($(CONFIG_DARWIN),yes) +OBJS+= carbon_events.o +LDFLAGS += -framework Carbon +endif + SRCS := $(OBJS:.o=.c) all: $(PROG) diff --git a/applications/mp4client/carbon_events.c b/applications/mp4client/carbon_events.c new file mode 100644 index 0000000..d4226bb --- /dev/null +++ b/applications/mp4client/carbon_events.c @@ -0,0 +1,109 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2005-2012 + * All rights reserved + * + * This file is part of GPAC / command-line client + * + * 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. + * + */ + +#if defined(__DARWIN__) || defined(__APPLE__) +#include +#endif + + +void gf_sys_set_args(int argc, const char **argv); +void send_open_url(const char *url); + +void RunApplicationEventLoop(void); +void QuitApplicationEventLoop(void); + +char *my_argv[2]; + +static int main_evt_loop_run = 1; + +static AEEventHandlerUPP open_app_UPP, open_doc_UPP; + +static pascal OSErr ae_open_app (const AppleEvent *ae_event, AppleEvent *ae_reply, long ae_ref_count) +{ + if (main_evt_loop_run) { + QuitApplicationEventLoop(); + main_evt_loop_run = 0; + } + return (noErr); +} + +static pascal OSErr ae_open_doc (const AppleEvent *ae_event, AppleEvent *ae_reply, long ae_ref_count) +{ + OSErr err; + FSRef ref; + AEDescList docList; + long count; + + err = AEGetParamDesc(ae_event, keyDirectObject, typeAEList, &docList); + if (err) + return (noErr); + + err = AECountItems(&docList, &count); + if (err == noErr) { + err = AEGetNthPtr(&docList, 1, typeFSRef, NULL, NULL, &ref, sizeof(FSRef), NULL); + if (err == noErr) { + char path[4096]; + FSRefMakePath(&ref, (UInt8 *) path, 4096); + if (main_evt_loop_run) { + my_argv[1] = strdup(path); + gf_sys_set_args(2, (const char **) my_argv); + } else { + send_open_url(path); + } + } + } + err = AEDisposeDesc(&docList); + + if (main_evt_loop_run) { + QuitApplicationEventLoop(); + main_evt_loop_run = 0; + } + return (noErr); +} + +void carbon_init () +{ + my_argv[0] = "GPAC"; + my_argv[1] = NULL; + + 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); + + main_evt_loop_run = 1; + RunApplicationEventLoop(); +} + +void carbon_uninit() +{ + + 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 d82b2fb..20970df 100644 --- a/applications/mp4client/extract.c +++ b/applications/mp4client/extract.c @@ -63,10 +63,29 @@ typedef struct tagBITMAPINFOHEADER { #include #include + +enum +{ + DUMP_NONE = 0, + DUMP_AVI = 1, + DUMP_BMP = 2, + DUMP_PNG = 3, + DUMP_RAW = 4, + DUMP_SHA1 = 5, + + //DuMP flags + DUMP_DEPTH_ONLY = 1<<16, + DUMP_RGB_DEPTH = 1<<17, + DUMP_RGB_DEPTH_SHAPE = 1<<18 +}; + + extern Bool is_connected; extern GF_Terminal *term; extern u64 Duration; extern GF_Err last_error; +extern Bool no_prog; + static GFINLINE u8 colmask(s32 a, s32 n) { @@ -87,16 +106,9 @@ static u32 put_pixel(FILE *fout, u32 type, u32 pf, char *ptr) case GF_PIXEL_BGR_32: case GF_PIXEL_RGBA: - //probably due to tinygl bug - verify -#ifndef GPAC_USE_TINYGL - fputc(ptr[3], fout); - fputc(ptr[2], fout); - fputc(ptr[1], fout); -#else fputc(ptr[2], fout); fputc(ptr[1], fout); fputc(ptr[0], fout); -#endif return 4; case GF_PIXEL_RGB_24: @@ -162,7 +174,7 @@ void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) if (fb->pixel_format==GF_PIXEL_GREYSCALE) sprintf(str, "%s_%d_depth.bmp", rad_name, img_num); else sprintf(str, "%s_%d.bmp", rad_name, img_num); - fout = gf_f64_open(str, "wb"); + fout = gf_fopen(str, "wb"); if (!fout) return; memset(&fh, 0, sizeof(fh)); @@ -177,7 +189,7 @@ void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) if (fb->pixel_format==GF_PIXEL_GREYSCALE) fi.biBitCount = 24; else fi.biBitCount = 24; fi.biCompression = BI_RGB; - fi.biSizeImage = fb->pitch_y * fb->height; + fi.biSizeImage = fb->width * fb->height * 3; /*NOT ALIGNED!!*/ gf_fwrite(&fh.bfType, 2, 1, fout); @@ -187,7 +199,6 @@ void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) gf_fwrite(&fh.bfOffBits, 4, 1, fout); gf_fwrite(&fi, 1, 40, fout); -//#ifndef GPAC_USE_TINYGL for (j=fb->height; j>0; j--) { ptr = fb->video_buffer + (j-1)*fb->pitch_y; for (i=0; iwidth; i++) { @@ -196,19 +207,7 @@ void write_bmp(GF_VideoSurface *fb, char *rad_name, u32 img_num) ptr += res; } } -//#else -#if 0 - for (j=0; jheight; j++) { - ptr = fb->video_buffer + j*fb->pitch; - for (i=0; iwidth; i++) { - u32 res = put_pixel(fout, 0, fb->pixel_format, ptr); - assert(res); - ptr += res; - } - } -#endif - - fclose(fout); + gf_fclose(fout); } #include @@ -237,12 +236,12 @@ void write_png(GF_VideoSurface *fb, char *rad_name, u32 img_num) dst = (char*)gf_malloc(sizeof(char)*dst_size); - fout = gf_f64_open(str, "wb"); + fout = gf_fopen(str, "wb"); if (fout) { GF_Err e = gf_img_png_enc(fb->video_buffer, fb->width, fb->height, fb->pitch_y, fb->pixel_format, dst, &dst_size); if (!e) { gf_fwrite(dst, dst_size, 1, fout); - fclose(fout); + gf_fclose(fout); } } @@ -262,7 +261,7 @@ void write_depthfile(GF_VideoSurface *fb, char *rad_name, u32 img_num) depth = (unsigned char *) fb->video_buffer; - fout = gf_f64_open("dump_depth", "wb"); + fout = gf_fopen("dump_depth", "wb"); if (!fout) return; for (j=0; jheight; j++) { for (i=0; iwidth; i++) { @@ -275,10 +274,10 @@ void write_depthfile(GF_VideoSurface *fb, char *rad_name, u32 img_num) #endif } } - fclose(fout); + gf_fclose(fout); } -void write_texture_file(GF_VideoSurface *fb, char *rad_name, u32 img_num, u32 dump_mode) +void write_texture_file(GF_VideoSurface *fb, char *rad_name, u32 img_num, u32 dump_mode_flags) { FILE *fout; @@ -287,8 +286,8 @@ void write_texture_file(GF_VideoSurface *fb, char *rad_name, u32 img_num, u32 du buf = (unsigned char *) fb->video_buffer; - if (dump_mode==6) fout = gf_f64_open("dump_rgbds", "wb"); - else if (dump_mode==9) fout = gf_f64_open("dump_rgbd", "wb"); + if (dump_mode_flags & DUMP_RGB_DEPTH_SHAPE) fout = gf_fopen("dump_rgbds", "wb"); + else if (dump_mode_flags & DUMP_RGB_DEPTH) fout = gf_fopen("dump_rgbd", "wb"); else return; if (!fout) return; @@ -297,7 +296,7 @@ void write_texture_file(GF_VideoSurface *fb, char *rad_name, u32 img_num, u32 du fputc(buf[i+j*fb->pitch_y], fout); } } - fclose(fout); + gf_fclose(fout); } @@ -317,7 +316,7 @@ void write_raw(GF_VideoSurface *fb, char *rad_name, u32 img_num) sprintf(str, "%s_%d.raw", rad_name, img_num); } - fout = gf_f64_open(str, "wb"); + fout = gf_fopen(str, "wb"); if (!fout) return; @@ -329,25 +328,33 @@ void write_raw(GF_VideoSurface *fb, char *rad_name, u32 img_num) ptr += res; } } - fclose(fout); + gf_fclose(fout); +} + +void write_hash(FILE *sha_out, char *buf, u32 size) +{ + u8 hash[20]; + gf_sha1_csum((u8 *)buf, size, hash); + fwrite(hash, 1, 20, sha_out); } /* creates a .bmp format greyscale image of the byte depthbuffer and a binary with only the content of the depthbuffer */ -void dump_depth (GF_Terminal *term, char *rad_name, u32 dump_type, u32 frameNum, char *conv_buf, void *avi_out) +void dump_depth (GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 frameNum, char *conv_buf, void *avi_out, FILE *sha_out) { GF_Err e; u32 i, k; + GF_VideoSurface fb; + u32 dump_mode = dump_mode_flags & 0x0000FFFF; /*lock it*/ e = gf_sc_get_screen_buffer(term->compositor, &fb, 1); if (e) fprintf(stderr, "Error grabbing depth buffer: %s\n", gf_error_to_string(e)); else fprintf(stderr, "OK\n"); /*export frame*/ - switch (dump_type) { - case 1: - case 8: + switch (dump_mode) { + case DUMP_AVI: /*reverse frame*/ for (k=0; kcompositor, &fb); + gf_sc_release_screen_buffer(term->compositor, &fb); } -void dump_frame(GF_Terminal *term, char *rad_name, u32 dump_type, u32 frameNum, char *conv_buf, void *avi_out) +void dump_frame(GF_Terminal *term, char *rad_name, u32 dump_mode_flags, u32 frameNum, char *conv_buf, void *avi_out, FILE *sha_out) { GF_Err e = GF_OK; u32 i, k, out_size; GF_VideoSurface fb; + u32 dump_mode = dump_mode_flags & 0x0000FFFF; + u32 depth_dump_mode = 0; + + if (dump_mode_flags & DUMP_RGB_DEPTH_SHAPE) depth_dump_mode = 3; + else if (dump_mode_flags & DUMP_RGB_DEPTH) depth_dump_mode = 2; + else if (dump_mode_flags & DUMP_DEPTH_ONLY) depth_dump_mode = 1; + /*lock it*/ - if (dump_type==5 || dump_type==6) e = gf_sc_get_screen_buffer(term->compositor, &fb, 2); - else if (dump_type== 9 || dump_type==10) e = gf_sc_get_screen_buffer(term->compositor, &fb, 3); - else e = gf_sc_get_screen_buffer(term->compositor, &fb, 0); + e = gf_sc_get_screen_buffer(term->compositor, &fb, depth_dump_mode); if (e) fprintf(stderr, "Error grabbing frame buffer: %s\n", gf_error_to_string(e)); /*export frame*/ - switch (dump_type) { - case 1: - case 5: - case 10: - case 8: + switch (dump_mode) { + case DUMP_AVI: + case DUMP_SHA1: /*reverse frame*/ for (k=0; kcompositor, &fb); } -Bool dump_file(char *url, char *out_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times) +#ifndef GPAC_DISABLE_AVILIB + +typedef struct +{ + GF_AudioListener al; + GF_Mutex *mx; + avi_t *avi; + 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; +} 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) + return; + + if (avil->audio_time >= avil->audio_time_init + avil->max_dur) + return; + + 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; + gf_term_set_option(term, GF_OPT_FORCE_AUDIO_CONFIG, 1); + } + + avil->nb_bytes+=buffer_size; + avil->flush_retry=0; + + if (avil->audio_time >= avil->audio_time_init) { + avil->nb_write++; + AVI_write_audio(avil->avi, buffer, buffer_size); + } + + + avil->audio_time = 1000*avil->nb_bytes/avil->time_scale; + + //we are behind video dump, force audio flush + if (avil->audio_time < avil->next_video_time) { + gf_term_step_clocks(term, 0); + } + gf_mx_v(avil->mx); +} + +void avi_audio_reconfig(void *udta, u32 samplerate, u32 bits_per_sample, u32 nb_channel, u32 channel_cfg) +{ + AVI_AudioListener *avil = (AVI_AudioListener *)udta; + + 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; u32 i = 0; @@ -593,7 +673,27 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode, Double fps, u32 width, u char szPath[GF_MAX_PATH]; char szOutPath[GF_MAX_PATH]; char *prev=NULL; + u32 time, prev_time, nb_frames, init_time; + u64 dump_dur; + char *conv_buf = NULL; +#ifndef GPAC_DISABLE_AVILIB + avi_t *avi_out = NULL; + avi_t *depth_avi_out = NULL; + AVI_AudioListener avi_al; + char comp[5]; +#else + void *avi_out = NULL; + void *depth_avi_out = NULL; +#endif + GF_Mutex *avi_mx = NULL; + + FILE *sha_out = NULL; + FILE *sha_depth_out = NULL; + char szPath_depth[GF_MAX_PATH]; + u32 cur_time_idx; + u32 mode = dump_mode_flags & 0x0000FFFF; + if (!out_url) out_url = url; prev = strstr(url, "://"); if (prev) { prev = strrchr(url, '/'); @@ -632,10 +732,8 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode, Double fps, u32 width, u gf_term_process_flush(term); } #ifndef GPAC_USE_TINYGL - fprintf(stderr, "not tinygl\n"); e = gf_sc_get_screen_buffer(term->compositor, &fb, 0); #else - fprintf(stderr, "tinygl\n"); e = gf_sc_get_screen_buffer(term->compositor, &fb, 1); #endif if (e != GF_OK) { @@ -667,105 +765,198 @@ Bool dump_file(char *url, char *out_url, u32 dump_mode, Double fps, u32 width, u gf_sc_release_screen_buffer(term->compositor, &fb); } - if (dump_mode==1 || dump_mode==5 || dump_mode==8 || dump_mode==10) { + + strcpy(szPath_depth, szOutPath); + + if (mode==DUMP_AVI) { #ifdef GPAC_DISABLE_AVILIB fprintf(stderr, "AVILib is disabled in this build of GPAC\n"); return 0; #else - u32 time, prev_time, nb_frames; - u64 dump_dur; - char *conv_buf; - avi_t *avi_out = NULL; - avi_t *depth_avi_out = NULL; - char szPath_depth[GF_MAX_PATH]; - char comp[5]; - strcpy(szPath_depth, szOutPath); strcat(szOutPath, ".avi"); avi_out = AVI_open_output_file(szOutPath); if (!avi_out) { fprintf(stderr, "Error creating AVI file %s\n", szOutPath); return 1; } - if (dump_mode==8) { +#endif + } + + if (mode==DUMP_SHA1) { + strcat(szOutPath, ".sha1"); + sha_out = gf_fopen(szOutPath, "wb"); + if (!sha_out) { + fprintf(stderr, "Error creating SHA file %s\n", szOutPath); + return 1; + } + } + + if (dump_mode_flags & DUMP_DEPTH_ONLY) { + if (mode==DUMP_AVI) { +#ifndef GPAC_DISABLE_AVILIB strcat(szPath_depth, "_depth.avi"); depth_avi_out = AVI_open_output_file(szPath_depth); if (!depth_avi_out) { - fprintf(stderr, "Error creating AVI file %s\n", szPath_depth); + fprintf(stderr, "Error creating depth AVI file %s\n", szPath_depth); return 1; } +#endif } + if (mode==DUMP_SHA1) { + strcat(szPath_depth, "_depth.sha1"); + sha_depth_out = gf_fopen(szPath_depth, "wb"); + if (!sha_depth_out) { + fprintf(stderr, "Error creating depgth SHA file %s\n", szPath_depth); + return 1; + } + } + } - if (!fps) fps = GF_IMPORT_DEFAULT_FPS; - time = prev_time = 0; - nb_frames = 0; - if (nb_times==2) { - prev_time = times[0]; - dump_dur = times[1] - times[0]; - } else { - dump_dur = times[0] ? times[0] : Duration; - } - if (!dump_dur) { - fprintf(stderr, "Warning: file has no duration, defaulting to 1 sec\n"); - dump_dur = 1000; - } + if (!fps) fps = GF_IMPORT_DEFAULT_FPS; + time = prev_time = 0; + nb_frames = 0; + + if (nb_times==2) { + prev_time = times[0]; + dump_dur = times[1] - times[0]; + } else if ((mode==DUMP_AVI) || (mode==DUMP_SHA1)) { + dump_dur = times[0] ? times[0] : Duration; + } else { + dump_dur = times[nb_times-1]; + dump_dur ++; + } + if (!dump_dur) { + fprintf(stderr, "Warning: file has no duration, defaulting to 1 sec\n"); + dump_dur = 1000; + } + + if (mode==DUMP_AVI) { + avi_mx = gf_mx_new("AVIMutex"); +#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 (dump_mode==8) AVI_set_video(depth_avi_out, width, height, fps, comp); - if (dump_mode != 5 && dump_mode!=10) conv_buf = gf_malloc(sizeof(char) * width * height * 3); - else conv_buf = gf_malloc(sizeof(char) * width * height * 4); - /*step to first frame*/ - if (prev_time) gf_term_step_clocks(term, prev_time); - - while (time < dump_dur) { - while ((gf_term_get_option(term, GF_OPT_PLAY_STATE) == GF_STATE_STEP_PAUSE)) { - gf_term_process_flush(term); - } - fprintf(stderr, "Dumping %02d/100 %% - time %.02f sec\r", (u32) ((100.0*prev_time)/dump_dur), prev_time/1000.0 ); + + if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { + memset(&avi_al, 0, sizeof(avi_al)); + avi_al.al.udta = &avi_al; + avi_al.al.on_audio_frame = avi_audio_frame; + avi_al.al.on_audio_reconfig = avi_audio_reconfig; + avi_al.mx = avi_mx; + avi_al.avi = avi_out; + avi_al.max_dur=dump_dur; + + gf_sc_add_audio_listener(term->compositor, &avi_al.al); + } + + 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) ) + conv_buf = gf_malloc(sizeof(char) * width * height * 4); + else + conv_buf = gf_malloc(sizeof(char) * width * height * 3); + } + + cur_time_idx = 0; + init_time = 0; + /*step to first frame*/ + if (prev_time) { + gf_term_step_clocks(term, prev_time); + init_time = prev_time; + prev_time=0; + } +#ifndef GPAC_DISABLE_AVILIB + avi_al.audio_time_init = avi_al.next_video_time = init_time; + avi_al.audio_clock_at_video_init = gf_term_get_clock(term); +#endif + + while (time < dump_dur) { + while ((gf_term_get_option(term, GF_OPT_PLAY_STATE) == GF_STATE_STEP_PAUSE)) { + gf_term_process_flush(term); + } + + 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 (avi_mx) gf_mx_p(avi_mx); + + if (dump_mode_flags & DUMP_DEPTH_ONLY) { - if (dump_mode==8) { /*we'll dump both buffers at once*/ gf_mx_p(term->compositor->mx); - dump_depth(term, szPath_depth, dump_mode, i+1, conv_buf, depth_avi_out); - dump_frame(term, szOutPath, dump_mode, i+1, conv_buf, avi_out); + dump_depth(term, szPath_depth, dump_mode_flags, i+1, conv_buf, depth_avi_out, sha_depth_out); + dump_frame(term, szOutPath, mode, i+1, conv_buf, avi_out, sha_out); gf_mx_v(term->compositor->mx); - + } else { + dump_frame(term, szOutPath, dump_mode_flags, i+1, conv_buf, avi_out, sha_out); } - else dump_frame(term, szOutPath, dump_mode, i+1, conv_buf, avi_out); - nb_frames++; - time = (u32) (nb_frames*1000/fps); - gf_term_step_clocks(term, time - prev_time); - prev_time = time; + if (avi_mx) gf_mx_v(avi_mx); - if (gf_prompt_has_input() && (gf_prompt_get_char()=='q')) { - fprintf(stderr, "Aborting dump\n"); - break; + } else { + if ( times[cur_time_idx] <= time) { + if (dump_mode_flags & (DUMP_DEPTH_ONLY | DUMP_RGB_DEPTH | DUMP_RGB_DEPTH_SHAPE) ) { + dump_depth(term, szOutPath, dump_mode_flags, cur_time_idx+1, NULL, NULL, NULL); + } else { + dump_frame(term, out_url, dump_mode_flags, cur_time_idx+1, NULL, NULL, NULL); + } + + cur_time_idx++; + if (cur_time_idx>=nb_times) + break; } } - AVI_close(avi_out); - if (dump_mode==8) AVI_close(depth_avi_out); - gf_free(conv_buf); - fprintf(stderr, "AVI Extraction 100/100\n"); -#endif /*GPAC_DISABLE_AVILIB*/ - } else { - if (times[0]) gf_term_step_clocks(term, times[0]); - for (i=0; iuser->init_flags & GF_TERM_NO_AUDIO)) { + avi_al.flush_retry=0; + while ((avi_al.flush_retry <100) && (avi_al.audio_time < dump_dur)) { + gf_term_step_clocks(term, 0); + gf_sleep(1); + avi_al.flush_retry++; } } + + if (! (term->user->init_flags & GF_TERM_NO_AUDIO)) { + gf_sc_remove_audio_listener(term->compositor, &avi_al.al); + } + if (avi_out) AVI_close(avi_out); + if (depth_avi_out) AVI_close(depth_avi_out); + if (avi_mx) gf_mx_del(avi_mx); +#endif + + if (sha_out) gf_fclose(sha_out); + if (sha_depth_out) gf_fclose(sha_depth_out); + + if (conv_buf) { + gf_free(conv_buf); + fprintf(stderr, "Dumping done: %d frames at %g FPS\n", nb_frames, fps); + } + return 0; } diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c index 4cb1f88..074ba52 100644 --- a/applications/mp4client/main.c +++ b/applications/mp4client/main.c @@ -23,6 +23,7 @@ * */ + /*includes both terminal and od browser*/ #include #include @@ -47,6 +48,10 @@ #if defined(__DARWIN__) || defined(__APPLE__) #include #include + +void carbon_init(); +void carbon_uninit(); + #endif #else @@ -55,7 +60,7 @@ /*local prototypes*/ void PrintWorldInfo(GF_Terminal *term); -void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number); +void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number, const char *URL); void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 indent, char *root_name); void ViewODs(GF_Terminal *term, Bool show_timing); @@ -65,11 +70,16 @@ static u32 gui_mode = 0; static Bool restart = GF_FALSE; static Bool reload = GF_FALSE; + +Bool no_prog = 0; + #if defined(__DARWIN__) || defined(__APPLE__) //we keep no decoder thread because of JS_GC deadlocks between threads ... static u32 threading_flags = GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_DECODER_THREAD; +#define VK_MOD GF_KEY_MOD_ALT #else static u32 threading_flags = 0; +#define VK_MOD GF_KEY_MOD_CTRL #endif static Bool no_audio = GF_FALSE; static Bool term_step = GF_FALSE; @@ -86,7 +96,7 @@ GF_Terminal *term; u64 Duration; GF_Err last_error = GF_OK; static Bool enable_add_ons = GF_TRUE; -static Fixed playback_speed = 1.0; +static Fixed playback_speed = FIX_ONE; static s32 request_next_playlist_item = GF_FALSE; FILE *playlist = NULL; @@ -114,23 +124,54 @@ u32 last_x, last_y; Bool right_down = GF_FALSE; void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum); + +enum +{ + DUMP_NONE = 0, + DUMP_AVI = 1, + DUMP_BMP = 2, + DUMP_PNG = 3, + DUMP_RAW = 4, + DUMP_SHA1 = 5, + + //DuMP flags + DUMP_DEPTH_ONLY = 1<<16, + DUMP_RGB_DEPTH = 1<<17, + DUMP_RGB_DEPTH_SHAPE = 1<<18 +}; + Bool dump_file(char *the_url, char *out_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times); +static Bool shell_visible = GF_TRUE; void hide_shell(u32 cmd_type) { #if defined(WIN32) && !defined(_WIN32_WCE) typedef HWND (WINAPI *GetConsoleWindowT)(void); HMODULE hk32 = GetModuleHandle("kernel32.dll"); GetConsoleWindowT GetConsoleWindow = (GetConsoleWindowT ) GetProcAddress(hk32,"GetConsoleWindow"); - if (cmd_type==0) ShowWindow( GetConsoleWindow(), SW_SHOW); - else if (cmd_type==1) ShowWindow( GetConsoleWindow(), SW_HIDE); + if (cmd_type==0) { + ShowWindow( GetConsoleWindow(), SW_SHOW); + shell_visible = GF_TRUE; + } + else if (cmd_type==1) { + ShowWindow( GetConsoleWindow(), SW_HIDE); + shell_visible = GF_FALSE; + } else if (cmd_type==2) PostMessage(GetConsoleWindow(), WM_CLOSE, 0, 0); + #endif } - +void send_open_url(const char *url) +{ + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_NAVIGATE; + evt.navigate.to_url = url; + gf_term_send_event(term, &evt); +} void PrintUsage() { @@ -143,7 +184,10 @@ void PrintUsage() "\t-rtix fileName: same as -rti but driven by GPAC logs\n" "\t-quiet: removes script message, buffering and downloading status\n" "\t-strict-error: exit when the player reports its first error\n" - "\t-opt option: Overrides an option in the configuration file. String format is section:key=value\n" + "\t-opt option: Overrides an option in the configuration file. String format is section:key=value. \n" + "\t \"section:key=null\" removes the key\n" + "\t \"section:*=null\" removes the section\n" + "\t-conf option: Same as -opt but does not start player.\n" "\t-log-file file: sets output log file. Also works with -lf\n" "\t-logs log_args: sets log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n" "\t levelX can be one of:\n" @@ -191,51 +235,57 @@ void PrintUsage() #else "\t-no-thread: disables thread usage (except for audio)\n" #endif - "\t-no-audio: disables audio \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" "\t-align vh: specifies v and h alignment for windowless mode\n" - " possible v values: t(op), m(iddle), b(ottom)\n" - " possible h values: l(eft), m(iddle), r(ight)\n" - " default alignment is top-left\n" - " default alignment is top-left\n" + "\t possible v values: t(op), m(iddle), b(ottom)\n" + "\t possible h values: l(eft), m(iddle), r(ight)\n" + "\t default alignment is top-left\n" + "\t default alignment is top-left\n" "\t-pause: pauses at first frame\n" + "\t-play-from T: starts from T seconds in media\n" + "\t-speed S: starts with speed S\n" "\t-loop: loops presentation\n" "\t-no-regulation: disables framerate regulation\n" "\t-bench: disable a/v output and bench source decoding (as fast as possible)\n" "\t-vbench: disable audio output, video sync bench source decoding/display (as fast as possible)\n" "\t-sbench: disable all decoders and bench systems layer (as fast as possible)\n" - "\t-fs: starts in fullscreen mode\n" - "\t-views v1:.:vN: creates an auto-stereo scene of N views. vN can be any type of URL supported by GPAC. \n" - " in this mode, URL argument of GPAC is ignored, GUI as well.\n" - " this is equivalent as using views://v1:.:N as an URL.\n" + "\t-fs: starts in fullscreen mode\n" + "\t-views v1:.:vN: creates an auto-stereo scene of N views. vN can be any type of URL supported by GPAC.\n" + "\t in this mode, URL argument of GPAC is ignored, GUI as well.\n" + "\t this is equivalent as using views://v1:.:N as an URL.\n" "\n" "\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-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" "\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" + "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" - "\r-out filename: name of the output file\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" - " with -avi [times]: dumps an rgbds-format .avi\n" + "\t with -avi [times]: dumps an rgbds-format .avi\n" "\t-rgbd: dumps the RGBD pixel format texture\n" - " with -avi [times]: dumps an rgbd-format .avi\n" + "\t with -avi [times]: dumps an rgbd-format .avi\n" "\t-depth: dumps depthmap (z-buffer) frames\n" - " with -avi [times]: dumps depthmap in grayscale .avi\n" - " with -bmp: dumps depthmap in grayscale .bmp\n" - " with -png: dumps depthmap in grayscale .png\n" + "\t with -avi [times]: dumps depthmap in grayscale .avi\n" + "\t with -bmp: dumps depthmap in grayscale .bmp\n" + "\t with -png: dumps depthmap in grayscale .png\n" "\t-fps FPS: specifies frame rate for AVI dumping (default: %f)\n" "\t-scale s: scales the visual size (default: 1)\n" "\t-fill: uses fill aspect ratio for dumping (default: none)\n" - "\t-show: show window while dumping (default: no)\n" + "\t-show: shows window while dumping (default: no)\n" "\n" - "\t-help: show this screen\n" + "\t-help: shows this screen\n" "\n" "MP4Client - GPAC command line player and dumper - version "GPAC_FULL_VERSION"\n" "GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n" @@ -257,6 +307,7 @@ void PrintHelp() "\tP: jumps to a given number ahead in the playlist\n" "\tr: reload current presentation\n" "\tD: disconnects the current presentation\n" + "\tG: selects object or service ID\n" "\n" "\tp: play/pause the presentation\n" "\ts: step one frame ahead\n" @@ -342,11 +393,11 @@ static void UpdateRTInfo(const char *legend) char szMsg[1024]; if (rti.total_cpu_usage && (bench_mode<2) ) { - sprintf(szMsg, "FPS %d CPU %2d (%02d) Mem %d kB", - (u32) gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024)); + sprintf(szMsg, "FPS %02.02f CPU %2d (%02d) Mem %d kB", + gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024)); } else { - sprintf(szMsg, "FPS %d CPU %02d Mem %d kB", - (u32) gf_term_get_framerate(term, 0), rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) ); + sprintf(szMsg, "FPS %02.02f CPU %02d Mem %d kB", + gf_term_get_framerate(term, 0), rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) ); } if (display_rti==2) { @@ -504,6 +555,16 @@ static const char * read_line_input(char * line, int maxSize, Bool showContent) return line; } +static void do_set_speed(Fixed desired_speed) +{ + if (gf_term_set_speed(term, desired_speed) == GF_OK) { + playback_speed = desired_speed; + fprintf(stderr, "Playing at %g speed\n", FIX2FLT(playback_speed)); + } else { + fprintf(stderr, "Adjusting speed to %g not supported for this content\n", FIX2FLT(desired_speed)); + } +} + Bool GPAC_EventProc(void *ptr, GF_Event *evt) { if (!term) return 0; @@ -511,14 +572,24 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) if (gui_mode==1) { if (evt->type==GF_EVENT_QUIT) { Run = 0; + } else if (evt->type==GF_EVENT_KEYDOWN) { + switch (evt->key.key_code) { + case GF_KEY_C: + if (evt->key.flags & (GF_KEY_MOD_CTRL|GF_KEY_MOD_ALT)) { + hide_shell(shell_visible ? 1 : 0); + if (shell_visible) gui_mode=2; + } + break; + default: + break; + } } return 0; } switch (evt->type) { case GF_EVENT_DURATION: - Duration = 1000; - Duration = (u64) (((s64) Duration) * evt->duration.duration); + Duration = (u64) ( 1000 * (s64) evt->duration.duration); CanSeek = evt->duration.can_seek; break; case GF_EVENT_MESSAGE: @@ -621,6 +692,12 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) case GF_KEY_ESCAPE: gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN)); break; + case GF_KEY_C: + if (evt->key.flags & (GF_KEY_MOD_CTRL|GF_KEY_MOD_ALT)) { + hide_shell(shell_visible ? 1 : 0); + if (!shell_visible) gui_mode=1; + } + break; case GF_KEY_F: if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Rendering rate: %f FPS\n", gf_term_get_framerate(term, 0)); break; @@ -646,11 +723,25 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) if (evt->key.flags & GF_KEY_MOD_CTRL) 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 (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); + } else { + fprintf(stderr, "Main addon not enabled\n"); + } + } + break; case GF_KEY_P: if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { - Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE); + u32 is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE) ; fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused"); - 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); + if ((is_pause == 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); + } } break; case GF_KEY_S: @@ -686,24 +777,18 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) gf_term_toggle_addons(term, addon_visible); break; case GF_KEY_UP: - if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { - playback_speed *= 2; - fprintf(stderr, "Playing at %g speed\n", FIX2FLT(playback_speed)); - gf_term_set_speed(term, playback_speed); + if (evt->key.flags & VK_MOD && is_connected) { + do_set_speed(playback_speed * 2); } break; case GF_KEY_DOWN: - if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { - playback_speed /= 2; - fprintf(stderr, "Playing at %g speed\n", FIX2FLT(playback_speed)); - gf_term_set_speed(term, playback_speed); + if (evt->key.flags & VK_MOD && is_connected) { + do_set_speed(playback_speed / 2); } break; case GF_KEY_LEFT: - if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) { - playback_speed = -playback_speed; - fprintf(stderr, "Playing at %g speed\n", FIX2FLT(playback_speed)); - gf_term_set_speed(term, playback_speed); + if (evt->key.flags & VK_MOD && is_connected) { + do_set_speed(-1 * playback_speed ); } break; @@ -715,6 +800,9 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) is_connected = 1; fprintf(stderr, "Service Connected\n"); eos_seen = GF_FALSE; + if (playback_speed != FIX_ONE) + gf_term_set_speed(term, playback_speed); + } else if (is_connected) { fprintf(stderr, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed"); is_connected = 0; @@ -758,7 +846,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt) u32 i, pos; /*todo - force playlist mode*/ if (readonly_playlist) { - fclose(playlist); + gf_fclose(playlist); playlist = NULL; } readonly_playlist = 0; @@ -927,6 +1015,7 @@ static Bool get_time_list(char *arg, u32 *times, u32 *nb_times) return 1; } +static u64 last_log_time=0; static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list) { FILE *logs = cbk; @@ -936,13 +1025,17 @@ static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list vsprintf(szMsg, fmt, list); UpdateRTInfo(szMsg + 6 /*"[RTI] "*/); } else { - if (log_time_start) fprintf(logs, "[At "LLD"]", gf_sys_clock_high_res() - log_time_start); + if (log_time_start) { + u64 now = gf_sys_clock_high_res(); + fprintf(logs, "At "LLD" (diff %d) - ", now - log_time_start, (u32) (now - last_log_time) ); + last_log_time = now; + } 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); + 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); @@ -951,8 +1044,8 @@ static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list static void init_rti_logs(char *rti_file, char *url, Bool use_rtix) { - if (rti_logs) fclose(rti_logs); - rti_logs = gf_f64_open(rti_file, "wt"); + if (rti_logs) gf_fclose(rti_logs); + rti_logs = gf_fopen(rti_file, "wt"); if (rti_logs) { fprintf(rti_logs, "!! GPAC RunTime Info "); if (url) fprintf(rti_logs, "for file %s", url); @@ -992,7 +1085,19 @@ void set_cfg_option(char *opt_string) strcpy(szKey, sep); strcpy(szVal, sep2+1); sep2[0] = '='; - if (!stricmp(szVal, "null")) szVal[0]=0; + + if (!stricmp(szKey, "*")) { + if (stricmp(szVal, "null")) { + fprintf(stderr, "Badly formatted option %s - expected Section:*=null\n", opt_string); + return; + } + 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); } @@ -1000,6 +1105,8 @@ void set_cfg_option(char *opt_string) #include #endif +static void progress_quiet(const void *cbck, const char *title, u64 done, u64 total) { } + int main (int argc, char **argv) { char c; @@ -1011,10 +1118,10 @@ int main (int argc, char **argv) Bool logs_set = GF_FALSE; Bool start_fs = GF_FALSE; Bool use_rtix = GF_FALSE; - Bool rgbds_dump = GF_FALSE; - Bool rgbd_dump = GF_FALSE; - Bool depth_dump = GF_FALSE; Bool pause_at_first = GF_FALSE; + Bool no_cfg_save = GF_FALSE; + Bool is_cfg_only = GF_FALSE; + Double play_from = 0; #ifdef GPAC_MEMORY_TRACKING Bool enable_mem_tracker = GF_FALSE; @@ -1033,7 +1140,7 @@ int main (int argc, char **argv) memset(&user, 0, sizeof(GF_User)); - dump_mode = 0; + dump_mode = DUMP_NONE; fill_ar = visible = GF_FALSE; url_arg = out_arg = the_cfg = rti_file = views = default_com = NULL; nb_times = 0; @@ -1052,8 +1159,11 @@ int main (int argc, char **argv) #else fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"); #endif - } - else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) { + } else if (!strcmp(arg, "-gui")) { + gui_mode = 1; + } else if (!strcmp(arg, "-guid")) { + gui_mode = 2; + } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) { PrintUsage(); return 1; } @@ -1064,6 +1174,7 @@ int main (int argc, char **argv) #else gf_sys_init(GF_FALSE); #endif + gf_sys_set_args(argc, (const char **) argv); cfg_file = gf_cfg_init(the_cfg, NULL); if (!cfg_file) { @@ -1079,78 +1190,33 @@ int main (int argc, char **argv) logs_set = GF_TRUE; } + if (!gui_mode) { + str = gf_cfg_get_key(cfg_file, "General", "ForceGUI"); + if (str && !strcmp(str, "yes")) gui_mode = 1; + } + for (i=1; i<(u32) argc; i++) { char *arg = argv[i]; -// if (isalnum(arg[0]) || (arg[0]=='/') || (arg[0]=='.') || (arg[0]=='\\') ) { - if (arg[0] != '-') { - url_arg = arg; - } else if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) { - the_cfg = argv[i+1]; - i++; - } else if (!strcmp(arg, "-rti")) { + + if (!strcmp(arg, "-rti")) { rti_file = argv[i+1]; i++; } else if (!strcmp(arg, "-rtix")) { rti_file = argv[i+1]; i++; use_rtix = GF_TRUE; - } else if (!strcmp(arg, "-fill")) { - fill_ar = GF_TRUE; - } else if (!strcmp(arg, "-gui")) { - gui_mode = 1; - } else if (!strcmp(arg, "-guid")) { - gui_mode = 2; - } else if (!strcmp(arg, "-show")) { - visible = 1; - } else if (!strcmp(arg, "-avi")) { - if (rgbds_dump) dump_mode = 5; - else if (depth_dump) dump_mode = 8; - else if (rgbd_dump) dump_mode = 10; - else dump_mode=1; - 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*/ - rgbds_dump = 1; - dump_mode=6; /* rgbds texture directly*/ - if (dump_mode==1) dump_mode = 5; /* .avi rgbds dump*/ - } else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/ - rgbd_dump = 1; - dump_mode=9; /* rgbd texture directly*/ - if (dump_mode==1) dump_mode = 10; /* .avi rgbds dump*/ - } else if (!strcmp(arg, "-depth")) { - depth_dump = 1; - if (dump_mode==2) dump_mode=7; /* grayscale .bmp depth dump*/ - else if (dump_mode==1) dump_mode=8; /* .avi depth dump*/ - else if (dump_mode==11)dump_mode=12; - else dump_mode=4; /*depth dump*/ - } else if (!strcmp(arg, "-bmp")) { - if(depth_dump) dump_mode=7; /*grayscale depth .bmp dump*/ - else dump_mode=2; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!strcmp(arg, "-png")) { - dump_mode=11; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!strcmp(arg, "-raw")) { - dump_mode = 3; - if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++; - } else if (!stricmp(arg, "-size")) { /*usage of %ud breaks sscanf on MSVC*/ if (sscanf(argv[i+1], "%dx%d", &forced_width, &forced_height) != 2) { forced_width = forced_height = 0; } i++; - } else if (!stricmp(arg, "-scale")) { - sscanf(argv[i+1], "%f", &scale); - i++; - } else if (!stricmp(arg, "-fps")) { - fps = atof(argv[i+1]); - i++; } else if (!strcmp(arg, "-quiet")) { be_quiet = 1; } else if (!strcmp(arg, "-strict-error")) { gf_log_set_strict_error(1); } else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) { - logfile = gf_f64_open(argv[i+1], "wt"); + logfile = gf_fopen(argv[i+1], "wt"); gf_log_set_callback(logfile, on_gpac_log); i++; } else if (!strcmp(arg, "-logs") ) { @@ -1163,100 +1229,178 @@ int main (int argc, char **argv) log_time_start = 1; } else if (!strcmp(arg, "-log-utc") || !strcmp(arg, "-lu")) { log_utc_time = 1; - } else if (!strcmp(arg, "-align")) { - if (argv[i+1][0]=='m') align_mode = 1; - else if (argv[i+1][0]=='b') align_mode = 2; - align_mode <<= 8; - if (argv[i+1][1]=='m') align_mode |= 1; - else if (argv[i+1][1]=='r') align_mode |= 2; - 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; #if defined(__DARWIN__) || defined(__APPLE__) else if (!strcmp(arg, "-thread")) threading_flags = 0; #else else if (!strcmp(arg, "-no-thread")) threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_WINDOW_NO_THREAD; #endif + else if (!strcmp(arg, "-no-compositor-thread")) threading_flags |= GF_TERM_NO_COMPOSITOR_THREAD; else if (!strcmp(arg, "-no-audio")) no_audio = 1; else if (!strcmp(arg, "-no-regulation")) no_regulation = 1; else if (!strcmp(arg, "-fs")) start_fs = 1; - else if (!strcmp(arg, "-pause")) pause_at_first = 1; - else if (!strcmp(arg, "-play-from")) { - play_from = atof((const char *) argv[i+1]); - } - else if (!strcmp(arg, "-exit")) auto_exit = 1; - else if (!strcmp(arg, "-mem-track")) { -#ifdef GPAC_MEMORY_TRACKING - enable_mem_tracker = 1; -#else - fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"); -#endif - } - else if (!strcmp(arg, "-out")) { - out_arg = gf_strdup(argv[i+1]); - } - else if (!strcmp(arg, "-loop")) loop_at_end = 1; - else if (!strcmp(arg, "-bench")) bench_mode = 1; - else if (!strcmp(arg, "-vbench")) bench_mode = 2; - else if (!strcmp(arg, "-sbench")) bench_mode = 3; - else if (!strcmp(arg, "-no-addon")) enable_add_ons = GF_FALSE; else if (!strcmp(arg, "-opt")) { set_cfg_option(argv[i+1]); i++; + } else if (!strcmp(arg, "-conf")) { + set_cfg_option(argv[i+1]); + is_cfg_only=GF_TRUE; + i++; } else if (!strcmp(arg, "-ifce")) { gf_cfg_set_key(cfg_file, "Network", "DefaultMCastInterface", argv[i+1]); i++; } - 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++; - } - else if (!stricmp(arg, "-service")) { - initial_service_id = atoi(argv[i+1]); - i++; - } - else if (!stricmp(arg, "-help")) { - PrintUsage(); - return 1; - } else { - fprintf(stderr, "Unrecognized option %s - skipping\n", arg); + 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")) { + no_cfg_save=1; + } + + + /*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; + + 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*/ + dump_mode |= DUMP_RGB_DEPTH_SHAPE; + } else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/ + dump_mode |= DUMP_RGB_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, "-loop")) loop_at_end = 1; + else if (!strcmp(arg, "-bench")) bench_mode = 1; + else if (!strcmp(arg, "-vbench")) bench_mode = 2; + else if (!strcmp(arg, "-sbench")) bench_mode = 3; + else if (!strcmp(arg, "-no-addon")) enable_add_ons = GF_FALSE; + + else if (!strcmp(arg, "-pause")) pause_at_first = 1; + else if (!strcmp(arg, "-play-from")) { + play_from = atof((const char *) argv[i+1]); + } + else if (!strcmp(arg, "-speed")) { + playback_speed = FLT2FIX( atof((const char *) argv[i+1]) ); + if (playback_speed <= 0) playback_speed = FIX_ONE; + } + 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; + else if (!strcmp(arg, "-align")) { + if (argv[i+1][0]=='m') align_mode = 1; + else if (argv[i+1][0]=='b') align_mode = 2; + align_mode <<= 8; + if (argv[i+1][1]=='m') align_mode |= 1; + else if (argv[i+1][1]=='r') align_mode |= 2; + i++; + } else if (!strcmp(arg, "-fill")) { + fill_ar = GF_TRUE; + } else if (!strcmp(arg, "-show")) { + visible = 1; + } + 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++; + } + 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 (dump_mode && !url_arg ) { fprintf(stderr, "Missing argument for dump\n"); PrintUsage(); - if (logfile) fclose(logfile); + if (logfile) gf_fclose(logfile); return 1; } - if (!url_arg && simulation_time_in_ms) - simulation_time_in_ms += gf_sys_clock(); - - if (!gui_mode) { - str = gf_cfg_get_key(cfg_file, "General", "ForceGUI"); - if (str && !strcmp(str, "yes")) gui_mode = 1; + if (!gui_mode && !url_arg && (gf_cfg_get_key(cfg_file, "General", "StartupFile") != NULL)) { + gui_mode=1; } - if (gui_mode) { - if (gui_mode==1) { - hide_shell(1); - //user.init_flags |= GF_TERM_WINDOW_NO_DECORATION; +#ifdef WIN32 + if (gui_mode==1) { + const char *opt; + TCHAR buffer[1024]; + DWORD res = GetCurrentDirectory(1024, buffer); + buffer[res] = 0; + opt = gf_cfg_get_key(cfg_file, "General", "ModulesDirectory"); + if (strstr(opt, buffer)) { + gui_mode=1; + } else { + gui_mode=2; } } +#endif + + if (gui_mode==1) { + hide_shell(1); + } + + if (!url_arg && simulation_time_in_ms) + simulation_time_in_ms += gf_sys_clock(); +#if defined(__DARWIN__) || defined(__APPLE__) + carbon_init(); +#endif + if (dump_mode) rti_file = NULL; @@ -1275,8 +1419,10 @@ int main (int argc, char **argv) /*setup dumping options*/ if (dump_mode) { - user.init_flags |= GF_TERM_NO_AUDIO | GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_REGULATION /*| GF_TERM_INIT_HIDE*/; + 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; + gf_cfg_set_key(cfg_file, "Audio", "DriverName", "Raw Audio Output"); + no_cfg_save=GF_TRUE; } else { init_w = forced_width; init_h = forced_height; @@ -1289,7 +1435,7 @@ int main (int argc, char **argv) if (user.modules) gf_modules_del(user.modules); gf_cfg_del(cfg_file); gf_sys_close(); - if (logfile) fclose(logfile); + if (logfile) gf_fclose(logfile); return 1; } fprintf(stderr, "Modules Found : %d \n", i); @@ -1304,10 +1450,12 @@ int main (int argc, char **argv) if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = 1; + //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; if (bench_mode) { gf_cfg_discard_changes(user.config); - auto_exit = 1; + auto_exit = GF_TRUE; gf_cfg_set_key(user.config, "Audio", "DriverName", "Raw Audio Output"); if (bench_mode!=2) { gf_cfg_set_key(user.config, "Video", "DriverName", "Raw Video Output"); @@ -1328,7 +1476,7 @@ int main (int argc, char **argv) gf_cfg_discard_changes(cfg_file); gf_cfg_del(cfg_file); gf_sys_close(); - if (logfile) fclose(logfile); + if (logfile) gf_fclose(logfile); return 1; } fprintf(stderr, "Terminal Loaded in %d ms\n", gf_sys_clock()-i); @@ -1379,61 +1527,59 @@ int main (int argc, char **argv) } dump_file(url_arg, out_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times); Run = 0; - } else - - /*connect if requested*/ - if (views) { - } else if (!gui_mode && url_arg) { - char *ext; - - strcpy(the_url, url_arg); - ext = strrchr(the_url, '.'); - if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) { - GF_Err e = GF_OK; - fprintf(stderr, "Opening Playlist %s\n", the_url); - - strcpy(pl_path, the_url); - /*this is not clean, we need to have a plugin handle playlist for ourselves*/ - if (!strncmp("http:", the_url, 5)) { - GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e); - if (sess) { - e = gf_dm_sess_process(sess); - if (!e) strcpy(the_url, gf_dm_sess_get_cache_name(sess)); - gf_dm_sess_del(sess); - } + } + else if (views) { + } + /*connect if requested*/ + else if (!gui_mode && url_arg) { + char *ext; + + strcpy(the_url, url_arg); + ext = strrchr(the_url, '.'); + if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) { + GF_Err e = GF_OK; + fprintf(stderr, "Opening Playlist %s\n", the_url); + + strcpy(pl_path, the_url); + /*this is not clean, we need to have a plugin handle playlist for ourselves*/ + if (!strncmp("http:", the_url, 5)) { + GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e); + if (sess) { + e = gf_dm_sess_process(sess); + if (!e) strcpy(the_url, gf_dm_sess_get_cache_name(sess)); + gf_dm_sess_del(sess); } + } - playlist = e ? NULL : gf_f64_open(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); - } - } else { - if (e) - fprintf(stderr, "Failed to open playlist %s: %s\n", the_url, gf_error_to_string(e) ); - fprintf(stderr, "Hit 'h' for help\n\n"); + 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); } } else { - fprintf(stderr, "Opening URL %s\n", the_url); - if (pause_at_first) fprintf(stderr, "[Status: Paused]\n"); - gf_term_connect_from_time(term, the_url, (u64) (play_from*1000), pause_at_first); + if (e) + fprintf(stderr, "Failed to open playlist %s: %s\n", the_url, gf_error_to_string(e) ); + fprintf(stderr, "Hit 'h' for help\n\n"); } } else { - fprintf(stderr, "Hit 'h' for help\n\n"); - str = gf_cfg_get_key(cfg_file, "General", "StartupFile"); - if (str) { - strcpy(the_url, "MP4Client "GPAC_FULL_VERSION); - gf_term_connect(term, str); - startup_file = 1; - } - if (url_arg) { - gf_cfg_set_key(cfg_file, "Temp", "GUIStartupFile", url_arg); - } + fprintf(stderr, "Opening URL %s\n", the_url); + if (pause_at_first) fprintf(stderr, "[Status: Paused]\n"); + gf_term_connect_from_time(term, the_url, (u64) (play_from*1000), pause_at_first); + } + } else { + fprintf(stderr, "Hit 'h' for help\n\n"); + str = gf_cfg_get_key(cfg_file, "General", "StartupFile"); + if (str) { + strcpy(the_url, "MP4Client "GPAC_FULL_VERSION); + gf_term_connect(term, str); + startup_file = 1; + is_connected = 1; } + } if (gui_mode==2) gui_mode=0; if (start_fs) gf_term_set_option(term, GF_OPT_FULLSCREEN, 1); @@ -1450,8 +1596,9 @@ int main (int argc, char **argv) while (Run) { + /*we don't want getchar to block*/ - if (gui_mode || !gf_prompt_has_input()) { + if ((gui_mode==1) || !gf_prompt_has_input()) { if (reload) { reload = 0; gf_term_disconnect(term); @@ -1486,14 +1633,14 @@ int main (int argc, char **argv) gf_sleep(rti_update_time_ms); } if (auto_exit && eos_seen && gf_term_get_option(term, GF_OPT_IS_OVER)) { - Run = 0; + Run = GF_FALSE; } /*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)) ) { - Run = 0; + Run = GF_FALSE; } continue; } @@ -1502,7 +1649,13 @@ int main (int argc, char **argv) force_input: switch (c) { case 'q': - Run = 0; + { + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_QUIT; + gf_term_send_event(term, &evt); + } +// Run = 0; break; case 'X': exit(0); @@ -1527,11 +1680,11 @@ force_input: fprintf(stderr, "Cannot read the absolute URL, aborting.\n"); break; } - playlist = gf_f64_open(the_url, "rt"); + playlist = gf_fopen(the_url, "rt"); if (playlist) { if (1 > fscanf(playlist, "%s", the_url)) { fprintf(stderr, "Cannot read any URL from playlist, aborting.\n"); - fclose( playlist); + gf_fclose( playlist); break; } fprintf(stderr, "Opening URL %s\n", the_url); @@ -1668,11 +1821,15 @@ force_input: case 'i': if (is_connected) { u32 ID; - do { - fprintf(stderr, "Enter OD ID (0 for main OD): "); - fflush(stderr); - } while( 1 > scanf("%ud", &ID)); - ViewOD(term, ID, (u32)-1); + fprintf(stderr, "Enter OD ID (0 for main OD): "); + fflush(stderr); + if (scanf("%ud", &ID) == 1) { + ViewOD(term, ID, (u32)-1, NULL); + } else { + char str_url[GF_MAX_PATH]; + if (scanf("%s", str_url) == 1) + ViewOD(term, 0, (u32)-1, str_url); + } } break; case 'j': @@ -1682,7 +1839,7 @@ force_input: fprintf(stderr, "Enter OD number (0 for main OD): "); fflush(stderr); } while( 1 > scanf("%ud", &num)); - ViewOD(term, (u32)-1, num); + ViewOD(term, (u32)-1, num, NULL); } break; case 'b': @@ -1834,7 +1991,7 @@ force_input: e = gf_term_scene_update(term, NULL, szCom); if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e)); } - break; + break; case 'e': { GF_Err e; @@ -1849,7 +2006,7 @@ force_input: e = gf_term_scene_update(term, "application/ecmascript", jsCode); if (e) fprintf(stderr, "Processing JS code failed: %s\n", gf_error_to_string(e)); } - break; + break; case 'L': { @@ -1863,7 +2020,7 @@ force_input: } gf_log_modify_tools_levels(szLog); } - break; + break; case 'g': { @@ -1871,7 +2028,7 @@ force_input: gf_sys_get_rti(rti_update_time_ms, &rti, 0); fprintf(stderr, "GPAC allocated memory "LLD"\n", rti.gpac_memory); } - break; + break; case 'M': { u32 size; @@ -1880,7 +2037,7 @@ force_input: } while (1 > scanf("%ud", &size)); gf_term_set_option(term, GF_OPT_VIDEO_CACHE_SIZE, size); } - break; + break; case 'H': { @@ -1891,7 +2048,7 @@ force_input: gf_term_set_option(term, GF_OPT_HTTP_MAX_RATE, http_bitrate); } - break; + break; case 'E': gf_term_set_option(term, GF_OPT_RELOAD_CONFIG, 1); @@ -1913,7 +2070,7 @@ force_input: } set_cfg_option(szOpt); } - break; + break; /*extract to PNG*/ case 'Z': @@ -1944,7 +2101,7 @@ force_input: sprintf(szFileName, "view%d_dump.png", offscreen_view); e = gf_term_get_offscreen_buffer(term, &fb, offscreen_view-1, 0); } else { - sprintf(szFileName, "video_dump.png"); + sprintf(szFileName, "gpac_video_dump_"LLU".png", gf_net_get_utc() ); e = gf_term_get_screen_buffer(term, &fb); } offscreen_view++; @@ -1961,13 +2118,13 @@ force_input: fprintf(stderr, "Error encoding PNG %s\n", gf_error_to_string(e) ); nb_pass = 0; } else { - FILE *png = gf_f64_open(szFileName, "wb"); + FILE *png = gf_fopen(szFileName, "wb"); if (!png) { fprintf(stderr, "Error writing file %s\n", szFileName); nb_pass = 0; } else { gf_fwrite(dst, dst_size, 1, png); - fclose(png); + gf_fclose(png); fprintf(stderr, "Dump to %s\n", szFileName); } } @@ -1996,7 +2153,7 @@ force_input: odm = NULL; root_od = gf_term_get_root_object(term); if (root_od) { - odm = gf_term_get_object(term, root_od, index); + odm = gf_term_get_object(term, root_od, index); if (odm) { gf_term_select_object(term, odm); } else { @@ -2005,7 +2162,7 @@ force_input: } } } - break; + break; case 'h': PrintHelp(); @@ -2019,26 +2176,50 @@ force_input: PrintAVInfo(GF_TRUE); } + /*FIXME: we have an issue in cleaning up after playing in bench mode and run-for 0 (buildbot tests). We for now disable error checks after run-for is done*/ + if (simulation_time_in_ms) { + gf_log_set_strict_error(0); + } + + i = gf_sys_clock(); gf_term_disconnect(term); if (rti_file) UpdateRTInfo("Disconnected\n"); fprintf(stderr, "Deleting terminal... "); - if (playlist) fclose(playlist); + if (playlist) gf_fclose(playlist); + +#if defined(__DARWIN__) || defined(__APPLE__) + carbon_uninit(); +#endif + gf_term_del(term); - fprintf(stderr, "done (in %d ms)\n", gf_sys_clock() - i); + fprintf(stderr, "done (in %d ms) - ran for %d ms\n", gf_sys_clock() - i, gf_sys_clock()); fprintf(stderr, "GPAC cleanup ...\n"); gf_modules_del(user.modules); + + if (no_cfg_save) + gf_cfg_discard_changes(cfg_file); + gf_cfg_del(cfg_file); gf_sys_close(); - if (rti_logs) fclose(rti_logs); - if (logfile) fclose(logfile); + + if (rti_logs) gf_fclose(rti_logs); + if (logfile) gf_fclose(logfile); if (gui_mode) { hide_shell(2); } + +#ifdef GPAC_MEMORY_TRACKING + if (enable_mem_tracker && (gf_memory_size() || gf_file_handles_count() )) { + gf_memory_print(); + return 2; + } +#endif + return 0; } @@ -2132,9 +2313,9 @@ void PrintAVInfo(Bool final) u32 dec_run_time = v_odi.last_frame_time - v_odi.first_frame_time; if (!dec_run_time) dec_run_time = 1; if (v_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*v_odi.current_time / v_odi.duration ) ); - fprintf(stderr, "%d frames FPS %.2f (max "LLU" us/f) rate avg %d max %d", v_odi.nb_dec_frames, ((Float)v_odi.nb_dec_frames*1000) / dec_run_time, v_odi.max_dec_time, (u32) v_odi.avg_bitrate/1000, (u32) v_odi.max_bitrate/1000); - if (v_odi.nb_droped) { - fprintf(stderr, " (Error during bench: %d frames drop)", v_odi.nb_droped); + fprintf(stderr, "%d frames FPS %.2f (max %d us/f) rate avg %d max %d", v_odi.nb_dec_frames, ((Float)v_odi.nb_dec_frames*1000) / dec_run_time, v_odi.max_dec_time, (u32) v_odi.avg_bitrate/1000, (u32) v_odi.max_bitrate/1000); + if (v_odi.nb_dropped) { + fprintf(stderr, " (Error during bench: %d frames drop)", v_odi.nb_dropped); } fprintf(stderr, "\n"); } @@ -2146,8 +2327,8 @@ void PrintAVInfo(Bool final) if (!dec_run_time) dec_run_time = 1; if (a_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*a_odi.current_time / a_odi.duration ) ); fprintf(stderr, "%d frames (ms/f %.2f avg %.2f max) rate avg %d max %d", a_odi.nb_dec_frames, ((Float)dec_run_time)/a_odi.nb_dec_frames, a_odi.max_dec_time/1000.0, (u32) a_odi.avg_bitrate/1000, (u32) a_odi.max_bitrate/1000); - if (a_odi.nb_droped) { - fprintf(stderr, " (Error during bench: %d frames drop)", a_odi.nb_droped); + if (a_odi.nb_dropped) { + fprintf(stderr, " (Error during bench: %d frames drop)", a_odi.nb_dropped); } fprintf(stderr, "\n"); } @@ -2160,7 +2341,7 @@ void PrintAVInfo(Bool 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; if (!dec_run_time) dec_run_time = 1; - fprintf(stderr, "%d frames FPS %.2f (max "LLD" us/f) rate avg %d max %d", s_odi.nb_dec_frames, ((Float)s_odi.nb_dec_frames*1000) / dec_run_time, s_odi.max_dec_time, (u32) s_odi.avg_bitrate/1000, (u32) s_odi.max_bitrate/1000); + fprintf(stderr, "%d frames FPS %.2f (max %d us/f) rate avg %d max %d", s_odi.nb_dec_frames, ((Float)s_odi.nb_dec_frames*1000) / dec_run_time, s_odi.max_dec_time, (u32) s_odi.avg_bitrate/1000, (u32) s_odi.max_bitrate/1000); fprintf(stderr, "\n"); } else { u32 nb_frames_drawn; @@ -2190,7 +2371,7 @@ void PrintAVInfo(Bool final) avg_dec_time = (Float) 1000000 * s_odi.nb_dec_frames; avg_dec_time /= s_odi.total_dec_time; if (s_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*s_odi.current_time / s_odi.duration ) ); - fprintf(stderr, "%d f %.2f ("LLU" us max) - rate %d ", s_odi.nb_dec_frames, avg_dec_time, s_odi.max_dec_time, (u32) s_odi.instant_bitrate/1000); + 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); @@ -2301,7 +2482,7 @@ void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 ind } } -void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) +void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number, const char *szURL) { GF_MediaInfo odi; u32 i, j, count, d_enum,id; @@ -2311,8 +2492,7 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) if (!root_odm) return; odm = NULL; - if ((!OD_ID && (number == (u32)(-1))) || - ((OD_ID == (u32)(-1)) && !number)) { + if (!szURL && ((!OD_ID && (number == (u32)-1)) || ((OD_ID == (u32)(-1)) && !number))) { odm = root_odm; if ((gf_term_get_object_info(term, odm, &odi) != GF_OK)) odm=NULL; } else { @@ -2321,6 +2501,7 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) odm = gf_term_get_object(term, root_odm, i); if (!odm) break; if (gf_term_get_object_info(term, odm, &odi) == GF_OK) { + if (szURL && strstr(odi.service_url, szURL)) break; if ((number == (u32)(-1)) && (odi.od->objectDescriptorID == OD_ID)) break; else if (i == (u32)(number-1)) break; } @@ -2328,6 +2509,7 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) } } if (!odm) { + if (szURL) fprintf(stderr, "cannot find OD for URL %s\n", szURL); if (number == (u32)-1) fprintf(stderr, "cannot find OD with ID %d\n", OD_ID); else fprintf(stderr, "cannot find OD with number %d\n", number); return; @@ -2360,10 +2542,9 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) } fprintf(stderr, "\n"); - if (odi.owns_service) { - fprintf(stderr, "Service Handler: %s\n", odi.service_handler); - fprintf(stderr, "Service URL: %s\n", odi.service_url); - } + fprintf(stderr, "Service Handler: %s\n", odi.service_handler); + fprintf(stderr, "Service URL: %s\n", odi.service_url); + if (odi.codec_name) { Float avg_dec_time; switch (odi.od_type) { @@ -2400,7 +2581,7 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) avg_dec_time = (Float) odi.total_dec_time; avg_dec_time /= odi.nb_dec_frames; } - fprintf(stderr, "\tBitrate over last second: %d kbps\n\tMax bitrate over one second: %d kbps\n\tAverage Decoding Time %.2f ms ("LLU" max)\n\tTotal decoded frames %d\n", + fprintf(stderr, "\tBitrate over last second: %d kbps\n\tMax bitrate over one second: %d kbps\n\tAverage Decoding Time %.2f us %d max)\n\tTotal decoded frames %d\n", (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time, odi.nb_dec_frames); } if (odi.protection) fprintf(stderr, "Encrypted Media%s\n", (odi.protection==2) ? " NOT UNLOCKED" : ""); @@ -2462,25 +2643,17 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) /*check language*/ if (esd->langDesc) { - u32 i=0; - char lan[4], *szLang; + s32 lang_idx; + char lan[4]; lan[0] = esd->langDesc->langCode>>16; lan[1] = (esd->langDesc->langCode>>8)&0xFF; lan[2] = (esd->langDesc->langCode)&0xFF; lan[3] = 0; - if ((lan[0]=='u') && (lan[1]=='n') && (lan[2]=='d')) szLang = "Undetermined"; - else { - szLang = lan; - while (GF_ISO639_Lang[i]) { - if (GF_ISO639_Lang[i+2][0] && strstr(GF_ISO639_Lang[i+1], lan)) { - szLang = (char*) GF_ISO639_Lang[i]; - break; - } - i+=3; - } + lang_idx = gf_lang_find(lan); + if (lang_idx>=0) { + fprintf(stderr, "\tStream Language: %s\n", gf_lang_get_name(lang_idx)); } - fprintf(stderr, "\tStream Language: %s\n", szLang); } } fprintf(stderr, "\n"); @@ -2588,9 +2761,11 @@ void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number) } } -void PrintODTiming(GF_Terminal *term, GF_ObjectManager *odm) +void PrintODTiming(GF_Terminal *term, GF_ObjectManager *odm, u32 indent) { GF_MediaInfo odi; + u32 ind = indent; + u32 i, count; if (!odm) return; if (gf_term_get_object_info(term, odm, &odi) != GF_OK) return; @@ -2598,31 +2773,50 @@ void PrintODTiming(GF_Terminal *term, GF_ObjectManager *odm) fprintf(stderr, "Service not attached\n"); return; } + while (ind) { + fprintf(stderr, " "); + ind--; + } - fprintf(stderr, "OD %d: ", odi.od->objectDescriptorID); - switch (odi.status) { - case 1: - fprintf(stderr, "Playing - "); - break; - case 2: - fprintf(stderr, "Paused - "); - break; - default: - fprintf(stderr, "Stopped - "); - break; + if (! odi.generated_scene) { + + fprintf(stderr, "- OD %d: ", odi.od->objectDescriptorID); + switch (odi.status) { + case 1: + fprintf(stderr, "Playing - "); + break; + case 2: + fprintf(stderr, "Paused - "); + break; + default: + fprintf(stderr, "Stopped - "); + break; + } + if (odi.buffer>=0) fprintf(stderr, "Buffer: %d ms - ", odi.buffer); + else fprintf(stderr, "Not buffering - "); + fprintf(stderr, "Clock drift: %d ms", odi.clock_drift); + fprintf(stderr, " - time: "); + PrintTime((u32) (odi.current_time*1000)); + fprintf(stderr, "\n"); + + } else { + fprintf(stderr, "+ Service %s:\n", odi.service_url); } - if (odi.buffer>=0) fprintf(stderr, "Buffer: %d ms - ", odi.buffer); - else fprintf(stderr, "Not buffering - "); - fprintf(stderr, "Clock drift: %d ms", odi.clock_drift); - fprintf(stderr, " - time: "); - PrintTime((u32) (odi.current_time*1000)); - fprintf(stderr, "\n"); + + count = gf_term_get_object_count(term, odm); + for (i=0; iobjectDescriptorID); - switch (odi.status) { - case 1: - fprintf(stderr, "Playing"); - break; - case 2: - fprintf(stderr, "Paused"); - break; - default: - fprintf(stderr, "Stopped"); - break; + ind = indent; + while (ind) { + fprintf(stderr, " "); + ind--; } - if (odi.buffer>=0) fprintf(stderr, " - Buffer: %d ms", odi.buffer); - if (odi.db_unit_count) fprintf(stderr, " - DB: %d AU", odi.db_unit_count); - if (odi.cb_max_count) fprintf(stderr, " - CB: %d/%d CUs", odi.cb_unit_count, odi.cb_max_count); - fprintf(stderr, "\n * %d decoded frames - %d dropped frames\n", odi.nb_dec_frames, odi.nb_droped); - avg_dec_time = 0; - if (odi.nb_dec_frames) { - avg_dec_time = (Float) odi.total_dec_time; - avg_dec_time /= odi.nb_dec_frames; + if (odi.generated_scene) { + fprintf(stderr, "+ Service %s:\n", odi.service_url); + } else { + fprintf(stderr, "- OD %d: ", odi.od->objectDescriptorID); + switch (odi.status) { + case 1: + fprintf(stderr, "Playing"); + break; + case 2: + fprintf(stderr, "Paused"); + break; + default: + fprintf(stderr, "Stopped"); + break; + } + if (odi.buffer>=0) fprintf(stderr, " - Buffer: %d ms", odi.buffer); + if (odi.db_unit_count) fprintf(stderr, " - DB: %d AU", odi.db_unit_count); + if (odi.cb_max_count) fprintf(stderr, " - CB: %d/%d CUs", odi.cb_unit_count, odi.cb_max_count); + + fprintf(stderr, "\n"); + ind = indent; + while (ind) { + fprintf(stderr, " "); + ind--; + } + + fprintf(stderr, " %d decoded frames - %d dropped frames\n", odi.nb_dec_frames, odi.nb_dropped); + + ind = indent; + while (ind) { + fprintf(stderr, " "); + ind--; + } + + avg_dec_time = 0; + if (odi.nb_dec_frames) { + avg_dec_time = (Float) odi.total_dec_time; + avg_dec_time /= odi.nb_dec_frames; + } + fprintf(stderr, " Avg Bitrate %d kbps (%d max) - Avg Decoding Time %.2f us (%d max)\n", + (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time); + } + + count = gf_term_get_object_count(term, odm); + for (i=0; i - - - - Debug - Win32 - - - Release - Win32 - - - - - GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {978A2D9F-E44F-4073-8032-333563BCC160} - bmp4demux - - - - Application - v110 - false - MultiByte - - - Application - v110 - false - MultiByte - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.60610.1 - - - ../../../bin/$(Platform)\$(Configuration)/ - obj\$(Platform)\$(Configuration)\$(ProjectName)\ - true - AllRules.ruleset - - - - - ../../../bin/$(Platform)\$(Configuration)/ - obj\$(Platform)\$(Configuration)\$(ProjectName)\ - false - AllRules.ruleset - - - - - - .\Debug/bmp4demux.tlb - - - - Disabled - ../../../include;%(AdditionalIncludeDirectories) - GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_CORE_TOOLS;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - $(IntDir) - $(IntDir) - $(IntDir) - true - Level3 - true - EditAndContinue - - - - - _DEBUG;%(PreprocessorDefinitions) - 0x040c - - - %(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - true - $(IntDir)$(ProjectName).pdb - Console - MachineX86 - - - true - .\Debug/bmp4demux.bsc - - - - - .\Release/bmp4demux.tlb - - - - MaxSpeed - OnlyExplicitInline - ../../../include;%(AdditionalIncludeDirectories) - GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_CORE_TOOLS;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\Release/bmp4demux.pch - .\Release/ - .\Release/ - .\Release/ - Level3 - true - - - NDEBUG;%(PreprocessorDefinitions) - 0x040c - - - %(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) - .\Release/bmp4demux.pdb - Console - MachineX86 - - - true - .\Release/bmp4demux.bsc - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + + GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {978A2D9F-E44F-4073-8032-333563BCC160} + bmp4demux + + + + Application + v110 + false + MultiByte + + + Application + v100 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + AllRules.ruleset + + + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + + + + .\Debug/bmp4demux.tlb + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + true + Level3 + true + EditAndContinue + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + MachineX86 + + + true + .\Debug/bmp4demux.bsc + + + + + .\Release/bmp4demux.tlb + + + + MaxSpeed + OnlyExplicitInline + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/bmp4demux.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) + .\Release/bmp4demux.pdb + Console + MachineX86 + + + true + .\Release/bmp4demux.bsc + + + + + \ No newline at end of file diff --git a/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters b/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters index 3f80c02..4a097c1 100644 --- a/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters +++ b/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters @@ -1,134 +1,137 @@ - - - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - - others - - - others - - - others - - - others - - - others - - - others - - - isoff - - - - - {c9a8f639-328c-4505-be50-4859357c2c00} - - - {e5ca7285-ca00-49d8-ac81-dff3d494be9a} - - + + + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + + others + + + others + + + others + + + others + + + others + + + others + + + isoff + + + others + + + + + {c9a8f639-328c-4505-be50-4859357c2c00} + + + {e5ca7285-ca00-49d8-ac81-dff3d494be9a} + + \ No newline at end of file diff --git a/applications/testapps/bmp4demux/build.sh b/applications/testapps/bmp4demux/build.sh index 36dab12..d1dd330 100644 --- a/applications/testapps/bmp4demux/build.sh +++ b/applications/testapps/bmp4demux/build.sh @@ -1,2 +1,2 @@ #!/bin/sh -gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB +gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_file.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB diff --git a/applications/testapps/broadcaster/broadcaster.c b/applications/testapps/broadcaster/broadcaster.c index 58485dc..85398a4 100644 --- a/applications/testapps/broadcaster/broadcaster.c +++ b/applications/testapps/broadcaster/broadcaster.c @@ -208,13 +208,13 @@ u32 tcp_server(void *par) if((*(input->config_flag)) == 0) { u32 num_retry; - fp = fopen("temp.cfg", "w+"); + fp = gf_fopen("temp.cfg", "w+"); if (!fp) { fprintf(stderr, "Error opening temp file for the configuration\n"); exit(1); } ret = gf_fwrite(buffer, 1, byte_read, fp); - fclose(fp); + gf_fclose(fp); /* parsing config info */ gf_config_file = gf_cfg_new(".", "temp.cfg"); @@ -228,7 +228,7 @@ u32 tcp_server(void *par) gf_sk_send(conn_socket, "OK\n", 3); memset(temp, 0, sizeof(temp)); - fp = fopen(input->config->scene_init_file, "w+"); + fp = gf_fopen(input->config->scene_init_file, "w+"); if (!fp) { fprintf(stderr, "Error opening temp file for reception of the initial scene\n"); exit(1); @@ -251,7 +251,7 @@ u32 tcp_server(void *par) break; } } - fclose(fp); + gf_fclose(fp); *(input->config_flag) = 1; } /* we only wait now for the config updates */ diff --git a/applications/testapps/broadcaster/broadcaster.dsp b/applications/testapps/broadcaster/broadcaster.dsp index 2edf9c5..b4303ba 100644 --- a/applications/testapps/broadcaster/broadcaster.dsp +++ b/applications/testapps/broadcaster/broadcaster.dsp @@ -1,146 +1,146 @@ -# Microsoft Developer Studio Project File - Name="broadcaster" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=broadcaster - 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 "broadcaster.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 "broadcaster.mak" CFG="broadcaster - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "broadcaster - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "broadcaster - 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)" == "broadcaster - 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)" == "broadcaster - 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 zlib.lib winmm.lib ws2_32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/broadcaster.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" - -!ENDIF - -# Begin Target - -# Name "broadcaster - Win32 Release" -# Name "broadcaster - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\broadcaster.c -# End Source File -# Begin Source File - -SOURCE=.\debug.c -# End Source File -# Begin Source File - -SOURCE=.\RTP_serv_generator.c -# End Source File -# Begin Source File - -SOURCE=.\RTP_serv_packetizer.c -# End Source File -# Begin Source File - -SOURCE=.\RTP_serv_sender.c -# End Source File -# Begin Source File - -SOURCE=.\sdp_generator.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\broadcaster.h -# End Source File -# Begin Source File - -SOURCE=.\debug.h -# End Source File -# Begin Source File - -SOURCE=.\RTP_serv_generator.h -# End Source File -# Begin Source File - -SOURCE=.\RTP_serv_packetizer.h -# End Source File -# Begin Source File - -SOURCE=.\RTP_serv_sender.h -# End Source File -# Begin Source File - -SOURCE=.\sdp_generator.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="broadcaster" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=broadcaster - 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 "broadcaster.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 "broadcaster.mak" CFG="broadcaster - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "broadcaster - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "broadcaster - 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)" == "broadcaster - 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)" == "broadcaster - 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 zlib.lib winmm.lib ws2_32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/broadcaster.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "broadcaster - Win32 Release" +# Name "broadcaster - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\broadcaster.c +# End Source File +# Begin Source File + +SOURCE=.\debug.c +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_generator.c +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_packetizer.c +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_sender.c +# End Source File +# Begin Source File + +SOURCE=.\sdp_generator.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\broadcaster.h +# End Source File +# Begin Source File + +SOURCE=.\debug.h +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_generator.h +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_packetizer.h +# End Source File +# Begin Source File + +SOURCE=.\RTP_serv_sender.h +# End Source File +# Begin Source File + +SOURCE=.\sdp_generator.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/broadcaster/sdp_generator.c b/applications/testapps/broadcaster/sdp_generator.c index 63b00df..2547037 100644 --- a/applications/testapps/broadcaster/sdp_generator.c +++ b/applications/testapps/broadcaster/sdp_generator.c @@ -16,7 +16,7 @@ int sdp_generator(PNC_CallbackData *data, char *ip_dest, char *sdp_fmt) gf_sk_get_local_info(data->chan->rtp, &port, &socket_type); - fp = fopen("broadcaster.sdp", "w+"); + fp = gf_fopen("broadcaster.sdp", "w+"); if(fp == NULL) { fprintf(stderr, "Cannot open SDP file broadcaster.sdp\n"); exit(1); @@ -61,7 +61,7 @@ int sdp_generator(PNC_CallbackData *data, char *ip_dest, char *sdp_fmt) sprintf(temp, "%s\n", sdp_fmt); ret = gf_fwrite(temp, 1, strlen(temp), fp); fflush(fp); - fclose(fp); + gf_fclose(fp); dprintf(DEBUG_sdp_generator, "SDP file generated in broadcaster.sdp\n"); return GF_OK; } diff --git a/applications/testapps/dmbrs/dmbrs.dsp b/applications/testapps/dmbrs/dmbrs.dsp index a94c742..8ae463f 100644 --- a/applications/testapps/dmbrs/dmbrs.dsp +++ b/applications/testapps/dmbrs/dmbrs.dsp @@ -1,90 +1,90 @@ -# Microsoft Developer Studio Project File - Name="dmbrs" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=dmbrs - Win32 Release -!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 "dmbrs.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 "dmbrs.mak" CFG="dmbrs - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "dmbrs - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "dmbrs - 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)" == "dmbrs - 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 zlib.lib winmm.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/dmbrs.exe" /libpath:"../../../extra_lib/lib/w32_rel" - -!ELSEIF "$(CFG)" == "dmbrs - 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" /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 zlib.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/dmbrs.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" - -!ENDIF - -# Begin Target - -# Name "dmbrs - Win32 Release" -# Name "dmbrs - Win32 Debug" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="dmbrs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=dmbrs - Win32 Release +!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 "dmbrs.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 "dmbrs.mak" CFG="dmbrs - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dmbrs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "dmbrs - 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)" == "dmbrs - 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 zlib.lib winmm.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/dmbrs.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "dmbrs - 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" /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 zlib.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/dmbrs.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "dmbrs - Win32 Release" +# Name "dmbrs - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/applications/testapps/dmbrs/main.c b/applications/testapps/dmbrs/main.c index 6cecfef..a9b64a7 100644 --- a/applications/testapps/dmbrs/main.c +++ b/applications/testapps/dmbrs/main.c @@ -26,15 +26,15 @@ void save_ts(char *filename, unsigned char *data) { - FILE *ts_out = fopen(filename,"a+b"); + FILE *ts_out = gf_fopen(filename,"a+b"); gf_fwrite(data, 1, 188, ts_out); - fclose(ts_out); + gf_fclose(ts_out); } void save_rs_0(char *filename, unsigned char *data) { - FILE *rs_out = fopen(filename,"a+b"); + FILE *rs_out = gf_fopen(filename,"a+b"); gf_fwrite(data, 1, 204, rs_out); - fclose(rs_out); + gf_fclose(rs_out); } void RS_Interleaver(GF_BitStream *bs, char *out_name) @@ -209,7 +209,7 @@ void main(int argc, char **argv) /* generation d'un TS aléatoire */ /* - if ((in=fopen(argv[1], "wb")) == NULL) { + if ((in=gf_fopen(argv[1], "wb")) == NULL) { printf( "Impossible d'ouvrir %s en lecture.\n", argv[1]); } { @@ -223,8 +223,8 @@ void main(int argc, char **argv) gf_fwrite(buffer, 1, 188, in); } } - fclose(in); - if ((in=fopen(argv[1], "rb")) == NULL) { + gf_fclose(in); + if ((in=gf_fopen(argv[1], "rb")) == NULL) { printf( "Impossible d'ouvrir %s en lecture.\n", argv[1]); } @@ -232,12 +232,12 @@ void main(int argc, char **argv) if (bs == NULL) return; RS_Interleaver(bs, argv[2]); - fclose(in); + gf_fclose(in); gf_bs_del(bs); */ - if ((in=fopen(argv[1], "rb")) == NULL) { + if ((in=gf_fopen(argv[1], "rb")) == NULL) { printf( "Impossible d'ouvrir %s en lecture.\n", argv[1]); } @@ -245,7 +245,7 @@ void main(int argc, char **argv) if (bs == NULL) return; RS_Deinterleaver(bs, argv[2]); - fclose(in); + gf_fclose(in); gf_bs_del(bs); } \ No newline at end of file diff --git a/applications/testapps/fmp4demux/build.sh b/applications/testapps/fmp4demux/build.sh index 36dab12..d1dd330 100755 --- a/applications/testapps/fmp4demux/build.sh +++ b/applications/testapps/fmp4demux/build.sh @@ -1,2 +1,2 @@ #!/bin/sh -gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB +gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_file.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB diff --git a/applications/testapps/fmp4demux/fmp4demux.sln b/applications/testapps/fmp4demux/fmp4demux.sln index 26bfd3d..d239628 100644 --- a/applications/testapps/fmp4demux/fmp4demux.sln +++ b/applications/testapps/fmp4demux/fmp4demux.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmp4demux", "fmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 - {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 - {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 - {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmp4demux", "fmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/applications/testapps/fmp4demux/fmp4demux.vcxproj b/applications/testapps/fmp4demux/fmp4demux.vcxproj index 371d252..d007fd2 100644 --- a/applications/testapps/fmp4demux/fmp4demux.vcxproj +++ b/applications/testapps/fmp4demux/fmp4demux.vcxproj @@ -1,189 +1,190 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {978A2D9F-E44F-4073-8032-333563BCC160} - fmp4demux - - - - Application - v110 - false - MultiByte - - - Application - v110 - false - MultiByte - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.60610.1 - - - ../../../bin/$(Platform)\$(Configuration)/ - obj\$(Platform)\$(Configuration)\$(ProjectName)\ - true - AllRules.ruleset - - - - - ../../../bin/$(Platform)\$(Configuration)/ - obj\$(Platform)\$(Configuration)\$(ProjectName)\ - false - AllRules.ruleset - - - - - - .\Debug/fmp4demux.tlb - - - - Disabled - ../../../include;%(AdditionalIncludeDirectories) - GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - $(IntDir) - $(IntDir) - $(IntDir) - true - Level3 - true - EditAndContinue - - - _DEBUG;%(PreprocessorDefinitions) - 0x040c - - - %(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - true - $(IntDir)$(ProjectName).pdb - Console - MachineX86 - - - true - .\Debug/fmp4demux.bsc - - - - - .\Release/fmp4demux.tlb - - - - MaxSpeed - OnlyExplicitInline - ../../../include;%(AdditionalIncludeDirectories) - GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\Release/fmp4demux.pch - .\Release/ - .\Release/ - .\Release/ - Level3 - true - - - NDEBUG;%(PreprocessorDefinitions) - 0x040c - - - %(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) - .\Release/fmp4demux.pdb - Console - MachineX86 - - - true - .\Release/fmp4demux.bsc - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + + GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {BEBEB264-EEA8-4FCF-9467-2E7988DD923B} + fmp4demux + + + + Application + v110 + false + MultiByte + + + Application + v100 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + AllRules.ruleset + + + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + + + + .\Debug/fmp4demux.tlb + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + MachineX86 + + + true + .\Debug/fmp4demux.bsc + + + + + .\Release/fmp4demux.tlb + + + + MaxSpeed + OnlyExplicitInline + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/fmp4demux.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) + .\Release/fmp4demux.pdb + Console + MachineX86 + + + true + .\Release/fmp4demux.bsc + + + + + \ No newline at end of file diff --git a/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters b/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters index b819529..5ea66a7 100644 --- a/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters +++ b/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters @@ -1,137 +1,140 @@ - - - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - isoff - - - - - {c9a8f639-328c-4505-be50-4859357c2c00} - - - {e5ca7285-ca00-49d8-ac81-dff3d494be9a} - - + + + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + isoff + + + others + + + + + {c9a8f639-328c-4505-be50-4859357c2c00} + + + {e5ca7285-ca00-49d8-ac81-dff3d494be9a} + + \ No newline at end of file diff --git a/applications/testapps/fmp4demux/main.c b/applications/testapps/fmp4demux/main.c index 482684a..8c6c22a 100644 --- a/applications/testapps/fmp4demux/main.c +++ b/applications/testapps/fmp4demux/main.c @@ -208,16 +208,16 @@ int main(int argc, char **argv) #endif /* This is an input file to read data from. Could be replaced by any other method to retrieve the data (e.g. JavaScript, socket, ...)*/ - input = gf_f64_open(argv[1], "rb"); + input = gf_fopen(argv[1], "rb"); if (!input) { fprintf(stdout, "Could not open file %s for reading.\n", argv[1]); gf_sys_close(); return 1; } - gf_f64_seek(input, 0, SEEK_END); - file_size = gf_f64_tell(input); - gf_f64_seek(input, 0, SEEK_SET); + gf_fseek(input, 0, SEEK_END); + file_size = gf_ftell(input); + gf_fseek(input, 0, SEEK_SET); /* Initializing the progressive reader */ memset(&reader, 0, sizeof(ISOProgressiveReader)); @@ -308,7 +308,7 @@ exit: gf_mx_del(reader.mutex); gf_free(reader.data); gf_isom_close(reader.movie); - fclose(input); + gf_fclose(input); gf_sys_close(); return ret; diff --git a/applications/testapps/hevcbench/defbench.h b/applications/testapps/hevcbench/defbench.h index cc54aab..2b233d6 100644 --- a/applications/testapps/hevcbench/defbench.h +++ b/applications/testapps/hevcbench/defbench.h @@ -1,111 +1,111 @@ -/* - * GPAC - Multimedia Framework C SDK - * - * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2012 - * All rights reserved - * - * This file is part of GPAC - sample DASH library usage - * - */ - -#ifndef __DEF_BENCH_H__ -#define __DEF_BENCH_H__ - -#include -#include -#include -#define SDL_MAIN_HANDLED -#include -#include - -#define GL_GLEXT_PROTOTYPES - -#include -#include - - - - -#define GL_CHECK_ERR {s32 res = glGetError(); if (res) GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("GL Error %d file %s line %d\n", res, __FILE__, __LINE__)); } - -/*macros for GL proto and fun declaration*/ -#ifdef _WIN32_WCE -#define GLAPICAST * -#elif defined(WIN32) -#include -#define GLAPICAST APIENTRY * -#else -#define GLAPICAST * -#endif - -#define GLDECL(ret, funname, args) \ -typedef ret (GLAPICAST proc_ ## funname)args; \ -extern proc_ ## funname funname; \ - -#define GLDECL_STATIC(funname) proc_ ## funname funname = NULL - -#if defined GPAC_USE_TINYGL -//no extensions with TinyGL -#elif defined (GPAC_USE_OGL_ES) -//no extensions with OpenGL ES -#elif defined(WIN32) || defined (GPAC_CONFIG_WIN32) -#define LOAD_GL_FUNCS -#define GET_GLFUN(funname) funname = (proc_ ## funname) wglGetProcAddress(#funname) -#elif defined(CONFIG_DARWIN_GL) -extern void (*glutGetProcAddress(const GLubyte *procname))( void ); -#define GET_GLFUN(funname) funname = (proc_ ## funname) glutGetProcAddress(#funname) -#else -#define LOAD_GL_FUNCS -extern void (*glXGetProcAddress(const GLubyte *procname))( void ); -#define GET_GLFUN(funname) funname = (proc_ ## funname) glXGetProcAddress(#funname) -#endif - - - -#define DEL_SHADER(_a) if (_a) { glDeleteShader(_a); _a = 0; } -#define DEL_PROGRAM(_a) if (_a) { glDeleteProgram(_a); _a = 0; } - - -GLDECL(GLuint, glCreateProgram, (void) ) -GLDECL(void, glDeleteProgram, (GLuint ) ) -GLDECL(void, glLinkProgram, (GLuint program) ) -GLDECL(void, glUseProgram, (GLuint program) ) -GLDECL(GLuint, glCreateShader, (GLenum shaderType) ) -GLDECL(void, glDeleteShader, (GLuint shader) ) -GLDECL(void, glShaderSource, (GLuint shader, GLsizei count, const char **string, const GLint *length) ) -GLDECL(void, glCompileShader, (GLuint shader) ) -GLDECL(void, glAttachShader, (GLuint program, GLuint shader) ) -GLDECL(void, glDetachShader, (GLuint program, GLuint shader) ) -GLDECL(void, glGetShaderiv, (GLuint shader, GLenum type, GLint *res) ) -GLDECL(void, glGetInfoLogARB, (GLuint shader, GLint size, GLsizei *rsize, const char *logs) ) -GLDECL(GLint, glGetUniformLocation, (GLuint prog, const char *name) ) -GLDECL(void, glUniform1f, (GLint location, GLfloat v0) ) -GLDECL(void, glUniform1i, (GLint location, GLint v0) ) -GLDECL(void, glActiveTexture, (GLenum texture) ) -GLDECL(void, glClientActiveTexture, (GLenum texture) ) -GLDECL(void, glGenBuffers, (GLsizei , GLuint *) ) -GLDECL(void, glDeleteBuffers, (GLsizei , GLuint *) ) -GLDECL(void, glBindBuffer, (GLenum, GLuint ) ) -GLDECL(void, glBufferData, (GLenum, int, void *, GLenum) ) -GLDECL(void, glBufferSubData, (GLenum, int, int, void *) ) -GLDECL(void *, glMapBuffer, (GLenum, GLenum) ) -GLDECL(void *, glUnmapBuffer, (GLenum) ) - - -#define GL_TEXTURE_RECTANGLE_EXT 0x84F5 - -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC -#define GL_STREAM_DRAW_ARB 0x88E0 -#define GL_WRITE_ONLY_ARB 0x88B9 -#define GL_DYNAMIC_DRAW_ARB 0x88E8 - -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 - - -#endif +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2012 + * All rights reserved + * + * This file is part of GPAC - sample DASH library usage + * + */ + +#ifndef __DEF_BENCH_H__ +#define __DEF_BENCH_H__ + +#include +#include +#include +#define SDL_MAIN_HANDLED +#include +#include + +#define GL_GLEXT_PROTOTYPES + +#include +#include + + + + +#define GL_CHECK_ERR {s32 res = glGetError(); if (res) GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("GL Error %d file %s line %d\n", res, __FILE__, __LINE__)); } + +/*macros for GL proto and fun declaration*/ +#ifdef _WIN32_WCE +#define GLAPICAST * +#elif defined(WIN32) +#include +#define GLAPICAST APIENTRY * +#else +#define GLAPICAST * +#endif + +#define GLDECL(ret, funname, args) \ +typedef ret (GLAPICAST proc_ ## funname)args; \ +extern proc_ ## funname funname; \ + +#define GLDECL_STATIC(funname) proc_ ## funname funname = NULL + +#if defined GPAC_USE_TINYGL +//no extensions with TinyGL +#elif defined (GPAC_USE_GLES1X) +//no extensions with OpenGL ES +#elif defined(WIN32) || defined (GPAC_CONFIG_WIN32) +#define LOAD_GL_FUNCS +#define GET_GLFUN(funname) funname = (proc_ ## funname) wglGetProcAddress(#funname) +#elif defined(CONFIG_DARWIN_GL) +extern void (*glutGetProcAddress(const GLubyte *procname))( void ); +#define GET_GLFUN(funname) funname = (proc_ ## funname) glutGetProcAddress(#funname) +#else +#define LOAD_GL_FUNCS +extern void (*glXGetProcAddress(const GLubyte *procname))( void ); +#define GET_GLFUN(funname) funname = (proc_ ## funname) glXGetProcAddress(#funname) +#endif + + + +#define DEL_SHADER(_a) if (_a) { glDeleteShader(_a); _a = 0; } +#define DEL_PROGRAM(_a) if (_a) { glDeleteProgram(_a); _a = 0; } + + +GLDECL(GLuint, glCreateProgram, (void) ) +GLDECL(void, glDeleteProgram, (GLuint ) ) +GLDECL(void, glLinkProgram, (GLuint program) ) +GLDECL(void, glUseProgram, (GLuint program) ) +GLDECL(GLuint, glCreateShader, (GLenum shaderType) ) +GLDECL(void, glDeleteShader, (GLuint shader) ) +GLDECL(void, glShaderSource, (GLuint shader, GLsizei count, const char **string, const GLint *length) ) +GLDECL(void, glCompileShader, (GLuint shader) ) +GLDECL(void, glAttachShader, (GLuint program, GLuint shader) ) +GLDECL(void, glDetachShader, (GLuint program, GLuint shader) ) +GLDECL(void, glGetShaderiv, (GLuint shader, GLenum type, GLint *res) ) +GLDECL(void, glGetInfoLogARB, (GLuint shader, GLint size, GLsizei *rsize, const char *logs) ) +GLDECL(GLint, glGetUniformLocation, (GLuint prog, const char *name) ) +GLDECL(void, glUniform1f, (GLint location, GLfloat v0) ) +GLDECL(void, glUniform1i, (GLint location, GLint v0) ) +GLDECL(void, glActiveTexture, (GLenum texture) ) +GLDECL(void, glClientActiveTexture, (GLenum texture) ) +GLDECL(void, glGenBuffers, (GLsizei , GLuint *) ) +GLDECL(void, glDeleteBuffers, (GLsizei , GLuint *) ) +GLDECL(void, glBindBuffer, (GLenum, GLuint ) ) +GLDECL(void, glBufferData, (GLenum, int, void *, GLenum) ) +GLDECL(void, glBufferSubData, (GLenum, int, int, void *) ) +GLDECL(void *, glMapBuffer, (GLenum, GLenum) ) +GLDECL(void *, glUnmapBuffer, (GLenum) ) + + +#define GL_TEXTURE_RECTANGLE_EXT 0x84F5 + +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 + +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 + + +#endif diff --git a/applications/testapps/hevcbench/hevcbench.vcxproj b/applications/testapps/hevcbench/hevcbench.vcxproj index 9f677d3..4abc588 100644 --- a/applications/testapps/hevcbench/hevcbench.vcxproj +++ b/applications/testapps/hevcbench/hevcbench.vcxproj @@ -1,262 +1,262 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F728CC84-A7D1-43D2-8A28-05CE9F2FE0D0} - - - - Application - false - MultiByte - - - Application - false - MultiByte - - - Application - false - MultiByte - - - Application - false - MultiByte - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - ../../../bin/$(Platform)\$(Configuration)/ - ../../../bin/$(Platform)\$(Configuration)/ - .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ - .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ - true - true - ../../../bin/$(Platform)\$(Configuration)/ - ../../../bin/$(Platform)\$(Configuration)/ - .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ - .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ - false - false - - - - - - - - - - Disabled - C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - .\obj\mp42ts_deb/$(ProjectName).pch - .\obj\mp42ts_deb/ - .\obj\mp42ts_deb/ - .\obj\mp42ts_deb/ - true - Level3 - true - EditAndContinue - - - _DEBUG;%(PreprocessorDefinitions) - 0x040c - - - odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) - true - $(IntDir)$(ProjectName).pdb - Console - false - - - MachineX86 - - - true - - - - - - - - - - - Disabled - C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - .\obj\mp42ts_deb/$(ProjectName).pch - .\obj\mp42ts_deb/ - .\obj\mp42ts_deb/ - .\obj\mp42ts_deb/ - true - Level3 - true - ProgramDatabase - - - _DEBUG;%(PreprocessorDefinitions) - 0x040c - - - odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) - true - $(IntDir)$(ProjectName).pdb - Console - false - - - - - true - - - - - - - - - - - MaxSpeed - OnlyExplicitInline - C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\obj\mp42ts_rel/$(ProjectName).pch - .\obj\mp42ts_rel/ - .\obj\mp42ts_rel/ - .\obj\mp42ts_rel/ - Level3 - true - - - NDEBUG;%(PreprocessorDefinitions) - 0x040c - - - odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) - $(IntDir)$(ProjectName).pdb - Console - false - - - MachineX86 - - - true - - - - - - - - - - - Full - AnySuitable - ../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\obj\mp42ts_rel/$(ProjectName).pch - .\obj\mp42ts_rel/ - .\obj\mp42ts_rel/ - .\obj\mp42ts_rel/ - Level3 - true - true - Speed - - - NDEBUG;%(PreprocessorDefinitions) - 0x040c - - - odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - ../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) - $(IntDir)$(ProjectName).pdb - Console - false - - - - - true - - - - - - - - {d3540754-e0cf-4604-ac11-82de9bd4d814} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F728CC84-A7D1-43D2-8A28-05CE9F2FE0D0} + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + ../../../bin/$(Platform)\$(Configuration)/ + ../../../bin/$(Platform)\$(Configuration)/ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ../../../bin/$(Platform)\$(Configuration)/ + ../../../bin/$(Platform)\$(Configuration)/ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + .\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + false + + + + + + + + + + Disabled + C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + .\obj\mp42ts_deb/$(ProjectName).pch + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + false + + + MachineX86 + + + true + + + + + + + + + + + Disabled + C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + .\obj\mp42ts_deb/$(ProjectName).pch + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + .\obj\mp42ts_deb/ + true + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + false + + + + + true + + + + + + + + + + + MaxSpeed + OnlyExplicitInline + C:\works\software\signals\modules\extra_lib\include\SDL2\;../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\obj\mp42ts_rel/$(ProjectName).pch + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + C:\works\software\signals\modules\extra_lib\lib/$(Platform)/$(Configuration);../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + $(IntDir)$(ProjectName).pdb + Console + false + + + MachineX86 + + + true + + + + + + + + + + + Full + AnySuitable + ../../../include;../../../extra_lib/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\obj\mp42ts_rel/$(ProjectName).pch + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + .\obj\mp42ts_rel/ + Level3 + true + true + Speed + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/$(Platform)/$(Configuration);%(AdditionalLibraryDirectories) + $(IntDir)$(ProjectName).pdb + Console + false + + + + + true + + + + + + + + {d3540754-e0cf-4604-ac11-82de9bd4d814} + + + + + \ No newline at end of file diff --git a/applications/testapps/hevcbench/main.c b/applications/testapps/hevcbench/main.c index 034e221..83bd46e 100644 --- a/applications/testapps/hevcbench/main.c +++ b/applications/testapps/hevcbench/main.c @@ -1,857 +1,858 @@ -/* - * GPAC - Multimedia Framework C SDK - * - * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2012 - * All rights reserved - * - * This file is part of GPAC - sample DASH library usage - * - */ - -#include "defbench.h" - - - -#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) -# pragma comment(lib, "libLibOpenHevcWrapper") -#pragma comment(lib, "SDL2") -//#pragma comment(lib, "SDL2main") -#pragma comment(lib, "opengl32") -#endif - -//0: memcpy - 1: memmove - 2: u32 * cast and for loop copy of u32* - 3: memset 0 - 4: not touching the mapped buffer: 5: full memcpy, rely on stride in pixelstorei -#define COPY_TYPE 0 -//set to 1 to disable final gltexImage in PBO mode -#define NO_TEX 0 - - -SDL_Window *window = NULL; -SDL_GLContext *glctx= NULL; -SDL_Renderer *render= NULL; -GLint txid[3]; -u8 *pY = NULL; -u8 *pU = NULL; -u8 *pV = NULL; -u32 width = 0; -u32 height = 0; -u32 size=0; -u32 bpp=8; -u32 Bpp=1; -GLint memory_format=GL_UNSIGNED_BYTE; -GLint pixel_format=GL_LUMINANCE; -GLint texture_type=GL_TEXTURE_RECTANGLE_EXT; -u32 gl_nb_frames = 1; -u64 gl_upload_time = 0; -u64 gl_draw_time = 0; -Bool pbo_mode = GF_TRUE; -Bool first_tx_load = GF_FALSE; -Bool use_vsync=0; - -GLint glsl_program; -GLint vertex_shader; -GLint fragment_shader; - -GLint pbo_Y=0; -GLint pbo_U=0; -GLint pbo_V=0; - -GLDECL_STATIC(glActiveTexture); -GLDECL_STATIC(glClientActiveTexture); -GLDECL_STATIC(glCreateProgram); -GLDECL_STATIC(glDeleteProgram); -GLDECL_STATIC(glLinkProgram); -GLDECL_STATIC(glUseProgram); -GLDECL_STATIC(glCreateShader); -GLDECL_STATIC(glDeleteShader); -GLDECL_STATIC(glShaderSource); -GLDECL_STATIC(glCompileShader); -GLDECL_STATIC(glAttachShader); -GLDECL_STATIC(glDetachShader); -GLDECL_STATIC(glGetShaderiv); -GLDECL_STATIC(glGetInfoLogARB); -GLDECL_STATIC(glGetUniformLocation); -GLDECL_STATIC(glUniform1f); -GLDECL_STATIC(glUniform1i); -GLDECL_STATIC(glGenBuffers); -GLDECL_STATIC(glDeleteBuffers); -GLDECL_STATIC(glBindBuffer); -GLDECL_STATIC(glBufferData); -GLDECL_STATIC(glBufferSubData); -GLDECL_STATIC(glMapBuffer); -GLDECL_STATIC(glUnmapBuffer); - - -static char *glsl_yuv_shader = "\ - #version 140\n\ - #extension GL_ARB_texture_rectangle : enable\n\ - uniform sampler2DRect y_plane;\ - uniform sampler2DRect u_plane;\ - uniform sampler2DRect v_plane;\ - uniform float width;\ - uniform float height;\ - const vec3 offset = vec3(-0.0625, -0.5, -0.5);\ - const vec3 R_mul = vec3(1.164, 0.000, 1.596);\ - const vec3 G_mul = vec3(1.164, -0.391, -0.813);\ - const vec3 B_mul = vec3(1.164, 2.018, 0.000);\ - out vec4 FragColor;\ - void main(void) \ - {\ - vec2 texc;\ - vec3 yuv, rgb;\ - texc = gl_TexCoord[0].st;\ - texc.y = 1.0 - texc.y;\ - texc.x *= width;\ - texc.y *= height;\ - yuv.x = texture2DRect(y_plane, texc).r; \ - texc.x /= 2.0;\ - texc.y /= 2.0;\ - yuv.y = texture2DRect(u_plane, texc).r; \ - yuv.z = texture2DRect(v_plane, texc).r; \ - yuv += offset; \ - rgb.r = dot(yuv, R_mul); \ - rgb.g = dot(yuv, G_mul); \ - rgb.b = dot(yuv, B_mul); \ - FragColor = vec4(rgb, 1.0);\ - }"; - -static char *default_glsl_vertex = "\ - varying vec3 gfNormal;\ - varying vec3 gfView;\ - void main(void)\ - {\ - gfView = vec3(gl_ModelViewMatrix * gl_Vertex);\ - gfNormal = normalize(gl_NormalMatrix * gl_Normal);\ - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ - gl_TexCoord[0] = gl_MultiTexCoord0;\ - }"; - - - -Bool sdl_compile_shader(u32 shader_id, const char *name, const char *source) -{ - GLint blen = 0; - GLsizei slen = 0; - u32 len; - if (!source || !shader_id) return 0; - len = (u32) strlen(source); - glShaderSource(shader_id, 1, &source, &len); - glCompileShader(shader_id); - - glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH , &blen); - if (blen > 1) { - char* compiler_log = (char*) gf_malloc(blen); -#ifdef CONFIG_DARWIN_GL - glGetInfoLogARB((GLhandleARB) shader_id, blen, &slen, compiler_log); -#else - glGetInfoLogARB(shader_id, blen, &slen, compiler_log); -#endif - GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[GLSL] Failed to compile shader %s: %s\n", name, compiler_log)); - gf_free (compiler_log); - return 0; - } - return 1; -} - -void sdl_init(u32 _width, u32 _height, u32 _bpp, u32 stride, Bool use_pbo) -{ - u32 i, flags; - Float hw, hh; - GLint loc; - GF_Matrix mx; - width = _width; - height = _height; - bpp = _bpp; - - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - - flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS | SDL_WINDOW_MAXIMIZED; - if (use_vsync) flags |= SDL_RENDERER_PRESENTVSYNC; - window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); - glctx = SDL_GL_CreateContext(window); - SDL_GL_MakeCurrent(window, glctx); - - render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); - - -#if (COPY_TYPE==5) - size = stride*height; -#else - size = width*height; -#endif - if (bpp>8) { - size *= 2; - Bpp = 2; - } - pY = gf_malloc(size*sizeof(u8)); - memset(pY, 0x80, size*sizeof(u8)); - pU = gf_malloc(size/4*sizeof(u8)); - memset(pU, 0, size/4*sizeof(u8)); - pV = gf_malloc(size/4*sizeof(u8)); - memset(pV, 0, size/4*sizeof(u8)); - - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - glViewport(0, 0, width, height); - - gf_mx_init(mx); - hw = ((Float)width)/2; - hh = ((Float)height)/2; - gf_mx_ortho(&mx, -hw, hw, -hh, hh, 50, -50); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(mx.m); - - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear(GL_DEPTH_BUFFER_BIT); - glDisable(GL_NORMALIZE); - glDisable(GL_DEPTH_TEST); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_LINE_SMOOTH); - glDisable(GL_LIGHTING); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glDisable(GL_CULL_FACE); - - - GET_GLFUN(glActiveTexture); - GET_GLFUN(glClientActiveTexture); - GET_GLFUN(glCreateProgram); - GET_GLFUN(glDeleteProgram); - GET_GLFUN(glLinkProgram); - GET_GLFUN(glUseProgram); - GET_GLFUN(glCreateShader); - GET_GLFUN(glDeleteShader); - GET_GLFUN(glShaderSource); - GET_GLFUN(glCompileShader); - GET_GLFUN(glAttachShader); - GET_GLFUN(glDetachShader); - GET_GLFUN(glGetShaderiv); - GET_GLFUN(glGetInfoLogARB); - GET_GLFUN(glGetUniformLocation); - GET_GLFUN(glUniform1f); - GET_GLFUN(glUniform1i); - GET_GLFUN(glGenBuffers); - GET_GLFUN(glDeleteBuffers); - GET_GLFUN(glBindBuffer); - GET_GLFUN(glBufferData); - GET_GLFUN(glBufferSubData); - GET_GLFUN(glMapBuffer); - GET_GLFUN(glUnmapBuffer); - - glsl_program = glCreateProgram(); - vertex_shader = glCreateShader(GL_VERTEX_SHADER); - sdl_compile_shader(vertex_shader, "vertex", default_glsl_vertex); - - fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - sdl_compile_shader(fragment_shader, "fragment", glsl_yuv_shader); - - glAttachShader(glsl_program, vertex_shader); - glAttachShader(glsl_program, fragment_shader); - glLinkProgram(glsl_program); - - glGenTextures(3, txid); - for (i=0; i<3; i++) { - - glEnable(texture_type); - glBindTexture(texture_type, txid[i] ); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (bpp>8) { - glPixelTransferi(GL_RED_SCALE, 64); - memory_format=GL_UNSIGNED_SHORT; - } - glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - if (bpp>8) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } - glDisable(texture_type); - } - - //sets uniforms: y, u, v textures point to texture slots 0, 1 and 2 - glUseProgram(glsl_program); - for (i=0; i<3; i++) { - const char *txname = (i==0) ? "y_plane" : (i==1) ? "u_plane" : "v_plane"; - loc = glGetUniformLocation(glsl_program, txname); - if (loc == -1) { - GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate texture %s in YUV shader\n", txname)); - continue; - } - glUniform1i(loc, i); - } - loc = glGetUniformLocation(glsl_program, "width"); - if (loc>= 0) { - Float w = (Float) width; - glUniform1f(loc, w); - } - loc = glGetUniformLocation(glsl_program, "height"); - if (loc>= 0) { - Float h = (Float) height; - glUniform1f(loc, h); - } - - glUseProgram(0); - - - if (glMapBuffer==NULL) use_pbo = GF_FALSE; - - - pbo_mode = use_pbo; - first_tx_load = use_pbo ? GF_FALSE : GF_TRUE; - if (use_pbo) { - glGenBuffers(1, &pbo_Y); - glGenBuffers(1, &pbo_U); - glGenBuffers(1, &pbo_V); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_Y); - glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size, NULL, GL_DYNAMIC_DRAW_ARB); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_U); - glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size/4, NULL, GL_DYNAMIC_DRAW_ARB); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_V); - glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size/4, NULL, GL_DYNAMIC_DRAW_ARB); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); - } -} - -void sdl_close() -{ - DEL_SHADER(vertex_shader); - DEL_SHADER(fragment_shader); - DEL_PROGRAM(glsl_program ); - - if (pbo_mode && pbo_Y) { - glDeleteBuffers(1, &pbo_Y); - glDeleteBuffers(1, &pbo_U); - glDeleteBuffers(1, &pbo_V); - } - - if (pY) gf_free(pY); - if (pU) gf_free(pU); - if (pV) gf_free(pV); - - if (glctx) SDL_GL_DeleteContext(glctx); - if (render) SDL_DestroyRenderer(render); - if (window) SDL_DestroyWindow(window); -} - -void sdl_draw_quad() -{ - Float w = ((Float)width)/2; - Float h = ((Float)height)/2; - - glBegin(GL_QUADS); - - glVertex3f(w, h, 0); - glTexCoord2f(1, 0); - - glVertex3f(w, -h, 0); - glTexCoord2f(0, 0); - - glVertex3f(-w, -h, 0); - glTexCoord2f(0, 1); - - glVertex3f(-w, h, 0); - glTexCoord2f(1, 1); - - glEnd(); -} - - -void sdl_draw_frame(u8 *pY, u8 *pU, u8 *pV, u32 w, u32 h, u32 bit_depth, u32 stride) -{ - u32 needs_stride = 0; - u64 now, end; - - if (stride != w) { - if (bit_depth==10) { - if (stride != 2*w) { - needs_stride = stride / 2; - } - } else { - needs_stride = stride; - } - } - - glEnable(texture_type); - - now = gf_sys_clock_high_res(); - - - if (first_tx_load) { - glBindTexture(texture_type, txid[0] ); - if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride); - glTexImage2D(texture_type, 0, 1, w, h, 0, pixel_format, memory_format, pY); - - glBindTexture(texture_type, txid[1] ); - if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride/2); - glTexImage2D(texture_type, 0, 1, w/2, h/2, 0, pixel_format, memory_format, pU); - - glBindTexture(texture_type, txid[2] ); - if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride/2); - glTexImage2D(texture_type, 0, 1, w/2, h/2, 0, pixel_format, memory_format, pV); - - if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - first_tx_load = GF_FALSE; - } else if (pbo_mode) { - u32 i, linesize, count, p_stride; - u8 *ptr; -#if (COPY_TYPE==2) - u32 *s, *d; - u32 j, c2; -#endif - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_Y); - ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); -#if (COPY_TYPE==5) - memcpy(ptr, pY, size); -#elif (COPY_TYPE==3) - memset(ptr, 0x80, size); -#elif (COPY_TYPE==4) -#else - linesize = width*Bpp; - p_stride = stride; - count = h; -#if (COPY_TYPE==2) - c2 = linesize/4; - s = (u32 *)pY; - d = (u32 *)ptr; -#endif - for (i=0; i=GF_ISOM_HEVCTYPE_HEVC_ONLY) { - track = i+1; - break; - } - } - - if (!track) { - gf_isom_close(isom); - sdl_close(); - gf_sys_close(); - return 0; - } - - count = gf_isom_get_sample_count(isom, track); - start = gf_sys_clock_high_res(); - - esd = gf_isom_get_esd(isom, track, 1); - ohevc = libOpenHevcInit(nb_threads, mode); - if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { - libOpenHevcCopyExtraData(ohevc, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength+8); - } - - libOpenHevcSetActiveDecoders(ohevc, 1); - libOpenHevcSetViewLayers(ohevc, 1); - - libOpenHevcStartDecoder(ohevc); - gf_odf_desc_del((GF_Descriptor *)esd); - gf_isom_set_sample_padding(isom, track, 8); - - run=1; - check_prompt=0; - for (i=0; idata, sample->dataLength, sample->DTS+sample->CTS_Offset) ) { - if (no_display) { - OpenHevc_Frame HVCFrame_ptr; - libOpenHevcGetOutput(ohevc, 1, &HVCFrame_ptr); - } else if (use_raw_memory) { - OpenHevc_Frame HVCFrame_ptr; - libOpenHevcGetOutput(ohevc, 1, &HVCFrame_ptr); - - - if (!sdl_is_init && !no_display) { - sdl_init(HVCFrame_ptr.frameInfo.nWidth, HVCFrame_ptr.frameInfo.nHeight, HVCFrame_ptr.frameInfo.nBitDepth, HVCFrame_ptr.frameInfo.nYPitch, use_pbo); - sdl_is_init=1; - start = gf_sys_clock_high_res(); - nb_frames_at_start = i+1; - } - - sdl_draw_frame((u8 *) HVCFrame_ptr.pvY, (u8 *) HVCFrame_ptr.pvU, (u8 *) HVCFrame_ptr.pvV, HVCFrame_ptr.frameInfo.nWidth, HVCFrame_ptr.frameInfo.nHeight, HVCFrame_ptr.frameInfo.nBitDepth, HVCFrame_ptr.frameInfo.nYPitch); - } else { - OpenHevc_Frame_cpy HVCFrame; - memset(&HVCFrame, 0, sizeof(OpenHevc_Frame_cpy) ); - - libOpenHevcGetPictureInfoCpy(ohevc, &HVCFrame.frameInfo); - - if (!sdl_is_init && !no_display) { - sdl_init(HVCFrame.frameInfo.nWidth, HVCFrame.frameInfo.nHeight, HVCFrame.frameInfo.nBitDepth, HVCFrame.frameInfo.nYPitch, use_pbo); - sdl_is_init=1; - start = gf_sys_clock_high_res(); - nb_frames_at_start = i+1; - } - - HVCFrame.pvY = (void*) pY; - HVCFrame.pvU = (void*) pU; - HVCFrame.pvV = (void*) pV; - - libOpenHevcGetOutputCpy(ohevc, 1, &HVCFrame); - - sdl_draw_frame(pY, pU, pV, HVCFrame.frameInfo.nWidth, HVCFrame.frameInfo.nHeight, HVCFrame.frameInfo.nBitDepth, HVCFrame.frameInfo.nYPitch); - } - } - - gf_isom_sample_del(&sample); - - now = gf_sys_clock_high_res(); - fprintf(stderr, "%d %% %d frames in %d ms - FPS %03.2f - push time "LLD" ms - draw "LLD" ms\r", 100*(i+1-nb_frames_at_start)/count, i+1-nb_frames_at_start, (now-start)/1000, 1000000.0 * (i+1-nb_frames_at_start) / (now-start), gl_upload_time / gl_nb_frames/1000 , (gl_draw_time - gl_upload_time) / gl_nb_frames/1000 ); - } else { - gf_sleep(10); - i--; - } - check_prompt++; - if (check_prompt==50) { - if (gf_prompt_has_input()) { - switch (gf_prompt_get_char()) { - case 'q': - run = 0; - break; - case 'm': - use_raw_memory = !use_raw_memory; - break; - case 'p': - if (paused) { - paused=0; - start += gf_sys_clock_high_res()-pause_time; - } else { - paused = 1; - pause_time=gf_sys_clock_high_res(); - } - break; - case 'r': - start = gf_sys_clock_high_res(); - nb_frames_at_start = i+1; - gl_upload_time = gl_draw_time = 0; - gl_nb_frames=1; - break; - - } - } - check_prompt=0; - } - } - now = gf_sys_clock_high_res(); - fprintf(stderr, "\nDecoded %d frames in %d ms - FPS %g\n", i+1, (now-start)/1000, 1000000.0 * (i+1) / (now-start) ); - - libOpenHevcClose(ohevc); - gf_isom_close(isom); - - if (!no_display) - sdl_close(); - - gf_sys_close(); - return 1; -} - +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2012 + * All rights reserved + * + * This file is part of GPAC - sample DASH library usage + * + */ + +#include "defbench.h" + + + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) +# pragma comment(lib, "libLibOpenHevcWrapper") +#pragma comment(lib, "SDL2") +//#pragma comment(lib, "SDL2main") +#pragma comment(lib, "opengl32") +#endif + +//0: memcpy - 1: memmove - 2: u32 * cast and for loop copy of u32* - 3: memset 0 - 4: not touching the mapped buffer: 5: full memcpy, rely on stride in pixelstorei +#define COPY_TYPE 0 +//set to 1 to disable final gltexImage in PBO mode +#define NO_TEX 0 + + +SDL_Window *window = NULL; +SDL_GLContext *glctx= NULL; +SDL_Renderer *render= NULL; +GLint txid[3]; +u8 *pY = NULL; +u8 *pU = NULL; +u8 *pV = NULL; +u32 width = 0; +u32 height = 0; +u32 size=0; +u32 bpp=8; +u32 Bpp=1; +GLint memory_format=GL_UNSIGNED_BYTE; +GLint pixel_format=GL_LUMINANCE; +GLint texture_type=GL_TEXTURE_RECTANGLE_EXT; +u32 gl_nb_frames = 1; +u64 gl_upload_time = 0; +u64 gl_draw_time = 0; +Bool pbo_mode = GF_TRUE; +Bool first_tx_load = GF_FALSE; +Bool use_vsync=0; + +GLint glsl_program; +GLint vertex_shader; +GLint fragment_shader; + +GLint pbo_Y=0; +GLint pbo_U=0; +GLint pbo_V=0; + +GLDECL_STATIC(glActiveTexture); +GLDECL_STATIC(glClientActiveTexture); +GLDECL_STATIC(glCreateProgram); +GLDECL_STATIC(glDeleteProgram); +GLDECL_STATIC(glLinkProgram); +GLDECL_STATIC(glUseProgram); +GLDECL_STATIC(glCreateShader); +GLDECL_STATIC(glDeleteShader); +GLDECL_STATIC(glShaderSource); +GLDECL_STATIC(glCompileShader); +GLDECL_STATIC(glAttachShader); +GLDECL_STATIC(glDetachShader); +GLDECL_STATIC(glGetShaderiv); +GLDECL_STATIC(glGetInfoLogARB); +GLDECL_STATIC(glGetUniformLocation); +GLDECL_STATIC(glUniform1f); +GLDECL_STATIC(glUniform1i); +GLDECL_STATIC(glGenBuffers); +GLDECL_STATIC(glDeleteBuffers); +GLDECL_STATIC(glBindBuffer); +GLDECL_STATIC(glBufferData); +GLDECL_STATIC(glBufferSubData); +GLDECL_STATIC(glMapBuffer); +GLDECL_STATIC(glUnmapBuffer); + + +static char *glsl_yuv_shader = "\ + #version 140\n\ + #extension GL_ARB_texture_rectangle : enable\n\ + uniform sampler2DRect y_plane;\ + uniform sampler2DRect u_plane;\ + uniform sampler2DRect v_plane;\ + uniform float width;\ + uniform float height;\ + const vec3 offset = vec3(-0.0625, -0.5, -0.5);\ + const vec3 R_mul = vec3(1.164, 0.000, 1.596);\ + const vec3 G_mul = vec3(1.164, -0.391, -0.813);\ + const vec3 B_mul = vec3(1.164, 2.018, 0.000);\ + out vec4 FragColor;\ + void main(void) \ + {\ + vec2 texc;\ + vec3 yuv, rgb;\ + texc = gl_TexCoord[0].st;\ + texc.y = 1.0 - texc.y;\ + texc.x *= width;\ + texc.y *= height;\ + yuv.x = texture2DRect(y_plane, texc).r; \ + texc.x /= 2.0;\ + texc.y /= 2.0;\ + yuv.y = texture2DRect(u_plane, texc).r; \ + yuv.z = texture2DRect(v_plane, texc).r; \ + yuv += offset; \ + rgb.r = dot(yuv, R_mul); \ + rgb.g = dot(yuv, G_mul); \ + rgb.b = dot(yuv, B_mul); \ + FragColor = vec4(rgb, 1.0);\ + }"; + +static char *default_glsl_vertex = "\ + varying vec3 gfNormal;\ + varying vec3 gfView;\ + void main(void)\ + {\ + gfView = vec3(gl_ModelViewMatrix * gl_Vertex);\ + gfNormal = normalize(gl_NormalMatrix * gl_Normal);\ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ + gl_TexCoord[0] = gl_MultiTexCoord0;\ + }"; + + + +Bool sdl_compile_shader(u32 shader_id, const char *name, const char *source) +{ + GLint blen = 0; + GLsizei slen = 0; + u32 len; + if (!source || !shader_id) return 0; + len = (u32) strlen(source); + glShaderSource(shader_id, 1, &source, &len); + glCompileShader(shader_id); + + glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH , &blen); + if (blen > 1) { + char* compiler_log = (char*) gf_malloc(blen); +#ifdef CONFIG_DARWIN_GL + glGetInfoLogARB((GLhandleARB) shader_id, blen, &slen, compiler_log); +#else + glGetInfoLogARB(shader_id, blen, &slen, compiler_log); +#endif + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[GLSL] Failed to compile shader %s: %s\n", name, compiler_log)); + gf_free (compiler_log); + return 0; + } + return 1; +} + +void sdl_init(u32 _width, u32 _height, u32 _bpp, u32 stride, Bool use_pbo) +{ + u32 i, flags; + Float hw, hh; + GLint loc; + GF_Matrix mx; + width = _width; + height = _height; + bpp = _bpp; + + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + + flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS | SDL_WINDOW_MAXIMIZED; + if (use_vsync) flags |= SDL_RENDERER_PRESENTVSYNC; + window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); + glctx = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, glctx); + + render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + + +#if (COPY_TYPE==5) + size = stride*height; +#else + size = width*height; +#endif + if (bpp>8) { + size *= 2; + Bpp = 2; + } + pY = gf_malloc(size*sizeof(u8)); + memset(pY, 0x80, size*sizeof(u8)); + pU = gf_malloc(size/4*sizeof(u8)); + memset(pU, 0, size/4*sizeof(u8)); + pV = gf_malloc(size/4*sizeof(u8)); + memset(pV, 0, size/4*sizeof(u8)); + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glViewport(0, 0, width, height); + + gf_mx_init(mx); + hw = ((Float)width)/2; + hh = ((Float)height)/2; + gf_mx_ortho(&mx, -hw, hw, -hh, hh, 50, -50); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(mx.m); + + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_NORMALIZE); + glDisable(GL_DEPTH_TEST); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glDisable(GL_CULL_FACE); + + + GET_GLFUN(glActiveTexture); + GET_GLFUN(glClientActiveTexture); + GET_GLFUN(glCreateProgram); + GET_GLFUN(glDeleteProgram); + GET_GLFUN(glLinkProgram); + GET_GLFUN(glUseProgram); + GET_GLFUN(glCreateShader); + GET_GLFUN(glDeleteShader); + GET_GLFUN(glShaderSource); + GET_GLFUN(glCompileShader); + GET_GLFUN(glAttachShader); + GET_GLFUN(glDetachShader); + GET_GLFUN(glGetShaderiv); + GET_GLFUN(glGetInfoLogARB); + GET_GLFUN(glGetUniformLocation); + GET_GLFUN(glUniform1f); + GET_GLFUN(glUniform1i); + GET_GLFUN(glGenBuffers); + GET_GLFUN(glDeleteBuffers); + GET_GLFUN(glBindBuffer); + GET_GLFUN(glBufferData); + GET_GLFUN(glBufferSubData); + GET_GLFUN(glMapBuffer); + GET_GLFUN(glUnmapBuffer); + + glsl_program = glCreateProgram(); + vertex_shader = glCreateShader(GL_VERTEX_SHADER); + sdl_compile_shader(vertex_shader, "vertex", default_glsl_vertex); + + fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + sdl_compile_shader(fragment_shader, "fragment", glsl_yuv_shader); + + glAttachShader(glsl_program, vertex_shader); + glAttachShader(glsl_program, fragment_shader); + glLinkProgram(glsl_program); + + glGenTextures(3, txid); + for (i=0; i<3; i++) { + + glEnable(texture_type); + glBindTexture(texture_type, txid[i] ); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (bpp>8) { + glPixelTransferi(GL_RED_SCALE, 64); + memory_format=GL_UNSIGNED_SHORT; + } + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (bpp>8) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + glDisable(texture_type); + } + + //sets uniforms: y, u, v textures point to texture slots 0, 1 and 2 + glUseProgram(glsl_program); + for (i=0; i<3; i++) { + const char *txname = (i==0) ? "y_plane" : (i==1) ? "u_plane" : "v_plane"; + loc = glGetUniformLocation(glsl_program, txname); + if (loc == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate texture %s in YUV shader\n", txname)); + continue; + } + glUniform1i(loc, i); + } + loc = glGetUniformLocation(glsl_program, "width"); + if (loc>= 0) { + Float w = (Float) width; + glUniform1f(loc, w); + } + loc = glGetUniformLocation(glsl_program, "height"); + if (loc>= 0) { + Float h = (Float) height; + glUniform1f(loc, h); + } + + glUseProgram(0); + + + if (glMapBuffer==NULL) use_pbo = GF_FALSE; + + + pbo_mode = use_pbo; + first_tx_load = use_pbo ? GF_FALSE : GF_TRUE; + if (use_pbo) { + glGenBuffers(1, &pbo_Y); + glGenBuffers(1, &pbo_U); + glGenBuffers(1, &pbo_V); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_Y); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size, NULL, GL_DYNAMIC_DRAW_ARB); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_U); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size/4, NULL, GL_DYNAMIC_DRAW_ARB); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_V); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, size/4, NULL, GL_DYNAMIC_DRAW_ARB); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + } +} + +void sdl_close() +{ + DEL_SHADER(vertex_shader); + DEL_SHADER(fragment_shader); + DEL_PROGRAM(glsl_program ); + + if (pbo_mode && pbo_Y) { + glDeleteBuffers(1, &pbo_Y); + glDeleteBuffers(1, &pbo_U); + glDeleteBuffers(1, &pbo_V); + } + + if (pY) gf_free(pY); + if (pU) gf_free(pU); + if (pV) gf_free(pV); + + if (glctx) SDL_GL_DeleteContext(glctx); + if (render) SDL_DestroyRenderer(render); + if (window) SDL_DestroyWindow(window); +} + +void sdl_draw_quad() +{ + Float w = ((Float)width)/2; + Float h = ((Float)height)/2; + + glBegin(GL_QUADS); + + glVertex3f(w, h, 0); + glTexCoord2f(1, 0); + + glVertex3f(w, -h, 0); + glTexCoord2f(0, 0); + + glVertex3f(-w, -h, 0); + glTexCoord2f(0, 1); + + glVertex3f(-w, h, 0); + glTexCoord2f(1, 1); + + glEnd(); +} + + +void sdl_draw_frame(u8 *pY, u8 *pU, u8 *pV, u32 w, u32 h, u32 bit_depth, u32 stride) +{ + u32 needs_stride = 0; + u64 now, end; + + if (stride != w) { + if (bit_depth==10) { + if (stride != 2*w) { + needs_stride = stride / 2; + } + } else { + needs_stride = stride; + } + } + + glEnable(texture_type); + + now = gf_sys_clock_high_res(); + + + if (first_tx_load) { + glBindTexture(texture_type, txid[0] ); + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride); + glTexImage2D(texture_type, 0, 1, w, h, 0, pixel_format, memory_format, pY); + + glBindTexture(texture_type, txid[1] ); + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride/2); + glTexImage2D(texture_type, 0, 1, w/2, h/2, 0, pixel_format, memory_format, pU); + + glBindTexture(texture_type, txid[2] ); + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, needs_stride/2); + glTexImage2D(texture_type, 0, 1, w/2, h/2, 0, pixel_format, memory_format, pV); + + if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + first_tx_load = GF_FALSE; + } else if (pbo_mode) { + u32 i, linesize, count, p_stride; + u8 *ptr; +#if (COPY_TYPE==2) + u32 *s, *d; + u32 j, c2; +#endif + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_Y); + ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); +#if (COPY_TYPE==5) + memcpy(ptr, pY, size); +#elif (COPY_TYPE==3) + memset(ptr, 0x80, size); +#elif (COPY_TYPE==4) +#else + linesize = width*Bpp; + p_stride = stride; + count = h; +#if (COPY_TYPE==2) + c2 = linesize/4; + s = (u32 *)pY; + d = (u32 *)ptr; +#endif + for (i=0; i=GF_ISOM_HEVCTYPE_HEVC_ONLY) { + track = i+1; + break; + } + } + + if (!track) { + gf_isom_close(isom); + sdl_close(); + gf_sys_close(); + return 0; + } + + count = gf_isom_get_sample_count(isom, track); + start = gf_sys_clock_high_res(); + + esd = gf_isom_get_esd(isom, track, 1); + ohevc = libOpenHevcInit(nb_threads, mode); + if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { + libOpenHevcCopyExtraData(ohevc, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength+8); + } + + libOpenHevcSetActiveDecoders(ohevc, 1); + libOpenHevcSetViewLayers(ohevc, 1); + + libOpenHevcStartDecoder(ohevc); + gf_odf_desc_del((GF_Descriptor *)esd); + gf_isom_set_sample_padding(isom, track, 8); + + run=1; + check_prompt=0; + for (i=0; idata, sample->dataLength, sample->DTS+sample->CTS_Offset) ) { + if (no_display) { + OpenHevc_Frame HVCFrame_ptr; + libOpenHevcGetOutput(ohevc, 1, &HVCFrame_ptr); + } else if (use_raw_memory) { + OpenHevc_Frame HVCFrame_ptr; + libOpenHevcGetOutput(ohevc, 1, &HVCFrame_ptr); + + + if (!sdl_is_init && !no_display) { + sdl_init(HVCFrame_ptr.frameInfo.nWidth, HVCFrame_ptr.frameInfo.nHeight, HVCFrame_ptr.frameInfo.nBitDepth, HVCFrame_ptr.frameInfo.nYPitch, use_pbo); + sdl_is_init=1; + start = gf_sys_clock_high_res(); + nb_frames_at_start = i+1; + } + + sdl_draw_frame((u8 *) HVCFrame_ptr.pvY, (u8 *) HVCFrame_ptr.pvU, (u8 *) HVCFrame_ptr.pvV, HVCFrame_ptr.frameInfo.nWidth, HVCFrame_ptr.frameInfo.nHeight, HVCFrame_ptr.frameInfo.nBitDepth, HVCFrame_ptr.frameInfo.nYPitch); + } else { + OpenHevc_Frame_cpy HVCFrame; + memset(&HVCFrame, 0, sizeof(OpenHevc_Frame_cpy) ); + + libOpenHevcGetPictureInfoCpy(ohevc, &HVCFrame.frameInfo); + + if (!sdl_is_init && !no_display) { + sdl_init(HVCFrame.frameInfo.nWidth, HVCFrame.frameInfo.nHeight, HVCFrame.frameInfo.nBitDepth, HVCFrame.frameInfo.nYPitch, use_pbo); + sdl_is_init=1; + start = gf_sys_clock_high_res(); + nb_frames_at_start = i+1; + } + + HVCFrame.pvY = (void*) pY; + HVCFrame.pvU = (void*) pU; + HVCFrame.pvV = (void*) pV; + + libOpenHevcGetOutputCpy(ohevc, 1, &HVCFrame); + + sdl_draw_frame(pY, pU, pV, HVCFrame.frameInfo.nWidth, HVCFrame.frameInfo.nHeight, HVCFrame.frameInfo.nBitDepth, HVCFrame.frameInfo.nYPitch); + } + } + + gf_isom_sample_del(&sample); + + now = gf_sys_clock_high_res(); + fprintf(stderr, "%d %% %d frames in %d ms - FPS %03.2f - push time "LLD" ms - draw "LLD" ms\r", 100*(i+1-nb_frames_at_start)/count, i+1-nb_frames_at_start, (now-start)/1000, 1000000.0 * (i+1-nb_frames_at_start) / (now-start), gl_upload_time / gl_nb_frames/1000 , (gl_draw_time - gl_upload_time) / gl_nb_frames/1000 ); + } else { + gf_sleep(10); + i--; + } + check_prompt++; + if (check_prompt==50) { + if (gf_prompt_has_input()) { + switch (gf_prompt_get_char()) { + case 'q': + run = 0; + break; + case 'm': + use_raw_memory = !use_raw_memory; + break; + case 'p': + if (paused) { + paused=0; + start += gf_sys_clock_high_res()-pause_time; + } else { + paused = 1; + pause_time=gf_sys_clock_high_res(); + } + break; + case 'r': + start = gf_sys_clock_high_res(); + nb_frames_at_start = i+1; + gl_upload_time = gl_draw_time = 0; + gl_nb_frames=1; + break; + + } + } + check_prompt=0; + } + } + now = gf_sys_clock_high_res(); + fprintf(stderr, "\nDecoded %d frames in %d ms - FPS %g\n", i+1, (now-start)/1000, 1000000.0 * (i+1) / (now-start) ); + + libOpenHevcClose(ohevc); + gf_isom_close(isom); + + if (!no_display) + sdl_close(); + + gf_sys_close(); + return 1; +} + diff --git a/applications/testapps/largefile/largefile.dsp b/applications/testapps/largefile/largefile.dsp index 3a568ad..e6b0c21 100644 --- a/applications/testapps/largefile/largefile.dsp +++ b/applications/testapps/largefile/largefile.dsp @@ -1,102 +1,102 @@ -# Microsoft Developer Studio Project File - Name="largefile" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=largefile - 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 "largefile.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 "largefile.mak" CFG="largefile - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "largefile - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "largefile - 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)" == "largefile - 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 winmm.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "largefile - 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" /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 winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "largefile - Win32 Release" -# Name "largefile - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="largefile" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=largefile - 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 "largefile.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 "largefile.mak" CFG="largefile - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "largefile - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "largefile - 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)" == "largefile - 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 winmm.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "largefile - 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" /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 winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "largefile - Win32 Release" +# Name "largefile - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/largefile/largefile.dsw b/applications/testapps/largefile/largefile.dsw index d1ebaae..12e531a 100644 --- a/applications/testapps/largefile/largefile.dsw +++ b/applications/testapps/largefile/largefile.dsw @@ -1,44 +1,44 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "largefile"=.\largefile.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name libgpac - End Project Dependency -}}} - -############################################################################### - -Project: "libgpac"=..\..\..\build\msvc6\libgpac.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: "largefile"=.\largefile.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libgpac + End Project Dependency +}}} + +############################################################################### + +Project: "libgpac"=..\..\..\build\msvc6\libgpac.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/applications/testapps/loadcompare/LoadCompare.dsp b/applications/testapps/loadcompare/LoadCompare.dsp index 033efac..5eed27f 100644 --- a/applications/testapps/loadcompare/LoadCompare.dsp +++ b/applications/testapps/loadcompare/LoadCompare.dsp @@ -1,112 +1,112 @@ -# Microsoft Developer Studio Project File - Name="LoadCompare" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=LoadCompare - 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 "LoadCompare.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 "LoadCompare.mak" CFG="LoadCompare - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "LoadCompare - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "LoadCompare - 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)" == "LoadCompare - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "LoadCompare___Win32_Release" -# PROP BASE Intermediate_Dir "LoadCompare___Win32_Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "obj/loadcompare_rel" -# PROP Intermediate_Dir "obj/loadcompare_rel" -# 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" /I "../../../extra_lib/include/zlib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c -# SUBTRACT CPP /YX -# 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 zlib.lib winmm.lib libxml2.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/LoadCompare.exe" /libpath:"../../../extra_lib/lib/w32_rel" - -!ELSEIF "$(CFG)" == "LoadCompare - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "LoadCompare___Win32_Debug" -# PROP BASE Intermediate_Dir "LoadCompare___Win32_Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "obj/loadcompare_deb" -# PROP Intermediate_Dir "obj/loadcompare_deb" -# 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" /I "../../../extra_lib/include/zlib" /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 zlib.lib winmm.lib libxml2.lib /nologo /subsystem:console /pdb:"obj/loadcompare_deb//LoadCompare.pdb" /debug /machine:I386 /out:"../../../bin/w32_deb/LoadCompare.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "LoadCompare - Win32 Release" -# Name "LoadCompare - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\loadcompare.c -# End Source File -# Begin Source File - -SOURCE=..\..\..\modules\svg_loader\lsr_parser.c -# End Source File -# Begin Source File - -SOURCE=..\..\..\modules\svg_loader\svg_parser.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="LoadCompare" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=LoadCompare - 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 "LoadCompare.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 "LoadCompare.mak" CFG="LoadCompare - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LoadCompare - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "LoadCompare - 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)" == "LoadCompare - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "LoadCompare___Win32_Release" +# PROP BASE Intermediate_Dir "LoadCompare___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "obj/loadcompare_rel" +# PROP Intermediate_Dir "obj/loadcompare_rel" +# 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" /I "../../../extra_lib/include/zlib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c +# SUBTRACT CPP /YX +# 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 zlib.lib winmm.lib libxml2.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/LoadCompare.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "LoadCompare - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "LoadCompare___Win32_Debug" +# PROP BASE Intermediate_Dir "LoadCompare___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "obj/loadcompare_deb" +# PROP Intermediate_Dir "obj/loadcompare_deb" +# 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" /I "../../../extra_lib/include/zlib" /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 zlib.lib winmm.lib libxml2.lib /nologo /subsystem:console /pdb:"obj/loadcompare_deb//LoadCompare.pdb" /debug /machine:I386 /out:"../../../bin/w32_deb/LoadCompare.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "LoadCompare - Win32 Release" +# Name "LoadCompare - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\loadcompare.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\modules\svg_loader\lsr_parser.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\modules\svg_loader\svg_parser.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/loadcompare/loadcompare.c b/applications/testapps/loadcompare/loadcompare.c index 8774281..54e2dec 100644 --- a/applications/testapps/loadcompare/loadcompare.c +++ b/applications/testapps/loadcompare/loadcompare.c @@ -382,14 +382,14 @@ GF_Err get_size(GF_LoadCompare *lc, char *item_name, char *item_path, u32 *size) *size = 0; - file = fopen(item_path, "rt"); + file = gf_fopen(item_path, "rt"); if (!file) { if (lc->verbose) fprintf(stdout, "Could not open file %s\n", item_path); e = GF_IO_ERR; } else { fseek(file, 0, SEEK_END); *size = (u32)ftell(file); - fclose(file); + gf_fclose(file); if (*size == 0) { if (lc->verbose) fprintf(stdout, "File %s has a size of 0\n", item_path); e = GF_IO_ERR; @@ -436,19 +436,19 @@ GF_Err create_gz_file(GF_LoadCompare *lc, char *item_name, char *item_path, u32 strcpy(gz_path, item_name); strcat(gz_path, "z"); gz = gzopen(gz_path, "wb"); - file = fopen(item_path, "rt"); + file = gf_fopen(item_path, "rt"); if (!gz || !file) { if (lc->verbose) fprintf(stdout, "Could not open file %s or %s\n", item_path, gz_path); e = GF_IO_ERR; } else { while ((read = fread(buffer, 1, 100, file))) gzwrite(gz, buffer, read); - fclose(file); + gf_fclose(file); gzclose(gz); - file = fopen(gz_path, "rb"); + file = gf_fopen(gz_path, "rb"); fseek(file, 0, SEEK_END); *size = (u32)ftell(file); - fclose(file); + gf_fclose(file); if (*size == 0) { if (lc->verbose) fprintf(stdout, "File %s has a size of 0\n", gz_path); e = GF_IO_ERR; @@ -645,7 +645,7 @@ int main(int argc, char **argv) } gf_sys_init(); - if (out) lc.out = fopen(out, "wt"); + if (out) lc.out = gf_fopen(out, "wt"); if (!lc.out) { fprintf(stderr, "Cannot open output file %s\n", out); return -1; @@ -691,7 +691,7 @@ int main(int argc, char **argv) } gf_list_del(lc.data); - if (lc.out) fclose(lc.out); + if (lc.out) gf_fclose(lc.out); gf_sys_close(); return 0; } diff --git a/applications/testapps/mp42ts/mp42ts.vcproj b/applications/testapps/mp42ts/mp42ts.vcproj index 31e13cb..0b2ab64 100644 --- a/applications/testapps/mp42ts/mp42ts.vcproj +++ b/applications/testapps/mp42ts/mp42ts.vcproj @@ -1,217 +1,217 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/testapps/mpedemux/main.c b/applications/testapps/mpedemux/main.c index f10076e..a3389d3 100644 --- a/applications/testapps/mpedemux/main.c +++ b/applications/testapps/mpedemux/main.c @@ -87,7 +87,7 @@ int main(int argc, char **argv) mpedemux->ts_demux->on_event = mpedemux_on_event; mpedemux->ts_demux->user = mpedemux; - mpedemux->ts_file = fopen(argv[1], "rb"); + mpedemux->ts_file = gf_fopen(argv[1], "rb"); while (1) { /*read chunks by chunks*/ diff --git a/applications/testapps/mpedemux/mpedemux.dsp b/applications/testapps/mpedemux/mpedemux.dsp index b4f3317..5aae5e6 100644 --- a/applications/testapps/mpedemux/mpedemux.dsp +++ b/applications/testapps/mpedemux/mpedemux.dsp @@ -1,90 +1,90 @@ -# Microsoft Developer Studio Project File - Name="mpedemux" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=mpedemux - 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 "mpedemux.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 "mpedemux.mak" CFG="mpedemux - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mpedemux - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "mpedemux - 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)" == "mpedemux - 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 zlib.lib winmm.lib ws2_32.lib js32.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/mpedemux.exe" /libpath:"../../../extra_lib/lib/w32_rel" - -!ELSEIF "$(CFG)" == "mpedemux - 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 zlib.lib winmm.lib ws2_32.lib js32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/mpedemux.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" - -!ENDIF - -# Begin Target - -# Name "mpedemux - Win32 Release" -# Name "mpedemux - Win32 Debug" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="mpedemux" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mpedemux - 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 "mpedemux.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 "mpedemux.mak" CFG="mpedemux - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mpedemux - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mpedemux - 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)" == "mpedemux - 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 zlib.lib winmm.lib ws2_32.lib js32.lib /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/mpedemux.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "mpedemux - 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 zlib.lib winmm.lib ws2_32.lib js32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/mpedemux.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "mpedemux - Win32 Release" +# Name "mpedemux - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/applications/testapps/mpeg2ts/main.c b/applications/testapps/mpeg2ts/main.c index 0d27634..a9f3a84 100644 --- a/applications/testapps/mpeg2ts/main.c +++ b/applications/testapps/mpeg2ts/main.c @@ -46,7 +46,7 @@ int main(int argc, char **argv) u32 size, fsize, fdone; GF_M2TS_Demuxer *ts; - FILE *src = fopen(argv[1], "rb"); + FILE *src = gf_fopen(argv[1], "rb"); ts = gf_m2ts_demux_new(); ts->on_event = on_m2ts_event; @@ -63,9 +63,9 @@ int main(int argc, char **argv) if (has_seen_pat) break; } - dest = fopen("pes.mp3", "wb"); + dest = gf_fopen("pes.mp3", "wb"); gf_m2ts_reset_parsers(ts); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_SET); fdone = 0; while (!feof(src)) { size = fread(data, 1, 188, src); @@ -78,9 +78,9 @@ int main(int argc, char **argv) } gf_set_progress("MPEG-2 TS Parsing", fsize, fsize); - fclose(src); + gf_fclose(src); gf_m2ts_demux_del(ts); - if (dest) fclose(dest); + if (dest) gf_fclose(dest); return 0; } diff --git a/applications/testapps/mpeg2ts/mpeg2ts.dsp b/applications/testapps/mpeg2ts/mpeg2ts.dsp index 37052e4..656390f 100644 --- a/applications/testapps/mpeg2ts/mpeg2ts.dsp +++ b/applications/testapps/mpeg2ts/mpeg2ts.dsp @@ -1,100 +1,100 @@ -# Microsoft Developer Studio Project File - Name="mpeg2ts" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=mpeg2ts - 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 "mpeg2ts.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 "mpeg2ts.mak" CFG="mpeg2ts - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mpeg2ts - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "mpeg2ts - 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)" == "mpeg2ts - 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 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)" == "mpeg2ts - 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 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 zlib.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "mpeg2ts - Win32 Release" -# Name "mpeg2ts - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="mpeg2ts" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mpeg2ts - 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 "mpeg2ts.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 "mpeg2ts.mak" CFG="mpeg2ts - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mpeg2ts - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mpeg2ts - 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)" == "mpeg2ts - 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 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)" == "mpeg2ts - 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 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 zlib.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mpeg2ts - Win32 Release" +# Name "mpeg2ts - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/applications/testapps/segmp4demux/build.sh b/applications/testapps/segmp4demux/build.sh index 36dab12..d1dd330 100644 --- a/applications/testapps/segmp4demux/build.sh +++ b/applications/testapps/segmp4demux/build.sh @@ -1,2 +1,2 @@ #!/bin/sh -gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB +gcc -o fmp4demux main.c ../../../src/utils/os_config_init.c ../../../src/utils/os_divers.c ../../../src/utils/os_file.c ../../../src/utils/os_thread.c ../../../src/utils/alloc.c ../../../src/utils/bitstream.c ../../../src/utils/configfile.c ../../../src/odf/desc_private.c ../../../src/odf/descriptors.c ../../../src/utils/error.c ../../../src/utils/list.c ../../../src/odf/odf_code.c ../../../src/odf/odf_codec.c ../../../src/odf/odf_command.c ../../../src/odf/odf_parse.c ../../../src/odf/slc.c ../../../src/utils/url.c ../../../src/media_tools/webvtt.c ../../../src/isomedia/avc_ext.c ../../../src/isomedia/box_code_3gpp.c ../../../src/isomedia/box_code_adobe.c ../../../src/isomedia/box_code_apple.c ../../../src/isomedia/box_code_base.c ../../../src/isomedia/box_code_drm.c ../../../src/isomedia/box_code_meta.c ../../../src/isomedia/box_funcs.c ../../../src/isomedia/data_map.c ../../../src/isomedia/drm_sample.c ../../../src/isomedia/isom_intern.c ../../../src/isomedia/isom_read.c ../../../src/isomedia/isom_store.c ../../../src/isomedia/isom_write.c ../../../src/isomedia/media.c ../../../src/isomedia/media_odf.c ../../../src/isomedia/meta.c ../../../src/isomedia/movie_fragments.c ../../../src/isomedia/sample_descs.c ../../../src/isomedia/stbl_read.c ../../../src/isomedia/stbl_write.c ../../../src/isomedia/track.c ../../../src/isomedia/tx3g.c -L../../../bin/gcc -lpthread -ldl -I../../../include -DGPAC_MINIMAL_ODF -DGPAC_DISABLE_AV_PARSERS -DGPAC_DISABLE_ISOM_DUMP -DGPAC_DISABLE_ZLIB diff --git a/applications/testapps/segmp4demux/segmp4demux.sln b/applications/testapps/segmp4demux/segmp4demux.sln index 8430f20..ca63192 100644 --- a/applications/testapps/segmp4demux/segmp4demux.sln +++ b/applications/testapps/segmp4demux/segmp4demux.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segmp4demux", "segmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 - {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 - {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 - {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segmp4demux", "segmp4demux.vcxproj", "{978A2D9F-E44F-4073-8032-333563BCC160}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.ActiveCfg = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Debug|Win32.Build.0 = Debug|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.ActiveCfg = Release|Win32 + {978A2D9F-E44F-4073-8032-333563BCC160}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/applications/testapps/segmp4demux/segmp4demux.vcxproj b/applications/testapps/segmp4demux/segmp4demux.vcxproj index aba1919..94ff320 100644 --- a/applications/testapps/segmp4demux/segmp4demux.vcxproj +++ b/applications/testapps/segmp4demux/segmp4demux.vcxproj @@ -1,190 +1,191 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {978A2D9F-E44F-4073-8032-333563BCC160} - segmp4demux - - - - Application - v110 - false - MultiByte - - - Application - v110 - false - MultiByte - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.60610.1 - - - ../../../bin/$(Platform)\$(Configuration)/ - obj\$(Platform)\$(Configuration)\$(ProjectName)\ - true - AllRules.ruleset - - - - - ../../../bin/$(Platform)\$(Configuration)/ - obj\$(Platform)\$(Configuration)\$(ProjectName)\ - false - AllRules.ruleset - - - - - - .\Debug/segmp4demux.tlb - - - - Disabled - ../../../include;%(AdditionalIncludeDirectories) - GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - $(IntDir) - $(IntDir) - $(IntDir) - true - Level3 - true - EditAndContinue - - - - - _DEBUG;%(PreprocessorDefinitions) - 0x040c - - - %(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - true - $(IntDir)$(ProjectName).pdb - Console - MachineX86 - - - true - .\Debug/segmp4demux.bsc - - - - - .\Release/segmp4demux.tlb - - - - MaxSpeed - OnlyExplicitInline - ../../../include;%(AdditionalIncludeDirectories) - GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_CORE_TOOLS;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\Release/segmp4demux.pch - .\Release/ - .\Release/ - .\Release/ - Level3 - true - - - NDEBUG;%(PreprocessorDefinitions) - 0x040c - - - %(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - true - ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) - .\Release/segmp4demux.pdb - Console - MachineX86 - - - true - .\Release/segmp4demux.bsc - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + + GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {365CEAE9-305B-43C9-B531-904E500F0809} + segmp4demux + + + + Application + v110 + false + MultiByte + + + Application + v100 + false + MultiByte + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + true + AllRules.ruleset + + + + + ../../../bin/$(Platform)\$(Configuration)/ + obj\$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + + + + .\Debug/segmp4demux.tlb + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZLIB;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir) + $(IntDir) + $(IntDir) + true + Level3 + true + EditAndContinue + + + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + $(OutDir);../../../extra_lib/lib/$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(IntDir)$(ProjectName).pdb + Console + MachineX86 + + + true + .\Debug/segmp4demux.bsc + + + + + .\Release/segmp4demux.tlb + + + + MaxSpeed + OnlyExplicitInline + ../../../include;%(AdditionalIncludeDirectories) + GPAC_DISABLE_MEDIA_IMPORT;GPAC_DISABLE_CORE_TOOLS;GPAC_DISABLE_ISOM_HINTING;GPAC_MINIMAL_ODF;GPAC_DISABLE_AV_PARSERS;GPAC_DISABLE_ISOM_DUMP;GPAC_DISABLE_ZILB;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\Release/segmp4demux.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + %(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ../../../extra_lib/lib/w32_rel;%(AdditionalLibraryDirectories) + .\Release/segmp4demux.pdb + Console + MachineX86 + + + true + .\Release/segmp4demux.bsc + + + + + \ No newline at end of file diff --git a/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters b/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters index 3f80c02..4a097c1 100644 --- a/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters +++ b/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters @@ -1,134 +1,137 @@ - - - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - isoff - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - others - - - - others - - - others - - - others - - - others - - - others - - - others - - - isoff - - - - - {c9a8f639-328c-4505-be50-4859357c2c00} - - - {e5ca7285-ca00-49d8-ac81-dff3d494be9a} - - + + + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + isoff + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + others + + + + others + + + others + + + others + + + others + + + others + + + others + + + isoff + + + others + + + + + {c9a8f639-328c-4505-be50-4859357c2c00} + + + {e5ca7285-ca00-49d8-ac81-dff3d494be9a} + + \ No newline at end of file diff --git a/applications/testapps/svg2bifs/svg2bifs.dsp b/applications/testapps/svg2bifs/svg2bifs.dsp index 335a2ce..066739a 100644 --- a/applications/testapps/svg2bifs/svg2bifs.dsp +++ b/applications/testapps/svg2bifs/svg2bifs.dsp @@ -1,90 +1,90 @@ -# Microsoft Developer Studio Project File - Name="svg2bifs" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=svg2bifs - 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 "svg2bifs.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 "svg2bifs.mak" CFG="svg2bifs - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "svg2bifs - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "svg2bifs - 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)" == "svg2bifs - 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 /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/svg2bifs.exe" /libpath:"../../../extra_lib/lib/w32_rel" - -!ELSEIF "$(CFG)" == "svg2bifs - 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" /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 /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/svg2bifs.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" - -!ENDIF - -# Begin Target - -# Name "svg2bifs - Win32 Release" -# Name "svg2bifs - Win32 Debug" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="svg2bifs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=svg2bifs - 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 "svg2bifs.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 "svg2bifs.mak" CFG="svg2bifs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "svg2bifs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "svg2bifs - 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)" == "svg2bifs - 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 /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/svg2bifs.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "svg2bifs - 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" /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 /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/svg2bifs.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" + +!ENDIF + +# Begin Target + +# Name "svg2bifs - Win32 Release" +# Name "svg2bifs - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/applications/ts2hds/f4m.c b/applications/ts2hds/f4m.c index 74f9603..0a51ba1 100644 --- a/applications/ts2hds/f4m.c +++ b/applications/ts2hds/f4m.c @@ -70,7 +70,7 @@ AdobeMultirate *adobe_alloc_multirate_manifest(char *id) am->base_url = "http://localhost/hds/tmp"; am->id = id; sprintf(filename, "%s.f4m", am->id); - am->f = fopen(filename, "wt"); + am->f = gf_fopen(filename, "wt"); if (!am->f) { fprintf(stderr, "Couldn't create Adobe multirate manifest file: %s\n", filename); assert(0); @@ -85,7 +85,7 @@ AdobeMultirate *adobe_alloc_multirate_manifest(char *id) as->id = "HD"; as->bitrate = 100; sprintf(filename, "%s_%s_%d.f4m", am->id, as->id, as->bitrate); - as->f = fopen(filename, "wt"); + as->f = gf_fopen(filename, "wt"); if (!as->f) { fprintf(stderr, "Couldn't create Adobe stream manifest file: %s\n", filename); assert(0); @@ -105,13 +105,13 @@ void adobe_free_multirate_manifest(AdobeMultirate *am) u32 i; if (am->f) - fclose(am->f); + gf_fclose(am->f); for (i=0; istreams); i++) { AdobeStream *as = gf_list_get(am->streams, i); assert(as); if (as->f) - fclose(as->f); + gf_fclose(as->f); //TODO: base_url and id may be stored as gf_strdup in the future gf_list_rem(am->streams, i); gf_free(as); @@ -154,9 +154,9 @@ GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t char filename[GF_MAX_PATH]; FILE *bstfile; sprintf(filename, "%s_%d.bootstrap", as->id, as->bitrate); - bstfile = fopen(filename, "wb"); + bstfile = gf_fopen(filename, "wb"); gf_fwrite(bootstrap, bootstrap_size, 1, bstfile); - fclose(bstfile); + gf_fclose(bstfile); } #endif e = adobe_gen_stream_manifest(as); diff --git a/applications/ts2hds/main.c b/applications/ts2hds/main.c index 0932fb3..6a707c8 100644 --- a/applications/ts2hds/main.c +++ b/applications/ts2hds/main.c @@ -51,7 +51,7 @@ static GFINLINE void usage(const char * progname) #ifdef GPAC_MEMORY_TRACKING "\t-mem-track: enables memory tracker\n" #endif - ); + , progname); } @@ -118,7 +118,7 @@ int main(int argc, char **argv) /* declarations */ /********************/ char *input, *output, tmpstr[GF_MAX_PATH]; - GF_ISOFile *isom_file_in, *isom_file_out; + GF_ISOFile *isom_file_in; GF_MediaImporter import; AdobeHDSCtx ctx; GF_Err e; @@ -136,7 +136,6 @@ int main(int argc, char **argv) input = NULL; output = NULL; isom_file_in = NULL; - isom_file_out = NULL; memset(&import, 0, sizeof(GF_MediaImporter)); e = GF_OK; memset(&ctx, 0, sizeof(ctx)); @@ -160,16 +159,16 @@ int main(int argc, char **argv) u32 metamoov64_len; unsigned char metamoov[GF_MAX_PATH]; u32 metamoov_len=GF_MAX_PATH; - FILE *f = fopen("metamoov64"/*input*/, "rt"); - gf_f64_seek(f, 0, SEEK_END); - metamoov64_len = (u32)gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + FILE *f = gf_fopen("metamoov64"/*input*/, "rt"); + gf_fseek(f, 0, SEEK_END); + metamoov64_len = (u32)gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); fread(metamoov64, metamoov64_len, 1, f); metamoov_len = gf_base64_decode(metamoov64, metamoov64_len, metamoov, metamoov_len); - fclose(f); - f = fopen("metamoov", "wb"); + gf_fclose(f); + f = gf_fopen("metamoov", "wb"); fwrite(metamoov, metamoov_len, 1, f); - fclose(f); + gf_fclose(f); return 0; } #endif @@ -183,17 +182,17 @@ int main(int argc, char **argv) GF_AdobeBootstrapInfoBox *abst = (GF_AdobeBootstrapInfoBox *)abst_New(); GF_BitStream *bs; #if 1 //64 - FILE *f = fopen("bootstrap64"/*input*/, "rt"); - gf_f64_seek(f, 0, SEEK_END); - bootstrap64_len = (u32)gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + FILE *f = gf_fopen("bootstrap64"/*input*/, "rt"); + gf_fseek(f, 0, SEEK_END); + bootstrap64_len = (u32)gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); fread(bootstrap64, bootstrap64_len, 1, f); bootstrap_len = gf_base64_decode(bootstrap64, bootstrap64_len, bootstrap, bootstrap_len); #else //binary bootstrap - FILE *f = fopen("bootstrap.bin"/*input*/, "rb"); - gf_f64_seek(f, 0, SEEK_END); - bootstrap_len = (u32)gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + FILE *f = gf_fopen("bootstrap.bin"/*input*/, "rb"); + gf_fseek(f, 0, SEEK_END); + bootstrap_len = (u32)gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); fread(bootstrap, bootstrap_len, 1, f); #endif bs = gf_bs_new(bootstrap+8, bootstrap_len-8, GF_BITSTREAM_READ); @@ -207,13 +206,13 @@ int main(int argc, char **argv) abst_Write((GF_Box*)abst, bs); bootstrap_len = (u32)gf_bs_get_position(bs); gf_bs_del(bs); - fclose(f); - f = fopen("bootstrap", "wt"); + gf_fclose(f); + f = gf_fopen("bootstrap", "wt"); bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_len, bootstrap64, GF_MAX_PATH); fwrite(bootstrap64, bootstrap64_len, 1, f); fprintf(f, "\n\n"); abst_dump((GF_Box*)abst, f); - fclose(f); + gf_fclose(f); abst_del((GF_Box*)abst); return 0; } diff --git a/applications/udptsseg/main.c b/applications/udptsseg/main.c index 3163737..5f41603 100644 --- a/applications/udptsseg/main.c +++ b/applications/udptsseg/main.c @@ -47,7 +47,7 @@ static GF_Err write_manifest(char *manifest, char *segment_dir, u32 segment_dura sprintf(manifest_name, "%s", manifest); } - manifest_fp = fopen(tmp_manifest, "w"); + manifest_fp = gf_fopen(tmp_manifest, "w"); if (!manifest_fp) { fprintf(stderr, "Could not create m3u8 manifest file (%s)\n", tmp_manifest); return GF_BAD_PARAM; @@ -62,7 +62,7 @@ static GF_Err write_manifest(char *manifest, char *segment_dir, u32 segment_dura if (end) { fprintf(manifest_fp, "#EXT-X-ENDLIST\n"); } - fclose(manifest_fp); + gf_fclose(manifest_fp); if (!rename(tmp_manifest, manifest_name)) { return GF_OK; @@ -213,7 +213,7 @@ int main(int argc, char **argv) } //write_manifest(segment_manifest, segment_dir, segment_duration, segment_prefix, segment_http_prefix, segment_index, 0, 0); } - ts_output_file = fopen(ts_out, "wb"); + ts_output_file = gf_fopen(ts_out, "wb"); if (!ts_output_file) { fprintf(stderr, "Error opening %s\n", ts_out); goto exit; @@ -265,7 +265,7 @@ int main(int argc, char **argv) } if ((now - last_segment_time) > segment_duration*1000) { last_segment_time = now; - fclose(ts_output_file); + gf_fclose(ts_output_file); fprintf(stderr, "Closing segment %s (%d bytes)\n", segment_name, last_segment_size); last_segment_size = 0; segment_index++; @@ -278,7 +278,7 @@ int main(int argc, char **argv) } else { sprintf(segment_name, "%s_%d.ts", segment_prefix, segment_index); } - ts_output_file = fopen(segment_name, "wb"); + ts_output_file = gf_fopen(segment_name, "wb"); if (!ts_output_file) { fprintf(stderr, "Error opening segment %s\n", segment_name); goto exit; diff --git a/applications/udptsseg/udptsseg.dsp b/applications/udptsseg/udptsseg.dsp index 5b39e61..008363c 100644 --- a/applications/udptsseg/udptsseg.dsp +++ b/applications/udptsseg/udptsseg.dsp @@ -1,94 +1,94 @@ -# Microsoft Developer Studio Project File - Name="udptsseg" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=udptsseg - 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 "udptsseg.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 "udptsseg.mak" CFG="udptsseg - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "udptsseg - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "udptsseg - 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)" == "udptsseg - 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 /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/udptsseg.exe" /libpath:"../../../extra_lib/lib/w32_rel" - -!ELSEIF "$(CFG)" == "udptsseg - 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 /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/udptsseg.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" -# SUBTRACT LINK32 /nodefaultlib - -!ENDIF - -# Begin Target - -# Name "udptsseg - Win32 Release" -# Name "udptsseg - Win32 Debug" -# Begin Source File - -SOURCE=.\main.c -# End Source File -# Begin Source File - -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="udptsseg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=udptsseg - 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 "udptsseg.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 "udptsseg.mak" CFG="udptsseg - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "udptsseg - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "udptsseg - 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)" == "udptsseg - 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 /nologo /subsystem:console /machine:I386 /out:"../../../bin/w32_rel/udptsseg.exe" /libpath:"../../../extra_lib/lib/w32_rel" + +!ELSEIF "$(CFG)" == "udptsseg - 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 /nologo /subsystem:console /debug /machine:I386 /out:"../../../bin/w32_deb/udptsseg.exe" /pdbtype:sept /libpath:"../../../extra_lib/lib/w32_deb" +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "udptsseg - Win32 Release" +# Name "udptsseg - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +# End Source File +# End Target +# End Project diff --git a/applications/udptsseg/udptsseg.vcproj b/applications/udptsseg/udptsseg.vcproj index 903fc49..8d40855 100644 --- a/applications/udptsseg/udptsseg.vcproj +++ b/applications/udptsseg/udptsseg.vcproj @@ -1,213 +1,213 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/smartphone 2003 (armv4)/release/install/archive.bat b/bin/smartphone 2003 (armv4)/release/install/archive.bat index 7ec194b..d8b2c8d 100644 --- a/bin/smartphone 2003 (armv4)/release/install/archive.bat +++ b/bin/smartphone 2003 (armv4)/release/install/archive.bat @@ -1,9 +1,16 @@ -set OLDDIR=%CD% -cd /d %~dp0 - -for /f "delims=" %%a in ('svnversion ') do set gpac_revision=%%a -set gpac_version="0.5.1-DEV-r%gpac_revision%" - -zip "GPAC_%gpac_version%_WindowsMobile.zip" ../*.dll ../*.exe ../*.plg - -cd /d %OLDDIR% +set OLDDIR=%CD% +cd /d %~dp0 + +for /f "delims=" %%a in ('git describe --tags --long') do @set VERSION=%%a +for /f "delims=" %%a in ('git describe --tags --abbrev=0') do @set TAG=%%a- +for /f "delims=" %%a in ('git rev-parse --abbrev-ref HEAD') do @set BRANCH=%%a +REM remove anotated tag from VERSION +setlocal enabledelayedexpansion +call set VERSION=%%VERSION:!TAG!=%% +setlocal disabledelayedexpansion +set revision="%VERSION%-%BRANCH%" +set gpac_version="0.5.2-DEV-r%gpac_revision%" + +zip "GPAC_%gpac_version%_WindowsMobile.zip" ../*.dll ../*.exe ../*.plg + +cd /d %OLDDIR% diff --git a/bin/smartphone 2003 (armv4)/release/install/build_installer.bat b/bin/smartphone 2003 (armv4)/release/install/build_installer.bat index ad3dcad..368a708 100644 --- a/bin/smartphone 2003 (armv4)/release/install/build_installer.bat +++ b/bin/smartphone 2003 (armv4)/release/install/build_installer.bat @@ -1,35 +1,42 @@ -set OLDDIR=%CD% -cd /d %~dp0 - -for /f "delims=" %%a in ('svnversion') do set gpac_revision=%%a - -set gpac_version="0.5.1-DEV-r%gpac_revision%" - -ECHO [Version] > gpaccab.inf -ECHO Provider = "GPAC %gpac_version%" >> gpaccab.inf -type gpac.inf >> gpaccab.inf - -CabWiz gpaccab.inf - -ECHO off - -ECHO [CEAppManager]> gpac.ini -ECHO Version = %gpac_version%>> gpac.ini -ECHO Component = GPAC for Windows Mobile>> gpac.ini -ECHO [GPAC for Windows Mobile]>> gpac.ini -ECHO Description = GPAC MPEG-4 Player>> gpac.ini -ECHO Uninstall = GPAC Osmophone>> gpac.ini -ECHO IconFile = ..\..\..\..\doc\osmo4.ico>> gpac.ini -ECHO IconIndex = 0 >> gpac.ini -ECHO CabFiles = gpaccab.cab >> gpac.ini - -ECHO on - -ezsetup -l english -i gpac.ini -r readme.txt -e ../../../../COPYING -o gpac.exe -rename gpac.exe "GPAC_%gpac_version%_WindowsMobile.exe" -DEL gpaccab.cab -DEL gpaccab.inf -DEL gpac.ini -DEL *.tmp - -cd /d %OLDDIR% +set OLDDIR=%CD% +cd /d %~dp0 + +for /f "delims=" %%a in ('git describe --tags --long') do @set VERSION=%%a +for /f "delims=" %%a in ('git describe --tags --abbrev=0') do @set TAG=%%a- +for /f "delims=" %%a in ('git rev-parse --abbrev-ref HEAD') do @set BRANCH=%%a +REM remove anotated tag from VERSION +setlocal enabledelayedexpansion +call set VERSION=%%VERSION:!TAG!=%% +setlocal disabledelayedexpansion +set revision="%VERSION%-%BRANCH%" + +set gpac_version="0.5.2-DEV-r%gpac_revision%" + +ECHO [Version] > gpaccab.inf +ECHO Provider = "GPAC %gpac_version%" >> gpaccab.inf +type gpac.inf >> gpaccab.inf + +CabWiz gpaccab.inf + +ECHO off + +ECHO [CEAppManager]> gpac.ini +ECHO Version = %gpac_version%>> gpac.ini +ECHO Component = GPAC for Windows Mobile>> gpac.ini +ECHO [GPAC for Windows Mobile]>> gpac.ini +ECHO Description = GPAC MPEG-4 Player>> gpac.ini +ECHO Uninstall = GPAC Osmophone>> gpac.ini +ECHO IconFile = ..\..\..\..\doc\osmo4.ico>> gpac.ini +ECHO IconIndex = 0 >> gpac.ini +ECHO CabFiles = gpaccab.cab >> gpac.ini + +ECHO on + +ezsetup -l english -i gpac.ini -r readme.txt -e ../../../../COPYING -o gpac.exe +rename gpac.exe "GPAC_%gpac_version%_WindowsMobile.exe" +DEL gpaccab.cab +DEL gpaccab.inf +DEL gpac.ini +DEL *.tmp + +cd /d %OLDDIR% diff --git a/bin/smartphone 2003 (armv4)/release/install/readme.txt b/bin/smartphone 2003 (armv4)/release/install/readme.txt index 08442c1..43ce565 100644 --- a/bin/smartphone 2003 (armv4)/release/install/readme.txt +++ b/bin/smartphone 2003 (armv4)/release/install/readme.txt @@ -1,6 +1,6 @@ -This will install GPAC for ARM PocketPC/SmartPhones 2003 Platforms - -GPAC is an open source MPEG-4 framework developped by ENST and available at: - http://gpac.sourceforge.net - -WARNING: THIS RELEASE COMES WITH NO WARRANTY, AND MAY EVEN DAMAGE YOUR HANDHELD DEVICE. PLEASE READ CAREFULLY THE LICENSE HEREJOIN +This will install GPAC for ARM PocketPC/SmartPhones 2003 Platforms + +GPAC is an open source MPEG-4 framework developped by ENST and available at: + http://gpac.sourceforge.net + +WARNING: THIS RELEASE COMES WITH NO WARRANTY, AND MAY EVEN DAMAGE YOUR HANDHELD DEVICE. PLEASE READ CAREFULLY THE LICENSE HEREJOIN diff --git a/configure b/configure index 446acd6..55d7b4c 100755 --- a/configure +++ b/configure @@ -26,6 +26,7 @@ TMPCXX="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.cpp" TMPE="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}" TMPO="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.o" TMPS="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.S" +TMPL="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.LOG" #default parameters @@ -90,7 +91,6 @@ has_x11_xv="no" no_gcc_opt="no" use_fixed_point="no" use_memory_tracking="no" -use_std_alloc="no" has_opengl="no" has_tinygl="no" enable_tinygl="no" @@ -102,6 +102,7 @@ has_openjpeg="no" gprof_build="no" static_build="no" want_pic="no" +want_gcov="no" has_joystick="no" has_xul="no" enable_joystick="no" @@ -178,13 +179,16 @@ need_inet_aton="no" CFLAGS="" CXXFLAGS="" GPAC_SH_FLAGS=-lpthread -DYN_LIB_SUFFIX="so" +DYN_LIB_SUFFIX=".so" X11_PATH="/usr/X11R6" OSS_CFLAGS="" OSS_LDFLAGS="" INSTFLAGS="" is_64="no" +ffmpeg_extra_ldflags="" +logs="config.log" +echo "Logs for GPAC configure $GPAC_CONFIGURATION" > $logs #configure usage @@ -216,14 +220,16 @@ GPAC configuration options: --dxsdk-path=DX_PATH specify directX SDK for MinGW [$dxsdk_path] --xulsdk-path=XUL_PATH specify Mozilla XUL (Gecko) SDK include path [$xulsdk_path] --mozdir=MOZ_PATH specify mozilla main directory path for system install + --extra-ff-ldflags=ELDFLAGS add ELDFLAGS to FFMPEG LDFLAGS [$ffmpeg_extra_ldflags] --enable-debug produce debug version --enable-gprof enable profiling + --enable-gcov enable coverage --enable-pic enable Position Independant Code for shared objects --strip enable strip --std-allocator uses standard lib memory allocator - --static-modules uses static modules whenever possible - --track-memory enable tracking of all memory allocated by gpac + --static-modules includes static modules in libgpac whenever possible + --enable-mem-track enable tracking of all memory allocated by gpac --disable-opt disable GCC optimizations --disable-ipv6 disable IPV6 support --disable-wx disable wxWidgets support @@ -244,8 +250,8 @@ GPAC configuration options: --enable-amr-nb enable AMR NB library --enable-amr-wb enable AMR WB library --enable-amr enable both AMR NB and WB libraries - --enable-static-bin GPAC static build - --static-mp4box configure for static linking of MP4Box. + --enable-static-bin link statically against libgpac + --static-mp4box configure for static linking of MP4Box only. --enable-depth enables depth handling in the compositor Configuration options for libgpac - all options can be enabled with --enable-optname @@ -323,9 +329,9 @@ for opt do ;; --mandir=*) mandir=`echo $opt | cut -d '=' -f 2` ;; - --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` && echo "\ncross-prefix detected: $cross_prefix" + --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` && echo "cross-prefix detected: $cross_prefix" ;; - --target-os=*) targetos=`echo $opt | cut -d '=' -f 2` && echo "\ntarget-os detected: $targetos" + --target-os=*) targetos=`echo $opt | cut -d '=' -f 2` && echo "target-os detected: $targetos" ;; --cc=*) cc_orig=`echo $opt | cut -d '=' -f 2` ;; @@ -339,6 +345,8 @@ for opt do ;; --extra-ldflags=*) LDFLAGS="$LDFLAGS ${opt#--extra-ldflags=}" ;; + --extra-ff-ldflags=*) ffmpeg_extra_ldflags=`echo $opt | cut -d '=' -f 2` + ;; --extra-libs=*) extralibs=${opt#--extra-libs=} ;; --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` @@ -349,11 +357,14 @@ for opt do ;; --enable-pic) want_pic="yes"; ;; + --enable-gcov) want_gcov="yes"; + ;; --verbose) verbose="yes"; ;; esac done + cc="${cc_orig}" cxx="${cxx_orig}" @@ -382,7 +393,7 @@ case "$cpu" in if [ -z "`echo $CFLAGS | grep -- -m32`" ]; then cpu="x86_64" want_pic="yes" - is_64="yes" + is_64="yes" fi fi ;; @@ -422,14 +433,6 @@ if test -z "$CFLAGS"; then CFLAGS="" fi -#if test "$win32" = "yes" ; then -# cross_prefix="" -#fi - -#if test "$mingw32" = "yes" ; then -# cross_prefix="" -#fi - cc="${cross_prefix}${cc}" #for ccache @@ -444,8 +447,8 @@ windres="${cross_prefix}${windres}" #check pkg_config if test "$cross_prefix" = "" ; then - if ! $pkg_config --version >/dev/null 2>&1 ; then - pkg_config="no" + if ! $pkg_config --version >/dev/null 2>>$logs ; then + pkg_config="no" fi fi @@ -456,8 +459,10 @@ source_path_used="yes" if test -z "$source_path" -o "$source_path" = "." ; then source_path="`pwd`" source_path_used="no" + build_path=$source_path else source_path="`cd \"$source_path\"; pwd`" + build_path="`pwd`" fi @@ -472,7 +477,7 @@ case $targetos in prefix="/boot/home/config" CFLAGS="$CFLAGS -DPIC -fomit-frame-pointer" # 3 gcc releases known for BeOS, each with ugly bugs - gcc_version="$($cc -v 2>&1 | grep version | cut -d ' ' -f3-)" + gcc_version="$($cc -v 2>>$logs | grep version | cut -d ' ' -f3-)" case "$gcc_version" in 2.9-beos-991026*|2.9-beos-000224*) echo "R5/GG gcc" ;; @@ -502,9 +507,8 @@ case $targetos in #include int main( void ) { return 0; } EOF - CFLAGS_NO_LTO=$(echo ${CFLAGS} | sed -e 's/\ -flto[-A-Za-z0-9=]*//g') - $cc ${CFLAGS_NO_LTO} -o $TMPO $TMPC 2>/dev/null && $($readelf -h $TMPO | grep "Class:.*ELF64$" >/dev/null 2>&1) + $cc ${CFLAGS_NO_LTO} -o $TMPO $TMPC 2>>$logs && $($readelf -h $TMPO | grep "Class:.*ELF64$" >/dev/null 2>>$logs) if test $? -eq 0; then is_64="yes" fi @@ -549,7 +553,7 @@ EOF cc="cc" Mac_Applications="/Applications" SHFLAGS="-dynamiclib" - DYN_LIB_SUFFIX="dylib" + DYN_LIB_SUFFIX=".dylib" extralibs="" GPAC_SH_FLAGS="" strip="strip -x" @@ -557,7 +561,7 @@ EOF LDFLAGS="$LDFLAGS" fi darwin="yes" - gcc_version=`$cc -v 2>&1 | grep version | cut -d ' ' -f3` + gcc_version=`$cc -v 2>>$logs | grep version | cut -d ' ' -f3` case "$gcc_version" in *2.95*) CFLAGS="$CFLAGS -no-cpp-precomp -pipe -fomit-frame-pointer" @@ -571,10 +575,11 @@ EOF esac ;; - MINGW32*) + MINGW32*|mingw32|MINGW64*|mingw64) js_flags="-DXP_PC -D_declspec=__declspec" mingw32="yes" win32="yes" + want_pic="no" extralibs="$extralibs -lws2_32 -lwinmm" CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" if test "$cross_prefix" != "" ; then @@ -582,25 +587,35 @@ EOF fi ;; - CYGWIN*) + CYGWIN*|cygwin*) js_flags=-DXP_PC extralibs="$extralibs -lws2_32 -lwinmm" cygwin="yes" win32="yes" ;; - Linux) + Linux|linux|android) js_flags="-DXP_UNIX -I/usr/include/js" LDFLAGS="$LDFLAGS -Wl,--warn-common -Wl,-z,defs" - #OSS_LDFLAGS="-laoss" linux="yes" case "$cpu" in sh4) CFLAGS="$CFLAGS -isystem \"$prefix/include\"" - #LDFLAGS="$LDFLAGS -L$prefix/lib" ;; esac - ;; + cat > $TMPC << EOF +#include +#if !defined (__BIONIC__) +#error +#endif +EOF + if $cc -c $CFLAGS $TMPC 0>/dev/null 2>$TMPL ; then + #bionic libc (android) + CFLAGS="$CFLAGS -DPTHREAD_HAS_NO_CANCEL" + GPAC_SH_FLAGS="" + fi + ;; + *) ;; esac @@ -608,7 +623,7 @@ esac #defines directory for binaries and libs (ex. for TinyGL) target_bin_dir="" if test "$cross_prefix" = "" ; then - target_bin_dir=`${cc} -v 2>&1 | sed -n '2p' | awk ' {print $2}'`-${cc_orig} + target_bin_dir=`${cc} -v 2>>$logs | sed -n '2p' | awk ' {print $2}'`-${cc_orig} else target_bin_dir=${cross_prefix}${cc_orig} fi @@ -626,17 +641,45 @@ local_inc=$source_path/extra_lib/include local_lib=extra_lib/lib/gcc +dolog() { + rv=$? + if [ $rv -eq 0 ] ; then + return 0; + fi + + echo "*** CC/CXX Test Failed (args $@) : ">>$logs + echo "">>$logs + cat $TMPL >> $logs + echo "">>$logs + echo "Source was: ">>$logs + cat $TMPC >> $logs + echo "">>$logs + echo "">>$logs + return 1; +} + +docc() { + $cc -o $TMPO $TMPC $@ 0>/dev/null 2>$TMPL + dolog $@ +} + + +docxx() { + $cc -o $TMPO $TMPC $@ 0>/dev/null 2>$TMPL + dolog $@ +} + #check GCC flags support cat > $TMPC << EOF #include int main( void ) { return 0; } EOF CFLAGS="$CFLAGS -Wall" -if $cc -o $TMPO $TMPC -fno-strict-aliasing 2> /dev/null ; then +if docc -fno-strict-aliasing ; then CFLAGS="$CFLAGS -fno-strict-aliasing" fi CXXFLAGS="$CFLAGS" -if $cc -o $TMPO $TMPC -lz -Wno-pointer-sign 2> /dev/null ; then +if docc -lz -Wno-pointer-sign ; then CFLAGS="$CFLAGS -Wno-pointer-sign" fi @@ -658,6 +701,11 @@ if test "$want_pic" = "yes" ; then CXXFLAGS="$CXXFLAGS -fPIC -DPIC" fi +if test "$want_gcov" = "yes" ; then + CFLAGS="$CFLAGS --coverage" + CXXFLAGS="$CXXFLAGS --coverage" + LDFLAGS="$LDFLAGS --coverage" +fi #force use of cflags with cc cc_naked=$cc @@ -668,27 +716,27 @@ cxx="$cxx $CXXFLAGS" #look for zlib cat > $TMPC << EOF #include -int main( void ) { } +int main( void ) { return 0; } EOF -if $cc -o $TMPO $TMPC -msse2 $LDFLAGS 2> /dev/null ; then +if docc -msse2 $LDFLAGS ; then CFLAGS="$CFLAGS -msse2" fi #look for zlib cat > $TMPC << EOF +#include +#include #include int main( void ) { if (strcmp(zlibVersion(), ZLIB_VERSION)) { puts("zlib version differs !!!"); return 1; } return 0; } EOF has_zlib="no" -#if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC -lz $LDFLAGS 2> /dev/null ; then - has_zlib="system" - fi -#fi +if docc -lz $LDFLAGS ; then + has_zlib="system" +fi if test "$has_zlib" = "no" ; then - if $cc -o $TMPO $TMPC -I"$local_inc/zlib" -L$local_lib -lz 2> /dev/null ; then + if docc -I"$local_inc/zlib" -L$local_lib -lz ; then has_zlib="local" fi fi @@ -696,12 +744,12 @@ fi #check dlopen cat > $TMPC << EOF #include -int main( void ) { return (int) dlopen("foo", 0); } +int main( void ) { dlopen("foo", 0); return 0; } EOF -if $cc -o $TMPE $TMPC > /dev/null 2>&1 ; then +if docc ; then dlopen="yes" -elif $cc -o $TMPE $TMPC $LDFLAGS -ldl > /dev/null 2>&1 ; then +elif docc $LDFLAGS -ldl ; then GPAC_SH_FLAGS="$GPAC_SH_FLAGS -ldl" fi @@ -716,43 +764,43 @@ if test "$has_js" = "no" ; then cat > $TMPC << EOF #include -int main( void ) { JSContext *cx; jsval *rp; return JS_AddValueRoot(cx, rp); } +int main( void ) { JSContext *cx=NULL; jsval rp; return JS_AddValueRoot(cx, &rp); } EOF #try local js_inc="$local_inc/js" js_flags="-DXP_UNIX -I$local_inc/js" - if $cc -o $TMPO $TMPC $js_flags -L$local_lib -ljs -lpthread 2> /dev/null ; then + if docc $js_flags -L$local_lib -ljs -lpthread ; then has_js="local" #dc added elif test "$pkg_config" != "no"; then #try pkg-config - if $pkg_config --exists mozilla-js 2> /dev/null ; then + if $pkg_config --exists mozilla-js ; then mozjs_pkgcfg="mozilla-js" - elif $pkg_config --exists mozjs 2> /dev/null ; then + elif $pkg_config --exists mozjs ; then mozjs_pkgcfg="mozjs" - elif $pkg_config --exists mozjs185 2> /dev/null ; then + elif $pkg_config --exists mozjs185 ; then mozjs_pkgcfg="mozjs185" - fi + fi if test $mozjs_pkgcfg != "no" ; then js_flags=`$pkg_config --cflags $mozjs_pkgcfg` js_lib_pkg=`$pkg_config --libs $mozjs_pkgcfg` - if $cc -o $TMPO $TMPC $js_flags $js_lib_pkg $LDFLAGS -lpthread 2> /dev/null ; then + if docc $js_flags $js_lib_pkg $LDFLAGS -lpthread ; then has_js="system" js_lib=`$pkg_config --libs $mozjs_pkgcfg` fi #try firefox folders (starting at ubuntu 11.10, no pkg-config) - elif ls -d /usr/lib/firefox* > /dev/null 2>&1 ; then + elif ls -d /usr/lib/firefox* > /dev/null 2>>$logs ; then firefox_version=`cd /usr/lib ; ls -d firefox* | grep -v addons | grep -v devel ; cd - > /dev/null` for i in $firefox_version ; do if test "$has_js" = "no" ; then js_inc="/usr/include/$i" js_flags="-DXP_UNIX -I$js_inc" js_lib="-L/usr/lib/$i/ -lxul -lmozsqlite3 -lmozalloc -lnssutil3 -lnss3 -lnspr4 -lsmime3" - if $cc -o $TMPO $TMPC $js_flags $js_lib 2> /dev/null ; then + if docc $js_flags $js_lib ; then has_js="$i" - elif $cc -o $TMPO $TMPC $js_flags -lnssutil3 $js_lib -lssl3 2> /dev/null ; then + elif docc $js_flags -lnssutil3 $js_lib -lssl3 ; then #firefox 11 compatibility has_js="$i" js_lib="-lnssutil3 $js_lib -lssl3" @@ -765,14 +813,14 @@ EOF #try prefix (DC) js_inc="$prefix/include/js" js_flags="-DXP_UNIX -I$prefix/include/js" - if $cc -o $TMPO $TMPC $js_flags -L$prefix/lib -ljs -lpthread 2> /dev/null ; then + if docc $js_flags -L$prefix/lib -ljs -lpthread ; then has_js="prefix" #dc added end else - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -ljs -lpthread 2> /dev/null ; then + if docc $js_flags $LDFLAGS -ljs -lpthread ; then js_inc="/usr/include" has_js="system" - elif $cc -o $TMPO $TMPC -DXP_UNIX -I$alt_macosx_dir/include/js -L$alt_macosx_dir/lib $LDFLAGS -ljs -lpthread 2> /dev/null ; then + elif docc -DXP_UNIX -I$alt_macosx_dir/include/js -L$alt_macosx_dir/lib $LDFLAGS -ljs -lpthread 2>>$logs ; then has_js="system" js_flags="-DXP_UNIX -I$alt_macosx_dir/include/js" js_lib="-L$alt_macosx_dir/lib -ljs" @@ -781,14 +829,14 @@ EOF #debian spidermonkey (smjs) js_flags="-DXP_UNIX -I/usr/include/smjs" js_inc="/usr/include/smjs" - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -lsmjs -lpthread 2> /dev/null ; then + if docc $js_flags $LDFLAGS -lsmjs -lpthread ; then has_js="system" js_lib="-lsmjs" else #debian spidermonkey (mozjs) js_flags="-DXP_UNIX -I/usr/include/mozjs" js_inc="/usr/include/mozjs" - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -lmozjs -lpthread 2> /dev/null ; then + if docc $js_flags $LDFLAGS -lmozjs -lpthread ; then has_js="system" js_lib="-lmozjs" fi @@ -808,7 +856,7 @@ fi #spidermonkey test for regular API if test "$has_js" = "no" ; then - cat > $TMPC << EOF +cat > $TMPC << EOF #include int main( void ) { return 0; } EOF @@ -819,40 +867,39 @@ EOF if test "$cpu" = "sh4" ; then lm_lib="-lm" fi - if $cc -o $TMPO $TMPC $js_flags $lm_lib -L$local_lib -ljs 2> /dev/null ; then + if docc $js_flags $lm_lib -L$local_lib -ljs ; then has_js="local" #dc added else - #try prefix (DC) js_inc="$prefix/include/js" js_flags="-DXP_UNIX -I$prefix/include/js" - if $cc -o $TMPO $TMPC $js_flags -L$prefix/lib -ljs 2> /dev/null ; then + if docc $js_flags -L$prefix/lib -ljs ; then has_js="prefix" #dc added end elif test "$pkg_config" != "no"; then - if $pkg_config --exists mozilla-js 2> /dev/null ; then - mozjs_pkgcfg="mozilla-js" - elif $pkg_config --exists mozjs 2> /dev/null ; then - mozjs_pkgcfg="mozjs" - elif $pkg_config --exists mozjs185 2> /dev/null ; then - mozjs_pkgcfg="mozjs185" - fi - - if test $mozjs_pkgcfg != "no" ; then + if $pkg_config --exists mozilla-js ; then + mozjs_pkgcfg="mozilla-js" + elif $pkg_config --exists mozjs ; then + mozjs_pkgcfg="mozjs" + elif $pkg_config --exists mozjs185 ; then + mozjs_pkgcfg="mozjs185" + fi + + if test $mozjs_pkgcfg != "no" ; then js_flags=`$pkg_config --cflags $mozjs_pkgcfg` js_lib_pkg=`$pkg_config --libs $mozjs_pkgcfg` - if $cc -o $TMPO $TMPC $js_flags $js_lib_pkg $LDFLAGS -lpthread 2> /dev/null ; then + if docc $js_flags $js_lib_pkg $LDFLAGS -lpthread ; then has_js="system" js_lib=`$pkg_config --libs $mozjs_pkgcfg` fi fi fi - if test "$has_js" = "no" ; then - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -ljs 2> /dev/null ; then + if test "$has_js" = "no" ; then + if docc $js_flags $LDFLAGS -ljs ; then js_inc="/usr/include" has_js="system" - elif $cc -o $TMPO $TMPC -DXP_UNIX -I$alt_macosx_dir/include/js -L$alt_macosx_dir/lib $LDFLAGS -ljs 2> /dev/null ; then + elif docc -DXP_UNIX -I$alt_macosx_dir/include/js -L$alt_macosx_dir/lib $LDFLAGS -ljs 2>>$logs ; then has_js="system" js_flags="-DXP_UNIX -I$alt_macosx_dir/include/js" js_lib="-L$alt_macosx_dir/lib -ljs" @@ -861,14 +908,14 @@ EOF #debian spidermonkey (smjs) js_flags="-DXP_UNIX -I/usr/include/smjs" js_inc="/usr/include/smjs" - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -lsmjs 2> /dev/null ; then + if docc $js_flags $LDFLAGS -lsmjs ; then has_js="system" js_lib="-lsmjs" else #debian spidermonkey (mozjs) js_flags="-DXP_UNIX -I/usr/include/mozjs" js_inc="/usr/include/mozjs" - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -lmozjs 2> /dev/null ; then + if docc $js_flags $LDFLAGS -lmozjs ; then has_js="system" js_lib="-lmozjs" fi @@ -885,35 +932,36 @@ if test "$has_js" != "no" ; then #if the lib has been compiled with or without the macro. We currently just decide that if the macro is present #in the header, it was enabled in the build if test "$new_js_api" = "no" ; then - if grep MOZILLA_1_8_BRANCH $js_inc/jsapi.h > /dev/null 2>&1 ; then + if grep MOZILLA_1_8_BRANCH $js_inc/jsapi.h > /dev/null 2>>$logs ; then js_flags="-DMOZILLA_1_8_BRANCH $js_flags" echo "WARNING: Turning on MOZILLA_1_8_BRANCH SpiderMonkey macro" echo "If you have troubles with scripts in GPAC, disable this macro and recompile" fi else + cat > $TMPC << EOF #include -int main( void ) { JSObject *obj; JS_GetPrivate(obj); } +int main( void ) { JSObject *obj; JS_GetPrivate(obj); return 0; } EOF - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS $js_lib 2> /dev/null ; then + if docc $js_flags $LDFLAGS $js_lib ; then cat > $TMPC << EOF #include -int main( void ) { jsval *vp; JSObject *obj = JS_NewObjectForConstructor(c, vp); } +int main( void ) { jsval vp; JSContext *cx=NULL; JSObject *obj = JS_NewObjectForConstructor(cx, &vp); return 0; } EOF - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS $js_lib 2> /dev/null ; then - js_flags="-DUSE_FFDEV_12 $js_flags" - elif grep JSMutableHandleValue $js_inc/jsapi.h | grep JSHasInstanceOp > /dev/null 2>&1 ; then - js_flags="-DUSE_FFDEV_18 $js_flags" - elif grep JSMutableHandleValue $js_inc/jsapi.h > /dev/null 2>&1 ; then - js_flags="-DUSE_FFDEV_18 $js_flags" - elif ! grep JS_ConstructObject $js_inc/jsapi.h > /dev/null 2>&1 ; then - js_flags="-DUSE_FFDEV_16 $js_flags" - elif grep JSHandleObject $js_inc/jsapi.h > /dev/null 2>&1 ; then - js_flags="-DUSE_FFDEV_15 $js_flags" + if docc $js_flags $LDFLAGS $js_lib ; then + js_flags="-DUSE_FFDEV_12 $js_flags" + elif grep JSMutableHandleValue $js_inc/jsapi.h | grep JSHasInstanceOp > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_18 $js_flags" + elif grep JSMutableHandleValue $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_18 $js_flags" + elif ! grep JS_ConstructObject $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_16 $js_flags" + elif grep JSHandleObject $js_inc/jsapi.h > /dev/null 2>>$logs ; then + js_flags="-DUSE_FFDEV_15 $js_flags" else - js_flags="-DUSE_FFDEV_14 $js_flags" - fi + js_flags="-DUSE_FFDEV_14 $js_flags" + fi fi fi fi @@ -924,15 +972,14 @@ fi if test "$has_js" != "no" ; then cat > $TMPC << EOF -cat > $TMPC << EOF #include -int main( void ) { JSContext *cx; JS_SetRuntimeThread(cx); } +int main( void ) { JSContext *cx=NULL; JS_SetRuntimeThread(cx); return 0;} EOF - if $cc -o $TMPO $TMPC $js_flags $LDFLAGS $js_lib 2> /dev/null ; then - js_flags="$js_flags" - else - js_flags="-DNO_JS_RUNTIMETHREAD $js_flags" - fi + if docc $js_flags $LDFLAGS $js_lib ; then + js_flags="$js_flags" + else + js_flags="-DNO_JS_RUNTIMETHREAD $js_flags" + fi fi @@ -945,7 +992,7 @@ cat > $TMPC << EOF #include int main( void ) { return 0; } EOF -if $cxx -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread 2> /dev/null ; then +if docxx -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread ; then has_platinum="yes" fi @@ -967,7 +1014,7 @@ int main( void ) { return 0; } EOF -if $cxx -o $TMPO $TMPC $LDFLAGS $avcap_cflags $avcap_ldflags 2> /dev/null ; then +if docxx -o $TMPO $TMPC $LDFLAGS $avcap_cflags $avcap_ldflags ; then has_avcap="yes" else if test "$darwin" = "yes" ; then @@ -977,7 +1024,7 @@ else avcap_cflags="-I$local_inc -I$local_inc/avcap/linux" avcap_ldflags="-lavcap -lpthread" fi - if $cxx -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags 2> /dev/null ; then + if docxx -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags ; then has_avcap="yes" avcap_ldflags="-L../../$local_lib $avcap_ldflags" fi @@ -987,24 +1034,24 @@ fi #look for opensvc support if test "$darwin" = "yes" ; then -osvc_cflags="-I/usr/include -I/usr/local/include" -osvc_ldflags="-L/usr/lib -L/usr/local/lib -lOpenSVCDec" + osvc_cflags="-I/usr/include -I/usr/local/include" + osvc_ldflags="-L/usr/lib -L/usr/local/lib -lOpenSVCDec" else -osvc_cflags="" -osvc_ldflags="-lOpenSVCDec" + osvc_cflags="" + osvc_ldflags="-lOpenSVCDec" fi cat > $TMPC << EOF #include int main( void ) { return 0; } EOF -if $cxx -o $TMPO $TMPC $osvc_cflags $LDFLAGS $osvc_ldflags 2> /dev/null ; then +if docc $osvc_cflags $LDFLAGS $osvc_ldflags ; then has_opensvc="yes" else osvc_cflags="-I$local_inc" osvc_ldflags="-lOpenSVCDec" -if $cxx -o $TMPO $TMPC $osvc_cflags $LDFLAGS -L$local_lib $osvc_ldflags 2> /dev/null ; then +if docc $osvc_cflags $LDFLAGS -L$local_lib $osvc_ldflags ; then has_opensvc="yes" osvc_ldflags="-L../../$local_lib $osvc_ldflags" fi @@ -1014,14 +1061,14 @@ fi #look for openhevc support if test "$darwin" = "yes" ; then -ohevc_cflags="-I/usr/include -I/usr/local/include" -ohevc_ldflags="-L/usr/lib -L/usr/local/lib -lLibOpenHevcWrapper -lm -lpthread " + ohevc_cflags="-I/usr/include -I/usr/local/include" + ohevc_ldflags="-L/usr/lib -L/usr/local/lib -lLibOpenHevcWrapper -lm -lpthread " elif test "$cross_prefix" = "" ; then -ohevc_cflags="" -ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" + ohevc_cflags="" + ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" else -ohevc_cflags="-I${prefix}include" -ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" + ohevc_cflags="-I${prefix}include" + ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" fi cat > $TMPC << EOF @@ -1029,12 +1076,12 @@ cat > $TMPC << EOF #include int main( void ) { libOpenHevcInit(1, 1); return 0; } EOF -if $cc -o $TMPO $TMPC $ohevc_cflags $ohevc_ldflags $LDFLAGS 2> /dev/null ; then +if docc $ohevc_cflags $ohevc_ldflags $LDFLAGS ; then has_openhevc="yes" else ohevc_cflags="-I$local_inc" ohevc_ldflags="-lLibOpenHevcWrapper -lm -lpthread" - if $cc -o $TMPO $TMPC $ohevc_cflags $ohevc_ldflags $LDFLAGS -L$local_lib 2> /dev/null ; then + if docc $ohevc_cflags $ohevc_ldflags $LDFLAGS -L$local_lib ; then has_openhevc="yes" ohevc_ldflags="-L../../$local_lib $ohevc_ldflags" fi @@ -1049,24 +1096,25 @@ cat > $TMPC << EOF #include FT_OUTLINE_H int main( void ) { return 0; } EOF +ft_cflags="-I$prefix/include " +ft_lflags="-L$prefix/lib -lfreetype" +if docc $CFLAGS_DIR $ft_cflags $ft_lflags $LDFLAGS ; then + has_ft="system" +fi if test "$cross_prefix" = "" ; then - ft_cflags="-I$prefix/include " - ft_lflags="-L$prefix/lib -lfreetype" - if $cc $CFLAGS_DIR -o $TMPO $TMPC $ft_cflags $ft_lflags $LDFLAGS 2> /dev/null ; then - has_ft="system" - else - ft_cflags="`freetype-config --cflags 2> /dev/null`" - ft_lflags="`freetype-config --libs 2> /dev/null`" - if $cc -o $TMPO $TMPC $ft_cflags $ft_lflags $LDFLAGS 2> /dev/null ; then + if test "$has_ft" = "no" ; then + ft_cflags="`freetype-config --cflags 2>>$logs`" + ft_lflags="`freetype-config --libs 2>>$logs`" + if docc $ft_cflags $ft_lflags $LDFLAGS ; then has_ft="system" fi fi fi if test "$has_ft" = "no" ; then - if test "`which freetype-config 2> /dev/null`" != ""; then + if test "`which freetype-config 2>>$logs`" != ""; then ft_cflags="-I$local_inc/freetype" ft_lflags="-L$local_lib -lfreetype" - if $cc -o $TMPO $TMPC $ft_cflags $ft_lflags 2> /dev/null ; then + if docc $ft_cflags $ft_lflags ; then has_ft="local" fi fi @@ -1090,7 +1138,7 @@ else LINK_SSL="-lssl -lcrypto" fi -if $cc -o $TMPO $TMPC $LINK_SSL $LDFLAGS 2> /dev/null ; then +if docc $LINK_SSL $LDFLAGS ; then has_ssl="yes" fi @@ -1103,31 +1151,34 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc $LDFLAGS -ljpeg ; then + has_jpeg="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC $LDFLAGS -ljpeg 2> /dev/null ; then - has_jpeg="system" - elif test "$alt_macosx_dir" != "" ; then - if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ljpeg 2> /dev/null ; then - has_jpeg="system" - fi - elif test "`which $prefix/bin/jpeg-config 2> /dev/null`" != ""; then - jpeg_cflags="`$prefix/bin/jpeg-config --cflags`" - jpeg_lflags="`$prefix/bin/jpeg-config --libs`" - if $cc -o $TMPO $TMPC $jpeg_cflags $jpeg_lflags $LDFLAGS 2> /dev/null ; then - has_jpeg="system" - fi - else - jpeg_cflags="-I$prefix/include" - jpeg_lflags="-L$prefix/lib -ljpeg" - if $cc -o $TMPO $TMPC $jpeg_cflags $jpeg_lflags $LDFLAGS 2> /dev/null ; then - has_jpeg="system" + if test "$has_jpeg" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ljpeg 2>>$logs ; then + has_jpeg="system" + fi + elif test "`which $prefix/bin/jpeg-config 2>>$logs`" != ""; then + jpeg_cflags="`$prefix/bin/jpeg-config --cflags`" + jpeg_lflags="`$prefix/bin/jpeg-config --libs`" + if docc $jpeg_cflags $jpeg_lflags $LDFLAGS ; then + has_jpeg="system" + fi + else + jpeg_cflags="-I$prefix/include" + jpeg_lflags="-L$prefix/lib -ljpeg" + if docc $jpeg_cflags $jpeg_lflags $LDFLAGS ; then + has_jpeg="system" + fi fi fi fi if test "$has_jpeg" = "no" ; then jpeg_cflags="-I$local_inc/jpeg" jpeg_lflags="-L$local_lib -ljpeg" - if $cc -o $TMPO $TMPC $jpeg_cflags $jpeg_lflags 2> /dev/null ; then + if docc $jpeg_cflags $jpeg_lflags ; then has_jpeg="local" fi fi @@ -1141,18 +1192,21 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc $LDFLAGS -lopenjpeg ; then + has_openjpeg="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC $LDFLAGS -lopenjpeg 2> /dev/null ; then - has_openjpeg="system" - elif test "$alt_macosx_dir" != "" ; then - if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ljpeg 2> /dev/null ; then - has_openjpeg="system" + if test "$has_openjpeg" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ljpeg 2>>$logs ; then + has_openjpeg="system" + fi fi fi fi if test "$has_openjpeg" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/openjpeg -L$local_lib -lopenjpeg 2> /dev/null ; then + if docc -I$local_inc/openjpeg -L$local_lib -lopenjpeg ; then has_openjpeg="local" fi fi @@ -1165,23 +1219,24 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +png_cflags="-I$prefix/include" +png_lflags="-L$prefix/lib -lpng -lz" +if docc $png_cflags $png_lflags $LDFLAGS ; then + has_png="system" +elif docc $LDFLAGS -lpng -lz ; then + has_png="system" +fi if test "$cross_prefix" = "" ; then - png_cflags="-I$prefix/include" - png_lflags="-L$prefix/lib -lpng -lz" - #-nostdlib prevents from searching standard compiler libraries - #if $cc -o $TMPO $TMPC -nostdlib $png_cflags $png_lflags 2> /dev/null ; then - if $cc -o $TMPO $TMPC $png_cflags $png_lflags $LDFLAGS 2> /dev/null ; then - has_png="system" - elif $cc -o $TMPO $TMPC $LDFLAGS -lpng -lz 2> /dev/null ; then - has_png="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lpng 2> /dev/null ; then - has_png="system" + if test "$has_png" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lpng 2>>$logs ; then + has_png="system" + fi fi fi fi if test "$has_png" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/png -L$local_lib -lpng 2> /dev/null ; then + if docc -I$local_inc/png -L$local_lib -lpng ; then has_png="local" fi fi @@ -1194,17 +1249,20 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc $LDFLAGS -lmad ; then + has_mad="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC $LDFLAGS -lmad 2> /dev/null ; then - has_mad="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lmad 2> /dev/null ; then - has_mad="system" + if test "$has_mad" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lmad 2>>$logs ; then + has_mad="system" + fi fi fi fi if test "$has_mad" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/mad -L$local_lib -lmad 2> /dev/null ; then + if docc -I$local_inc/mad -L$local_lib -lmad ; then has_mad="local" fi fi @@ -1213,6 +1271,7 @@ fi #look for A52DEC support cat > $TMPC << EOF +#include #define uint32_t unsigned int #define uint8_t unsigned char #include @@ -1220,17 +1279,20 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc $LDFLAGS -la52 ; then + has_a52="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC $LDFLAGS -la52 2> /dev/null ; then - has_a52="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -la52 2> /dev/null ; then - has_a52="system" + if test "$has_a52" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -la52 2>>$logs ; then + has_a52="system" + fi fi fi fi if test "$has_a52" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc -L$local_lib -la52 2> /dev/null ; then + if docc -I$local_inc -L$local_lib -la52 ; then has_a52="local" fi fi @@ -1243,19 +1305,22 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc -I$prefix/include -L$prefix/lib $LDFLAGS -lxvidcore -lpthread ; then + has_xvid="system" +elif docc $LDFLAGS -lxvidcore -lpthread ; then + has_xvid="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC -I$prefix/include -L$prefix/lib $LDFLAGS -lxvidcore -lpthread 2> /dev/null ; then - has_xvid="system" - elif $cc -o $TMPO $TMPC $LDFLAGS -lxvidcore -lpthread 2> /dev/null ; then - has_xvid="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lxvidcore -lpthread 2> /dev/null ; then - has_xvid="system" + if test "$has_xvid" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lxvidcore -lpthread 2>>$logs ; then + has_xvid="system" + fi fi fi fi if test "$has_xvid" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/xvid -L$local_lib -lxvidcore -lpthread 2> /dev/null ; then + if docc -I$local_inc/xvid -L$local_lib -lxvidcore -lpthread ; then has_xvid="local" fi fi @@ -1268,17 +1333,20 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc $LDFLAGS -lfaad -lm ; then + has_faad="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC $LDFLAGS -lfaad -lm 2> /dev/null ; then - has_faad="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfaad 2> /dev/null ; then - has_faad="system" + if test "$has_faad" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfaad 2>>$logs ; then + has_faad="system" + fi fi fi fi if test "$has_faad" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/faad -L$local_lib -lfaad -lm 2> /dev/null ; then + if docc -I$local_inc/faad -L$local_lib -lfaad -lm ; then has_faad="local" fi fi @@ -1288,9 +1356,10 @@ fi #look for FFMPEG support ffmpeg_cflags="" -ffmpeg_lflags="-lz -lavcodec -lavformat -lavutil -lswscale -lavdevice" +ffmpeg_lflags="-lz -lavcodec -lavformat -lavutil -lswscale -lavdevice $ffmpeg_extra_ldflags" + if test "$cross_prefix" = "" -a "$pkg_config" != "no"; then - if $pkg_config --exists libavcodec libavformat libswscale libavdevice libavutil 2> /dev/null ; then + if $pkg_config --exists libavcodec libavformat libswscale libavdevice libavutil ; then ffmpeg_cflags=`$pkg_config --cflags libavcodec libavformat libswscale libavutil libavdevice` ffmpeg_lflags=`$pkg_config --libs libavcodec libavformat libswscale libavutil libavdevice` has_ffmpeg="system" @@ -1304,17 +1373,18 @@ int main(void) { } EOF -if $cc -o $TMPO $TMPC $ffmpeg_cflags $ffmpeg_lflags $LDFLAGS 2> /dev/null ; then +if docc $ffmpeg_cflags $ffmpeg_lflags $LDFLAGS ; then old_ffmpeg_inc="no" else old_ffmpeg_inc="yes" cat > $TMPC << EOF #include +#include int main(void) { AVFrame *f1, *f2; + printf("ID %d", AV_CODEC_ID_H264); f2 = av_frame_clone(f1); - AV_CODEC_ID_H264; return 0; } EOF @@ -1323,29 +1393,33 @@ fi cat > $TMPC << EOF #include +#include int main(void) { - CODEC_ID_H264; + printf("ID %d", CODEC_ID_H264); return 0; } EOF -if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC -I$prefix/include -L$prefix/lib $ffmpeg_lflags $LDFLAGS 2> /dev/null ; then - has_ffmpeg="system" - ffmpeg_cflags="-I$prefix/include" - ffmpeg_lflags="-L$prefix/lib $ffmpeg_lflags" - elif $cc -o $TMPO $TMPC $ffmpeg_lflags $LDFLAGS 2> /dev/null ; then - has_ffmpeg="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $ffmpeg_lflags $LDFLAGS 2> /dev/null ; then - has_ffmpeg="system" - ffmpeg_cflags="-I$alt_macosx_dir/include" - ffmpeg_lflags="-L$alt_macosx_dir/lib $ffmpeg_lflags" +if docc -I$prefix/include -L$prefix/lib $ffmpeg_lflags $LDFLAGS ; then + has_ffmpeg="system" + ffmpeg_cflags="-I$prefix/include" + ffmpeg_lflags="-L$prefix/lib $ffmpeg_lflags" +elif docc $ffmpeg_lflags $LDFLAGS ; then + has_ffmpeg="system" +fi +if test "$cross_prefix" = "" ; then + if test "$has_ffmpeg" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $ffmpeg_lflags $LDFLAGS 2>>$logs ; then + has_ffmpeg="system" + ffmpeg_cflags="-I$alt_macosx_dir/include" + ffmpeg_lflags="-L$alt_macosx_dir/lib $ffmpeg_lflags" + fi fi fi fi if test "$has_ffmpeg" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc -L$local_lib $ffmpeg_lflags 2> /dev/null ; then + if docc -I$local_inc -L$local_lib $ffmpeg_lflags ; then has_ffmpeg="local" ffmpeg_cflags="-I$local_inc" ffmpeg_lflags="-L$local_lib $ffmpeg_lflags" @@ -1355,12 +1429,13 @@ fi cat > $TMPC << EOF #include #include +#include int main(void) { - CODEC_ID_H264; + printf("ID %d", CODEC_ID_H264); return 0; } EOF -if $cc -o $TMPO $TMPC $ffmpeg_cflags $ffmpeg_lflags 2> /dev/null ; then +if docc $ffmpeg_cflags $ffmpeg_lflags ; then is_libav="no" else @@ -1372,7 +1447,7 @@ int main(void) { } EOF - if $cc -o $TMPO $TMPC $ffmpeg_cflags $ffmpeg_lflags 2> /dev/null ; then + if docc $ffmpeg_cflags $ffmpeg_lflags ; then is_libav="yes" else is_libav="new" @@ -1384,11 +1459,12 @@ cat > $TMPC << EOF #include "libavresample/avresample.h" int main(void) { AVAudioResampleContext *aresampler = avresample_alloc_context(); + free(aresampler); return 0; } EOF -if $cc -o $TMPO $TMPC $ffmpeg_cflags $ffmpeg_lflags -lavresample 2> /dev/null ; then +if docc $ffmpeg_cflags $ffmpeg_lflags -lavresample ; then has_libavresample="yes" else has_libavresample="no" @@ -1400,7 +1476,7 @@ freenect_flags="" freenect_ld="-lfreenect" has_freenect="no" if test "$pkg_config" != "no"; then - if $pkg_config --exists libfreenect 2> /dev/null ; then + if $pkg_config --exists libfreenect ; then freenect_flags=`$pkg_config --cflags libfreenect` freenect_libs=`$pkg_config --libs libfreenect` has_freenect="system" @@ -1415,19 +1491,22 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF +if docc $LDFLAGS -lfreenect ; then + has_freenect="system" +fi if test "$cross_prefix" = "" ; then - if $cc -o $TMPO $TMPC $LDFLAGS -lfreenect 2> /dev/null ; then - has_freenect="system" - elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfreenect 2> /dev/null ; then - has_freenect="system" - freenect_flags=-I$alt_macosx_dir/include - freenect_ld=-L$alt_macosx_dir/lib -lfreenect + if test "$has_freenect" = "no" ; then + if test "$alt_macosx_dir" != "" ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lfreenect 2>>$logs ; then + has_freenect="system" + freenect_flags=-I$alt_macosx_dir/include + freenect_ld=-L$alt_macosx_dir/lib -lfreenect + fi fi fi fi if test "$has_freenect" = "no" ; then - if $cc -o $TMPO $TMPC -I$local_inc/freenect -L$local_lib -lfreenect 2> /dev/null ; then + if docc -I$local_inc/freenect -L$local_lib -lfreenect ; then has_freenect="local" freenect_flags=-I$local_inc/freenect freenect_ld=-L$local_lib -lfreenect @@ -1443,13 +1522,13 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF -if $cc -o $TMPO $TMPC $LDFLAGS -lvorbis 2> /dev/null ; then +if docc $LDFLAGS -lvorbis ; then has_vorbis="system" elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lvorbis 2> /dev/null ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -lvorbis 2>>$logs ; then has_vorbis="system" fi -elif $cc -o $TMPO $TMPC -I$local_inc -L$local_lib -lvorbis -lm 2> /dev/null ; then +elif docc -I$local_inc -L$local_lib -lvorbis -lm ; then has_vorbis="local" fi @@ -1461,13 +1540,13 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF -if $cc -o $TMPO $TMPC $LDFLAGS -ltheora 2> /dev/null ; then +if docc $LDFLAGS -ltheora ; then has_theora="system" elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ltheora -logg 2> /dev/null ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -ltheora -logg 2>>$logs ; then has_theora="system" fi -elif $cc -o $TMPO $TMPC -I$local_inc -L$local_lib -ltheora -logg -lm 2> /dev/null ; then +elif docc -I$local_inc -L$local_lib -ltheora -logg -lm ; then has_theora="local" fi @@ -1479,13 +1558,13 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF -if $cc -o $TMPO $TMPC $LDFLAGS -logg 2> /dev/null ; then +if docc $LDFLAGS -logg ; then has_ogg="system" elif test "$alt_macosx_dir" != "" ; then - if $cc -o $TMPO $TMPC -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -logg 2> /dev/null ; then + if docc -I$alt_macosx_dir/include -L$alt_macosx_dir/lib $LDFLAGS -logg 2>>$logs ; then has_ogg="system" fi -elif $cc -o $TMPO $TMPC -I$local_inc -L$local_lib -logg -lm 2> /dev/null ; then +elif docc -I$local_inc -L$local_lib -logg -lm ; then has_ogg="local" else has_vorbis=no @@ -1502,7 +1581,7 @@ if test "$darwin" = "yes" ; then int main( void ) { return 0; } EOF - if $cc -o $TMPO $TMPC -DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss -L$alt_macosx_dir/lib -loss $LDFLAGS 2> /dev/null ; then + if docc -DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss -L$alt_macosx_dir/lib -loss $LDFLAGS 2>>$logs ; then has_oss_audio="yes" OSS_CFLAGS="-DLIBOSS_INTERNAL -I$alt_macosx_dir/include/ -I$alt_macosx_dir/include/liboss" OSS_LDFLAGS="-L$alt_macosx_dir/lib -loss" @@ -1518,7 +1597,7 @@ else int main( void ) { return 0; } EOF - if $cc -o $TMPO $TMPC 2> /dev/null ; then + if docc ; then has_oss_audio="yes" else cat > $TMPC << EOF @@ -1529,7 +1608,7 @@ EOF int main( void ) { return 0; } EOF - if $cc -o $TMPO $TMPC $LDFLAGS 2> /dev/null ; then + if docc $LDFLAGS ; then has_oss_audio="yes" fi fi @@ -1543,7 +1622,7 @@ has_wx="no" wx_too_old="no" if test "$cross_prefix" = "" ; then - if type wx-config >/dev/null 2>&1; then + if type wx-config >/dev/null 2>>$logs; then wx_version=`wx-config --version | sed 's/[^0-9]//g'` @@ -1571,7 +1650,7 @@ if test "$cross_prefix" = "" ; then int main( void ) { return 0; } EOF - if $cc $wx_cflags -o $TMPO $TMPCXX $wx_lflags > /dev/null 2>&1 ; then + if $cc $wx_cflags -o $TMPO $TMPCXX $wx_lflags > /dev/null 2>>$logs ; then wx_version=`wx-config --version | sed 's/[^0-9]//g'` if test "$wx_version" -lt 254 ; then wx_too_old="yes" @@ -1585,6 +1664,7 @@ fi #look for IPv6 cat > $TMPC << EOF +#include #include #include #include @@ -1594,11 +1674,14 @@ struct sockaddr_storage saddr; struct ipv6_mreq mreq6; getaddrinfo(0,0,0,0); getnameinfo(0,0,0,0,0,0,0); +memset(&saddr, 0, sizeof(saddr)); +memset(&mreq6, 0, sizeof(mreq6)); IN6_IS_ADDR_MULTICAST( (struct in6_addr *) 0); +return 0; } EOF -if $cc -o $TMPE $TMPC $LDFLAGS $extralibs > /dev/null 2>&1 ; then +if docc $LDFLAGS $extralibs ; then has_ipv6="yes" fi @@ -1612,7 +1695,7 @@ int main( void ) { } EOF -if $cc -o $TMPE $TMPC $LDFLAGS > /dev/null 2>&1 ; then +if docc $LDFLAGS ; then has_dvb4linux="yes" fi @@ -1624,10 +1707,11 @@ cat > $TMPC << EOF #include #include int main( void ) { +return 0; } EOF -if $cc -o $TMPE $TMPC $LDFLAGS > /dev/null 2>&1 ; then +if docc $LDFLAGS ; then has_xmlrpc="yes" fi @@ -1637,10 +1721,11 @@ fi cat > $TMPC << EOF #include int main( void ) { +return 0; } EOF -if $cc -o $TMPE $TMPC $LDFLAGS > /dev/null 2>&1 ; then +if docc $LDFLAGS ; then has_alsa="yes" fi @@ -1650,10 +1735,11 @@ fi cat > $TMPC << EOF #include int main( void ) { +return 0; } EOF -if $cc -o $TMPE $TMPC $LDFLAGS > /dev/null 2>&1 ; then +if docc $LDFLAGS ; then has_pulseaudio="yes" fi @@ -1663,9 +1749,10 @@ fi cat > $TMPC << EOF #include int main( void ) { +return 0; } EOF -if $cc -o $TMPE $TMPC $LDFLAGS > /dev/null 2>&1 ; then +if docc $LDFLAGS ; then has_jack="yes" fi @@ -1678,7 +1765,7 @@ int main( void ) { return 0; } EOF directfb_inc="/usr/include/directfb" directfb_lib="-ldirectfb -lfusion -ldirect" -if $cc -o $TMPO $TMPC -I$directfb_inc -L$directfb_lib $LDFLAGS 2> /dev/null ; then +if docc -I$directfb_inc -L$directfb_lib $LDFLAGS ; then has_directfb="yes" fi @@ -1690,7 +1777,7 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF -if $cc -o $TMPO $TMPC -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS 2> /dev/null ; then +if docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then has_x11="yes" #look for X11 shared memory support @@ -1702,7 +1789,7 @@ if $cc -o $TMPO $TMPC -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS 2> /dev/null int main( void ) { return 0; } EOF - if $cc -o $TMPO $TMPC -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS 2> /dev/null ; then + if docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then has_x11_shm="yes" fi @@ -1714,7 +1801,7 @@ EOF int main( void ) { return 0; } EOF - if $cc -o $TMPO $TMPC -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS 2> /dev/null ; then + if docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then has_x11_xv="yes" fi @@ -1731,7 +1818,7 @@ for opt do ;; --enable-sdl-static=*) sdl_static="yes" ;; - --enable-jack=*) has_jack="yes" + --enable-jack) has_jack="yes" ;; --X11-path=*) X11_PATH=`echo $opt | cut -d '=' -f 2` ;; @@ -1743,7 +1830,7 @@ for opt do ;; --enable-amr-nb-fixed) has_amr_nb_fixed="yes" ;; - --disable-pulseaudio=*) has_pulseaudio="no" + --disable-pulseaudio) has_pulseaudio="no" ;; --enable-amr-nb) has_amr_nb="yes" ;; @@ -1753,7 +1840,7 @@ for opt do ;; --disable-oggvorbis) has_oggvorbis="no" ;; - --disable-jack=*) has_jack="no" + --disable-jack) has_jack="no" ;; --disable-alsa) has_alsa="no" ;; @@ -1777,9 +1864,7 @@ for opt do ;; --strip) INSTFLAGS="-s $INSTFLAGS" ;; - --std-allocator) use_std_alloc="yes" - ;; - --track-memory) use_memory_tracking="yes" + --enable-mem-track) use_memory_tracking="yes" ;; --enable-tinygl) enable_tinygl="yes" ;; @@ -1836,12 +1921,12 @@ for opt do echo fi fi - has_zlib=$tmp_has_zlib - elif test "$tmp_has_zlib" = "no" ; then - echo - echo "WARNING!! : you have forced not to use ZLIB. This will disable some core functionalities of GPAC." - echo - has_zlib="force-no" + has_zlib=$tmp_has_zlib + elif test "$tmp_has_zlib" = "no" ; then + echo + echo "WARNING!! : you have forced not to use ZLIB. This will disable some core functionalities of GPAC." + echo + has_zlib="force-no" fi ;; --use-ogg=*) has_ogg=${opt#--use-ogg=} @@ -1854,7 +1939,7 @@ for opt do ;; --enable-joystick) enable_joystick="yes" ;; - --enable-pulseaudio=*) has_pulseaudio="yes" + --enable-pulseaudio) has_pulseaudio="yes" ;; --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_isoff="yes"; disable_isoff_write="yes"; disable_isoff_hint="yes"; disable_isoff_frag="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_ttml="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds="yes"; disable_hevc="yes" ;; @@ -2105,9 +2190,9 @@ if test "$disable_3d" = "no" ; then else LINK3D="-lGL -lGLU -lX11" fi - if $cc -o $TMPO $TMPC $LINK3D $LDFLAGS 2> /dev/null ; then + if docc $LINK3D $LDFLAGS ; then has_opengl="yes" - elif $cc -o $TMPO $TMPC -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS 2> /dev/null ; then + elif docc -I$X11_PATH/include -L$X11_PATH/lib $LDFLAGS ; then has_opengl="yes" INCL3D="-I$X11_PATH/include" LINK3D="-L$X11_PATH/lib $LINK3D" @@ -2119,11 +2204,11 @@ fi cat > $TMPC << EOF #include -int main( void ) { int a ; a = TINYGL ; } +int main( void ) { int a ; a = TINYGL ; return 0;} EOF if test "$enable_tinygl" = "yes" ;then - if $cc -o $TMPO $TMPC $LDFLAGS -lTinyGL 2> /dev/null ; then + if docc $LDFLAGS -lTinyGL ; then has_tinygl="yes" has_opengl="yes" LINK3D="-lTinyGL" @@ -2138,15 +2223,15 @@ cat > $TMPCXX << EOF int main( void ) { return 0; } EOF -if $cc -o $TMPO $TMPCXX -I$xulsdk_path $LDFLAGS 2> /dev/null ; then +if docxx -I$xulsdk_path $LDFLAGS ; then has_xul="system" xul_flags="-I$xulsdk_path $xul_flags" fi if test "$pkg_config" != "no"; then if test "$has_xul" = "no" ; then - if $pkg_config --exists libxul 2> /dev/null ; then - if $cxx -o $TMPO $TMPCXX `$pkg_config --cflags libxul` `$pkg_config --libs libxul` ; then + if $pkg_config --exists libxul 2>>$logs ; then + if docxx -o $TMPO $TMPCXX `$pkg_config --cflags libxul` `$pkg_config --libs libxul` ; then has_xul="system" xul_flags="`$pkg_config --cflags libxul` `$pkg_config --libs libxul`" fi @@ -2155,13 +2240,13 @@ if test "$pkg_config" != "no"; then fi if test "$has_xul" = "no" ; then - if $cc -o $TMPO $TMPCXX $xul_flags -I$local_inc/gecko-sdk/include $LDFLAGS 2> /dev/null ; then + if docxx $xul_flags -I$local_inc/gecko-sdk/include $LDFLAGS ; then has_xul="local" xul_flags="-I$local_inc/gecko-sdk/include $xul_flags" else #xulrunner directories are sometimes included through js/xul/ff packages if test ! "$has_js" = "no" -a ! "$has_js" = "local" ; then - if $cc -o $TMPO $TMPCXX $js_flags $js_lib_pkg $LDFLAGS 2> /dev/null ; then + if docxx $js_flags $js_lib_pkg $LDFLAGS ; then if test "$mozjs_pkgcfg" != "no" ; then xul_flags=`$pkg_config --cflags $mozjs_pkgcfg` has_xul="$has_js" @@ -2179,7 +2264,7 @@ cat > $TMPC << EOF int main( void ) { return 0; } EOF if test "$enable_joystick" = "yes" ;then - if $cc -o $TMPO $TMPC $LDFLAGS 2> /dev/null ; then + if docc $LDFLAGS ; then has_joystick="yes" fi fi @@ -2196,11 +2281,11 @@ if test "$win32" = "yes" ; then int main( void ) { return 0; } EOF - if $cc -o $TMPO $TMPC $LDFLAGS 2> /dev/null ; then + if docc $LDFLAGS ; then has_mingw_directx="yes" else dx_path="$dxsdk_path" - if $cc -o $TMPO $TMPC -I$dxsdk_path/include -L$dxsdk_path/lib -lddraw 2> /dev/null ; then + if docc -I$dxsdk_path/include -L$dxsdk_path/lib -lddraw ; then has_mingw_directx="yes" fi fi @@ -2221,7 +2306,7 @@ fi #if test "$cross_prefix" = "" ; then - if type $sdl_config >/dev/null 2>&1; then + if type $sdl_config >/dev/null 2>>$logs; then cat > $TMPC << EOF #include @@ -2236,7 +2321,7 @@ EOF fi sdl_cflags=`$sdl_config --cflags` - if $cc -o $TMPO $sdl_cflags $TMPC $LDFLAGS $sdl_lib_flags > /dev/null 2>&1 ; then + if docc $sdl_cflags $LDFLAGS $sdl_lib_flags ; then _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes @@ -2256,7 +2341,7 @@ if test "$has_sdl" = "no" ; then fi if test "$cross_prefix" = "" ; then - if type $sdl_config >/dev/null 2>&1; then + if type $sdl_config >/dev/null 2>>$logs; then cat > $TMPC << EOF #include @@ -2271,7 +2356,7 @@ EOF fi sdl_cflags=`$sdl_config --cflags` - if $cc -o $TMPO $sdl_cflags $TMPC $LDFLAGS $sdl_lib_flags > /dev/null 2>&1 ; then + if docc $sdl_cflags $LDFLAGS $sdl_lib_flags ; then _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes @@ -2298,7 +2383,7 @@ return (*((uint8_t*)(&i))) == 0x67; } EOF - if $cc -o $TMPO $TMPC $LDFLAGS 2>/dev/null ; then + if docc $LDFLAGS 2>>$logs ; then $TMPO && bigendian="yes" else echo big/little endian test failed @@ -2326,6 +2411,22 @@ if test "$static_mp4box" = "yes"; then has_js="no" has_jpeg="no" has_png="no" + has_mad="no" + has_ft="no" + has_openjpeg="no" + has_mad="no" + has_faad="no" + has_xvid="no" + has_ffmpeg="no" + has_ogg="no" + has_theora="no" + has_vorbis="no" + has_a52="no" + has_opensvc="no" + has_openhevc="no" + has_freenect="no" + has_platinum="no" + static_build="yes" fi if test "$cpu" = "sh4"; then @@ -2337,45 +2438,45 @@ if test "$cpu" = "sh4"; then fi if test "$disable_player" = "yes" ; then -disable_scenegraph="yes" + disable_scenegraph="yes" fi if test "$disable_scenegraph" = "yes" ; then -disable_3d="yes" -disable_svg="yes" -disable_vrml="yes" -disable_x3d="yes" -disable_bifs="yes" -disable_bifs_enc="yes" -disable_laser="yes" -disable_seng="yes" -disable_qtvr="yes" -disable_swf="yes" -disable_scene_stats="yes" -disable_scene_dump="yes" -disable_scene_encode="yes" -disable_loader_isoff="yes" -disable_loader_bt="yes" -disable_loader_xmt="yes" -disable_streaming="yes" -disable_player="yes" -disable_smgr="yes" -has_js="no" + disable_3d="yes" + disable_svg="yes" + disable_vrml="yes" + disable_x3d="yes" + disable_bifs="yes" + disable_bifs_enc="yes" + disable_laser="yes" + disable_seng="yes" + disable_qtvr="yes" + disable_swf="yes" + disable_scene_stats="yes" + disable_scene_dump="yes" + disable_scene_encode="yes" + disable_loader_isoff="yes" + disable_loader_bt="yes" + disable_loader_xmt="yes" + disable_streaming="yes" + disable_player="yes" + disable_smgr="yes" + has_js="no" fi if test "$disable_mpd" = "yes"; then -disable_dash="yes" + disable_dash="yes" fi if test "$disable_od_parse" = "yes" ; then -disable_loader_isoff="yes" -disable_loader_bt="yes" -disable_loader_xmt="yes" + disable_loader_isoff="yes" + disable_loader_bt="yes" + disable_loader_xmt="yes" fi if test "$disable_parsers" = "yes" ; then -has_jpeg="no" -has_png="no" + has_jpeg="no" + has_png="no" fi #prepare for config.h writing @@ -2386,23 +2487,22 @@ echo "#define GF_CONFIG_H" >> $TMPH echo "#define GPAC_CONFIGURATION \"$GPAC_CONFIGURATION\"" >> $TMPH version="`grep '#define GPAC_VERSION ' \"$source_path/include/gpac/version.h\" | cut -d '"' -f 2`" -version_major=`grep '#define GPAC_VERSION_MAJOR ' $source_path/include/gpac/version.h | sed -e 's/.*\([0-9]\)\+$/\1/'` -version_minor=`grep '#define GPAC_VERSION_MINOR ' $source_path/include/gpac/version.h | sed -e 's/.*\([0-9]\)\+$/\1/'` -version_micro=`grep '#define GPAC_VERSION_MICRO ' $source_path/include/gpac/version.h | sed -e 's/.*\([0-9]\)\+$/\1/'` +version_major=`grep '#define GPAC_VERSION_MAJOR ' $source_path/include/gpac/version.h | sed 's/[^0-9]*//g'` +version_minor=`grep '#define GPAC_VERSION_MINOR ' $source_path/include/gpac/version.h | sed 's/[^0-9]*//g'` +version_micro=`grep '#define GPAC_VERSION_MICRO ' $source_path/include/gpac/version.h | sed 's/[^0-9]*//g'` soname_version="${version_major}.${version_minor}.${version_micro}" -if [ -d ".svn" ]; then - if which svnversion 2> /dev/null - then - revision="`svnversion \"$source_path\"`" - echo "#define GPAC_SVN_REVISION \"$revision\"" > $source_path/include/gpac/revision.h - else - echo "Cannot find SVN revision" - fi + +if [ -d ".git" ]; then + TAG=$(git describe --tags --abbrev=0 2>>$logs) + VERSION=$(echo `git describe --tags --long 2>>$logs || echo "UNKNOWN"` | sed "s/^$TAG-//") + BRANCH=$(git rev-parse --abbrev-ref HEAD 2>>$logs || echo "UNKNOWN") + revision="$VERSION-$BRANCH" + echo "#define GPAC_GIT_REVISION \"$revision\"" > $source_path/include/gpac/revision.h else - if [ ! -e "$source_path/include/gpac/revision.h" ]; then - echo "#define GPAC_SVN_REVISION \"4065\"" > $source_path/include/gpac/revision.h - fi + if [ ! -e "$source_path/include/gpac/revision.h" ]; then + echo "#define GPAC_GIT_REVISION \"UNKNOWN-UNKNOWN\"" > $source_path/include/gpac/revision.h + fi fi echo "" @@ -2423,7 +2523,6 @@ echo "debug version: $debuginfo" echo "GProf enabled: $gprof_build" echo "Static build enabled: $static_build" echo "Memory tracking enabled: $use_memory_tracking" -echo "Use standard memory allocator: $use_std_alloc" echo "Fixed-Point Version: $use_fixed_point" echo "IPV6 Support: $has_ipv6" echo "Static Modules: $static_modules" @@ -2742,12 +2841,6 @@ if test "$has_amr_wb" = "yes" ; then fi echo "" -if test "$use_memory_tracking" = "yes"; then - echo "!! WARNING: GPAC Memory tracking is enabled !!" - echo "!! This may corrupt third-party tools using libgpac !!" - echo "!! Use at your own risk, and only for GPAC benchmarking !!" - echo "" -fi #needs gmon for win32 gprof if test "$gprof_build" = "yes"; then @@ -2841,8 +2934,6 @@ fi if test "$use_memory_tracking" = "yes"; then echo "#define GPAC_MEMORY_TRACKING" >> $TMPH -elif test "$use_std_alloc" = "yes"; then - echo "#define GPAC_STD_ALLOCATOR" >> $TMPH fi @@ -2881,9 +2972,11 @@ fi if test "$win32" = "no" ; then echo "GPAC_SH_FLAGS=$GPAC_SH_FLAGS" >> config.mak + echo "EXE_SUFFIX=" >> config.mak echo "DYN_LIB_SUFFIX=$DYN_LIB_SUFFIX" >> config.mak else - echo "DYN_LIB_SUFFIX=dll" >> config.mak + echo "EXE_SUFFIX=.exe" >> config.mak + echo "DYN_LIB_SUFFIX=.dll" >> config.mak fi @@ -2970,6 +3063,7 @@ echo "DISABLE_DVBX=$disable_dvbx" >> config.mak echo "DISABLE_AVILIB=$disable_avi" >> config.mak echo "DISABLE_M2PS=$disable_m2ps" >> config.mak echo "DISABLE_OGG=$disable_ogg" >> config.mak +echo "DISABLE_ISOFF=$disable_isoff" >> config.mak echo "DISABLE_ISOFF_HINT=$disable_isoff_hint" >> config.mak echo "DISABLE_VOBSUB=$disable_vobsub" >> config.mak echo "DISABLE_TTXT=$disable_ttxt" >> config.mak @@ -2996,12 +3090,6 @@ echo "DISABLE_M2TS=$disable_m2ts" >> config.mak echo "GPAC_USE_TINYGL=$has_tinygl" >> config.mak echo "OGL_INCLS=$INCL3D" >> config.mak -if test "$disable_isoff" = "yes" -o "$disable_isoff_write" = "yes" ; then - echo "DISABLE_ISOFF=yes" >> config.mak -else - echo "DISABLE_ISOFF=no" >> config.mak -fi - echo "HAS_OPENGL=$has_opengl" >> config.mak if test "$has_opengl" = "yes" ; then @@ -3038,6 +3126,7 @@ echo "CONFIG_AMR_NB_FT=$has_amr_nb" >> config.mak echo "CONFIG_AMR_WB_FT=$has_amr_wb" >> config.mak echo "DEBUGBUILD=$debuginfo" >> config.mak echo "GPROFBUILD=$gprof_build" >> config.mak +echo "MP4BOX_STATIC=$static_mp4box" >> config.mak echo "STATICBUILD=$static_build" >> config.mak echo "CONFIG_IPV6=$has_ipv6" >> config.mak @@ -3127,8 +3216,6 @@ else fi echo "X11_INC_PATH=$X11_PATH/include" >> config.mak -echo "MP4BOX_STATIC=$static_mp4box" >> config.mak - echo "RENOIR_ENABLE=$enable_renoir" >> config.mak GPAC_ENST_INC=no @@ -3141,10 +3228,11 @@ if test "$enst_dir" = "enst"; then cat > $TMPC << EOF #include int main( void ) { +return 0; } EOF - if $cc -o $TMPE $TMPC -L$local_lib -liconv > /dev/null 2>&1 ; then + if docc -L$local_lib -liconv ; then GPAC_ENST=yes echo "LIBGPAC_ENST=`cd src; ls enst/*.c | sed -e 's/\.c/.o/' | tr -s '\r\n' ' ' ; cd ..`" >> config.mak else @@ -3190,7 +3278,7 @@ if test "$source_path_used" = "yes" ; then ln -sf "$source_path/modules/Makefile" modules/Makefile for dir in $MOD_DIRS ; do - if ls "$source_path/$dir/Makefile" > /dev/null 2>&1; then + if [ -f "$source_path/$dir/Makefile" ]; then mkdir -p "$dir" ln -sf "$source_path/$dir/Makefile" "$dir/Makefile" fi @@ -3208,6 +3296,7 @@ else fi echo "SRC_PATH=$source_path" >> config.mak +echo "BUILD_PATH=$build_path" >> config.mak echo "LOCAL_INC_PATH=$local_inc" >> config.mak @@ -3222,6 +3311,7 @@ else echo "config.h is unchanged" fi +echo "Check config.log for detection failures" rm -f $TMPO $TMPC $TMPE $TMPS $TMPCXX $TMPH diff --git a/doc/INSTALL.w32 b/doc/INSTALL.w32 index 21411fb..a338b23 100644 --- a/doc/INSTALL.w32 +++ b/doc/INSTALL.w32 @@ -30,7 +30,7 @@ II GPAC compilation If you have not installed the SpiderMonkey (JavaScript, libjs), JPEG or PNG libraries, remove the indicated macros in the file gpac/include/gpac/internal/config_static.h recompile (libgpac_dll compilation will fail if zlib is not found) - Note: If you wish to build the fixed-point version of GPAC (not recommended), you will have to modify by hand the file gpac/include/gpac/math.h + Note: If you wish to build the fixed-point version of GPAC (not recommended), you will have to modify by hand the file gpac/include/gpac/maths.h and replace the line #define GPAC_NO_FIXED_POINT by the line diff --git a/doc/configuration.html b/doc/configuration.html index 8c8bdbd..b1c2ec4 100644 --- a/doc/configuration.html +++ b/doc/configuration.html @@ -1,875 +1,903 @@ - - - - - - GPAC Configuration documentation - - -

-
-GPAC Configuration file documentation
Version 0.5.0
-
-Last Modified $LastChangedDate: 2014-06-10 15:08:09 +0100 (Tue, 10 Jun 2014) $ -

- -

- -Overview -

-Some applications in the GPAC framework use a configuration file shared among modules and reloadable at run time. Modules may use the configuration file as well (to avoid multiple config files). This doc attempts to provide explanations for the different options. -

-The config file is based on the win32 .ini file model, thus is ordered by sections and keys. -
A section is declared as SectionName. Defined sections are: -
-General -RecentFiles -Systems -Compositor -Audio -Video -Network -FontEngine -Downloader -HTTPProxy -Streaming -MimeTypes -StreamingCache -SAXLoader -XviD -FFMPEG -ISOReader -DVB -DASH -ALSA -Shortcuts -OpenHEVC -DSMCC - -

-

-A key is declared as keyName=value. The key value is not interpreted and always handled as ASCII text. -

-
    -
  • -On Windows plateforms, this config file is called "GPAC.cfg" and is usually located in C:\\Program Files\\GPAC. Note that Osmo4 will always create a config file in its own directory when none is found. -

    -
  • -
  • -On Windows CE plateform, this config file is called "GPAC.cfg" and is usually located in \\Program Files\\GPAC. Note that Osmo4 / CE will always create a config file in its own directory when none is found. -

    -
  • -
  • -On GNU/Linux plateforms, this config file is called ".gpacrc" and is always located at the root of the user home directory (for ex, /home/jean/.gpacrc). -

    -
  • -
-
- -

Note on module names: -
Module names as given in the config file are names exported by each interface and not name of the physical library file (.dll, .so, ...). The physical file name can however be used to identify a module - it will then be replaced by the module name. - -

-

- - -Section "General" Back to top -

-The General section of the config file holds player specific options. -

-ModulesDirectory [value: path to directory] -

-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. -

-CacheDirectory [value: path to storage directory] -

-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. -

-StartupFile [value: filename] -

-Specifies file to load upon startup of most clients (Osmo4/MP4Client). If not specified, no file is loaded. -

- -LogFile [value: filename] -

-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. -

-Logs [value: tool[:tool]@level:tool[:tool]@level] -

-Specifies log level for each tool. 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
  • -
-

- -

-

-

- -Options defined for Osmo4 (Windows version and wxWidgets version):

-Loop [value: "yes" "no"] -

-Specifies whether the presentation has to be restarted when done playing. -

-ConsoleOff [value: "yes" "no"] -

-Specifies whether application messages (script, buffering, download progress) are displayed in the console or not. -

-SingleInstance [value: "yes", "no"] -

-Specifies if the player should be a single instance application or not (Osmo4-Win32 only). -

-LookForSubtitles [value: "yes" "no"] -

-Specifies if Osmo4 shall look for subtitle files when opening a presentation. -

-ViewXMT [value: "yes" "no"] -

-Specifies if scene dumping shall be done in XML (XMT, X3D) or in VRML-like syntax (BT, WRL). -

-ConfigPanel [value: positive integer] -

-Specifies the latest config panel selected by user. -

-NoMIMETypeFetch [value: "yes", "no"] -

-Specifies if the player has to check for mime type when following hyperlinks, or only follow links of known extensions. -

-Loop [value: "yes", "no"] -

-Specifies if the playlist shall be restarted when playback is over. -

-PLEntry [value: positive integer] -

-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
  • -
-FillScreen [value: "yes", "no"] -

-Specifies if the display area shall fill all available space on screen. WindowsMobile/Symbian only -

-DisableBackLight [value: "yes", "no"] -

-Specifies if the screen backlighting shall be disabled while playing. WindowsMobile/Symbian only -

-LastWorkingDir [value: "yes", "no"] -

-Specifies the directory of the last local file opened. Smartphone Windows only -

-Browser [value: string] -

-Specifies prefered browser for WWW anchors and scene graph viewing - Only used by Osmo4/wxWidgets. -

- - -Section "RecentFiles" Back to top -

-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) -

- - -Section "Systems" Back to top -

-The "Systems" section of the config file holds all configuration options for the MPEG-4 Systems engine. -

-LanguageName [value: string] -

-Specifies the user prefered language in readable english. This is used to select streams in case of alternate content in an audio object. -

-Language3CC [value: 3-char code from ISO 639-2] -

-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. -

-Language2CC [value: 2-char code from ISO 639-1] -

-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. -

-DrawLateFrames [value: "yes" "no"] -

-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. -

-ForceSingleClock [value: "yes" "no"] -

-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. -

-ThreadingPolicy [value: "Free" "Single" "Multi"] -

-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. -

-Priority [value: "low" "normal" "high" "real-time"] -

-Specifies the priority of the decoders (priority is applied to decoder thread(s) regardless of threading mode). -

-TimeSlice [value: unsigned integer] -

-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; -

-ModuleUnload [value: "yes" "no"] -

-Specifies whether modules should be unloaded if not used or not. Default: "yes". -

-ResyncLateClock [value: unsigned integer] -

-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. -

-NoVisualThread [value: "yes" "no"] -

-Specifies whether the visual rendering is done in the main codec manager or in a dedicated thread. -

-DefAudioDec , DefVideoDec and DefImageDec [value: string] -

-Specifies which module to use by default for audio/video/image decoding. The string is the name of the module to be used (same considerations as other modules, cf introduction). -

-codec_XX_XX [value: string] -

-Allows to specify default media module (audio/video) per stream type and object type. This is usefull 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). -

- - -Section "Compositor" Back to top -

-The "Compositor" section of the config file holds all configuration options for the compositor (logical rendering engine). -

-Raster2D [value: string] -

-Specifies the 2D rasterizer to use for vectorial drawing. Same as above, this module cannot be reloaded during a presentation.

-FrameRate [value: float] -

-Specifies the simulation frame-rate of the presentation - this value is also used by the MPEG-4 Systems engine to determine when a BIFS frame is mature for decoding.

-AntiAlias [value: "None" "All" "Text"] -

-Specifies antialiasing settings - whether the setting is applied or not depends on the graphics module / graphic card. -

-
    -
  • "None": no anti-aliasing
  • -
  • "Text": anti-aliasing for text only
  • -
  • "All": complete anti-aliasing
  • -
-HighSpeed [value: "yes" "no"] -

-Specifies whether rendering should target speed or quality - whether the setting is applied or not depends on the renderer, graphics module / graphic card.

-ForceSceneSize [value: "yes" "no"] -

-Forces the scene to resize to the biggest bitmap available if no size info is given in the BIFS configuration.

-StressMode [value: "yes" "no"] -

-Specifies that the renderer runs in worst case scenario, recomputing display lists and reloading textures (sending them to graphics card) at each frame even when no change has occured.

-BoundingVolume [value: "None" "Box" "AABB"] -

-Specifies whether the bounding volume of an object shall be drawn or not. Note that the 2D renderer only uses rectangles as bounding volumes. The "AABB" value is used by the -3D renderer only, and specifies the object bounding-box tree shall be drawn.

-ColorKey [value: unsigned hexadecimal integer, formated as AARRGGBB] -

-Specifies the color key to use for windowless rendering. GPAC currently doesn't support true alpha blitting to desktop due to limitations in most windowing toolkit, it therefore uses color keying mechanism. The alpha part of the key is used for global transparency of GPAC's output, if supported. -

-BackColor [value: unsigned hexadecimal integer, formated as AARRGGBB] -

-Specifies the background color to use when displaying transparent images or video with no scene compoistion instructions. -

-DrawMode [value: "immediate" "defer" "defer-debug"] -

-Specifies whether immediate drawing should be used or not. In immediate mode, the screen is completely redrawn at each frame. In defer mode -object positioning is tracked from frame to frame and dirty rectangles info is collected in order to redraw the minimal amount of the screen buffer. Whether -the setting is applied or not depends on the graphics module (currently all modules handle both mode). Defer Debug mode only renders changed areas.

-ScalableZoom [value: "yes" "no"] -

-Specifies whether scalable zoom should be used or not. When scalable zoom is enabled, resizing the output window will also recompute all vectorial objects. Otherwise only the final buffer is stretched.

-DisableYUV [value: "yes" "no"] -

-Disables YUV hardware support (YUV hardware support may not be available for the current video output module).

-TextureFromDecoderMemory [value: "yes" "no"] -

-Allows video textures to be build directly from video decoder internal buffers. This may increase performances on some systems. Default is no.

- - - -ForceOpenGL [value: "always", "disable", "hybrid", "raster"] -

-Specifies that 2D rendering will be performed by OpenGL rather than raster 2D. This will involve polygon tesselation which may not be supported on all platforms, and 2D graphics will not loo as nice as 2D mode. The hybrid mode performs software drawing of 2D graphics with no textures (better quality) and uses OpenGL for all textures. The raster mode only uses OpenGL for pixel IO but does not perform polygin fill (no tesselation) (slow, mainly for test purposes).

-DefaultNavigationMode [value: "Walk", "Fly", "Examine"] -

-Overrides the default navigation mode of MPEG-4/VRML (Walk) and X3D (Examine).

-RasterOutlines [value: "yes" "no"] -

-Specifies that outlining shall be done through OpenGL pen width rather than vectorial outlining.

-PolygonAA [value: "yes" "no"] -

-Specifies whether polygon antialiasing should be used in full antialiasing mode. If not set, only lines and points antialiasing are used.

-DisableBackFaceCulling [value: "yes" "no"] -

-Specifies whether backface culling shall be disable or not. If not set, backface culling is performed.

-Wireframe [value: "WireNone" "WireOnly" "WireOnSolid"] -

-Specifies wireframe drawing options:

-
    -
  • "WireNone": objects are drawn as solid
  • -
  • "WireOnly": objects are drawn as wireframe only
  • -
  • "WireOnSolid": objects are drawn as solid and wireframe is then drawn
  • -
-DisableRectExt [value: "yes" "no"] -

-Specifies whether OpenGL rectangular texture extension (GL_EXT_texture_rectangle or GL_NV_texture_rectangle) shall be used or not.

-
    -
  • "yes": textures whose dimensions are not power of two are rescaled except if hardware support non-power-of-two textures (GL_ARB_texture_non_power_of_two) natively.
  • -
  • "no": if extension is available, textures are used without rescaling. Note that in this case texture transformations are disabled.
  • -
-EmulatePOW2 [value: "yes" "no"] -

-Enables power of 2 emulation. Ignored if openGL rectangular texture extension is enabled.

-
    -
  • "yes": video texture is not resized but emulated with padding. This usually speeds up video mapping on shapes but disables texture transformations.
  • -
  • "no": video is resized to a power of 2 texture when mapping to a shape.
  • -
-DisableGLUScale [value: "yes" "no"] -

-Disables usage of gluScaleImage, which may be slower but nicer than GPAC's software stretch routines.

-TextureTextMode (value: "Default", "Never", "Always"] -

-Specifies whether text shall be drawn to a texture and then rendered or directly rendered. Using textured text can improve text rendering in 3D and also improve text-on-video like content. Default value will use texturing for OpenGL rendering.

-OpenGLExtensions [value: string] -

-Read-only option listing the OpenGL extensions supported by the GL driver. Only valid after the 3D renderer has been used. -

-StereoType [value: "None", "SideBySide", "TopToBottom", "Anaglyph", "Columns", "Rows", "SPV19", "Custom"] -

-Specifies the stereo output type (default "None"). If your graphic card does not support OpenGL shaders, only SideBySide and TopToBottom modes will be available.

-
    -
  • "SideBySide": images are displayed side by side from left to right.
  • -
  • "TopToBottom": images are displayed from top (laft view) to bottom (right view).
  • -
  • "Anaglyph": Standard color anaglyph (red for left view, green and blue for right view) is used.
  • -
  • "Columns": images are interleaved by columns, left view on even columns and left view on odd columns.
  • -
  • "Rows": images are interleaved by columns, left view on even rows and left view on odd rows.
  • -
  • "SPV19": images are interleaved by for SpatialView 19'' 5 views display, fullscreen mode.
  • -
  • "Custom": images are interleaved according to the shader specified by InterleaverShader -
- -NumViews [value: unsigned integer] -

-Specifies the number of views to use in stereo mode. If mode is "Anaglyph", "Columns" or "Rows", the number of views is forced to 2.

- -InterleaverShader [value: path to fragment shader file] -

-Specifies the fragment shader file to use for view interleaving. Each view is rendered in its own texture. The shader is exposed each view as uniform sampler2D gfViewX, where X is the view number starting from the left (gfView1).

- -ReverseViews [value: "yes", "no"] -

-Specifies if the view order should be reversed (from right to left) or not.

-EyeSeparation [value: float] -

-Specifies the eye separation in cm (distance between the cameras). Default: 6.3 cm.

-CameraLayout [value: "OffAxis", Linear", "Circular"] -

-Specifies the camera layout. The default value is OffAxis in (auto-)stereo modes, ignored in mono mode.

-ViewDistance [value: integer] -

-Specifies the distance in cm between the camera and the zero-disparity plane. There is currently no automatic calibration of depth in GPAC.

- - -

- - -Section "Audio" Back to top -

The "Audio" section of the config file holds all configuration options for the audio rendering engine and hardware.

-DriverName [value: string] -

-Specifies the driver to use for audio rendering. This driver cannot be reloaded at run-time, the complete system must be restarted.

-ForceConfig [value: "yes" "no"] -

-Forces a given sound card configuration to be used. If not set the sound card will be setup to use 2 audio buffers of 1024 samples each. -This may not work properly on some audio cards due to hardware latency, therefore forcing the config may be very usefull.

-NumBuffers [value: positive integer, 0 forbidden] -

-When config is forced, specifies the number of audio buffers to allocate (audio buffers are played in ring).

-TotalDuration [value: positive integer, 0 forbidden] -

-When config is forced, specifies the total audio buffer size in milliseconds. Be aware that the longer the audio buffer is, the longer the audio latency will be when pausing an -audio object. The quality of fast forward audio playback will also be degradated when using large audio buffers.

-NoResync [value: "yes" "no"] -

-Disables audio resynchronization: audio data is never dropped but may get out of sync.

-DisableMultiChannel [value: "yes" "no"] -

-Disables audio multichannel output and always downmix to stereo. This may be usefull if the multichannel output behaves weirdly.

-DisableNotification [value: "yes" "no"] -

-Disables usage of audio buffer notifications when supported (currently only DirectSound supports it). If DirectSound audio sounds weird try without notifications.

-Volume [value: integer (0-100)] -

-Default audio volume used when launching GPAC.

-Pan [value: integer (0-100)] -

-Default audio stereo balance used when launching GPAC - 0 for full left, 100 for full right, 50 for balanced.

-Filter [value: string] -

-Defines a set of audio filters. Audio filters are declared as a list of strings separated with ";;". The exact syntax of the string is filter specific.

- -

- - -Section "Video" Back to top -

The "Video" section of the config file holds all configuration options for the video renderer and hardware.

-DriverName [value: string] -

-Specifies the driver to use for video memory access. This driver cannot be reloaded at run-time, the complete system must be restarted.

-SwitchResolution [value: "yes" "no"] -

-Specifies fullscreen resolution mode. If enabled, selects smallest video resolution larger than scene size, otherwise use current video resolution.

-HardwareMemory [value: "Auto" "Always" "Never"] -

-Only valid for 2D renderer. Specifies if main video backbuffer is always on hardware, always on system memory or selected by GPAC (default mode). Depending on the scene type, this may drastically change the playback speed.

-DisableColorKeying [value: "yes" "no"] -

-Only valid for 2D renderer. Specifies if partial overlays should be disabled. If not disabled, hardware color keying for overlays is tested and used if present. Otherwise, only the top-most video with no overlapping objects will be drawn using overlays. Default value is "no".

-UseGLDoubleBuffering [value: "yes" "no"] -

-Specifies if OpenGL double buffering shall be used. Default is "no".

-GLNbBitsPerComponent [value: positive integer] -

-Specifies the number of bits per color component. Default is 5.

-GLNbBitsDepth [value: positive integer] -

-Specifies the number of bits for the depth buffer. Default is 16.

-X113DOffscreenMode [value: "Window" "VisibleWindow" "Pixmap"] -

-Specifies the type of OpenGL offscreen rendering in X11. Default mode is "Pixmap".

-
    -
  • "Window": A hidden window is used to perform offscreen rendering. Depending on your video driver and X11 configuration, this may not work.
  • -
  • "VisibleWindow": A visible window is used to perform offscreen rendering. This can be usefull while debugging.
  • -
  • "Pixmap": An X11 Pixmap is used to perform offscreen rendering. Depending on your video driver and X11 configuration, this may not work and can even crash the player.
  • -
- - -

- -Section "Network" Back to top -

The "Network" section of the config file holds all configuration options for the network used by modules and systems engine.

-AutoReconfigUDP [value: "yes" "no"] -

-Specifies if network manager shall reconnect a scene if UDP is not present.

-DataTimeout [value: positive integer] -

-Specifies timeout in ms befor initial media buffering aborts. Default terminal value is 20000 (20 seconds).

-UDPNotAvailable [value: "yes" "no"] -

-Specifies if UDP traffic is not available. This is automatically set by GPAC if AutoReconfigUDP is set.

-UDPTimeout [value: positive integer] -

-Specifies timeout in ms for initial UDP detection. Once a UDP packet is recieved the timeout is ignored.

-BufferLength [value: positive integer] -

-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.

-RebufferLength [value: positive integer] -

-Specifies rebuffering length of the decoding buffer in milliseconds. Whenever the decoding buffer fullness is less than this value, the object clock is paused and -the stream rebuffered till BufferLength. Therefore a value of 0 means no rebuffering. A module may decide to use a different value based on protocol and network jitters. -

-MobileIP [value: IP Address] -

-Specifies a Mobile IP interface overriding the default IP. If set, all sockets will be locally bound to this IP address.

-

-DefaultMCastInterface [value: IP Address] -

-Specifies a default IP interface for Multicast overriding the default IP.If not set, the multicast will be setup using the default IP.

-

-HTTPRebuffer [value: positive integer] -

-Specifies the default HTTP rebuffer time in ms. When playback position reaches download position, playback will be paused if this integer is not zero. Playback will resume once the HTTPRebuffer ms of playback are available. Default value is 5000 ms.

-

-HTTPAutoRebuffer [value: "yes", "no"] -

-Specifies whether auto rebuffering is used. When auto-rebuffering is used, playback only resumes when estimated time to download the rest of the movie is less than remaining time of the playback. Default value is no.

-

- - -

- -Section "FontEngine" Back to top -

The "FontEngine" section of the config file holds all configuration options for the font handling. The GPAC rendering module handles text through vectorial outline, allowing graphics module development without having to -integrate text rendering which is always heavy work.

-FontReader [value: string] -

-Specifies the module to use for font handling. This module cannot be reloaded at run-time, GPAC must be restarted.

-WaitForFontLoad [value: "yes" "no"] -

-Forces to wait for SVG fonts to be loaded before displaying frames - default is "no".

-FontDirectory (value: path to TrueType (*.ttf, *.ttc) font directory] -

-Specifies the directory where fonts are located - currently only one directory can be specified (however nothing stops a font module from using a private directory). -
Note: -The freetype module will scan the entire sub-directories for fonts. -

-FontSerif [value: string]}: specifies default SERIF font.
-FontSans [value: string]}: specifies default SANS font.
-FontFixed [value: string]}: specifies default fixed font.
-
-Note:
-The FreeType module uses this section to cache familly names to font file name associations. - - -

- -Section "Downloader" Back to top -

The "Downloader" section of the config file holds all configuration options for file downloading and caching.

-CleanCache [value: "yes" "no"] -

-Specifies whether downloaded files shall be removed once used.

-DisableCache [value: "yes" "no"] -

-Specifies whether HTTP caching instructions are disabled or not.

-MaxRate [value: positive integer] -

-Specifies a maximum data rate in kilo bits per seconds for file downloading. This is used for simulation purposes. A value of 0 means no rate restriction.

-UserAgent [value: string] -

-Specifies an alternate user agent (default one is "GPAC $VERSION").

-HTTPHeadTimeout [value: positive integer] -

-Specifies timeout in milliseconds before considering HEAD request failed. 0 means no HEAD request is issued, only GET.

- -

- -Section "HTTPProxy" Back to top -

The "HTTPProxy" section of the config file holds configuration option for HTTP proxy adressing. Currently only one proxy can be enabled, and no URI selection is done.

-Enabled [value: "yes" "no"] -

-Specifies whether the proxy should be used or not when downloading files.

-Name [value: string] -

-Specifies the proxy name (IP address or resolved name) without protocol identifier (eg, no "http://"). If not present, the proxy is disabled.

-Port [value: positive integer] -

-Specifies the port to use with the proxy. If no port is specified, the default HTTP port (80) is used.

- -

- -Section "Streaming" Back to top -

The "Streaming" section of the config file holds all configuration options for real-time streaming using IETF SDP/RTSP/RTP/RTCP protocols.

-DefaultPort [value: unsigned short] -

-Specifies the default port to use when connecting to a server (ignored if a port is specified in the url) if the port is 80 or 8080 (HTTP), the client will connect to the -RTSP server through an HTTP tunnel, and transport will take place on the RTSP connection.

-ReorderSize [value: positive integer] -

-Size of the RTP reordering buffer - 0 means no reordering. Ignored when transport takes place on the RTSP connection. The bigger this value, the longer the reordering delay will be.

-RTPoverRTSP [value: "yes" "no" "OnlyCritical"] -

-Specifies whether RTP packets should be carried on the RTSP connection (TCP or UDP), or carried on UDP. If the connection port is an HTTP port, this value is assumed to be true. If set to OnlyCritical, transport will take place on TCP only if a critical media (eg, neither audio nor video) is found in the session.

-RTSPTimeout [value: positive integer] -

-Specifies connection timeout with the server: an RTSP request is considered as failed when the timeout expires.

-ForceFirstPort [value: positive integer] -

-Specifies first port for RTP channels. If not set, the default first port used by GPAC is 7040.

-NATKeepAlive [value: positive integer] -

-Specifies the maximum inactivity period in milliseconds for RTP sockets. If no data is received after this period, an empty RTP packet will be sent in order to keep any NAT alive. If 0 (default), disables NAT keep-alive packets.

-ForceMulticastIP [value: IP4 or IP6 address] -

-Forces the specified multicast address to be used instead of the regular unicast. Note that some servers may not support multicast initiation by the client.

-ForceMulticastTTL [value: Positive integer] -

-Indicates the TTL to use when the client initiates the multicast. Default value is 127.

-FirstPacketDrop [value: positive integer] -

-Specifies the sequence number of the first RTP packet to be droped - 0 means no packet drop. Used for packet drop simulation tests.

-PacketDropFrequency [value: positive integer] -

-Specifies the frequency at which SL packets are droped. If value is 20, one packet every 20 recieved packets will be droped. Used for packet drop simulation tests.

- -

- - -Section "MimeTypes" Back to top -

This section is used to keep MIME types and file associations for GPAC modules. -
The format of the key is: -
mimeType="fileExt1 filexExt2 .. filexExtN" "MimeType description" ModuleName -
-The description is used for GUI purposes (open file dialogs). You may modify the file extension list to support your own extensions. -MIME Type is always checked when processing a remote ressource (eg http file) in order to load the appropriated modules. -If MIME type is not available, provided extensions are first checked, then all input modules are queried. -

- -

- - -Section "StreamingCache" Back to top -

The "StreamingCache" section of the config file holds all configuration options for the streaming cache. Streaming cache allows for recording of -live sources such as RTP/RTSP sessions and internet radios. This is currently just an experimental feature in GPAC.

-RecordDirectory [value: path] -

-Specifies path for recorded files. Cached data is written directly to disk (no re-interleaving or similar processes). -If not specified, the default cache directory (cf General) is used.

-BaseFileName [value: string] -

-Specifies the base name for recorded files. If not present in configuration file, the service name (URL) is used.

-KeepExistingFiles [value: "yes" "no"] -

-Specifies if cached files with same name should be kept or not. If not, an integer number is added to the cached file name, the higest number for the latest file.

- -

- - -Section "SAXLoader" Back to top -

The "SAXLoader" section of the config file holds all configuration options for XML SAX parsing of SVG, XMT and X3D files.

-Progressive [value: "yes" "no" "DOM"] -

Specifies XML parsing mode used by different file loaders using the SAX parser.

-
    -
  • "yes": SAX parsing is used with progressive loading of the document.
  • -
  • "no": SAX parsing is used, document will first be completely downloaded.
  • -
  • "DOM": DOM parsing is used, document will first be completely downloaded. Only supported by libXML2 plugin, otherwise handled as "no".
  • -
-MaxDuration [value positive integer] -

-Specifies the maximum amount of time the SAX parser should spent loading a portion of the document. Only used with SAX Progressive mode

- -

- - -Section "XviD" Back to top -

The "XviD" section of the config file holds all configuration options for the XviD codec.

-PostProc [value: "FilmEffect" "Deblock_Y" "Deblock_UV"] -

-Specifies filters to apply when decoding video. The string is a list of filters separated with a space character.

-
    -
  • "FilmEffect": xvid 1.0.0 filmEffect.
  • -
  • "Deblock_Y": Y plane deblocking filter.
  • -
  • "Deblock_UV": UV plane deblocking filter.
  • -
-Threaded [value "yes" "no"] -

Specifies whether the decoder should run in its own thread or not.

- -

- - -Section "FFMPEG" Back to top -

The "FFMPEG" section of the config file holds all configuration options for the FFMPEG demuxer and decoder.

-DataBufferMS [value: positive integer] -

-Specifies the amount of video/audio data (in milliseconds) to be bufferer before starting decoding. For developpers only.

-IOBufferSize [value: positive integer] -

-Specifies the size (in bytes) of the buffer used to fecth data from network (http playback only). Default size is 8192 bytes.

- -

- - -Section "ISOReader" Back to top -

The "ISOReader" section of the config file holds all configuration options for the ISO Media File demuxer.

-IgnoreMPEG-4ForBrands [value: Full 4CC or 4CC pattern (abc* ab*)] -

-Ignores all MPEG-4 systems tracks and IOD for files showing the listed brands in their compatible brand list.

- -

- - -Section "DVB" Back to top -

The "DVB" section of the config file holds all configuration options for DVB playback on GNU/Linux systems.

-ChannelsFile [value: Absolute file path] -

-Specifies the DVB channels configuration file as produced by dvbtools' scan util.

- -

- - -Section "DASH" Back to top -

The "DASH" section of the config file holds all configuration options for DASH or HLS/M3U8 playback.

-KeepFiles [value: yes, no] -

-Specifies whether downloaded files should not be deleted.

-AutoSwitchCount [value: positive integer] -

-For debug purposes, instructs the player to switch representation every N segments. If 0 (default), switching is disabled.

-BufferMode [value: segments, minBuffer, none] -

-Selects buffer mode: -

    -
  • segments: buffers complete segments as indicated in MPD before handing them to the player.
  • -
  • minBuffer: asks the player to buffer media for the time indicated in the MPD (default mode), but segments are not pre-buffered.
  • -
  • none: uses the player settings for buffering.
  • -
-

-DisableSwitching [value: yes, no] -

-Disables automatic adaptation logic. Default is no

-MemoryStorage [value: yes, no] -

-Files are only stored in memory and destroyed after playback, no disk IO is used. Default is yes

-UseMaxResolution [value: yes, no] -

-Forces the player to set the output video resolution to the max resolution available instead of resizing the window. Default is yes

-UseScreenResolution [value: yes, no] -

-Disables all resolutions that are higher than the screen resolution. Default is yes

-StartRepresentation [value: minBandwidth, maxBandwidth, minQuality, maxQuality] -

-Instructs the DASH client to start playing the indicated representation before doing any switching. Default is minBandwidth.

-InitialTimeshift [value: positive integer ] -

-If between 0 and 100, indicates the percentage of the timeshift buffer when starting playback.
-If more than 100, indicates the number of milliseconds to rewind in the timeshift buffer when starting playback.
-Default is 0 to tune to the live point.

-LowLatency [value: always, chunk, no] -

-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.

-AllowAbort [value: yes, no] -

-Enables aborts of HTTP transfer when rate gets too low. This may result in a packet drops. Default is no.

-UseServerUTC [value: yes, no] -

-Enables using Server-UTC HTTP header to compensate any drift between client and server. Default is yes.

-DebugAdaptationSet [value: integer] -

-Plays only the adaptation set indicated by its index in the MPD. If index is negative, all sets are used (default mode). -

- -

- - -Section "ALSA" Back to top -

The "ALSA" section of the config file holds all configuration options of the ALSA audio output module on GNU/Linux systems.

-DeviceName [value: string] -

-Specifies the ALSA device to use. Default device is "hw:0,0".

- -

- - -Section "StreamingText" Back to top -

The "StreamingText" section of the config file holds all configuration options for the 3GPP/MPEG-4 Streaming Text decoder.

-UseTexturing [value: "yes" "no"] -

-Specifies whether the text shall be drawn using an intermediate texture or not.<OutlineText [value: "yes" "no"] -

-Specifies whether the text shall be drawn with a black thin outline or not.

- - -

- - -Section "Shortcuts" Back to top -

The "Shortcuts" section of the config file holds all shortcuts in GPAC. You can define a shorcut for an action as:
-'action'='keyname' or 'action'='ctrl+keyname' or 'action'='alt+keyname' or "='action'='ctrl+alt+keyname'
-Shift is not supported as a key modifier, and case is insensitive. -Currently defined actions are as follows:

-Play or Pause
-Stop
-Step
-Exit
-Mute
-VolumeUp
-VolumeDown
-JumpForward
-JumpBackward
-JumpStart
-JumpEnd
-FastForward
-FineForward
-SlowForward
-FastRewind
-FineRewind
-SlowRewind
-Next
-Previous
- -

- - -Section "DSMCC" Back to top -

-The "DSMCC" section of the config file holds the configuration option for the processing of DSMCC data. -

-Activated [value: "true" "false"] -

-Specifies if the DSMCC data will be processed (true). It implies creations of directories and files in the temp directory.

- - -

- - -Section "OpenHEVC" Back to top -

-The openHEVC section of the config file holds the configuration option for the OpenHEVC decoder. -

-NumThreads [value: unsigned integer] -

-Specifies the number of threads to allocate to the OpenHEVC decoder. Default is the number of detected cores minus one, or one if core detection fails.

-ThreadingType [value: frame , wpp , frame+wpp ] -

-Specifies the threading type for the openHEVC decoder. Default is frame (wpp disabled).

-CBUnits [value: unsigned integer ] -

-Specifies the number of decoded frames in memory before display. Default value is 4.

-PackHFR [value: yes, no ] -

-Packs 4 consecutive frames in a single 4x frame.

- - -

- - -Section "DirectFB" Back to top -

-The "DirectFB" section of the config file holds the configuration options for the DirectFB output module. You may also want to check the official documentation. -

-DisableAcceleration [value: "yes" "no"] -

-Forces to disable hardware acceleration.

-DisableDisplay [value: "yes" "no"] -

-Specifies the DisableDisplay parameter value.

-FlipSyncMode [value: "waitsync" "wait" "sync" "swap"] -

-Specifies the flip sync mode.

-DisableBlit [value: "yes" "no"] -

-Forces to disable hardware blitting.

-WindowMode [value: "X11" "SDL"] -

-Specifies the underlying windowing library.

- - - + + + + + + GPAC Configuration documentation + + +

+
+GPAC Configuration file documentation
Version 0.5.2-dev
+
+

+ +

+ +Overview +

+Some applications in the GPAC framework use a configuration file shared among modules and reloadable at run time. Modules may use the configuration file as well (to avoid multiple config files). This doc attempts to provide explanations for the different options. +

+The config file is ordered by sections and keys. +
A section is declared as SectionName. Defined sections are: +
+General +RecentFiles +Systems +Compositor +Audio +Video +Network +FontEngine +Downloader +HTTPProxy +Streaming +MimeTypes +StreamingCache +SAXLoader +XviD +FFMPEG +ISOReader +DVB +DASH +ALSA +Shortcuts +DSMCC +OpenHEVC +DirectFB +DektecVideo + +

+

+A key is declared as keyName=value. The key value is not interpreted and always handled as ASCII text. +

+
    +
  • +On Windows plateforms, this config file is called "GPAC.cfg" and is usually located in C:\\Program Files\\GPAC. Note that Osmo4 will always create a config file in its own directory when none is found. +

    +
  • +
  • +On Windows CE plateform, this config file is called "GPAC.cfg" and is usually located in \\Program Files\\GPAC. Note that Osmo4 / CE will always create a config file in its own directory when none is found. +

    +
  • +
  • +On GNU/Linux plateforms, this config file is called ".gpacrc" and is always located at the root of the user home directory (for ex, /home/jean/.gpacrc). +

    +
  • +
+
+ +

Note on module names: +
Module names as given in the config file are names exported by each interface and not name of the physical library file (.dll, .so, ...). The physical file name can however be used to identify a module - it will then be replaced by the module name. + +

+

+ + +Section "General" Back to top +

+The General section of the config file holds player specific options. +

+ModulesDirectory [value: path to directory] +

+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. +

+CacheDirectory [value: path to storage directory] +

+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. +

+StartupFile [value: filename] +

+Specifies file to load upon startup of most clients (Osmo4/MP4Client). If not specified, no file is loaded. +

+ +LogFile [value: filename] +

+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. +

+Logs [value: tool[:tool]@level:tool[:tool]@level] +

+Specifies log level for each tool. 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
  • +
+

+ +

+

+

+ +Options defined for Osmo4 (Windows version and wxWidgets version):

+Loop [value: "yes" "no"] +

+Specifies whether the presentation has to be restarted when done playing. +

+ConsoleOff [value: "yes" "no"] +

+Specifies whether application messages (script, buffering, download progress) are displayed in the console or not. +

+SingleInstance [value: "yes", "no"] +

+Specifies if the player should be a single instance application or not (Osmo4-Win32 only). +

+LookForSubtitles [value: "yes" "no"] +

+Specifies if Osmo4 shall look for subtitle files when opening a presentation. +

+ViewXMT [value: "yes" "no"] +

+Specifies if scene dumping shall be done in XML (XMT, X3D) or in VRML-like syntax (BT, WRL). +

+ConfigPanel [value: positive integer] +

+Specifies the latest config panel selected by user. +

+NoMIMETypeFetch [value: "yes", "no"] +

+Specifies if the player has to check for mime type when following hyperlinks, or only follow links of known extensions. +

+Loop [value: "yes", "no"] +

+Specifies if the playlist shall be restarted when playback is over. +

+PLEntry [value: positive integer] +

+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
  • +
+FillScreen [value: "yes", "no"] +

+Specifies if the display area shall fill all available space on screen. WindowsMobile/Symbian only +

+DisableBackLight [value: "yes", "no"] +

+Specifies if the screen backlighting shall be disabled while playing. WindowsMobile/Symbian only +

+LastWorkingDir [value: "yes", "no"] +

+Specifies the directory of the last local file opened. Smartphone Windows only +

+Browser [value: string] +

+Specifies prefered browser for WWW anchors and scene graph viewing - Only used by Osmo4/wxWidgets. +

+ + +Section "RecentFiles" Back to top +

+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) +

+ + +Section "Systems" Back to top +

+The "Systems" section of the config file holds all configuration options for the MPEG-4 Systems engine. +

+LanguageName [value: string] +

+Specifies the user prefered language in readable english. This is used to select streams in case of alternate content in an audio object. +

+Language3CC [value: 3-char code from ISO 639-2] +

+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. +

+Language2CC [value: 2-char code from ISO 639-1] +

+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. +

+DrawLateFrames [value: "yes" "no"] +

+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. +

+ForceSingleClock [value: "yes" "no"] +

+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. +

+ThreadingPolicy [value: "Free" "Single" "Multi"] +

+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. +

+Priority [value: "low" "normal" "high" "real-time"] +

+Specifies the priority of the decoders (priority is applied to decoder thread(s) regardless of threading mode). +

+TimeSlice [value: unsigned integer] +

+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; +

+ModuleUnload [value: "yes" "no"] +

+Specifies whether modules should be unloaded if not used or not. Default: "yes". +

+ResyncLateClock [value: unsigned integer] +

+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. +

+NoVisualThread [value: "yes" "no"] +

+Specifies whether the visual rendering is done in the main codec manager or in a dedicated thread. +

+DefAudioDec , DefVideoDec and DefImageDec [value: string] +

+Specifies which module to use by default for audio/video/image decoding. The string is the name of the module to be used (same considerations as other modules, cf introduction). +

+codec_XX_XX [value: string] +

+Allows to specify default media module (audio/video) per stream type and object type. This is usefull 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). +

+ + +Section "Compositor" Back to top +

+The "Compositor" section of the config file holds all configuration options for the compositor (logical rendering engine). +

+Raster2D [value: string] +

+Specifies the 2D rasterizer to use for vectorial drawing. Same as above, this module cannot be reloaded during a presentation.

+FrameRate [value: float] +

+Specifies the simulation frame-rate of the presentation - this value is also used by the MPEG-4 Systems engine to determine when a BIFS frame is mature for decoding.

+AntiAlias [value: "None" "All" "Text"] +

+Specifies antialiasing settings - whether the setting is applied or not depends on the graphics module / graphic card. +

+
    +
  • "None": no anti-aliasing
  • +
  • "Text": anti-aliasing for text only
  • +
  • "All": complete anti-aliasing
  • +
+HighSpeed [value: "yes" "no"] +

+Specifies whether rendering should target speed or quality - whether the setting is applied or not depends on the renderer, graphics module / graphic card.

+ForceSceneSize [value: "yes" "no"] +

+Forces the scene to resize to the biggest bitmap available if no size info is given in the BIFS configuration.

+StressMode [value: "yes" "no"] +

+Specifies that the renderer runs in worst case scenario, recomputing display lists and reloading textures (sending them to graphics card) at each frame even when no change has occured.

+BoundingVolume [value: "None" "Box" "AABB"] +

+Specifies whether the bounding volume of an object shall be drawn or not. Note that the 2D renderer only uses rectangles as bounding volumes. The "AABB" value is used by the +3D renderer only, and specifies the object bounding-box tree shall be drawn.

+ColorKey [value: unsigned hexadecimal integer, formated as AARRGGBB] +

+Specifies the color key to use for windowless rendering. GPAC currently doesn't support true alpha blitting to desktop due to limitations in most windowing toolkit, it therefore uses color keying mechanism. The alpha part of the key is used for global transparency of GPAC's output, if supported. +

+BackColor [value: unsigned hexadecimal integer, formated as AARRGGBB] +

+Specifies the background color to use when displaying transparent images or video with no scene compoistion instructions. +

+DrawMode [value: "immediate" "defer" "defer-debug"] +

+Specifies whether immediate drawing should be used or not. In immediate mode, the screen is completely redrawn at each frame. In defer mode +object positioning is tracked from frame to frame and dirty rectangles info is collected in order to redraw the minimal amount of the screen buffer. Whether +the setting is applied or not depends on the graphics module (currently all modules handle both mode). Defer Debug mode only renders changed areas.

+ScalableZoom [value: "yes" "no"] +

+Specifies whether scalable zoom should be used or not. When scalable zoom is enabled, resizing the output window will also recompute all vectorial objects. Otherwise only the final buffer is stretched.

+DisableYUV [value: "yes" "no"] +

+Disables YUV hardware support (YUV hardware support may not be available for the current video output module).

+TextureFromDecoderMemory [value: "yes" "no"] +

+Allows video textures to be build directly from video decoder internal buffers. This may increase performances on some systems. Default is no.

+ForceOpenGL [value: "always", "disable", "hybrid", "raster"] +

+Specifies that 2D rendering will be performed by OpenGL rather than raster 2D. This will involve polygon tesselation which may not be supported on all platforms, and 2D graphics will not loo as nice as 2D mode. The hybrid mode performs software drawing of 2D graphics with no textures (better quality) and uses OpenGL for all textures. The raster mode only uses OpenGL for pixel IO but does not perform polygin fill (no tesselation) (slow, mainly for test purposes).

+EnablePBO [value: "yes", "no"] +

+Uses PixelBufferObjects to push YUV textures to GPU in OpenGL Mode.. This may slightly increase the performances of the playback.

+DefaultNavigationMode [value: "Walk", "Fly", "Examine"] +

+Overrides the default navigation mode of MPEG-4/VRML (Walk) and X3D (Examine).

+RasterOutlines [value: "yes" "no"] +

+Specifies that outlining shall be done through OpenGL pen width rather than vectorial outlining.

+PolygonAA [value: "yes" "no"] +

+Specifies whether polygon antialiasing should be used in full antialiasing mode. If not set, only lines and points antialiasing are used.

+DisableBackFaceCulling [value: "yes" "no"] +

+Specifies whether backface culling shall be disable or not. If not set, backface culling is performed.

+Wireframe [value: "WireNone" "WireOnly" "WireOnSolid"] +

+Specifies wireframe drawing options:

+
    +
  • "WireNone": objects are drawn as solid
  • +
  • "WireOnly": objects are drawn as wireframe only
  • +
  • "WireOnSolid": objects are drawn as solid and wireframe is then drawn
  • +
+DisableRectExt [value: "yes" "no"] +

+Specifies whether OpenGL rectangular texture extension (GL_EXT_texture_rectangle or GL_NV_texture_rectangle) shall be used or not.

+
    +
  • "yes": textures whose dimensions are not power of two are rescaled except if hardware support non-power-of-two textures (GL_ARB_texture_non_power_of_two) natively.
  • +
  • "no": if extension is available, textures are used without rescaling. Note that in this case texture transformations are disabled.
  • +
+EmulatePOW2 [value: "yes" "no"] +

+Enables power of 2 emulation. Ignored if openGL rectangular texture extension is enabled.

+
    +
  • "yes": video texture is not resized but emulated with padding. This usually speeds up video mapping on shapes but disables texture transformations.
  • +
  • "no": video is resized to a power of 2 texture when mapping to a shape.
  • +
+DisableGLUScale [value: "yes" "no"] +

+Disables usage of gluScaleImage, which may be slower but nicer than GPAC's software stretch routines.

+TextureTextMode (value: "Default", "Never", "Always"] +

+Specifies whether text shall be drawn to a texture and then rendered or directly rendered. Using textured text can improve text rendering in 3D and also improve text-on-video like content. Default value will use texturing for OpenGL rendering.

+OpenGLExtensions [value: string] +

+Read-only option listing the OpenGL extensions supported by the GL driver. Only valid after the 3D renderer has been used. +

+StereoType [value: "None", "SideBySide", "TopToBottom", "Anaglyph", "Columns", "Rows", "SPV19", "Custom"] +

+Specifies the stereo output type (default "None"). If your graphic card does not support OpenGL shaders, only SideBySide and TopToBottom modes will be available.

+
    +
  • "SideBySide": images are displayed side by side from left to right.
  • +
  • "TopToBottom": images are displayed from top (laft view) to bottom (right view).
  • +
  • "Anaglyph": Standard color anaglyph (red for left view, green and blue for right view) is used.
  • +
  • "Columns": images are interleaved by columns, left view on even columns and left view on odd columns.
  • +
  • "Rows": images are interleaved by columns, left view on even rows and left view on odd rows.
  • +
  • "SPV19": images are interleaved by for SpatialView 19'' 5 views display, fullscreen mode.
  • +
  • "Custom": images are interleaved according to the shader specified by InterleaverShader +
+ +NumViews [value: unsigned integer] +

+Specifies the number of views to use in stereo mode. If mode is "Anaglyph", "Columns" or "Rows", the number of views is forced to 2.

+ +InterleaverShader [value: path to fragment shader file] +

+Specifies the fragment shader file to use for view interleaving. Each view is rendered in its own texture. The shader is exposed each view as uniform sampler2D gfViewX, where X is the view number starting from the left (gfView1).

+ +ReverseViews [value: "yes", "no"] +

+Specifies if the view order should be reversed (from right to left) or not.

+EyeSeparation [value: float] +

+Specifies the eye separation in cm (distance between the cameras). Default: 6.3 cm.

+CameraLayout [value: "OffAxis", Linear", "Circular"] +

+Specifies the camera layout. The default value is OffAxis in (auto-)stereo modes, ignored in mono mode.

+ViewDistance [value: integer] +

+Specifies the distance in cm between the camera and the zero-disparity plane. There is currently no automatic calibration of depth in GPAC.

+ + +

+ + +Section "Audio" Back to top +

The "Audio" section of the config file holds all configuration options for the audio rendering engine and hardware.

+DriverName [value: string] +

+Specifies the driver to use for audio rendering. This driver cannot be reloaded at run-time, the complete system must be restarted.

+ForceConfig [value: "yes" "no"] +

+Forces a given sound card configuration to be used. If not set the sound card will be setup to use 2 audio buffers of 1024 samples each. +This may not work properly on some audio cards due to hardware latency, therefore forcing the config may be very usefull.

+NumBuffers [value: positive integer, 0 forbidden] +

+When config is forced, specifies the number of audio buffers to allocate (audio buffers are played in ring).

+TotalDuration [value: positive integer, 0 forbidden] +

+When config is forced, specifies the total audio buffer size in milliseconds. Be aware that the longer the audio buffer is, the longer the audio latency will be when pausing an +audio object. The quality of fast forward audio playback will also be degradated when using large audio buffers.

+NoResync [value: "yes" "no"] +

+Disables audio resynchronization: audio data is never dropped but may get out of sync.

+DisableMultiChannel [value: "yes" "no"] +

+Disables audio multichannel output and always downmix to stereo. This may be usefull if the multichannel output behaves weirdly.

+DisableNotification [value: "yes" "no"] +

+Disables usage of audio buffer notifications when supported (currently only DirectSound supports it). If DirectSound audio sounds weird try without notifications.

+Volume [value: integer (0-100)] +

+Default audio volume used when launching GPAC.

+Pan [value: integer (0-100)] +

+Default audio stereo balance used when launching GPAC - 0 for full left, 100 for full right, 50 for balanced.

+Filter [value: string] +

+Defines a set of audio filters. Audio filters are declared as a list of strings separated with ";;". The exact syntax of the string is filter specific.

+ +

+ + +Section "Video" Back to top +

The "Video" section of the config file holds all configuration options for the video renderer and hardware.

+DriverName [value: string] +

+Specifies the driver to use for video memory access. This driver cannot be reloaded at run-time, the complete system must be restarted.

+SwitchResolution [value: "yes" "no"] +

+Specifies fullscreen resolution mode. If enabled, selects smallest video resolution larger than scene size, otherwise use current video resolution.

+HardwareMemory [value: "Auto" "Always" "Never"] +

+Only valid for 2D renderer. Specifies if main video backbuffer is always on hardware, always on system memory or selected by GPAC (default mode). Depending on the scene type, this may drastically change the playback speed.

+DisableColorKeying [value: "yes" "no"] +

+Only valid for 2D renderer. Specifies if partial overlays should be disabled. If not disabled, hardware color keying for overlays is tested and used if present. Otherwise, only the top-most video with no overlapping objects will be drawn using overlays. Default value is "no".

+UseGLDoubleBuffering [value: "yes" "no"] +

+Specifies if OpenGL double buffering shall be used. Default is "no".

+GLNbBitsPerComponent [value: positive integer] +

+Specifies the number of bits per color component. Default is 5.

+GLNbBitsDepth [value: positive integer] +

+Specifies the number of bits for the depth buffer. Default is 16.

+X113DOffscreenMode [value: "Window" "VisibleWindow" "Pixmap"] +

+Specifies the type of OpenGL offscreen rendering in X11. Default mode is "Pixmap".

+
    +
  • "Window": A hidden window is used to perform offscreen rendering. Depending on your video driver and X11 configuration, this may not work.
  • +
  • "VisibleWindow": A visible window is used to perform offscreen rendering. This can be usefull while debugging.
  • +
  • "Pixmap": An X11 Pixmap is used to perform offscreen rendering. Depending on your video driver and X11 configuration, this may not work and can even crash the player.
  • +
+ + +

+ +Section "Network" Back to top +

The "Network" section of the config file holds all configuration options for the network used by modules and systems engine.

+AutoReconfigUDP [value: "yes" "no"] +

+Specifies if network manager shall reconnect a scene if UDP is not present.

+DataTimeout [value: positive integer] +

+Specifies timeout in ms befor initial media buffering aborts. Default terminal value is 20000 (20 seconds).

+UDPNotAvailable [value: "yes" "no"] +

+Specifies if UDP traffic is not available. This is automatically set by GPAC if AutoReconfigUDP is set.

+UDPTimeout [value: positive integer] +

+Specifies timeout in ms for initial UDP detection. Once a UDP packet is recieved the timeout is ignored.

+BufferLength [value: positive integer] +

+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.

+RebufferLength [value: positive integer] +

+Specifies rebuffering length of the decoding buffer in milliseconds. Whenever the decoding buffer fullness is less than this value, the object clock is paused and +the stream rebuffered till BufferLength. Therefore a value of 0 means no rebuffering. A module may decide to use a different value based on protocol and network jitters. +

+LowLatencyBufferMax [value: positive integer] +

+Specifies the maximum buffer level for low latency mode, in ms. If media buffer max is above this value, full buffering will be done (clock resume at first frame displayed). Default value is 500 ms.

+

+MobileIP [value: IP Address] +

+Specifies a Mobile IP interface overriding the default IP. If set, all sockets will be locally bound to this IP address.

+

+DefaultMCastInterface [value: IP Address] +

+Specifies a default IP interface for Multicast overriding the default IP.If not set, the multicast will be setup using the default IP.

+

+HTTPRebuffer [value: positive integer] +

+Specifies the default HTTP rebuffer time in ms. When playback position reaches download position, playback will be paused if this integer is not zero. Playback will resume once the HTTPRebuffer ms of playback are available. Default value is 5000 ms.

+

+HTTPAutoRebuffer [value: "yes", "no"] +

+Specifies whether auto rebuffering is used. When auto-rebuffering is used, playback only resumes when estimated time to download the rest of the movie is less than remaining time of the playback. Default value is no.

+

+ + + +

+ +Section "FontEngine" Back to top +

The "FontEngine" section of the config file holds all configuration options for the font handling. The GPAC rendering module handles text through vectorial outline, allowing graphics module development without having to +integrate text rendering which is always heavy work.

+FontReader [value: string] +

+Specifies the module to use for font handling. This module cannot be reloaded at run-time, GPAC must be restarted.

+WaitForFontLoad [value: "yes" "no"] +

+Forces to wait for SVG fonts to be loaded before displaying frames - default is "no".

+FontDirectory (value: path to TrueType (*.ttf, *.ttc) font directory] +

+Specifies the directory where fonts are located - currently only one directory can be specified (however nothing stops a font module from using a private directory). +
Note: +The freetype module will scan the entire sub-directories for fonts. +

+FontSerif [value: string]}: specifies default SERIF font.
+FontSans [value: string]}: specifies default SANS font.
+FontFixed [value: string]}: specifies default fixed font.
+
+Note:
+The FreeType module uses this section to cache familly names to font file name associations. + + +

+ +Section "Downloader" Back to top +

The "Downloader" section of the config file holds all configuration options for file downloading and caching.

+CleanCache [value: "yes" "no"] +

+Specifies whether downloaded files shall be removed once used.

+DisableCache [value: "yes" "no"] +

+Specifies whether HTTP caching instructions are disabled or not.

+AllowOfflineCache [value: "yes" "no"] +

+When enabled, allows HTTP request to use cached file if any when network is not available.

+MaxRate [value: positive integer] +

+Specifies a maximum data rate in kilo bits per seconds for file downloading. This is used for simulation purposes. A value of 0 means no rate restriction.

+UserAgent [value: string] +

+Specifies an alternate user agent (default one is "GPAC $VERSION").

+HTTPHeadTimeout [value: positive integer] +

+Specifies timeout in milliseconds before considering HEAD request failed. 0 means no HEAD request is issued, only GET.

+ +

+ +Section "HTTPProxy" Back to top +

The "HTTPProxy" section of the config file holds configuration option for HTTP proxy adressing. Currently only one proxy can be enabled, and no URI selection is done.

+Enabled [value: "yes" "no"] +

+Specifies whether the proxy should be used or not when downloading files.

+Name [value: string] +

+Specifies the proxy name (IP address or resolved name) without protocol identifier (eg, no "http://"). If not present, the proxy is disabled.

+Port [value: positive integer] +

+Specifies the port to use with the proxy. If no port is specified, the default HTTP port (80) is used.

+ +

+ +Section "Streaming" Back to top +

The "Streaming" section of the config file holds all configuration options for real-time streaming using IETF SDP/RTSP/RTP/RTCP protocols.

+DefaultPort [value: unsigned short] +

+Specifies the default port to use when connecting to a server (ignored if a port is specified in the url) if the port is 80 or 8080 (HTTP), the client will connect to the +RTSP server through an HTTP tunnel, and transport will take place on the RTSP connection.

+ReorderSize [value: positive integer] +

+Size of the RTP reordering buffer - 0 means no reordering. Ignored when transport takes place on the RTSP connection. The bigger this value, the longer the reordering delay will be.

+RTPoverRTSP [value: "yes" "no" "OnlyCritical"] +

+Specifies whether RTP packets should be carried on the RTSP connection (TCP or UDP), or carried on UDP. If the connection port is an HTTP port, this value is assumed to be true. If set to OnlyCritical, transport will take place on TCP only if a critical media (eg, neither audio nor video) is found in the session.

+RTSPTimeout [value: positive integer] +

+Specifies connection timeout with the server: an RTSP request is considered as failed when the timeout expires.

+ForceFirstPort [value: positive integer] +

+Specifies first port for RTP channels. If not set, the default first port used by GPAC is 7040.

+NATKeepAlive [value: positive integer] +

+Specifies the maximum inactivity period in milliseconds for RTP sockets. If no data is received after this period, an empty RTP packet will be sent in order to keep any NAT alive. If 0 (default), disables NAT keep-alive packets.

+ForceMulticastIP [value: IP4 or IP6 address] +

+Forces the specified multicast address to be used instead of the regular unicast. Note that some servers may not support multicast initiation by the client.

+ForceMulticastTTL [value: Positive integer] +

+Indicates the TTL to use when the client initiates the multicast. Default value is 127.

+FirstPacketDrop [value: positive integer] +

+Specifies the sequence number of the first RTP packet to be droped - 0 means no packet drop. Used for packet drop simulation tests.

+PacketDropFrequency [value: positive integer] +

+Specifies the frequency at which SL packets are droped. If value is 20, one packet every 20 recieved packets will be droped. Used for packet drop simulation tests.

+ +

+ + +Section "MimeTypes" Back to top +

This section is used to keep MIME types and file associations for GPAC modules. +
The format of the key is: +
mimeType="fileExt1 filexExt2 .. filexExtN" "MimeType description" ModuleName +
+The description is used for GUI purposes (open file dialogs). You may modify the file extension list to support your own extensions. +MIME Type is always checked when processing a remote ressource (eg http file) in order to load the appropriated modules. +If MIME type is not available, provided extensions are first checked, then all input modules are queried. +

+ +

+ + +Section "StreamingCache" Back to top +

The "StreamingCache" section of the config file holds all configuration options for the streaming cache. Streaming cache allows for recording of +live sources such as RTP/RTSP sessions and internet radios. This is currently just an experimental feature in GPAC.

+RecordDirectory [value: path] +

+Specifies path for recorded files. Cached data is written directly to disk (no re-interleaving or similar processes). +If not specified, the default cache directory (cf General) is used.

+BaseFileName [value: string] +

+Specifies the base name for recorded files. If not present in configuration file, the service name (URL) is used.

+KeepExistingFiles [value: "yes" "no"] +

+Specifies if cached files with same name should be kept or not. If not, an integer number is added to the cached file name, the higest number for the latest file.

+ +

+ + +Section "SAXLoader" Back to top +

The "SAXLoader" section of the config file holds all configuration options for XML SAX parsing of SVG, XMT and X3D files.

+Progressive [value: "yes" "no" "DOM"] +

Specifies XML parsing mode used by different file loaders using the SAX parser.

+
    +
  • "yes": SAX parsing is used with progressive loading of the document.
  • +
  • "no": SAX parsing is used, document will first be completely downloaded.
  • +
  • "DOM": DOM parsing is used, document will first be completely downloaded. Only supported by libXML2 plugin, otherwise handled as "no".
  • +
+MaxDuration [value positive integer] +

+Specifies the maximum amount of time the SAX parser should spent loading a portion of the document. Only used with SAX Progressive mode

+ +

+ + +Section "XviD" Back to top +

The "XviD" section of the config file holds all configuration options for the XviD codec.

+PostProc [value: "FilmEffect" "Deblock_Y" "Deblock_UV"] +

+Specifies filters to apply when decoding video. The string is a list of filters separated with a space character.

+
    +
  • "FilmEffect": xvid 1.0.0 filmEffect.
  • +
  • "Deblock_Y": Y plane deblocking filter.
  • +
  • "Deblock_UV": UV plane deblocking filter.
  • +
+Threaded [value "yes" "no"] +

Specifies whether the decoder should run in its own thread or not.

+ +

+ + +Section "FFMPEG" Back to top +

The "FFMPEG" section of the config file holds all configuration options for the FFMPEG demuxer and decoder.

+DataBufferMS [value: positive integer] +

+Specifies the amount of video/audio data (in milliseconds) to be bufferer before starting decoding. For developpers only.

+IOBufferSize [value: positive integer] +

+Specifies the size (in bytes) of the buffer used to fecth data from network (http playback only). Default size is 8192 bytes.

+ +

+ + +Section "ISOReader" Back to top +

The "ISOReader" section of the config file holds all configuration options for the ISO Media File demuxer.

+IgnoreMPEG-4ForBrands [value: Full 4CC or 4CC pattern (abc* ab*)] +

+Ignores all MPEG-4 systems tracks and IOD for files showing the listed brands in their compatible brand list.

+ +

+ + +Section "DVB" Back to top +

The "DVB" section of the config file holds all configuration options for DVB playback on GNU/Linux systems.

+ChannelsFile [value: Absolute file path] +

+Specifies the DVB channels configuration file as produced by dvbtools' scan util.

+ +

+ + +Section "DASH" Back to top +

The "DASH" section of the config file holds all configuration options for DASH or HLS/M3U8 playback.

+KeepFiles [value: yes, no] +

+Specifies whether downloaded files should not be deleted.

+AutoSwitchCount [value: positive integer] +

+For debug purposes, instructs the player to switch representation every N segments. If 0 (default), switching is disabled.

+BufferMode [value: segments, minBuffer, none] +

+Selects buffer mode: +

    +
  • segments: buffers complete segments as indicated in MPD before handing them to the player.
  • +
  • minBuffer: asks the player to buffer media for the time indicated in the MPD (default mode), but segments are not pre-buffered.
  • +
  • none: uses the player settings for buffering.
  • +
+

+DisableSwitching [value: yes, no] +

+Disables automatic adaptation logic. Default is no

+MemoryStorage [value: yes, no] +

+Files are only stored in memory and destroyed after playback, no disk IO is used. Default is yes

+UseMaxResolution [value: yes, no] +

+Forces the player to set the output video resolution to the max resolution available instead of resizing the window. Default is yes

+UseScreenResolution [value: yes, no] +

+Disables all resolutions that are higher than the screen resolution. Default is yes

+StartRepresentation [value: minBandwidth, maxBandwidth, minQuality, maxQuality] +

+Instructs the DASH client to start playing the indicated representation before doing any switching. Default is minBandwidth.

+InitialTimeshift [value: positive integer ] +

+If between 0 and 100, indicates the percentage of the timeshift buffer when starting playback.
+If more than 100, indicates the number of milliseconds to rewind in the timeshift buffer when starting playback.
+Default is 0 to tune to the live point.

+LowLatency [value: always, chunk, no] +

+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.

+AllowAbort [value: yes, no] +

+Enables aborts of HTTP transfer when rate gets too low. This may result in a packet drops. Default is no.

+UseServerUTC [value: yes, no] +

+Enables using Server-UTC HTTP header to compensate any drift between client and server. Default is yes.

+DebugAdaptationSet [value: integer] +

+Plays only the adaptation set indicated by its index in the MPD. If index is negative, all sets are used (default mode). +

+SwitchProbeCount [value: unsigned integer] +

+Sets how many segments the client shall wait before switching up bandwidth. If 0, switch will happen as soon as the bandwidth is enough, but this is more prone to network variations. +Default value is 1. +

+ + + +

+ + +Section "ALSA" Back to top +

The "ALSA" section of the config file holds all configuration options of the ALSA audio output module on GNU/Linux systems.

+DeviceName [value: string] +

+Specifies the ALSA device to use. Default device is "hw:0,0".

+ +

+ + +Section "StreamingText" Back to top +

The "StreamingText" section of the config file holds all configuration options for the 3GPP/MPEG-4 Streaming Text decoder.

+UseTexturing [value: "yes" "no"] +

+Specifies whether the text shall be drawn using an intermediate texture or not.<OutlineText [value: "yes" "no"] +

+Specifies whether the text shall be drawn with a black thin outline or not.

+ + +

+ + +Section "Shortcuts" Back to top +

The "Shortcuts" section of the config file holds all shortcuts in GPAC. You can define a shorcut for an action as:
+'action'='keyname' or 'action'='ctrl+keyname' or 'action'='alt+keyname' or "='action'='ctrl+alt+keyname'
+Shift is not supported as a key modifier, and case is insensitive. +Currently defined actions are as follows:

+Play or Pause
+Stop
+Step
+Exit
+Mute
+VolumeUp
+VolumeDown
+JumpForward
+JumpBackward
+JumpStart
+JumpEnd
+FastForward
+FineForward
+SlowForward
+FastRewind
+FineRewind
+SlowRewind
+Next
+Previous
+ +

+ + +Section "DSMCC" Back to top +

+The "DSMCC" section of the config file holds the configuration option for the processing of DSMCC data. +

+Activated [value: "true" "false"] +

+Specifies if the DSMCC data will be processed (true). It implies creations of directories and files in the temp directory.

+ + +

+ + +Section "OpenHEVC" Back to top +

+The openHEVC section of the config file holds the configuration option for the OpenHEVC decoder. +

+NumThreads [value: unsigned integer] +

+Specifies the number of threads to allocate to the OpenHEVC decoder. Default is the number of detected cores minus one, or one if core detection fails.

+ThreadingType [value: frame , wpp , frame+wpp ] +

+Specifies the threading type for the openHEVC decoder. Default is frame (wpp disabled).

+CBUnits [value: unsigned integer ] +

+Specifies the number of decoded frames in memory before display. Default value is 4.

+PackHFR [value: yes, no ] +

+Packs 4 consecutive frames in a single 4x frame.

+ + +

+ + +Section "DirectFB" Back to top +

+The "DirectFB" section of the config file holds the configuration options for the DirectFB output module. You may also want to check the official documentation. +

+DisableAcceleration [value: "yes" "no"] +

+Forces to disable hardware acceleration.

+DisableDisplay [value: "yes" "no"] +

+Specifies the DisableDisplay parameter value.

+FlipSyncMode [value: "waitsync" "wait" "sync" "swap"] +

+Specifies the flip sync mode.

+DisableBlit [value: "yes" "no"] +

+Forces to disable hardware blitting.

+WindowMode [value: "X11" "SDL"] +

+Specifies the underlying windowing library.

+ + +

+ + +Section "DektecVideo" Back to top +

+The "DektecVideo" section of the config file holds the configuration options for the Dektec SDI video output module. +

+SDIOutput [value: unsigned integer] +

+Specifies the output port of the card. Default value is 1.

+ + + diff --git a/extra_lib/include/DTAPI.h b/extra_lib/include/DTAPI.h new file mode 100644 index 0000000..2a027a0 --- /dev/null +++ b/extra_lib/include/DTAPI.h @@ -0,0 +1,7232 @@ +//*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#* DTAPI.h *#*#*#*#*#*#*#*#*#* (C) 2000-2015 DekTec +// +// DTAPI - C++ API for DekTec PCI/PCI-Express cards, USB-2 adapters and network devices +// + +#ifndef __DTAPI_H +#define __DTAPI_H + +// DTAPI version +#define DTAPI_VERSION_MAJOR 5 +#define DTAPI_VERSION_MINOR 14 +#define DTAPI_VERSION_BUGFIX 0 +#define DTAPI_VERSION_BUILD 56 + +//-.-.-.-.-.-.-.-.-.-.-.-.- Additional Libraries to be Linked In -.-.-.-.-.-.-.-.-.-.-.-.- + +#ifdef _WIN32 + +#ifndef _LIB // Do not link libraries into DTAPI itself +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "ws2_32.lib") +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "comctl32.lib") +#pragma comment(lib, "wbemuuid.lib") +#endif + +#ifndef _DTAPI_DISABLE_AUTO_LINK + // Are we using multi-threaded-DLL or static runtime libraries? + #ifdef _DLL + // Link with DLL runtime version (/MD) + #ifdef _DEBUG + #ifdef _WIN64 + #pragma comment(lib, "DTAPI64MDd.lib") // Debug 64bit + #pragma message("Automatically linking with DTAPI64MDd.lib") + #else + #pragma comment(lib, "DTAPIMDd.lib") // Debug 32bit + #pragma message("Automatically linking with DTAPIMDd.lib") + #endif + #else + #ifdef _WIN64 + #pragma comment(lib, "DTAPI64MD.lib") // Release 64bit + #pragma message("Automatically linking with DTAPI64MD.lib") + #else + #pragma comment(lib, "DTAPIMD.lib") // Release 32bit + #pragma message("Automatically linking with DTAPIMD.lib") + #endif + #endif + #else + // Link to static runtime version (/MT) + #ifdef _DEBUG + #ifdef _WIN64 + #pragma comment(lib, "DTAPI64MTd.lib") // Debug 64bit + #pragma message("Automatically linking with DTAPI64MTd.lib") + #else + #pragma comment(lib, "DTAPIMTd.lib") // Debug 32bit + #pragma message("Automatically linking with DTAPIMTd.lib") + #endif + #else + #ifdef _WIN64 + #pragma comment(lib, "DTAPI64MT.lib") // Release 64bit + #pragma message("Automatically linking with DTAPI64MT.lib") + #else + #pragma comment(lib, "DTAPIMT.lib") // Release 32bit + #pragma message("Automatically linking with DTAPIMT.lib") + #endif + #endif + #endif +#endif +#endif // #ifdef _WIN32 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- Includes -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- + +#ifndef _WIN32 + // Linux specific includes: For NULL type definition + #include + // For intptr_t + #include +#endif + +// STL includes +#include +#include +#include +#include +#include + +// When creating a DLL under Windows, disable warnings related to exporting STL +// instantiations in classes. +// See also: http://support.microsoft.com/kb/q168958/ +#ifdef _MSC_VER + #pragma warning(disable: 4251) +#endif + +// Macro used to mark functions as deprecated. Using deprecated functions will generate +// a compiler warning, pushing API users to stop using these functions. +#ifdef __GNUC__ +#define DTAPI_DEPRECATED(func, msg) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define DTAPI_DEPRECATED(func, msg) __declspec(deprecated(msg)) func +#else +#define DTAPI_DEPRECATED(func, msg) func +#endif + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- Support Types -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- + +#ifdef _WIN32 + typedef unsigned __int64 __uint64; +#else + typedef signed long long __int64; + typedef unsigned long long __uint64; +#endif + +// All DTAPI code lives in namespace Dtapi +namespace Dtapi +{ + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- Forward declarations -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- + +class AdvDemod; +class DtaPlusDevice; +class DtDemodPars; +class DtDvbT2Pars; +class DteDevice; +class DtSdiUtility; +class FrameBufImpl; +class IDevice; +class IDtDemodEvent; +class InpChannel; +class IXpMutex; +class MplpHelper; +class OutpChannel; +class SdiMatrixImpl; + +struct DtDabEnsembleInfo; +struct DtDabEtiStreamSelPars; +struct DtDabStreamSelPars; +struct DtDabTransmitterIdInfo; +struct DtDemodParsAtsc; +struct DtDemodParsDab; +struct DtDemodParsDvbC2; +struct DtDemodParsDvbS; +struct DtDemodParsDvbS2; +struct DtDemodParsDvbT; +struct DtDemodParsDvbT2; +struct DtDemodParsIq; +struct DtDemodParsIq2131; +struct DtDemodParsIsdbt; +struct DtDemodParsQam; +struct DtDemodLdpcStats; +struct DtDemodMaLayerData; +struct DtDemodMaLayerStats; +struct DtDemodPlpBlocks; +struct DtDvbC2DemodL1Part2Data; +struct DtDvbC2DemodL1PlpSigData; +struct DtDvbC2ModStatus; +struct DtDvbC2Pars; +struct DtDvbC2PlpPars; +struct DtDvbC2StreamSelPars; +struct DtDvbC2XFecFrameHeader; +struct DtDvbCidPars; +struct DtDvbS2ModStatus; +struct DtDvbS2ModCod; +struct DtDvbS2Pars; +struct DtDemodParsDvbS2Adv; +struct DtDvbTStreamSelPars; +struct DtDvbTTpsInfo; +struct DtDvbT2DemodL1Data; +struct DtDvbT2ModStatus; +struct DtDvbT2StreamSelPars; +struct DtFractionInt; +struct DtIsdbtStreamSelPars; +struct DtIsdbTmmPars; +struct DtPar; +struct DtPlpInpPars; +struct DtStatistic; +struct DtT2MiStreamSelPars; +struct DtVirtualOutData; +struct DtRsDecStats; +struct DtVitDecStats; + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//=+=+=+=+=+=+=+=+=+=+=+=+ DTAPI HELPER CLASSES AND HELPER TYPES +=+=+=+=+=+=+=+=+=+=+=+=+ +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DTAPI_RESULT -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- + +// Type returned by most API calls +typedef unsigned int DTAPI_RESULT; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtExc -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Exception object thrown from API calls (if API call throws an exception) +// +class DtExc +{ +public: + const DTAPI_RESULT m_Error; // DTAPI result code (i.e. reason of exception) + +public: + DtExc(DTAPI_RESULT e) : m_Error(e) {} + virtual ~DtExc() {} +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtBufferInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +struct DtBufferInfo +{ + int m_VidStd; // Video standard + int m_NumColumns; // Number of columns + __int64 m_NumReceived; // Number of frames received + __int64 m_NumDropped; // Number of frames dropped + __int64 m_NumTransmitted; // Number of frames transmitted + __int64 m_NumDuplicated; // Number of frames duplicated +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtCaps - Capabilities -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Scalable type for storing (combinations of) capability flags. +// It can be used with bitwise operators for testing and setting of capabilities. +// +class DtCaps +{ + // Number of 64-bit integers used to represent a capability + static const int DTCAPS_SIZE = 3; + +public: + DtCaps(); + DtCaps(int BitNr); + DtCaps(__int64 F1, __int64 F2, __int64 F3); + +public: + int GetCapIndex() const; + std::string ToString() const; + DtCaps operator & (const DtCaps& Caps) const; + DtCaps& operator &= (const DtCaps& Caps); + DtCaps operator | (const DtCaps& Caps) const; + DtCaps& operator |= (const DtCaps& Caps); + bool operator == (const DtCaps& Caps) const; + bool operator == (const int Zero) const; + bool operator != (const DtCaps& Caps) const; + bool operator != (const int Zero) const; + __int64 operator [] (const int n) const; + DtCaps operator ~ () const; + // Implementation data +private: + __int64 m_Flags[DTCAPS_SIZE]; +}; + +// Capabilities +#define DTAPI_CAP_EMPTY Dtapi::DtCaps() // DtCaps without any capability flags + +// Capability group APPS - Applications +#define DTAPI_CAP_C2X Dtapi::DtCaps(0) // C2Xpert +#define DTAPI_CAP_DP Dtapi::DtCaps(1) // DtGrabber+ and DtTV +#define DTAPI_CAP_DTTV Dtapi::DtCaps(2) // DtTV +#define DTAPI_CAP_E Dtapi::DtCaps(3) // DtEncode +#define DTAPI_CAP_J Dtapi::DtCaps(4) // DtJitter +#define DTAPI_CAP_MR Dtapi::DtCaps(5) // MuxXpert runtime +#define DTAPI_CAP_MS Dtapi::DtCaps(6) // MuxXpert SDK +#define DTAPI_CAP_MX Dtapi::DtCaps(7) // MuxXpert +#define DTAPI_CAP_RC Dtapi::DtCaps(8) // StreamXpress remote control +#define DTAPI_CAP_RX Dtapi::DtCaps(9) // RFXpert +#define DTAPI_CAP_SP Dtapi::DtCaps(10) // StreamXpress stream player +#define DTAPI_CAP_SPNIC Dtapi::DtCaps(11) // StreamXpress through local NIC +#define DTAPI_CAP_SX Dtapi::DtCaps(12) // StreamXpert analyzer +#define DTAPI_CAP_SXDGL Dtapi::DtCaps(13) // StreamXpert analyzer (dongled) +#define DTAPI_CAP_SY Dtapi::DtCaps(14) // SdEye +#define DTAPI_CAP_XP Dtapi::DtCaps(15) // Xpect +#define DTAPI_CAP_T2X Dtapi::DtCaps(16) // T2Xpert + +// Capability group BOOLIO - Boolean I/O capabilities +#define DTAPI_CAP_BW Dtapi::DtCaps(17) // Isochronous bandwidth allocated +#define DTAPI_CAP_FAILSAFE Dtapi::DtCaps(18) // A fail-over relay is available +#define DTAPI_CAP_FRACMODE Dtapi::DtCaps(19) // Fractional mode is supported +#define DTAPI_CAP_GENLOCKED Dtapi::DtCaps(20) // Locked to a genlock reference +#define DTAPI_CAP_GENREF Dtapi::DtCaps(21) // Genlock reference input +#define DTAPI_CAP_SWS2APSK Dtapi::DtCaps(22) // DVB-S2 APSK mode + +// Capability group DEMODPROPS - Demodulation properties +#define DTAPI_CAP_ANTPWR Dtapi::DtCaps(23) // Antenna power +#define DTAPI_CAP_LNB Dtapi::DtCaps(24) // LNB +#define DTAPI_CAP_RX_ADV Dtapi::DtCaps(25) // Advanced demodulation + +// Capability group FREQBAND - Frequency band +#define DTAPI_CAP_LBAND Dtapi::DtCaps(26) // L-band 950-2150MHz +#define DTAPI_CAP_VHF Dtapi::DtCaps(27) // VHF-band 47-470MHz +#define DTAPI_CAP_UHF Dtapi::DtCaps(28) // UHF-band 400-862MHz + +// Capability group IODIR - I/O direction +#define DTAPI_CAP_DISABLED Dtapi::DtCaps(29) // Port is disabled +#define DTAPI_CAP_INPUT Dtapi::DtCaps(30) // Uni-directional input +#define DTAPI_CAP_OUTPUT Dtapi::DtCaps(31) // Uni-directional output + +// Subcapabilities of IODIR, DTAPI_CAP_INPUT +#define DTAPI_CAP_SHAREDANT Dtapi::DtCaps(32) // Get antenna signal from another port + +// Subcapabilities of IODIR, DTAPI_CAP_OUTPUT +#define DTAPI_CAP_DBLBUF Dtapi::DtCaps(33) // Double buffered output +#define DTAPI_CAP_LOOPS2L3 Dtapi::DtCaps(34) // Loop-through of DVB-S2 in L3-frames +#define DTAPI_CAP_LOOPS2TS Dtapi::DtCaps(35) // Loop-through of an DVB-S(2) input +#define DTAPI_CAP_LOOPTHR Dtapi::DtCaps(36) // Loop-through of another input + +// Capability group IOPROPS - Miscellaneous I/O properties +#define DTAPI_CAP_ASIPOL Dtapi::DtCaps(37) // ASI output signal can be inverted +#define DTAPI_CAP_HUFFMAN Dtapi::DtCaps(38) // Huffman coding for SDI +#define DTAPI_CAP_IPPAIR Dtapi::DtCaps(39) // Network port supports failover +#define DTAPI_CAP_L3MODE Dtapi::DtCaps(40) // L3-frame mode +#define DTAPI_CAP_MATRIX Dtapi::DtCaps(41) // Matrix API support +#define DTAPI_CAP_MATRIX2 Dtapi::DtCaps(42) // High-level Matrix API support +#define DTAPI_CAP_RAWASI Dtapi::DtCaps(43) // Raw ASI +#define DTAPI_CAP_SDI10BNBO Dtapi::DtCaps(44) // 10-bit network byte order +#define DTAPI_CAP_SDITIME Dtapi::DtCaps(45) // SDI timestamping +#define DTAPI_CAP_TIMESTAMP64 Dtapi::DtCaps(46) // 64-bit timestamping +#define DTAPI_CAP_TRPMODE Dtapi::DtCaps(47) // Transparent mode +#define DTAPI_CAP_TS Dtapi::DtCaps(48) // MPEG-2 transport stream +#define DTAPI_CAP_TXONTIME Dtapi::DtCaps(49) // Transmit on timestamp +#define DTAPI_CAP_VIRTUAL Dtapi::DtCaps(50) // Virtual port, no physical connection + +// Capability group IOSTD - I/O standard +#define DTAPI_CAP_3GSDI Dtapi::DtCaps(51) // 3G-SDI +#define DTAPI_CAP_ASI Dtapi::DtCaps(52) // DVB-ASI transport stream +#define DTAPI_CAP_DEMOD Dtapi::DtCaps(53) // Demodulation +#define DTAPI_CAP_GPSTIME Dtapi::DtCaps(54) // Supports GPS-time +#define DTAPI_CAP_HDSDI Dtapi::DtCaps(55) // HD-SDI +#define DTAPI_CAP_IFADC Dtapi::DtCaps(56) // IF A/D converter +#define DTAPI_CAP_IP Dtapi::DtCaps(57) // Transport stream over IP +#define DTAPI_CAP_MOD Dtapi::DtCaps(58) // Modulator output +#define DTAPI_CAP_PHASENOISE Dtapi::DtCaps(59) // Phase noise injector +#define DTAPI_CAP_RS422 Dtapi::DtCaps(60) // RS422 port +#define DTAPI_CAP_SDI Dtapi::DtCaps(61) // SD-SDI +#define DTAPI_CAP_SPI Dtapi::DtCaps(62) // DVB-SPI transport stream +#define DTAPI_CAP_SPISDI Dtapi::DtCaps(63) // SD-SDI on a parallel port + +// Subcapabilities of IOSTD, DTAPI_CAP_3GSDI +#define DTAPI_CAP_1080P50 Dtapi::DtCaps(64) // 1080p/50 lvl A +#define DTAPI_CAP_1080P50B Dtapi::DtCaps(65) // 1080p/50 lvl B +#define DTAPI_CAP_1080P59_94 Dtapi::DtCaps(66) // 1080p/59.94 lvl A +#define DTAPI_CAP_1080P59_94B Dtapi::DtCaps(67) // 1080p/59.94 lvl B +#define DTAPI_CAP_1080P60 Dtapi::DtCaps(68) // 1080p/60 lvl A +#define DTAPI_CAP_1080P60B Dtapi::DtCaps(69) // 1080p/60 lvl B + +// Subcapabilities of IOSTD, DTAPI_CAP_HDSDI +#define DTAPI_CAP_1080I50 Dtapi::DtCaps(70) // 1080i/50 +#define DTAPI_CAP_1080I59_94 Dtapi::DtCaps(71) // 1080i/59.94 +#define DTAPI_CAP_1080I60 Dtapi::DtCaps(72) // 1080i/60 +#define DTAPI_CAP_1080P23_98 Dtapi::DtCaps(73) // 1080p/23.98 +#define DTAPI_CAP_1080P24 Dtapi::DtCaps(74) // 1080p/24 +#define DTAPI_CAP_1080P25 Dtapi::DtCaps(75) // 1080p/25 +#define DTAPI_CAP_1080P29_97 Dtapi::DtCaps(76) // 1080p/29.97 +#define DTAPI_CAP_1080P30 Dtapi::DtCaps(77) // 1080p/30 +#define DTAPI_CAP_1080PSF23_98 Dtapi::DtCaps(78) // 1080psf/23.98 +#define DTAPI_CAP_1080PSF24 Dtapi::DtCaps(79) // 1080psf/24 +#define DTAPI_CAP_1080PSF25 Dtapi::DtCaps(80) // 1080psf/25 +#define DTAPI_CAP_1080PSF29_97 Dtapi::DtCaps(81) // 1080psf/29.97 +#define DTAPI_CAP_1080PSF30 Dtapi::DtCaps(82) // 1080psf/30 +#define DTAPI_CAP_720P23_98 Dtapi::DtCaps(83) // 720p/23.98 +#define DTAPI_CAP_720P24 Dtapi::DtCaps(84) // 720p/24 +#define DTAPI_CAP_720P25 Dtapi::DtCaps(85) // 720p/25 +#define DTAPI_CAP_720P29_97 Dtapi::DtCaps(86) // 720p/29.97 +#define DTAPI_CAP_720P30 Dtapi::DtCaps(87) // 720p/30 +#define DTAPI_CAP_720P50 Dtapi::DtCaps(88) // 720p/50 +#define DTAPI_CAP_720P59_94 Dtapi::DtCaps(89) // 720p/59.94 +#define DTAPI_CAP_720P60 Dtapi::DtCaps(90) // 720p/60 + +// Subcapabilities of IOSTD, DTAPI_CAP_SDI +#define DTAPI_CAP_525I59_94 Dtapi::DtCaps(91) // 525i/59.94 +#define DTAPI_CAP_625I50 Dtapi::DtCaps(92) // 625i/50 + +// Subcapabilities of IOSTD, DTAPI_CAP_SPISDI +#define DTAPI_CAP_SPI525I59_94 Dtapi::DtCaps(93) // SPI 525i/59.94 +#define DTAPI_CAP_SPI625I50 Dtapi::DtCaps(94) // SPI 625i/50 + +// Capability group MODSTD - Modulation standards +#define DTAPI_CAP_TX_ATSC Dtapi::DtCaps(95) // ATSC 8-VSB modulation +#define DTAPI_CAP_TX_CMMB Dtapi::DtCaps(96) // CMMB modulation +#define DTAPI_CAP_TX_DAB Dtapi::DtCaps(97) // DAB modulation +#define DTAPI_CAP_TX_DTMB Dtapi::DtCaps(98) // DTMB modulation +#define DTAPI_CAP_TX_DVBC2 Dtapi::DtCaps(99) // DVB-C2 modulation +#define DTAPI_CAP_TX_DVBS Dtapi::DtCaps(100) // DVB-S modulation +#define DTAPI_CAP_TX_DVBS2 Dtapi::DtCaps(101) // DVB-S2 modulation +#define DTAPI_CAP_TX_DVBS2X Dtapi::DtCaps(102) // DVB-S2X modulation +#define DTAPI_CAP_TX_DVBT Dtapi::DtCaps(103) // DVB-T modulation +#define DTAPI_CAP_TX_DVBT2 Dtapi::DtCaps(104) // DVB-T2 modulation +#define DTAPI_CAP_TX_GOLD Dtapi::DtCaps(105) // GOLD for modulators +#define DTAPI_CAP_TX_IQ Dtapi::DtCaps(106) // I/Q sample modulation +#define DTAPI_CAP_TX_ISDBS Dtapi::DtCaps(107) // ISDB-S modulation +#define DTAPI_CAP_TX_ISDBT Dtapi::DtCaps(108) // ISDB-T modulation +#define DTAPI_CAP_TX_ISDBTMM Dtapi::DtCaps(109) // ISDB-Tmm modulation +#define DTAPI_CAP_TX_MH Dtapi::DtCaps(110) // ATSC-MH modulation +#define DTAPI_CAP_TX_QAMA Dtapi::DtCaps(111) // QAM-A modulation +#define DTAPI_CAP_TX_QAMB Dtapi::DtCaps(112) // QAM-B modulation +#define DTAPI_CAP_TX_QAMC Dtapi::DtCaps(113) // QAM-C modulation +#define DTAPI_CAP_TX_SWMC Dtapi::DtCaps(114) // SW multi-channel modulation +#define DTAPI_CAP_TX_T2MI Dtapi::DtCaps(115) // T2MI transmission +#define DTAPI_CAP_TX_T2SPLP Dtapi::DtCaps(116) // DVB-T2 single PLP modulation + +// Capability group MODPROPS - Modulation properties +#define DTAPI_CAP_ADJLVL Dtapi::DtCaps(117) // Adjustable output level +#define DTAPI_CAP_CM Dtapi::DtCaps(118) // Channel simulation +#define DTAPI_CAP_CW Dtapi::DtCaps(119) // Continuous wave +#define DTAPI_CAP_DIGIQ Dtapi::DtCaps(120) // Digital I/Q sample output +#define DTAPI_CAP_DVBCID Dtapi::DtCaps(121) // DVB carrier ID +#define DTAPI_CAP_IF Dtapi::DtCaps(122) // IF output +#define DTAPI_CAP_MUTE Dtapi::DtCaps(123) // Mute RF output signal +#define DTAPI_CAP_ROLLOFF Dtapi::DtCaps(124) // Adjustable roll-off factor +#define DTAPI_CAP_S2APSK Dtapi::DtCaps(125) // DVB-S2 16-APSK/32-APSK +#define DTAPI_CAP_SNR Dtapi::DtCaps(126) // AWGN insertion +#define DTAPI_CAP_TX_16MHZ Dtapi::DtCaps(127) // 16MHz bandwidth mode +#define DTAPI_CAP_TX_SFN Dtapi::DtCaps(128) // SNF operation + +// Capability group RFCLKSEL - RF clock source selection +#define DTAPI_CAP_RFCLKEXT Dtapi::DtCaps(129) // External RF clock input +#define DTAPI_CAP_RFCLKINT Dtapi::DtCaps(130) // Internal RF clock reference + +// Capability group RXSTD - Receiver standards +#define DTAPI_CAP_RX_ATSC Dtapi::DtCaps(131) // ATSC 8-VSB reception +#define DTAPI_CAP_RX_CMMB Dtapi::DtCaps(132) // CMMB reception +#define DTAPI_CAP_RX_DAB Dtapi::DtCaps(133) // DAB reception +#define DTAPI_CAP_RX_DTMB Dtapi::DtCaps(134) // DTMB reception +#define DTAPI_CAP_RX_DVBC2 Dtapi::DtCaps(135) // DVB-C2 reception +#define DTAPI_CAP_RX_DVBS Dtapi::DtCaps(136) // DVB-S reception +#define DTAPI_CAP_RX_DVBS2 Dtapi::DtCaps(137) // DVB-S2 reception +#define DTAPI_CAP_RX_DVBT Dtapi::DtCaps(138) // DVB-T reception +#define DTAPI_CAP_RX_DVBT2 Dtapi::DtCaps(139) // DVB-T2 reception +#define DTAPI_CAP_RX_GOLD Dtapi::DtCaps(140) // GOLD for receivers +#define DTAPI_CAP_RX_IQ Dtapi::DtCaps(141) // I/Q sample reception +#define DTAPI_CAP_RX_ISDBS Dtapi::DtCaps(142) // ISDB-S reception +#define DTAPI_CAP_RX_ISDBT Dtapi::DtCaps(143) // ISDB-T reception +#define DTAPI_CAP_RX_MH Dtapi::DtCaps(144) // ATSC-MH reception +#define DTAPI_CAP_RX_QAMA Dtapi::DtCaps(145) // QAM-A reception +#define DTAPI_CAP_RX_QAMB Dtapi::DtCaps(146) // QAM-B reception +#define DTAPI_CAP_RX_QAMC Dtapi::DtCaps(147) // QAM-C reception +#define DTAPI_CAP_RX_T2MI Dtapi::DtCaps(148) // T2MI reception + +// Capability group SPICLKSEL - Parallel port clock source selection +#define DTAPI_CAP_SPICLKEXT Dtapi::DtCaps(149) // External clock input +#define DTAPI_CAP_SPICLKINT Dtapi::DtCaps(150) // Internal clock reference + +// Capability group SPIMODE - Parallel port mode +#define DTAPI_CAP_SPIFIXEDCLK Dtapi::DtCaps(151) // SPI fixed clock with valid signal +#define DTAPI_CAP_SPIDVBMODE Dtapi::DtCaps(152) // SPI DVB mode +#define DTAPI_CAP_SPISER8B Dtapi::DtCaps(153) // SPI serial 8-bit mode +#define DTAPI_CAP_SPISER10B Dtapi::DtCaps(154) // SPI serial 10-bit mode + +// Capability group SPISTD - Parallel port I/O standard +#define DTAPI_CAP_SPILVDS1 Dtapi::DtCaps(155) // LVDS1 +#define DTAPI_CAP_SPILVDS2 Dtapi::DtCaps(156) // LVDS2 +#define DTAPI_CAP_SPILVTTL Dtapi::DtCaps(157) // LVTTL + +// Capability group TSRATESEL - Transport-stream rate selection +#define DTAPI_CAP_EXTTSRATE Dtapi::DtCaps(158) // External TS rate clock input +#define DTAPI_CAP_EXTRATIO Dtapi::DtCaps(159) // External TS rate clock with ratio +#define DTAPI_CAP_INTTSRATE Dtapi::DtCaps(160) // Internal TS rate clock reference +#define DTAPI_CAP_LOCK2INP Dtapi::DtCaps(161) // Lock TS rate to input port + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtCmmbPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// CMMB Modulation Parameters +// +struct DtCmmbPars +{ + int m_Bandwidth; // CMMB Bandwitdh + int m_TsRate; // CMMB TS rate in bps + int m_TsPid; // PID on which the CMMB stream is found + int m_AreaId; // Area ID (0..127) + int m_TxId; // Transmitter ID (128..255) + +public: + DtCmmbPars(); + DTAPI_RESULT RetrieveTsRateFromTs(char* pBuffer, int NumBytes); + bool operator == (DtCmmbPars& Rhs); + bool operator != (DtCmmbPars& Rhs); +}; + +// DtOutpChannel::SetModControl - Bandwidth +#define DTAPI_CMMB_BW_2MHZ 0x00000000 +#define DTAPI_CMMB_BW_8MHZ 0x00000001 + +//-.-.-.-.-.-.-.-.-.-.-.- DtCmPars - Channel Modelling Parameters -.-.-.-.-.-.-.-.-.-.-.-. + +// Maximum number of fading paths +#define DTAPI_CM_MAX_PATHS 32 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtCmPath -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure describes the fading parameters for a single path in a +// multi-path simulation. +// +struct DtCmPath +{ + enum Type + { + CONSTANT_DELAY, // Constant delay/phase + CONSTANT_DOPPLER, // Constant frequency shift + RAYLEIGH_JAKES, // Rayleigh fading with Jakes power spectral density + // (mobile path model) + RAYLEIGH_GAUSSIAN // Rayleigh fading with Gaussian power spectral + // density (ionospheric path model) + }; + Type m_Type; // Type of path fading + double m_Attenuation; // Attenuation in dB + double m_Delay; // Delay in us + double m_Phase; // Phase shift in degrees for CONSTANT_DELAY paths + double m_Doppler; // Doppler frequency in Hz + + // Constructor - Gives parameters a default value + DtCmPath() : + m_Type(CONSTANT_DELAY), + m_Attenuation(0.0), m_Delay(0.0), m_Phase(0.0), m_Doppler(0.0) + {} + // Operators + bool operator == (DtCmPath& Rhs); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtCmPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure describes channel-modeling parameters. It\92s used to simulate the +// transmission distortions that may occur in the channel between a transmitter and +// a receiver. +// +struct DtCmPars +{ + bool m_EnableAwgn; // Enable white Gaussian noise (AWGN) injection + double m_Snr; // Signal-to-noise ratio in dB + bool m_EnablePaths; // Enable multi-path simulation + std::vector m_Paths; // Parameters per path + + // Constructor and operators + DtCmPars(); + bool operator == (DtCmPars&); + bool operator != (DtCmPars& Rhs) { return !(*this == Rhs); } +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtConstelPoint -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// This structure describes a constellation point in a receiver constellation diagram +// +struct DtConstelPoint +{ + int m_X, m_Y; // X and Y coordinates +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- IDtDemodEvent -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Callback event interface for demodulators +// +class IDtDemodEvent +{ +public: + virtual void TuningFreqHasChanged(__int64 OldFreqHz, __int64 NewFreqHz) {} + virtual void TuningParsHaveChanged( + __int64 OldFreqHz, int OldModType, int OldParXtra[3], + __int64 NewFreqHz, int NewModType, int NewParXtra[3]) {} +}; + + +// Maximum number of IpV6 addresses per interface +#define MAX_IPV6_ADDR 3 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDeviceDesc -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure describes a DekTec device +// +struct DtDeviceDesc +{ + int m_Category; // Device category (DTAPI_CAT_XXX) + __int64 m_Serial; // Unique serial number of the device + int m_PciBusNumber; // PCI-bus number + int m_SlotNumber; // PCI-slot number + int m_UsbAddress; // USB address + int m_TypeNumber; // Device type number + int m_SubType; // Device subtype (0=none, 1=A, ...) + int m_DeviceId; // Device ID + int m_VendorId; // Vendor ID + int m_SubsystemId; // Subsystem ID + int m_SubVendorId; // Subsystem Vendor ID + int m_NumHwFuncs; // Number of hardware funtions hosted by device + int m_HardwareRevision; // Hardware revision (e.g. 302 = 3.2) + int m_FirmwareVersion; // Firmware version + int m_FirmwareVariant; // Firmware variant + int m_NumDtInpChan; // Number of input channels (max) + int m_NumDtOutpChan; // Number of output channels (max) + int m_NumPorts; // Number of physical ports + unsigned char m_Ip[4]; // IP address (only valid for DTE-31xx devices) + unsigned char m_IpV6[MAX_IPV6_ADDR][16]; + // IP address (only valid for DTE-31xx devices) + unsigned char m_MacAddr[6]; // MAC address (only valid for DTE-31xx devices) + int m_PcieNumLanes; // Number of allocated PCIe lanes + int m_PcieMaxLanes; // Maximum number of PCIe lanes + int m_PcieLinkSpeed; // Current PCIe link speed (GEN1, 2 or 3) + int m_PcieMaxSpeed; // Maximum PCIe link speed (GEN1, 2 or 3) +}; + +// Device categories +#define DTAPI_CAT_PCI 0 // PCI or PCI-Express device +#define DTAPI_CAT_USB 1 // USB-2 or USB-3 device +#define DTAPI_CAT_NW 2 // Network device +#define DTAPI_CAT_IP 3 // Network appliance: DTE-31xx +#define DTAPI_CAT_NIC 4 // Non-DekTec network card +#define DTAPI_CAT_NWAP 5 // Network Advanced Protocol(VLAN device) + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDtaPlusDeviceDesc -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// This structure describes a DekTec DTA-plus device +// +struct DtDtaPlusDeviceDesc +{ + __int64 m_Serial; // Unique serial number of the device + std::string m_DevicePath; // Path of file to open to interface with the device +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDvbCidPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for specifying the DVB channel identification for satellite (DVB-S2) +// ETSI TS 103 129 +// +struct DtDvbCidPars +{ + bool m_Enable; // Enable DVB-CID signalling + unsigned int m_GuidHigh; // DVB-CID Global Unique Identifier MSBs + unsigned int m_GuidLow; // DVB-CID Global Unique Identifier LSBs + + // CID content. Key: Content ID (0...31); Value: Content information (24-bit) + // Content ID 0 (carrier ID format) shall have the value 0x0001 + std::map m_Content; + + DTAPI_RESULT CheckValidity(); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtEventArgs -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Details for a specific event +// +struct DtEventArgs +{ + DtEventArgs() : m_Value1(0), m_Value2(0), m_pContext(0) {}; + + int m_HwCat; // Hardware category: DTAPI_CAT_XXX + __int64 m_Serial; // Serial number of device causing event + int m_Value1; // Event value #1 + int m_Value2; // Event value #2 + void* m_pContext; // Context-specific pointer +}; + +// Event call back function +typedef void (*pDtEventCallback)(int Event, const DtEventArgs* pArgs); + +// Global events +#define DT_EVENT_TYPE_ADD 0x00000001 +#define DT_EVENT_TYPE_REMOVE 0x00000002 +// Device events +#define DT_EVENT_TYPE_POWER 0x00000004 +#define DT_EVENT_TYPE_GENLOCK 0x00000008 +#define DT_EVENT_TYPE_TEST 0x80000000 +// Network events +#define DT_EVENT_IP_CHANGED 0x01000000 +#define DT_EVENT_ADMINST_CHANGED 0x02000000 + +#define DT_EVENT_TYPE_ALL 0xFFFFFFFF + +// Event values +#define DT_EVENT_VALUE1_POWER_UP 1 +#define DT_EVENT_VALUE1_POWER_DOWN 2 +#define DT_EVENT_VALUE1_NO_LOCK 1 +#define DT_EVENT_VALUE1_LOCKED 2 +#define DT_EVENT_VALUE2_XXX 1 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFiltCoeff -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// A single FIR filter coefficient +// +struct DtFiltCoeff +{ + int m_TapIdx; // Tap number + double m_Coeff; // FIR coefficient +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFilterPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Filter coefficients for use in a FIR filter +// +struct DtFilterPars +{ + std::vector m_FiltCoeffs; +}; + +// Maximum number of filter coefficients +#define DTAPI_MAX_NUM_COEFFS 64 + +#define DTAPI_FRAME_STATUS_OK 0 +#define DTAPI_FRAME_STATUS_ERR_NO_SIGNAL 1 +#define DTAPI_FRAME_STATUS_ERR_STD_MISMATCH 2 + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFractionInt -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// A rational number, expressed as the quotient of two integers +// +struct DtFractionInt +{ + int m_Num, m_Den; + DtFractionInt() { m_Num = 0; m_Den = 1; } + DtFractionInt(int Num, int Den) { m_Num = Num; m_Den = Den; } +}; + + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFrameInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +struct DtFrameInfo +{ + int m_VidStd; // Video standard + __int64 m_Timestamp; // 64-bit timestamp + __int64 m_FrameNumber; // 64-bit frame number + __int64 m_Rp188; // RP188 timestamp + int m_RxMode; // RX mode at the time this frame was received + int m_Status; // One of DTAPI_FRAME_STATUS_* +}; + +//-.-.-.-.-.-.-.-.-.-.- DtHwFuncDesc - Hardware Function Descriptor -.-.-.-.-.-.-.-.-.-.-. +// +// Structure describing a hardware function +// +struct DtHwFuncDesc +{ + DtDeviceDesc m_DvcDesc; // Device descriptor + int m_ChanType; // Channel type (OR-able) + DtCaps m_Flags; // Capability flags (OR-able) + int m_IndexOnDvc; // Relative index of hardware function + int m_Port; // Physical port number + unsigned char m_Ip[4]; // IP V4 address (TS-over-IP functions only) + unsigned char m_IpV6[MAX_IPV6_ADDR][16]; + // IP V6 address (TS-over-IP functions only) + unsigned char m_MacAddr[6]; // MAC address (TS-over-IP functions only) +}; + +// Hardware Function - Channel types +// For IP hardware functions, both DTAPI_CHAN_INPUT and DTAPI_CHAN_OUTPUT are set +#define DTAPI_CHAN_DISABLED 0 // Channel is disabled +#define DTAPI_CHAN_INPUT 1 // Input channel +#define DTAPI_CHAN_OUTPUT 2 // Output channel +#define DTAPI_CHAN_DBLBUF 4 // Double-buffered copy of an output +#define DTAPI_CHAN_LOOPTHR 8 // Loop-through copy of another port + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIoConfig - I/O Configuration -.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Stores the I/O configuration parameters for one I/O port configuration +// +struct DtIoConfig +{ + int m_Port; // Port number + int m_Group; // Config group, linked to I/O capability groups + int m_Value; // Config value, linked to I/O capabilities + int m_SubValue; // Config sub value, linked to I/O sub capabilities + __int64 m_ParXtra[2]; // Extra parameters, e.g. source port number + + // Constructor - Gives parameters a default value + DtIoConfig() + { + m_Port = -1; + m_Group = -1; + m_Value = m_SubValue = -1; + m_ParXtra[0] = m_ParXtra[1] = -1; + } + DtIoConfig(int Port, int Group) + { + m_Port = Port; + m_Group = Group; + m_Value = m_SubValue = -1; + m_ParXtra[0] = m_ParXtra[1] = -1; + } +}; + +// I/O configuration groups +#define DTAPI_IOCONFIG_IODIR 0 // I/O direction +#define DTAPI_IOCONFIG_IOSTD 1 // I/O standard +#define DTAPI_IOCONFIG_RFCLKSEL 2 // RF clock source selection +#define DTAPI_IOCONFIG_SPICLKSEL 3 // Parallel port clock source selection +#define DTAPI_IOCONFIG_SPIMODE 4 // Parallel port mode +#define DTAPI_IOCONFIG_SPISTD 5 // Parallel port I/O standard +#define DTAPI_IOCONFIG_TSRATESEL 6 // Transport-stream rate selection + +// I/O configuration groups - Boolean I/O +#define DTAPI_IOCONFIG_BW 7 // Isochronous bandwidth allocated +#define DTAPI_IOCONFIG_FAILSAFE 8 // A fail-over relay is available +#define DTAPI_IOCONFIG_FRACMODE 9 // Fractional mode is supported +#define DTAPI_IOCONFIG_GENLOCKED 10 // Locked to a genlock reference +#define DTAPI_IOCONFIG_GENREF 11 // Genlock reference input +#define DTAPI_IOCONFIG_SWS2APSK 12 // DVB-S2 APSK mode + +// Values for boolean I/O configuration options +#define DTAPI_IOCONFIG_TRUE 13 // Turn I/O capability on +#define DTAPI_IOCONFIG_FALSE 14 // Turn I/O capability off + +// Values for group IO_CONFIG_IODIR (I/O direction) +#define DTAPI_IOCONFIG_DISABLED 15 // Port is disabled +#define DTAPI_IOCONFIG_INPUT 16 // Uni-directional input +#define DTAPI_IOCONFIG_OUTPUT 17 // Uni-directional output + +// SubValues for group DTAPI_IOCONFIG_IODIR, value DTAPI_IOCONFIG_INPUT +#define DTAPI_IOCONFIG_SHAREDANT 18 // Get antenna signal from another port + +// SubValues for group DTAPI_IOCONFIG_IODIR, value DTAPI_IOCONFIG_OUTPUT +#define DTAPI_IOCONFIG_DBLBUF 19 // Double buffered output +#define DTAPI_IOCONFIG_LOOPS2L3 20 // Loop-through of DVB-S2 in L3-frames +#define DTAPI_IOCONFIG_LOOPS2TS 21 // Loop-through of an DVB-S(2) input +#define DTAPI_IOCONFIG_LOOPTHR 22 // Loop-through of another input + +// Values for group IO_CONFIG_IOSTD (I/O standard) +#define DTAPI_IOCONFIG_3GSDI 23 // 3G-SDI +#define DTAPI_IOCONFIG_ASI 24 // DVB-ASI transport stream +#define DTAPI_IOCONFIG_DEMOD 25 // Demodulation +#define DTAPI_IOCONFIG_GPSTIME 26 // Supports GPS-time +#define DTAPI_IOCONFIG_HDSDI 27 // HD-SDI +#define DTAPI_IOCONFIG_IFADC 28 // IF A/D converter +#define DTAPI_IOCONFIG_IP 29 // Transport stream over IP +#define DTAPI_IOCONFIG_MOD 30 // Modulator output +#define DTAPI_IOCONFIG_PHASENOISE 31 // Phase noise injector +#define DTAPI_IOCONFIG_RS422 32 // RS422 port +#define DTAPI_IOCONFIG_SDI 33 // SD-SDI +#define DTAPI_IOCONFIG_SPI 34 // DVB-SPI transport stream +#define DTAPI_IOCONFIG_SPISDI 35 // SD-SDI on a parallel port + +// SubValues for group DTAPI_IOCONFIG_IOSTD, value DTAPI_IOCONFIG_3GSDI +#define DTAPI_IOCONFIG_1080P50 36 // 1080p/50 lvl A +#define DTAPI_IOCONFIG_1080P50B 37 // 1080p/50 lvl B +#define DTAPI_IOCONFIG_1080P59_94 38 // 1080p/59.94 lvl A +#define DTAPI_IOCONFIG_1080P59_94B 39 // 1080p/59.94 lvl B +#define DTAPI_IOCONFIG_1080P60 40 // 1080p/60 lvl A +#define DTAPI_IOCONFIG_1080P60B 41 // 1080p/60 lvl B + +// SubValues for group DTAPI_IOCONFIG_IOSTD, value DTAPI_IOCONFIG_HDSDI +#define DTAPI_IOCONFIG_1080I50 42 // 1080i/50 +#define DTAPI_IOCONFIG_1080I59_94 43 // 1080i/59.94 +#define DTAPI_IOCONFIG_1080I60 44 // 1080i/60 +#define DTAPI_IOCONFIG_1080P23_98 45 // 1080p/23.98 +#define DTAPI_IOCONFIG_1080P24 46 // 1080p/24 +#define DTAPI_IOCONFIG_1080P25 47 // 1080p/25 +#define DTAPI_IOCONFIG_1080P29_97 48 // 1080p/29.97 +#define DTAPI_IOCONFIG_1080P30 49 // 1080p/30 +#define DTAPI_IOCONFIG_1080PSF23_98 50 // 1080psf/23.98 +#define DTAPI_IOCONFIG_1080PSF24 51 // 1080psf/24 +#define DTAPI_IOCONFIG_1080PSF25 52 // 1080psf/25 +#define DTAPI_IOCONFIG_1080PSF29_97 53 // 1080psf/29.97 +#define DTAPI_IOCONFIG_1080PSF30 54 // 1080psf/30 +#define DTAPI_IOCONFIG_720P23_98 55 // 720p/23.98 +#define DTAPI_IOCONFIG_720P24 56 // 720p/24 +#define DTAPI_IOCONFIG_720P25 57 // 720p/25 +#define DTAPI_IOCONFIG_720P29_97 58 // 720p/29.97 +#define DTAPI_IOCONFIG_720P30 59 // 720p/30 +#define DTAPI_IOCONFIG_720P50 60 // 720p/50 +#define DTAPI_IOCONFIG_720P59_94 61 // 720p/59.94 +#define DTAPI_IOCONFIG_720P60 62 // 720p/60 + +// SubValues for group DTAPI_IOCONFIG_IOSTD, value DTAPI_IOCONFIG_SDI +#define DTAPI_IOCONFIG_525I59_94 63 // 525i/59.94 +#define DTAPI_IOCONFIG_625I50 64 // 625i/50 + +// SubValues for group DTAPI_IOCONFIG_IOSTD, value DTAPI_IOCONFIG_SPISDI +#define DTAPI_IOCONFIG_SPI525I59_94 65 // SPI 525i/59.94 +#define DTAPI_IOCONFIG_SPI625I50 66 // SPI 625i/50 + +// Values for group IO_CONFIG_RFCLKSEL (RF clock source selection) +#define DTAPI_IOCONFIG_RFCLKEXT 67 // External RF clock input +#define DTAPI_IOCONFIG_RFCLKINT 68 // Internal RF clock reference + +// Values for group IO_CONFIG_SPICLKSEL (Parallel port clock source selection) +#define DTAPI_IOCONFIG_SPICLKEXT 69 // External clock input +#define DTAPI_IOCONFIG_SPICLKINT 70 // Internal clock reference + +// Values for group IO_CONFIG_SPIMODE (Parallel port mode) +#define DTAPI_IOCONFIG_SPIFIXEDCLK 71 // SPI fixed clock with valid signal +#define DTAPI_IOCONFIG_SPIDVBMODE 72 // SPI DVB mode +#define DTAPI_IOCONFIG_SPISER8B 73 // SPI serial 8-bit mode +#define DTAPI_IOCONFIG_SPISER10B 74 // SPI serial 10-bit mode + +// Values for group IO_CONFIG_SPISTD (Parallel port I/O standard) +#define DTAPI_IOCONFIG_SPILVDS1 75 // LVDS1 +#define DTAPI_IOCONFIG_SPILVDS2 76 // LVDS2 +#define DTAPI_IOCONFIG_SPILVTTL 77 // LVTTL + +// Values for group IO_CONFIG_TSRATESEL (Transport-stream rate selection) +#define DTAPI_IOCONFIG_EXTTSRATE 78 // External TS rate clock input +#define DTAPI_IOCONFIG_EXTRATIO 79 // External TS rate clock with ratio +#define DTAPI_IOCONFIG_INTTSRATE 80 // Internal TS rate clock reference +#define DTAPI_IOCONFIG_LOCK2INP 81 // Lock TS rate to input port + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIqData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure representing an I/Q data sample +// +struct DtIqData +{ + int m_I, m_Q; // I/Q sample pair +}; +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIqDirectPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Direct-IQ Modulation Parameters +// +struct DtIqDirectPars +{ + DtFractionInt m_SampleRate; // Sample rate + int m_IqPacking; // IQ-Packing; None, Auto, 10- or 12-bit packing + int m_ChanFilter; // Channel filter + int m_Interpolation; // Interpolation method + + +public: + DTAPI_RESULT CheckValidity(void); +}; + + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbsLayerPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// DtIsdbsLayerPars +// +struct DtIsdbsLayerPars +{ + int m_NumSlots; // Number of slots + int m_ModCod; // Modulation method and Code rate +}; + +// Number of slots per ISDB-S frame +#define DTAPI_ISDBS_SLOTS_PER_FRAME 48 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbsPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// ISDB-S parameters including per-layer parameters +// +struct DtIsdbsPars +{ + DtIsdbsPars() : m_DoMux(false), m_B15Mode(false) {} + + bool m_DoMux; // Hierarchical multiplexing yes/no + + // Parameters for when m_DoMux==false + bool m_B15Mode; // ARIB B.15 mode (true) or TMCC in sync bytes (false) + + // Parameters for when m_DoMux==true + int m_Emergency; // Switch-on control for emergency broadcast + int m_RelTs2TsId[8]; // Relative TS to TS-ID mapping + // Slot to relative TS mapping + int m_Slot2RelTs[DTAPI_ISDBS_SLOTS_PER_FRAME]; + // Modulation parameters per hierarchical layer + DtIsdbsLayerPars m_LayerPars[4]; + + DTAPI_RESULT CheckValidity(void); + void Init(void); + bool operator == (DtIsdbsPars& Rhs); + bool operator != (DtIsdbsPars& Rhs); +}; + +// ISDB-S modulation method and code rate +#define DTAPI_ISDBS_MODCOD_BPSK_1_2 1 +#define DTAPI_ISDBS_MODCOD_QPSK_1_2 2 +#define DTAPI_ISDBS_MODCOD_QPSK_2_3 3 +#define DTAPI_ISDBS_MODCOD_QPSK_3_4 4 +#define DTAPI_ISDBS_MODCOD_QPSK_5_6 5 +#define DTAPI_ISDBS_MODCOD_QPSK_7_8 6 +#define DTAPI_ISDBS_MODCOD_8PSK_2_3 7 +#define DTAPI_ISDBS_MODCOD_NOT_ALLOC 15 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbtLayerData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Parameters per hierarchical ISDB-T layer used for statistic: DTAPI_STAT_ISDBT_PARSDATA +// +struct DtIsdbtLayerData +{ + int m_NumSegments; // Number of segments + int m_Modulation; // Modulation type + int m_CodeRate; // Code rate + int m_TimeInterleave; // Time interleaving 0..4 (new spec limits the + // maximum value to 3 instead of 4). + // Time interleaving I = 0 if ti = 0 or + // I = (1 << (ti + 2 - mode)) if ti != 0 + DtIsdbtLayerData(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbtLayerPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Parameters per hierarchical ISDB-T layer +// +struct DtIsdbtLayerPars +{ + int m_NumSegments; // Number of segments + int m_Modulation; // Modulation type + int m_CodeRate; // Code rate + int m_TimeInterleave; // Time interleaving + // Derived: + int m_BitRate; // Bits per second assuming 6 MHz channel +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbtParamsData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// ISDB-T parameters including per-layer parameters used for statistic: +// DTAPI_STAT_ISDBT_PARSDATA +// +struct DtIsdbtParamsData +{ + int m_BType; // Broadcast type + int m_Mode; // Transmission mode: 1, 2 or 3 + int m_Guard; // Guard interval + int m_PartialRx; // Use first layer for partial reception. + // Ignored for radio broadcasts + // Layer-A/B/C parameters + DtIsdbtLayerData m_LayerPars[3]; + + DtIsdbtParamsData(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbtPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// ISDB-T parameters including per-layer parameters +// +struct DtIsdbtPars +{ + bool m_DoMux; // Hierarchical multiplexing yes/no + bool m_FilledOut; // Members have been given a value + int m_ParXtra0; // #Segments, bandwidth, sample rate, sub channel + int m_BType; // Broadcast type + int m_Mode; // Transmission mode + int m_Guard; // Guard interval + int m_PartialRx; // Partal reception + int m_Emergency; // Switch-on control for emergency broadcast + int m_IipPid; // PID used for multiplexing IIP packet + int m_LayerOther; // Other PIDs are mapped to this layer + int m_Virtual13Segm; // Virtual 13-segment mode + + // Layer-A/B/C parameters + DtIsdbtLayerPars m_LayerPars[3]; + + // PID-to-layer mapping + std::map m_Pid2Layer; + + // Derived: + bool m_Valid; // The parameter set is valid + int m_TotalBitrate; // Bitrate of entire stream + + // Member function + DtIsdbtPars(); + static bool BTypeCompat(int BType, int NumSegm); + DTAPI_RESULT CheckValidity(int& ResultCode); + DTAPI_RESULT ComputeRates(void); + void MakeConsistent(); + void MakeNumSegmConsistent(); + int NumSegm(); + DTAPI_RESULT RetrieveParsFromTs(char* pBuffer, int NumBytes); + bool operator == (DtIsdbtPars& Rhs); + bool operator != (DtIsdbtPars& Rhs); +}; + + + + +// ISDB-T layer selection used for demodulation +#define DTAPI_ISDBT_LAYER_NONE -1 +#define DTAPI_ISDBT_LAYER_AUTO -2 + +// PID-to-layer mapping +#define DTAPI_ISDBT_LAYER_A 1 +#define DTAPI_ISDBT_LAYER_B 2 +#define DTAPI_ISDBT_LAYER_C 4 + +// DtIsdbtPars.m_BType - Broadcast type +#define DTAPI_ISDBT_BTYPE_TV 0 // 1/3/13-segment TV broadcast +#define DTAPI_ISDBT_BTYPE_RAD1 1 // 1-segment radio broadcast +#define DTAPI_ISDBT_BTYPE_RAD3 2 // 3-segment radio broadcast + +// DtIsdbtPars.m_Guard - Guard interval +#define DTAPI_ISDBT_GUARD_1_32 0 +#define DTAPI_ISDBT_GUARD_1_16 1 +#define DTAPI_ISDBT_GUARD_1_8 2 +#define DTAPI_ISDBT_GUARD_1_4 3 + +// DtIsdbtLayerPars.m_Modulation - Modulation type +#define DTAPI_ISDBT_MOD_DQPSK 0 +#define DTAPI_ISDBT_MOD_QPSK 1 +#define DTAPI_ISDBT_MOD_QAM16 2 +#define DTAPI_ISDBT_MOD_QAM64 3 + +// DtIsdbtLayerPars.m_CodeRate - Code rate +#define DTAPI_ISDBT_RATE_1_2 0 +#define DTAPI_ISDBT_RATE_2_3 1 +#define DTAPI_ISDBT_RATE_3_4 2 +#define DTAPI_ISDBT_RATE_5_6 3 +#define DTAPI_ISDBT_RATE_7_8 4 + +// DtOutpChannel::SetModControl - Initial Total Number of Segments +#define DTAPI_ISDBT_SEGM_1 0x00000001 +#define DTAPI_ISDBT_SEGM_3 0x00000003 +#define DTAPI_ISDBT_SEGM_13 0x0000000D +#define DTAPI_ISDBT_SEGM_MSK 0x0000000F + +// DtOutpChannel::SetModControl - Bandwidth +#define DTAPI_ISDBT_BW_5MHZ 0x00000010 +#define DTAPI_ISDBT_BW_6MHZ 0x00000020 +#define DTAPI_ISDBT_BW_7MHZ 0x00000030 +#define DTAPI_ISDBT_BW_8MHZ 0x00000040 +#define DTAPI_ISDBT_BW_MSK 0x000000F0 + +// DtOutpChannel::SetModControl - Sample Rate +#define DTAPI_ISDBT_SRATE_1_1 0x00000100 +#define DTAPI_ISDBT_SRATE_1_2 0x00000200 +#define DTAPI_ISDBT_SRATE_1_4 0x00000300 +#define DTAPI_ISDBT_SRATE_1_8 0x00000400 +#define DTAPI_ISDBT_SRATE_27_32 0x00000500 +#define DTAPI_ISDBT_SRATE_135_64 0x00000600 +#define DTAPI_ISDBT_SRATE_MSK 0x00000F00 + +// DtOutpChannel::SetModControl - Sub Channel +#define DTAPI_ISDBT_SUBCH_MSK 0x0003F000 +#define DTAPI_ISDBT_SUBCH_SHIFT 12 + +// Result codes for DtIsdbtPars::CheckValidity +#define DTAPI_ISDBT_OK 0 +#define DTAPI_ISDBT_E_BTYPE 1 +#define DTAPI_ISDBT_E_NSEGM 2 +#define DTAPI_ISDBT_E_PARTIAL 3 +#define DTAPI_ISDBT_E_NOT_FILLED 4 +#define DTAPI_ISDBT_E_SUBCHANNEL 5 +#define DTAPI_ISDBT_E_SRATE 6 +#define DTAPI_ISDBT_E_BANDWIDTH 7 +#define DTAPI_ISDBT_E_MODE 8 +#define DTAPI_ISDBT_E_GUARD 9 + + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMatrixInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +struct DtMatrixInfo +{ + int m_VidStd; // Video standard + int m_Scaling; // Scaled frame format + int m_NumColumns; // Number of columns +}; + +// Maximum number of fading paths, used in DtModPars +#define DTAPI_MAX_OUTPUTS 16 + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtModPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for storing a complete set of modulation parameters. +// +// NOTE FOR ISDB-T: DtModPars.m_ParXtra0 is never used, all ISDB-T parameters are stored +// in DtIsdbtPars (in *m_pXtraPars). +// +struct DtModPars +{ + // Modulation parameters + int m_ModType; // Modulation type; -1 = not set + int m_ParXtra0; // ParXtra0 (Code Rate / J.83 Annex); -1 = not set + int m_ParXtra1; // ParXtra1; -1 = not set + int m_ParXtra2; // ParXtra2; -1 = not set + void* m_pXtraPars; // Extra CMMB/ISDB-S/ISDB-T/DVB-C2/DVB-T2 parameters + + // Single Frequency Network parameters + int m_SfnMode; // SFN-operation mode DTAPI_SFN_MODE_XXXX + int m_SfnTimeOffset; // SFN time offset in nano seconds + int m_SfnAllowedTimeDiff; // Maximum allowed time difference in nano-seconds + + // Rates; Set to -1 (not set) by SetModControl, except for symbol rate which is set + // to a default value for modulation types that support a symbol rate. + // If both symbol and TS rate are set, TS rate takes precedence. + int m_SymRate; // Symbol rate in baud + DtFractionInt m_TsRate; // Transport-stream rate in bps + + // Channel modelling per output channel + bool m_IsCmEnable[DTAPI_MAX_OUTPUTS]; + // Channel modelling is enabled yes/no + DtCmPars m_CmPars[DTAPI_MAX_OUTPUTS]; + // Channel modelling parameters + + // Custom roll-off roll + bool m_IsRoEnable; // Custom roll-off filter enable yes/no + DtFilterPars m_RollOffFilter; // Custom roll-off filter parameters + + // Miscellaneous + int m_OutputLevel; // Output level; -9999 = not set + double m_RfFreqHz; // RF frequency in Hz + unsigned char m_S2PlHdrScrSeq[12]; + // DVB-S2 PL header scrambling sequence + DtDvbCidPars m_DvbCidPars; // DVB carrier identification for satellite + int m_TxMode; // Transmit mode; Included here because packet + // size affects the modulation process + int m_StuffMode; // Stuffing mode + + // Operations + DTAPI_RESULT CheckPars(); + DTAPI_RESULT SetModControl(int ModType, int, int, int, void* pXtraPars); + + // Member functions + DtCmmbPars* pCmmbPars() { return (DtCmmbPars*)m_pXtraPars; } + DtDvbC2Pars* pDvbC2Pars() { return (DtDvbC2Pars*)m_pXtraPars; } + DtDvbS2Pars* pDvbS2Pars() { return (DtDvbS2Pars*)m_pXtraPars; } + DtDvbT2Pars* pDvbT2Pars() { return (DtDvbT2Pars*)m_pXtraPars; } + DtIqDirectPars* pIqDirectPars() { return (DtIqDirectPars*)m_pXtraPars; } + DtIsdbsPars* pIsdbsPars() { return (DtIsdbsPars*)m_pXtraPars; } + DtIsdbtPars* pIsdbtPars() { return (DtIsdbtPars*)m_pXtraPars; } + DtIsdbTmmPars* pIsdbTmmPars() { return (DtIsdbTmmPars*)m_pXtraPars; } + + // Predicates + bool HasSymRate(); + bool IsAdtbT(), IsAdtbtDtmb(), IsAtsc(), IsAtscMh(), IsCmmb(), IsCmEnable(int i=0); + bool IsDab(); + bool IsDtmb(), IsDvbC2(), IsDvbCidEnable(), IsDvbS(), IsDvbS2(), IsDvbS2Apsk(), + IsDvbS2L3(), IsDvbS2X(), IsDvbS2XL3(), IsDvbS2Mux(); + bool IsDvbT(), IsDvbT2(), IsIqDirect(), IsIsdbS(), IsIsdbT(), IsIsdbTmm(); + bool IsModTypeSet(), IsOfdm(), IsQam(), IsQamA(), IsQamB(), IsQamC(), IsQamAC(); + bool IsRoEnable(), IsSfnEnable(), IsT2Mi(); + bool RequiresMplpMod(); + + // Constructor, destructor + DtModPars(); + ~DtModPars(); +private: + // No implementation is provided for the copy constructor + DtModPars(const DtModPars&); + +private: + void CleanUpXtraPars(); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtPar .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Generic structure to represent a single parameter setting. +// It is used in the advanced demodulator for setting and retrieving parameter settings. +// +struct DtPar +{ + DtPar(); + DtPar(int ParId); // Constructor with DTAPI_PAR_xxx initialization + virtual ~DtPar(); + + // Value types supported for parameters + enum ParValueType + { + PAR_VT_UNDEFINED, PAR_VT_BOOL, PAR_VT_DOUBLE, PAR_VT_INT + }; + + DTAPI_RESULT m_Result; // Result of retrieving the parameters + int m_ParId; // Identifies the parameter: DTAPI_PAR_XXX + int m_IdXtra[4]; // Extra identification parameters + ParValueType m_ValueType; // Value type of parameter: PAR_VT_XXX + union { + bool m_ValueBool; // Value if value type is PAR_VT_BOOL + double m_ValueDouble; // Value if value type is PAR_VT_DOUBLE + int m_ValueInt; // Value if value type is PAR_VT_INT + void* m_pValue; // Pointer for complex types + }; + void Cleanup(); + DTAPI_RESULT GetName(const char*& pName, const char*& pShortName); + DTAPI_RESULT GetName(const wchar_t*& pName, const wchar_t*& pShortName); + DTAPI_RESULT GetValue(int &Value); + DTAPI_RESULT GetValue(double &Value); + DTAPI_RESULT GetValue(bool &Value); + DTAPI_RESULT SetId(int ParameterId); + DTAPI_RESULT SetValue(int Value); + DTAPI_RESULT SetValue(double Value); + DTAPI_RESULT SetValue(bool Value); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); + + // Serialisation of an array of parameters + static DTAPI_RESULT FromXml(const std::wstring&, DtPar*& pPars, int& Count); + static DTAPI_RESULT ToXml(DtPar* pPars, int Count, std::wstring& XmlString); + + // Assignment operator + DtPar& operator=(const DtPar&); + +private: + // No implementation is provided for the copy constructor + DtPar(const DtPar&); +}; + +// Integer parameters +#define DTAPI_PAR_DEMOD_THREADS 0x001 // Number of Threads/CPU cores used for + // software demodulation: default 4 +#define DTAPI_PAR_DEMOD_LDPC_MAX 0x002 // LDPC maximum iterations: default 50 +#define DTAPI_PAR_DEMOD_LDPC_AVG 0x003 // LDPC average iterations limit, used + // to limit CPU load; default 16 +// Boolean parameters +#define DTAPI_PAR_DEMOD_MER_ENA 0x004 // Enable MER calculation; default on +// Undefined parameter +#define DTAPI_PAR_UNDEFINED 0x000 // Value is not defined yet + +// Unsported item values +#define DTAPI_PAR_UNSUP_INTITEM 0x80000000 // Unsupported integer item +#define DTAPI_PAR_UNSUP_UINTITEM 0xFFFFFFFF // Unsupported unsigned integer item + + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtPhaseNoisePars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for specifying the phase noise parameters +// +struct DtPhaseNoisePars +{ + DtFractionInt m_SampleRate; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtRawIpHeader -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Header placed in front of all IP Packets when DTAPI_RXMODE_IPRAW mode is used +// +struct DtRawIpHeader +{ + unsigned short m_Tag; // 0x44A0h = \91D\92160 + unsigned short m_Length; // IP packet length + unsigned int m_TimeStamp; // IP packet arrival/transmit timestamp +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtStatistic -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +struct DtStatistic +{ + DtStatistic(); + DtStatistic(int StatisticId); // Constructor with DTAPI_STAT_xxx initialization + virtual ~DtStatistic(); + + // Value types supported for statistics + // NOTE: ALWAYS ADD NEW TYPES TO END OF LIST, FOR BACKWARDS COMPATIBILITY + enum StatValueType + { + STAT_VT_UNDEFINED, STAT_VT_BOOL, STAT_VT_DOUBLE, STAT_VT_INT, + STAT_VT_DVBC2_L1P2, STAT_VT_DVBC2_PLPSIG, STAT_VT_DVBT2_L1, + STAT_VT_ISDBT_PARS, STAT_VT_LDPC_STATS, STAT_VT_MA_DATA, + STAT_VT_MA_STATS, STAT_VT_PLP_BLOCKS, STAT_VT_VIT_STATS, + STAT_VT_DAB_ENSEM, STAT_VT_RS_STATS, STAT_VT_DVBT_TPS, STAT_VT_DAB_TXID + }; + + + DTAPI_RESULT m_Result; // Result of retrieving the statistic + int m_StatisticId; // Identifies the statistic: DTAPI_STAT_XXX + int m_IdXtra[4]; // Extra identification parameters + StatValueType m_ValueType; // Value type of statistic: STAT_VT_XXX + union { + bool m_ValueBool; // Value if value type is STAT_VT_BOOL + double m_ValueDouble; // Value if value type is STAT_VT_DOUBLE + int m_ValueInt; // Value if value type is STAT_VT_INT + void* m_pValue; // Pointer if value type is STAT_VT_DVBC2_L1P2, + // STAT_VT_DVBC2_PLPSIG, STAT_VT_DVBT_TPS, + // STAT_VT_DVBT2_L1, STAT_VT_VIT_STATS + // STAT_VT_DAB_ENSEM or STAT_VT_RS_STATS, + // STAT_VT_DAB_TXID + }; + void Cleanup(); + DTAPI_RESULT GetName(const char*& pName, const char*& pShortName); + DTAPI_RESULT GetName(const wchar_t*& pName, const wchar_t*& pShortName); + DTAPI_RESULT GetValue(int &Value); + DTAPI_RESULT GetValue(double &Value); + DTAPI_RESULT GetValue(bool &Value); + DTAPI_RESULT GetValue(DtDabEnsembleInfo*& pValue); + DTAPI_RESULT GetValue(DtDabTransmitterIdInfo*& pValue); + DTAPI_RESULT GetValue(DtDvbC2DemodL1Part2Data*& pValue); + DTAPI_RESULT GetValue(DtDvbC2DemodL1PlpSigData*& pValue); + DTAPI_RESULT GetValue(DtDvbTTpsInfo*& pValue); + DTAPI_RESULT GetValue(DtDvbT2DemodL1Data*& pValue); + DTAPI_RESULT GetValue(DtDemodLdpcStats*& pValue); + DTAPI_RESULT GetValue(DtDemodMaLayerData*& pValue); + DTAPI_RESULT GetValue(DtDemodMaLayerStats*& pValue); + DTAPI_RESULT GetValue(DtDemodPlpBlocks*& pValue); + DTAPI_RESULT GetValue(DtIsdbtParamsData*& pValue); + DTAPI_RESULT GetValue(DtRsDecStats*& pValue); + DTAPI_RESULT GetValue(DtVitDecStats*& pValue); + DTAPI_RESULT SetId(int StatisticId); + DTAPI_RESULT SetValue(int Value); + DTAPI_RESULT SetValue(double Value); + DTAPI_RESULT SetValue(bool Value); + DTAPI_RESULT SetValue(DtDabEnsembleInfo& pValue); + DTAPI_RESULT SetValue(DtDabTransmitterIdInfo& pValue); + DTAPI_RESULT SetValue(DtDvbC2DemodL1Part2Data& Value); + DTAPI_RESULT SetValue(DtDvbC2DemodL1PlpSigData& Value); + DTAPI_RESULT SetValue(DtDvbTTpsInfo& pValue); + DTAPI_RESULT SetValue(DtDvbT2DemodL1Data& Value); + DTAPI_RESULT SetValue(DtDemodLdpcStats& Value); + DTAPI_RESULT SetValue(DtDemodMaLayerData& Value); + DTAPI_RESULT SetValue(DtDemodMaLayerStats& Value); + DTAPI_RESULT SetValue(DtDemodPlpBlocks& Value); + DTAPI_RESULT SetValue(DtIsdbtParamsData& Value); + DTAPI_RESULT SetValue(DtRsDecStats& pValue); + DTAPI_RESULT SetValue(DtVitDecStats& pValue); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); + + // Serialisation of an array of statistics + static DTAPI_RESULT FromXml(const std::wstring&, DtStatistic*&, int& Count); + static DTAPI_RESULT ToXml(DtStatistic* pStatistics, int Count, std::wstring&); + + // Assignment operator + DtStatistic& operator=(const DtStatistic&); + +private: + // No implementation is given of the copy constructor + DtStatistic(const DtStatistic&); +}; + +// Integer statistics +#define DTAPI_STAT_BADPCKCNT 0x003 // Count of uncorrected packets +#define DTAPI_STAT_CNR 0x105 // Carrier-to-noise ratio in dB +#define DTAPI_STAT_DVBC2_DSLICEDISC 0x010 // DVB-C2 Data slice discontinuity count +#define DTAPI_STAT_DVBC2_L1HDR_ERR 0x00E // DVB-C2 L1 Preamble header error count +#define DTAPI_STAT_DVBC2_L1P2_ERR 0x00F // DVB-C2 L1-Part 2 error count +#define DTAPI_STAT_DVBT2_L1PRE_ERR 0x00C // DVB-T2 L1-Pre error count +#define DTAPI_STAT_DVBT2_L1POST_ERR 0x00D // DVB-T2 L1-Post error count +#define DTAPI_STAT_EBN0 0x111 // Eb/N0 in dB (estimated on MER) +#define DTAPI_STAT_ESN0 0x110 // Es/N0 in dB (estimated on MER) +#define DTAPI_STAT_LINKMARGIN 0x10F // Link margin in dB +#define DTAPI_STAT_MER 0x106 // Modulation error rate in dB +#define DTAPI_STAT_MOD_SAT 0x004 // Modulator saturation count +#define DTAPI_STAT_RELOCKCNT 0x00A // Receiver re-lock count +#define DTAPI_STAT_RFLVL_CHAN 0x005 // RF power level for channel bandwidth +#define DTAPI_STAT_RFLVL_CHAN_QS 0x015 // Quick scan of channel level +#define DTAPI_STAT_RFLVL_NARROW 0x006 // RF power level for a narrow bandwidth +#define DTAPI_STAT_RFLVL_NARROW_QS 0x016 // Quick scan of channel level +#define DTAPI_STAT_RS 0x008 // Reed-Solomon error counter +#define DTAPI_STAT_SNR 0x107 // Signal-to-noise ratio in dB +#define DTAPI_STAT_TEMP_TUNER 0x009 // Tuner temperature +#define DTAPI_STAT_T2MI_OVFS 0x00B // DVB-T2 T2-MI overflow count + +// Double statistics +#define DTAPI_STAT_BER_POSTBCH 0x100 // Post-BCH bit error rate +#define DTAPI_STAT_BER_POSTLDPC 0x101 // Post-LDPC bit error rate +#define DTAPI_STAT_BER_POSTVIT 0x102 // Post-Viterbi bit error rate +#define DTAPI_STAT_BER_PREBCH 0x10D // Pre-BCH bit error rate +#define DTAPI_STAT_BER_PRELDPC 0x10E // Pre-LDPC bit error rate +#define DTAPI_STAT_BER_PRERS 0x103 // Pre-Reed-Solomon bit error rate +#define DTAPI_STAT_BER_PREVIT 0x104 // Pre-Viterbi bit error rate +#define DTAPI_STAT_FER_POSTBCH 0x116 // Post-BCH frame error rate +#define DTAPI_STAT_FREQ_SHIFT 0x10B // Input frequency shift (Hz) +#define DTAPI_STAT_OCCUPIEDBW 0x112 // Occupied bandwidth +#define DTAPI_STAT_PER 0x108 // Packet error rate +#define DTAPI_STAT_ROLLOFF 0x113 // Roll-off factor in percentage +#define DTAPI_STAT_SAMPRATE_OFFSET 0x10C // Sample rate offset (ppm) + +// Boolean lock statistics +#define DTAPI_STAT_CARRIER_LOCK 0x201 // Carrier lock +#define DTAPI_STAT_FEC_LOCK 0x202 // FEC lock +#define DTAPI_STAT_LOCK 0x200 // Overall lock status +#define DTAPI_STAT_PACKET_LOCK 0x203 // Packet lock +#define DTAPI_STAT_SPECTRUMINV 0x205 // Spectrum inversion +#define DTAPI_STAT_VIT_LOCK 0x204 // Viterbi lock + +// Complex statistics +#define DTAPI_STAT_DAB_ENSEM_INFO 0x308 // DAB ensemble information from the + // Fast Information Channel (FIC) +#define DTAPI_STAT_DAB_TXID_INFO 0x30C // DAB transmitter ID information +#define DTAPI_STAT_DVBC2_L1P2DATA 0x300 // DVB-C2 Layer-1 Part 2 data +#define DTAPI_STAT_DVBC2_PLPSIGDATA 0x301 // DVB-C2 Layer-1 PLP signalling data +#define DTAPI_STAT_DVBT_TPS_INFO 0x30B // DVB-T TPS information +#define DTAPI_STAT_DVBT2_L1DATA 0x302 // DVB-T2 Layer-1 data +#define DTAPI_STAT_ISDBT_PARSDATA 0x303 // ISDB-T parameters data +#define DTAPI_STAT_LDPC_STATS 0x304 // DVB-C2/T2 LDPC statistics +#define DTAPI_STAT_MA_DATA 0x305 // DVB-C2/T2 mode adaptation data +#define DTAPI_STAT_MA_STATS 0x306 // DVB-C2/T2 mode adaptation statistics +#define DTAPI_STAT_PLP_BLOCKS 0x307 // DVB-C2/T2 PLP number of FEC blocks +#define DTAPI_STAT_RSDEC_STATS 0x30A // Reed-Solomon decoder statistics +#define DTAPI_STAT_VITDEC_STATS 0x309 // Viterbi decoder statistics + +// DekTec internal statistics +#define DTAPI_STAT_AGC1 0x001 // First AGC value +#define DTAPI_STAT_AGC2 0x002 // Second AGC value +#define DTAPI_STAT_RFLVL_UNCALIB 0x007 // Uncalibrated RF power level +#define DTAPI_STAT_RFLVL_UNCALIB_DBM 0x10A // Uncalibrated RF power level in dBm +#define DTAPI_STAT_SYNTAX_ERR_CNT 0x114 // Num syntax errors in usb bitstream +#define DTAPI_STAT_OVERFLOW_CNT 0x115 // Number of dtapi<>kernel buf overflows + +// Unsupported item values +#define DTAPI_STAT_UNDEFINED 0x000 // Value is not defined yet +#define DTAPI_STAT_UNSUP_INTITEM 0x80000000 // Unsupported integer item +#define DTAPI_STAT_UNSUP_UINTITEM 0xFFFFFFFF // Unsupported unsigned integer item + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIpQosStats -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Quality-of-Service related statistics for SDI/TS-over-IP channels, measured over a +// certain period of time (the "time period"). +// +// If the mode is "Seamless Protection Switching of IP Datagrams" (SMPTE 2022-7 mode), +// QoS statistics are maintained for path 1, path 2, and for the reconstructed stream. +// If the mode is not SMPTE 2022-7 ("single-path" mode), the QoS statistics are stored +// in the members for path 1. +// +// This structure is contained in the DtIpStat structure, once with the statistics +// measured over the last second, and once with statistics measured over the last minute. +// +struct DtIpQosStats +{ + // Packet Error Rate (PER) for path 1, path 2 and for the reconstructed stream. + // The PER is the number of lost IP packets per second. + double m_Per1, m_Per2, m_PerAfterFec; + + // Delay factor in microseconds for path 1 and path 2. + // The delay factor is an indication of the jitter of the IP stream. It is defined + // as the maximum difference between the actual arrival time of a UDP/RTP packet + // and the ideal (jitterless) arrival time of that packet. + double m_DelayFactor1, m_DelayFactor2; + + // The skew is the minimal and maximal difference over the time period + // (1 sec or 1 minute) in arrival time between IP packets on path 1 and on path 2. + // If m_Skew is positive, path 1 has a longer delay than path 2; if m_Skew is + // negative, path 2 has the longer delay. + // Note: PD as defined in SMPTE 2022-7 is the absolute value of m_Skew. + double m_MinSkew; // Min. Skew between path 1 and path 2 + double m_MaxSkew; // Max. Skew between path 1 and path 2 + + //Inter Packet arrival time of Ip packet per port over time period (1 sec or 1 minute) + double m_MinIpat1, m_MinIpat2; // Min. IPAT path1 and path2 + double m_MaxIpat1, m_MaxIpat2; // Max. IPAT path1 and path2 +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. DtIpProfile -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for describing the IP transmission "profile". It defines the maximum +// bitrate and (in SMPTE 2022-7 mode only) the maximum skew between path 1 and path 2. +// DtIpProfile is used to dimension buffer sizes at the receiver. +// +struct DtIpProfile +{ + // m_Profile defines the maximum bitrate and the maximum path skew. + // Member variables m_MaxBitrate and m_MaxSkew are used only if m_Profile is + // DTAPI_IP_USER_DEFINED, otherwise m_Profile implicitly sets their values. + int m_Profile; // IP transmission profile + + // m_MaxBitrate is used for single paths and in SMPTE 2022-7 mode. + unsigned int m_MaxBitrate; // Maximum bitrate in bps + + // m_MaxSkew is used only in SMPTE 2022-7 mode. It defines the maximum skew + // between the two IP transmission paths. + int m_MaxSkew; // Maximum skew between path 1 and path 2 in ms + + // Set the video standard to transmit/receive. + int m_VideoStandard; // DTAPI_VIDSTD_ defines. +}; + +// IP tranmission profile (DtIpProfile::m_Profile) +#define DTAPI_IP_PROF_NOT_DEFINED 0 // Not defined +#define DTAPI_IP_USER_DEFINED 1 // Use m_MaxBitrate and m_MaxSkew +// LBR (Low Bit Rate) profiles +#define DTAPI_IP_LBR_LOW_SKEW 2 // m_MaxSkew=10ms, m_MaxBitrate=10Mbps +#define DTAPI_IP_LBR_MODERATE_SKEW 3 // m_MaxSkew=50ms, m_MaxBitrate=10Mbps +#define DTAPI_IP_LBR_HIGH_SKEW 4 // m_MaxSkew=450ms, m_MaxBitrate=10Mbps +// SBR (Slower Bit Rate) profiles +#define DTAPI_IP_SBR_LOW_SKEW 5 // m_MaxSkew=10ms, m_MaxBitrate=270Mbps +#define DTAPI_IP_SBR_MODERATE_SKEW 6 // m_MaxSkew=50ms, m_MaxBitrate=270Mbps +#define DTAPI_IP_SBR_HIGH_SKEW 7 // m_MaxSkew=450ms, m_MaxBitrate=270Mbps +// HBR (High Bit Rate) profiles +#define DTAPI_IP_HBR_LOW_SKEW 5 // m_MaxSkew=10ms, m_MaxBitrate=3Gbps +#define DTAPI_IP_HBR_MODERATE_SKEW 6 // m_MaxSkew=50ms, m_MaxBitrate=3Gbps +#define DTAPI_IP_HBR_HIGH_SKEW 7 // m_MaxSkew=150ms, m_MaxBitrate=3Gbps + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIpPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for storing SDI/TS-over-IP parameters +// +struct DtIpPars +{ +public: + // Primary link + unsigned char m_Ip[16]; // IP address (IPv4/IPv6) + unsigned short m_Port; // Port number + unsigned char m_SrcFltIp[16]; // Source filter: IP address (IPv4/IPv6) + unsigned short m_SrcFltPort; // Source filter: port number + int m_VlanId; // VLAN ID + int m_VlanPriority; // VLAN priority + + // Redundant link (path 2 in SMPTE 2022-7 mode) + unsigned char m_Ip2[16]; // IP address (IPv4/IPv6) + unsigned short m_Port2; // Port number + unsigned char m_SrcFltIp2[16]; // Source filter: IP address (IPv4/IPv6) + unsigned short m_SrcFltPort2; // Source filter: port number + int m_VlanId2; // VLAN ID + int m_VlanPriority2; // VLAN priority + + int m_TimeToLive; // Time-to-Live setting for IP Tx + int m_NumTpPerIp; // Number of transport packets per IP packet + int m_Protocol; // Protocol: DTAPI_PROTO_UDP/RTP + int m_DiffServ; // Differentiated services + int m_FecMode; // Error correction mode: DTAPI_FEC_DISABLE/2D + int m_FecNumRows; // 'D' = #rows in FEC matrix + int m_FecNumCols; // 'L' = #columns in FEC matrix + + // Control and status flags: DTAPI_IP_V4, DTAPI_IP_V6, DTAPI_IP_TX_MANSRCPORT + int m_Flags; + + // Seamless Protection Switching of IP Datagrams (SMPTE 2022-7) + + // Transmission- or reception mode. It determines whether "seamless protection + // switching of IP datagrams" according to SMPTE 2022-7 is applied. + // DTAPI_IP_NORMAL Default value for non-redundant Rx or Tx. + // DTAPI_IP_TX_2022_7 Apply SMPTE 2022-7 for Tx. IP packets will be duplicated to + // path 1 (primary link) and path 2 (redundant link) + // DTAPI_IP_RX_2022_7 Apply SMPTE 2022-7 for Rx. IP packets from path 1 and path 2 + // will be seamlessly combined into a single logical stream. + int m_Mode; + + // The IP transmission profile determines the maximum bitrate and the maximum skew + // between transmission path 1 and path 2. + DtIpProfile m_IpProfile; +public: + DtIpPars(); + ~DtIpPars(); +}; + +// Legacy +#define DtTsIpPars DtIpPars + +// Error correction modes (DtIpPars::m_FecMode) +#define DTAPI_FEC_DISABLE 0 +#define DTAPI_FEC_2D 1 // FEC reconstruction +#define DTAPI_FEC_2D_M1 1 // Mode1: FECdT = DVBdT + .5 * DVBdT +#define DTAPI_FEC_2D_M2 2 // Mode2: FECdT = DVBdT +#define DTAPI_FEC_2D_M1_B 3 // Mode1: FECdT = DVBdT + .5 * DVBdT (BLOCK) +#define DTAPI_FEC_2D_M2_B 4 // Mode2: FECdT = DVBdT (BLOCK) + +// Optional control/status flags (DtIpPars::m_Flags) +#define DTAPI_IP_V4 0x00 +#define DTAPI_IP_V6 0x01 +#define DTAPI_IP_TX_MANSRCPORT 0x10 +#define DTAPI_IP_RX_DIFFSRCPORTFEC 0x20 + +// Transmission/reception mode (DtIpPars::m_Mode) +#define DTAPI_IP_NORMAL 0 +#define DTAPI_IP_TX_2022_7 1 // Dual-path SMPTE 2022-7 transmission +#define DTAPI_IP_RX_2022_7 2 // Dual-path SMPTE 2022-7 reception +// Legacy definitions +#define DTAPI_IP_TX_DBLBUF DTAPI_IP_TX_2022_7 +#define DTAPI_IP_RX_DBLBUF DTAPI_IP_RX_2022_7 + +// IP protocol (DtIpPars::m_Protocol) +#define DTAPI_PROTO_UDP 0 +#define DTAPI_PROTO_RTP 1 +#define DTAPI_PROTO_AUTO 2 +#define DTAPI_PROTO_UNKN 2 + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. DtIpStat .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for retrieving the IP statistics for an SDI/TS-over-IP channel. +// +// Counters start at zero, but counters are not reset after being read. +// Counter wraps must be handled by the application. +// +// If the mode is "Seamless Protection Switching of IP Datagrams" (SMPTE 2022-7 mode), +// counters are maintained for path 1, path 2, and for the reconstructed stream. +// If this mode is not active, only path 1 counters are valid. +// +struct DtIpStat +{ + // Total number of received or transmitted IP packets.This is the number of IP packets + // that the stream should contain, so lost packets are included in this counter. + unsigned int m_TotNumIpPackets; + + // Number of IP packets lost before and after FEC. + // In SMPTE 2022-7 mode, these counters apply to the reconstructed stream. + unsigned int m_LostIpPacketsBeforeFec, m_LostIpPacketsAfterFec; + + // Counters for the number of received and number of lost IP packets for path 1 + // and for path 2. + // m_NumIpPacketsLost1 = m_TotNumIpPackets - m_NumIpPacketsReceived1 + // m_NumIpPacketsLost2 = m_TotNumIpPackets - m_NumIpPacketsReceived2 + unsigned int m_NumIpPacketsReceived1, m_NumIpPacketsReceived2; + unsigned int m_NumIpPacketsLost1, m_NumIpPacketsLost2; + + // QoS statistics measured over the last second, and over the last minute. + DtIpQosStats m_QosStatsLastSec, m_QosStatsLastMin; +}; + +// Legacy +#define DtTsIpStat DtIpStat + + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtTunePars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for setting tuner specific parameters +// +struct DtTunePars +{ + union { + // DTA-2131 specific tuner parameters + struct { + int m_TunerStandard; // DTAPI_TUNMOD_xxx + int m_TunerBandwidth; // Tuning bandwidth in Hz + int m_IfFrequency; // IF frequency in Hz + // (-1 according tuner standard) + int m_LpfCutOff; // Low-pass filter cutoff; DTAPI_TUN31_LPF_x + int m_LpfOffset; // Low-pass filter offset; DTAPI_TUN31_LPF_x + int m_HiPass; // Hi Pass filter; DTAPI_TUN31_HPF_x + int m_DcNotchIfPpf; // Enable DC notch IF PPF; DTAPI_TUN31_NOTCH_x + int m_IfNotch; // Enable IF notch; DTAPI_TUN31_NOTCH_x + int m_IfNotchToRssi; // Enable IF notch to RSSI; DTAPI_TUN31_NOTCH_x + } m_Dta2131TunePars; + } u; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtVidStdInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +struct DtVidStdInfo +{ + int m_VidStd; // Video Standard + int m_LinkStd; // Link standard + bool m_IsHd; // true: is an HD format: false: is SD format + bool m_Is4k; // true: is a 4k resolution + + int m_VidWidth; // Width in pixels + int m_VidHeight; // Height in number of lines + + // NOTE: for 4k the following members describe the properties of a single link + bool m_IsInterlaced; // Is interlaced + int m_NumLines; // Number of lines per frame + double m_Fps; // Frame rate + bool m_IsFractional; // Fractional framerate + + int m_FrameNumSym; // Size of frame (in # symbols) + int m_LineNumSym; // # of symbol per line + int m_LineNumSymHanc; // # of HANC symbols per line + int m_LineNumSymVanc; // # of VANC symbols per line + int m_LineNumSymEav; // # of EAV symbols per line + int m_LineNumSymSav; // # of SAV symbols per line + + // Field 1 + int m_Field1StartLine; // Line # of first line for field 1 + int m_Field1EndLine; // Line # of last line for field 1 + int m_Field1VidStartLine; // Line # of first line containing active video + int m_Field1VidEndLine; // Line # of last line containing active video + + // Field 2 + int m_Field2StartLine; // Line # of first line for field 2 + int m_Field2EndLine; // Line # of last line for field 2 + int m_Field2VidStartLine; // Line # of first line containing active video + int m_Field2VidEndLine; // Line # of last line containing active video +}; + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ DEMODULATION PARAMETERS +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDemodDvbS2ModCodSettings -.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for storing the DVB-S2 +// +struct DtDemodDvbS2ModCodSettings +{ + bool m_Enable; // Demodulation of this MODCOD (yes/no) + int m_SnrThreshold; // SNR threshold of this MODCOD for automute algorithm + DtDemodDvbS2ModCodSettings() : m_Enable(false), m_SnrThreshold(0) {} + DtDemodDvbS2ModCodSettings(bool Enable, int SnrThreshold) : + m_Enable(Enable), m_SnrThreshold(SnrThreshold) {} +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for storing a complete set of demodulation parameters +// +class DtDemodPars +{ +public: + DtDemodPars(); + DtDemodPars(const DtDemodPars&); + ~DtDemodPars(); +public: + DTAPI_RESULT CheckValidity(); + int GetModType() const; + DTAPI_RESULT SetModType(int ModType); + DtDemodParsAtsc* Atsc() const; + DtDemodParsDab* Dab() const; + DtDemodParsDvbC2* DvbC2() const; + DtDemodParsDvbS* DvbS() const; + DtDemodParsDvbS2* DvbS2() const; + DtDemodParsDvbS2Adv* DvbS2Adv() const; + DtDemodParsDvbT* DvbT() const; + DtDemodParsDvbT2* DvbT2() const; + DtDemodParsIq* Iq() const; + DtDemodParsIq2131* Iq2131() const; + DtDemodParsIsdbt* Isdbt() const; + DtDemodParsQam* Qam() const; + + // Predicates + bool IsAtsc() const, IsDab() const, IsDvbC2() const, IsDvbS() const, + IsDvbS2() const, IsDvbT() const,IsDvbT2() const, IsIq() const, IsIq2131() const, + IsIsdbt() const, IsQam() const; + + // Operators + void operator=(const DtDemodPars& Pars); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); + + // Conversion helper + DTAPI_RESULT FromOldStyle(int ModType, int ParXtra0, int ParXtra1, int ParXtra2); + DTAPI_RESULT ToOldStyle(int& ModType, int& ParXtra0, int& ParXtra1, int& ParXtra2); +private: + int m_ModType; // Modulation type + void* m_pDemodPars; // Demodulation parameters; Type depends on m_ModType +private: + void CleanUpDemodPars(); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsAtsc -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Demodulation parameters for modulation type DTAPI_MOD_ATSC +// +struct DtDemodParsAtsc +{ + int m_Constellation; // VSB constellation +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDab -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Demodulation parameters for modulation type DTAPI_MOD_DAB +// +struct DtDemodParsDab +{ +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDvbC2 -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_DVBC2 +// +struct DtDemodParsDvbC2 +{ + int m_Bandwidth; // Bandwidth +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDvbS -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Demodulation parameters for modulation type DTAPI_MOD_DVBS +// +struct DtDemodParsDvbS +{ + int m_CodeRate; // DVB-S coderate + int m_SpecInv; // Spectral inversion (yes/no) + int m_SymRate; // Symbol rate in baud +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDvbS2 -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_DVBS2 +// +struct DtDemodParsDvbS2 +{ + int m_CodeRate; // Coderate + int m_Pilots; // Pilots (yes/no) + int m_SpecInv; // Spectral inversion (yes/no) + int m_FecFrame; // Long or short FECFRAME + int m_SymRate; // Symbol rate in baud +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDvbS2Adv -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Advanced demodulation parameters for modulation type DTAPI_MOD_DVBS2 +// +struct DtDemodParsDvbS2Adv : DtDemodParsDvbS2 +{ + bool m_AutoMuteModCods; // MODCODS with an SNR threshold above the current SNR + // will not be demodulated + int m_HysteresisMargin; // Margin to add on top of the SNR threshold before + // re-enabling a certain modcod, in units of 0.1 dB + std::map m_ModCods; + // List with supported modcods + DtDemodParsDvbS2Adv(); + DTAPI_RESULT DeleteModCod(DtDvbS2ModCod ModCod); + DTAPI_RESULT InitSnrThreshold(int TypeNumber); + DTAPI_RESULT SetModCod(DtDvbS2ModCod ModCod, DtDemodDvbS2ModCodSettings &Settings); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDvbT -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_DVBT +// +struct DtDemodParsDvbT +{ + int m_CodeRate; // Coderate + int m_Bandwidth; // Bandwidth + int m_Constellation; // Constellation + int m_Guard; // Guard interval + int m_Interleaving; // Interleaving + int m_Mode; // Transmission mode +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsDvbT2 -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_DVBT2 +// +struct DtDemodParsDvbT2 +{ + int m_Bandwidth; // Bandwidth + int m_T2Profile; // DVB-T2 profile (Base/Lite) +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsIq -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_IQ +// +struct DtDemodParsIq +{ + int m_Bandwidth; // Signal bandwidth in Hz + int m_IqDemodType; // IQ demodulation type (DTAPI_DEMOD_QAM or + // DTAPI_DEMOD_OFDM) + int m_SampleRate; // Sample rate in Hz +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsIq2131 -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_IQ_2131 (DTA-2131 specific) +// +struct DtDemodParsIq2131 +{ + int m_IqDemodFreq; // IQ demodulation frequency in Hz + DtFilterPars m_LpfFilter; // Anti-aliasing filter + double m_LpfScaleFactor; // Scale factor after anti-aliasing filter + int m_SampleRate; // Sample rate in Hz + DtTunePars m_TunePars; // Tuning parameters +}; + +// IQ-demodulation type +#define DTAPI_DEMOD_OFDM 0 // OFDM IQ-demodulation type +#define DTAPI_DEMOD_QAM 1 // QAM IQ-demodulation type + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsIsdbt .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_ISDBT +// +struct DtDemodParsIsdbt +{ + int m_Bandwidth; // Bandwidth DTAPI_ISDBT_BW_xMHZ + int m_SubChannel; // Sub channel number, 0..41, default= 22 + int m_NumberOfSegments; // Number of segments DTAPI_ISDBT_SEGM_x + DtDemodParsIsdbt() : m_SubChannel(22) {} +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodParsQam -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Demodulation parameters for modulation type DTAPI_MOD_QAMxxx +// +struct DtDemodParsQam +{ + int m_Annex; // ITU-T J.83 Annex + int m_Interleaving; // Interleaving; ignored for Annex A and C + int m_SymRate; // Symbol rate in baud +}; + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+ Common Demodulation Structures +=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodLdpcStats -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// LDCP statistic information for DVB-T2 and DVB-C2 +// +struct DtDemodLdpcStats +{ + __int64 m_FecBlocksCount; // #Decoded FEC blocks + __int64 m_UncorrFecBlocksCount;// #Uncorrected FEC blocks after BCH (not exact) + __int64 m_FecBlocksCount1; // #Decoded FEC blocks, reset at the same time + // as m_FecBlocksItCount/min/max + __int64 m_FecBlocksItCount; // Total #LDPC iterations + // Average #LDPC iteration = + // m_FecBlocksItCount / m_FecBlocksCount1 + int m_FecBlocksItMin; // Minimum #LDPC iterations (-1 after reset) + int m_FecBlocksItMax; // Maximum #LDPC iterations (-1 after reset) + __int64 m_BchBitCount; // #Decoded data bits, including BCH bits + // Currently only data+BCH bits are taken into account (LDPC parity bits are ignored), + // so the BER before LDPC is approximatively: m_BchBitErrorCount / m_BchBitCount + // This is accurate only if there are no uncorrected blocks (m_UncorrFecBlocksCount=0) + __int64 m_BchBitErrorCount; // Bit error count before LDPC +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodMaLayerStats -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// LMode adaption layer statistics for DVB-T2 and DVB-C2 +// +struct DtDemodMaLayerStats +{ + __int64 m_HdrCrc8ErrorCount; // #CRC8 errors for BBframe header + __int64 m_PckCrc8ErrorCount; // #CRC8 errors for packets (only for m_Hem = 0) + __int64 m_FramingErrorCount; // SYNCD/DFL/UPL consistency errors + __int64 m_CommonPlpResyncCount;// Number of times a resynchronization between data + // and common PLP was needed. It normally happens + // only in case of receive errors. This field is only + // updated in the corresponding data PLP. +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtRsDecStats -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Reed-Solomon decoder info +// +struct DtRsDecStats +{ + bool m_Locked; // Decoder is locked + __int64 m_ByteSkipCount; // Bytes skipped while looking for sync + __int64 m_PacketCount; // Decoded packets + __int64 m_UncorrPacketCount; // Uncorrected packets + __int64 m_ByteErrorCount; // Byte error count + __int64 m_BitErrorCount; // Bit error count +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtVitDecStats -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Viterbi decoder info (pre-viterbi BER) +// +struct DtVitDecStats +{ + __int64 m_BitCount; // Input bit count + __int64 m_BitErrorCount; // Bit error count +}; + + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodMaLayerData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Mode adaption layer info for DVB-T2 and DVB-C2 +struct DtDemodMaLayerData +{ + bool m_Hem; // High efficiency mode + bool m_Npd; // Null packet deletion + int m_Issy; // ISSY: mode, see DTAPI_DVBx2_ISSY_x + int m_IssyBufs; // ISSY: current 'BUFS' value + int m_IssyTto; // ISSY: last 'TTO' value (DVB-T2 only) + int m_IssyBufStat; // ISSY: last 'BUFSTAT' value (DVB-C2/S2 only) + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDemodPlpBlocks -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Number of FEC blocks per frame +// +struct DtDemodPlpBlocks +{ + int m_NumBlocks; // Last plp_num_blocks + int m_NumBlocksMin; // Minimum plp_num_blocks (-1 = no new value since + // reset) + int m_NumBlocksMax; // Maximum plp_num_blocks + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//+=+=+=+=+=+=+=+=+ Demodulator Blindscan and Spectrum scan definitions +=+=+=+=+=+=+=+=+= + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtTransmitter -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure describing a transmitter. Used by DtInpChannel::BlindScan to return the +// transmitters found by scanning a frequency band. +// +struct DtTransmitter +{ + __int64 m_FreqHz; // Center frequency of the transmitter + int m_ModType; // Modulation type + int m_SymbolRate; // Symbol rate +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtBsProgess -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure describing the progress of an asynchronous BlindScan. +// Used by asynchronous DtInpChannel::BlindScan to return current state and the +// transmitters found by scanning a frequency band using the DtBsProgressFunc callback. +// +struct DtBsProgress +{ + enum BsEvent + { + BS_STEP, // One frequency step is completed + BS_CANCELLED, // Blindscan is cancelled + BS_DONE // Blindscan is completed + }; + + __int64 m_FreqHz; // Center frequency found + DtDemodPars m_DemodPars; // Demodulator parameters found for this transmitter + BsEvent m_ProgressEvent; // Progress event + bool m_ChannelFound; // If set, the channel is found on the transmitter + // frequency + DTAPI_RESULT m_Result; // Result of the blindscan + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); + +public: + DtBsProgress(); + ~DtBsProgress(); +}; + +// Function to receive asynchronous progess. +typedef void DtBsProgressFunc(DtBsProgress& Progress, void* pOpaque); + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtRfLevel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure describing a RF-level on a frequency. +// Used by DtInpChannel::SpectrumScan to return the RF-levels found by scanning a +// frequency band. +// +struct DtRfLevel +{ + __int64 m_FreqHz; // Center frequency of the RF level + int m_RfLevel; // RF level found in units of 0.1dBmV +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtSpsProgress -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure describing the progress of an asynchronous SpectrumScan. +// Used by DtInpChannel::SpectrumScan to return current state and the RF-Levels +// found by scanning a frequency band using the DtSpsProgressFunc callback. +// +struct DtSpsProgress { + + enum SpsEvent + { + SPS_STEP, // One frequency step is completed + SPS_CANCELLED, // SpectrumScan is cancelled + SPS_DONE // SpectrumScan is completed + }; + + DtRfLevel m_DtRfLevel; // A single level + SpsEvent m_ProgressEvent; // Progress event + DTAPI_RESULT m_Result; // Result of the spectrumscan + + //Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); + +public: + DtSpsProgress(); + ~DtSpsProgress(); +}; + +// Function to receive asynchronous spectrum scan progess. +typedef void DtSpsProgressFunc(DtSpsProgress& Progress, void* pOpaque); + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ MAIN DTAPI CLASSES +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDevice -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class representing a DekTec Device +// +class DtDevice +{ + // Constructor, destructor +public: + DtDevice(); + virtual ~DtDevice(); +private: + // No implementation is provided for the copy constructor + DtDevice(const DtDevice&); + + // Public access functions +public: + virtual int Category(void); + virtual int ChanType(int Port); + virtual int FirmwareVersion(void); + virtual bool IsAttached(void); + virtual int TypeNumber(void); + virtual bool HasCaps(int Port, const DtCaps Caps) const; + + // Public member functions +public: + virtual DTAPI_RESULT AttachToIpAddr(unsigned char Ip[4]); + virtual DTAPI_RESULT AttachToSerial(__int64 SerialNumber); + virtual DTAPI_RESULT AttachToSlot(int PciBusNumber, int SlotNumber); + virtual DTAPI_RESULT AttachToType(int TypeNumber, int DeviceNo=0); + virtual DTAPI_RESULT ClearGpsErrors(); + virtual DTAPI_RESULT Detach(void); + virtual DTAPI_RESULT DetectIoStd(int Port, int& Value, int& SubValue); + virtual DTAPI_RESULT FlashDisplay(int NumFlashes=5, int OnTime=100, int OffTime=100); + virtual DTAPI_RESULT GetAttribute(int AttrId, int& AttrValue); + virtual DTAPI_RESULT GetAttribute(int Port, int AttrId, int& AttrValue); + virtual DTAPI_RESULT GetAttribute(int Port, int AttrId, DtModPars& ModParVals, + int& AttrValue); + virtual DTAPI_RESULT GetDescriptor(DtDeviceDesc& DvcDesc); + virtual DTAPI_RESULT GetDeviceDriverVersion(int& Major, int& Minor, int& BugFix, + int& Build); + virtual DTAPI_RESULT GetDisplayName(wchar_t* pName); + virtual DTAPI_RESULT GetDisplayName(char* pName); + virtual DTAPI_RESULT GetFanSpeed(int Fan, int& Rpm); + virtual DTAPI_RESULT GetFanTemperature(int Fan, int& Temp); + virtual DTAPI_RESULT GetFirmwareVersion(int& FirmwareVersion); + virtual DTAPI_RESULT GetGenlockState(int& State, int& RefVidStd); + virtual DTAPI_RESULT GetGenlockState(int& State); + virtual DTAPI_RESULT GetGpsStatus(int& Status, int& Error); + virtual DTAPI_RESULT GetGpsTime(int& GpsTime); + virtual DTAPI_RESULT GetIoConfig(DtIoConfig& IoCfg); + virtual DTAPI_RESULT GetIoConfig(int Port, int Group, int& Value); + virtual DTAPI_RESULT GetIoConfig(int Port, int Group, int& Value, int& SubValue); + virtual DTAPI_RESULT GetIoConfig(int Port, int Group, int& Value, int& SubValue, + __int64& ParXtra0); + virtual DTAPI_RESULT GetIoConfig(int Port, int Group, int& Value, int& SubValue, + __int64& ParXtra0, __int64& ParXtra1); + virtual DTAPI_RESULT GetNwSpeed(int Port, bool& Enable, int& Speed); + virtual DTAPI_RESULT GetRefClkCnt(int& RefClkCnt); + virtual DTAPI_RESULT GetRefClkCnt(__uint64& RefClkCnt); + virtual DTAPI_RESULT GetRefClkCnt(int& RefClkCnt, int& RefClkFreqHz); + virtual DTAPI_RESULT GetRefClkCnt(__uint64& RefClkCnt, int& RefClkFreqHz); + virtual DTAPI_RESULT GetRefClkFreq(int& RefClkFreqHz); + virtual DTAPI_RESULT GetStateFlags(int Port, int &StateFlags); + virtual DTAPI_RESULT GetUsbSpeed(int& UsbSpeed); + virtual DTAPI_RESULT GetVcxoState(bool& Enable, int& Lock, int& VcxoClkFreqHz); + virtual DTAPI_RESULT HwFuncScan(int NumEntries, int& NumEntriesResult, + DtHwFuncDesc* pHwFuncs); + virtual DTAPI_RESULT LedControl(int LedControl); + virtual DTAPI_RESULT RegisterCallback(pDtEventCallback Callback, void* pContext, + int EventTypes, void** pId = NULL); + virtual DTAPI_RESULT SetDisplayName(wchar_t* pName); + virtual DTAPI_RESULT SetDisplayName (char* pName); + virtual DTAPI_RESULT SetIoConfig(int Port, int Group, int Value, int SubValue = -1, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + virtual DTAPI_RESULT SetIoConfig(DtIoConfig* pIoConfigs, int Count); + virtual DTAPI_RESULT SetNwSpeed(int Port, bool Enable, int Speed); + virtual DTAPI_RESULT UnregisterCallback(void* pId); + virtual DTAPI_RESULT VpdDelete(const char* pTag); + virtual DTAPI_RESULT VpdDelete(const wchar_t* pTag); + virtual DTAPI_RESULT VpdRead(const char* pTag, char* pVpdItem); + virtual DTAPI_RESULT VpdRead(const wchar_t* pTag, wchar_t* pVpdItem); + virtual DTAPI_RESULT VpdRead(const char* pTag, char* pVpdItem, int& ItemSize); + virtual DTAPI_RESULT VpdRead(const wchar_t* pTag, char* pVpdItem, int& ItemSize); + virtual DTAPI_RESULT VpdWrite(const char* pTag, char* pVpdItem); + virtual DTAPI_RESULT VpdWrite(const wchar_t* pTag, wchar_t* pVpdItem); + virtual DTAPI_RESULT VpdWrite(const char* pTag, char* pVpdItem, int ItemSize); + virtual DTAPI_RESULT VpdWrite(const wchar_t* pTag, char* pVpdItem, int ItemSize); + +protected: + virtual void LoadDeviceData(); +private: + static void DtEventCallback(int Event, DtEventArgs* pArgs); + + // Public attributes +public: + DtDeviceDesc m_DvcDesc; // Device descriptor, initialized in attach + DtHwFuncDesc* m_pHwf; // Hardware functions, initialized in attach + + // Implementation data +private: + std::list m_EventSubscriberList; + + // Friends + friend class DtInpChannel; + friend class DtOutpChannel; + +public: // TODOSD should be protected + IDevice* m_pDev; +}; + +// Attribute identifiers +#define DTAPI_ATTR_LEVEL_MAX 1 +#define DTAPI_ATTR_LEVEL_RANGE 2 +#define DTAPI_ATTR_LEVEL_STEPSIZE 3 +#define DTAPI_ATTR_RFFREQ_ABSMAX 4 +#define DTAPI_ATTR_RFFREQ_ABSMIN 5 +#define DTAPI_ATTR_RFFREQ_MAX 6 +#define DTAPI_ATTR_RFFREQ_MIN 7 +#define DTAPI_ATTR_SAMPRHW_ABSMAX 8 +#define DTAPI_ATTR_SAMPRHW_ABSMIN 9 +#define DTAPI_ATTR_SAMPRHW_HARDLIM 10 +#define DTAPI_ATTR_SAMPRHW_MAX 11 +#define DTAPI_ATTR_SAMPRHW_MIN 12 +#define DTAPI_ATTR_SAMPRATE_ABSMAX 13 +#define DTAPI_ATTR_SAMPRATE_ABSMIN 14 +#define DTAPI_ATTR_SAMPRATE_MAX 15 +#define DTAPI_ATTR_SAMPRATE_MIN 16 +#define DTAPI_ATTR_NUM_FANS 17 +#define DTAPI_ATTR_PCIE_REQ_BW 18 +#define DTAPI_ATTR_PCIE_AVAIL_BW 19 + +// Order in which devices should be listed by DtapiDeviceScan/DtapiHwFuncScan +#define DTAPI_SCANORDER_ORIG 0 // Devices are returned in order determined by OS +#define DTAPI_SCANORDER_SN 1 // Devices are sorted by serial number + +// String conversion - Device type number (e.g. "DTA-100", "DTA-102") +#define DTAPI_DVC2STR_TYPE_NMB 0 +// String conversion - Device type number + location (e.g. "DTA-100 in slot 5"); +#define DTAPI_DVC2STR_TYPE_AND_LOC 1 +// String conversion - Device type number (e.g. "DTA-100", "DTA-102") +#define DTAPI_HWF2STR_TYPE_NMB 0 +// String conversion - Device type number + port (e.g. "DTA-124 port 1") +#define DTAPI_HWF2STR_TYPE_AND_PORT 1 +// String conversion - Device type number + location (e.g. "DTA-100 in slot 5"); +#define DTAPI_HWF2STR_TYPE_AND_LOC 2 +// String conversion - Interface type (e.g. "DVB-ASI" or "DVB-C") +#define DTAPI_HWF2STR_ITF_TYPE 3 +// String conversion - Short version of interface type (e.g. "ASI" instead "DVB-ASI") +#define DTAPI_HWF2STR_ITF_TYPE_SHORT 4 + +// Current genlock state +#define DTAPI_GENL_NO_REF 1 +#define DTAPI_GENL_LOCKING 2 +#define DTAPI_GENL_LOCKED 3 + +// Status and error flags for GPS-Synchronisation +#define DTAPI_GPS_1PPS_SYNC 0x000001 +#define DTAPI_GPS_10MHZ_SYNC 0x000002 +#define DTAPI_GPS_1PPS_ERROR 0x000001 + +// Constants for GetStateFlags() on port level +#define DTAPI_STATE_FLAG_INSUFF_USB_BW 0x010000 +#define DTAPI_STATE_FLAG_SDI_NO_LOCK 0x020000 +#define DTAPI_STATE_FLAG_SDI_INVALID 0x040000 +// Constants for GetStateFlags() on device level +#define DTAPI_STATE_FLAG_VPD_CORRUPT 0x000001 +#define DTAPI_STATE_FLAG_NO_SERIAL 0x000002 +#define DTAPI_STATE_FLAG_NO_USB3 0x000004 +#define DTAPI_STATE_FLAG_SLEEPING 0x000008 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDtaPlusDevice -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class representing a DekTec DTA-plus Device +// +class DtDtaPlusDevice +{ + // Constructor, destructor +public: + DtDtaPlusDevice(); + virtual ~DtDtaPlusDevice(); +private: + // No implementation is provided for the copy constructor + DtDtaPlusDevice(const DtDtaPlusDevice&); + + // Public access functions +public: + bool IsAttached(void); + + // Public member functions +public: + DTAPI_RESULT AttachToDevice(const DtDtaPlusDeviceDesc &DvcDesc); + DTAPI_RESULT AttachToSerial(__int64 SerialNumber); + DTAPI_RESULT Detach(); + DTAPI_RESULT GetDeviceStatus(int &Status); + DTAPI_RESULT GetTempControlStatus(int &ControlStatus); + DTAPI_RESULT GetTemperature(int &Temperature); + DTAPI_RESULT GetSerialNumber(__int64 &SerialNumber); + DTAPI_RESULT SetRfOutLevel(int Level); + DTAPI_RESULT SetFreq(int Freq); + +private: + DtaPlusDevice* m_Dev; +}; + +// DTA-plus status codes +#define DTAPI_DTAPLUS_STATUS_OFF 0 // DTA-Plus not ready for operation +#define DTAPI_DTAPLUS_STATUS_ON 1 // DTA-Plus ready for operation +#define DTAPI_DTAPLUS_STATUS_ATTN_FOLLOW_UP 2 // DTA-Plus attenuator ctrl following up +#define DTAPI_DTAPLUS_STATUS_ATTN_FOLLOW_DOWN 3 //DTA-Plus attenuator ctrl following down +#define DTAPI_DTAPLUS_STATUS_DAC_FOLLOW_UP 4 // DTA-Plus DAC control following up +#define DTAPI_DTAPLUS_STATUS_DAC_FOLLOW_DOWN 5 // DTA-Plus DAC control following down +#define DTAPI_DTAPLUS_STATUS_HOLD 6 // DTA-Plus has valid input signal +#define DTAPI_DTAPLUS_STATUS_NO_SIGNAL 7 // DTA-Plus has no input signal +#define DTAPI_DTAPLUS_STATUS_OVER_POWER 8 // DTA-Plus input signal is too high + +// DTA-plus temperature control states +#define DTAPI_DTAPLUS_TEMP_CONTROL_OFF 0 // DTA-Plus temperature control is off +#define DTAPI_DTAPLUS_TEMP_CONTROL_FAN_ON 1 // DTA-Plus fan is on +#define DTAPI_DTAPLUS_TEMP_CONTROL_HEATER_ON 2 // DTA-Plus heater is on + +// Ethernet speed +#define DTAPI_NWSPEED_AUTO 0 // Set +#define DTAPI_NWSPEED_NOLIN 0 // Get +#define DTAPI_NWSPEED_10MB_HALF 1 +#define DTAPI_NWSPEED_10MB_FULL 2 +#define DTAPI_NWSPEED_100MB_HALF 3 +#define DTAPI_NWSPEED_100MB_FULL 4 +#define DTAPI_NWSPEED_1GB_MASTER 5 +#define DTAPI_NWSPEED_1GB_SLAVE 6 + +// Microcode upload states +#define DTAPI_UCODE_NOT_LOADED 0 +#define DTAPI_UCODE_LOADING 1 +#define DTAPI_UCODE_LOADED 2 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtInpChannel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class to represent an input channel +// +class DtInpChannel +{ +public: + DtInpChannel(); + virtual ~DtInpChannel(); +private: + // No implementation is provided for the copy constructor + DtInpChannel(const DtInpChannel&); + +public: + DtHwFuncDesc m_HwFuncDesc; // Hardware function descriptor + + // Convenience functions +public: + int Category(void) { return m_HwFuncDesc.m_DvcDesc.m_Category; } + int FirmwareVersion(void) { return m_HwFuncDesc.m_DvcDesc.m_FirmwareVersion; } + bool IsAttached(void) { return m_pInp != NULL; } + int TypeNumber(void) { return m_HwFuncDesc.m_DvcDesc.m_TypeNumber; } + bool HasCaps(const DtCaps Caps) const + { + return ((m_HwFuncDesc.m_Flags & Caps) == Caps); + } + +public: + DTAPI_RESULT AttachToPort(DtDevice* pDtDvc, int Port, + bool Exclusive=true, bool ProbeOnly=false); + DTAPI_RESULT BlindScan(int NumEntries, int& NumEntriesResult, + DtTransmitter* pScanResults, __int64 FreqHzSteps=10000000LL, + __int64 StartFreqHz=-1, __int64 EndFreqHz=-1); + DTAPI_RESULT BlindScan(DtBsProgressFunc* pCallback, void* pOpaque, + const DtDemodPars& DemodPars, + __int64 FreqHzSteps=10000000LL, __int64 StartFreqHz=-1, + __int64 EndFreqHz=-1); + DTAPI_RESULT CancelBlindScan(); + DTAPI_RESULT CancelSpectrumScan(); + DTAPI_RESULT ClearFifo(); + DTAPI_RESULT ClearFlags(int Latched); + DTAPI_RESULT Detach(int DetachMode); + DTAPI_RESULT DetectIoStd(int& Value, int& SubValue); + DTAPI_RESULT Equalise(int EqualiserSetting); + DTAPI_RESULT GetConstellationPoints(int NumPoints, DtConstelPoint* pPoint); + DTAPI_RESULT GetDemodControl(int& ModType, + int& ParXtra0, int& ParXtra1, int& ParXtra2); + DTAPI_RESULT GetDemodControl(DtDemodPars* pDemodPars); + DTAPI_RESULT GetDescriptor(DtHwFuncDesc& HwFunDesc); + DTAPI_RESULT GetFifoLoad(int& FifoLoad); + DTAPI_RESULT GetFlags(int& Flags, int& Latched); + DTAPI_RESULT GetIoConfig(int Group, int& Value); + DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue); + DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, __int64& ParXtra0); + DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, + __int64& ParXtra0, __int64& ParXtra1); + DTAPI_RESULT GetIpPars(DtIpPars* pIpPars); + DTAPI_RESULT GetIpStat(DtIpStat* pIpStat); + DTAPI_RESULT GetMaxFifoSize(int& MaxFifoSize); + DTAPI_RESULT GetPars(int Count, DtPar* pPars); + DTAPI_RESULT GetRxClkFreq(int& RxClkFreq); + DTAPI_RESULT GetRxControl(int& RxControl); + DTAPI_RESULT GetRxMode(int& RxMode); + DTAPI_RESULT GetStatistics(int Count, DtStatistic* pStatistics); + DTAPI_RESULT GetStatistic(int Type, int& Statistic); + DTAPI_RESULT GetStatistic(int Type, double& Statistic); + DTAPI_RESULT GetStatistic(int Type, bool& Statistic); + DTAPI_RESULT GetStatus(int& PacketSize, int& NumInv, int& ClkDet, + int& AsiLock, int& RateOk, int& AsiInv); + DTAPI_RESULT GetStreamSelection(DtDabEtiStreamSelPars& StreamSel); + DTAPI_RESULT GetStreamSelection(DtDabStreamSelPars& StreamSel); + DTAPI_RESULT GetStreamSelection(DtDvbC2StreamSelPars& StreamSel); + DTAPI_RESULT GetStreamSelection(DtDvbTStreamSelPars& StreamSel); + DTAPI_RESULT GetStreamSelection(DtDvbT2StreamSelPars& StreamSel); + DTAPI_RESULT GetStreamSelection(DtIsdbtStreamSelPars& StreamSel); + DTAPI_RESULT GetStreamSelection(DtT2MiStreamSelPars& StreamSel); + DTAPI_RESULT GetSupportedStatistics(int& Count, DtStatistic* pStatistics); + DTAPI_RESULT GetTargetId(int& Present, int& TargetId); + DTAPI_RESULT GetTsRateBps(int& TsRate); + DTAPI_RESULT GetTunerFrequency(__int64& FreqHz, int TunerId=-1); + DTAPI_RESULT GetViolCount(int& ViolCount); + DTAPI_RESULT I2CLock(int TimeOut); + DTAPI_RESULT I2CUnlock(void); + DTAPI_RESULT I2CRead(int DvcAddr, char* pBuffer, int NumBytesToRead); + DTAPI_RESULT I2CWrite(int DvcAddr, char* pBuffer, int NumBytesToWrite); + DTAPI_RESULT I2CWriteRead(int DvcAddrWrite, char* pBufferWrite, int NumBytesToWrite, + int DvcAddrRead, char* pBufferRead, int NumBytesToRead); + DTAPI_RESULT LedControl(int LedControl); + DTAPI_RESULT LnbEnable(bool Enable); + DTAPI_RESULT LnbEnableTone(bool Enable); + DTAPI_RESULT LnbSetVoltage(int Level); + DTAPI_RESULT LnbSendBurst(int BurstType); + DTAPI_RESULT LnbSendDiseqcMessage(const unsigned char* MsgOut, int NumBytesOut); + DTAPI_RESULT LnbSendDiseqcMessage(const unsigned char* MsgOut, int NumBytesOut, + unsigned char* MsgIn, int& NumBytesIn); + DTAPI_RESULT PolarityControl(int Polarity); + DTAPI_RESULT Read(char* pBuffer, int NumBytesToRead); + DTAPI_RESULT Read(char* pBuffer, int NumBytesToRead, int TimeOut); + DTAPI_RESULT ReadFrame(unsigned int* pFrame, int& FrameSize, int TimeOut=-1); + DTAPI_RESULT RegisterDemodCallback(IDtDemodEvent* pIEvent, __int64 Events=-1); + DTAPI_RESULT Reset(int ResetMode); + DTAPI_RESULT SetAdcSampleRate(int SampleRate); + DTAPI_RESULT SetAntPower(int AntPower); + DTAPI_RESULT SetDemodControl(int ModType, int ParXtra0, int ParXtra1, int ParXtra2); + DTAPI_RESULT SetDemodControl(DtDemodPars *pDemodPars); + DTAPI_RESULT SetErrorStatsMode(int ModType, int Mode); + DTAPI_RESULT SetFifoSize(int FifoSize); + DTAPI_RESULT SetIoConfig(int Group, int Value, int SubValue = -1, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + DTAPI_RESULT SetIpPars(DtIpPars* pIpPars); + DTAPI_RESULT SetPars(int Count, DtPar* pPars); + DTAPI_RESULT SetRxControl(int RxControl); + DTAPI_RESULT SetRxMode(int RxMode); + DTAPI_RESULT SetStreamSelection(DtDabEtiStreamSelPars& StreamSel); + DTAPI_RESULT SetStreamSelection(DtDabStreamSelPars& StreamSel); + DTAPI_RESULT SetStreamSelection(DtDvbC2StreamSelPars& StreamSel); + DTAPI_RESULT SetStreamSelection(DtDvbTStreamSelPars& StreamSel); + DTAPI_RESULT SetStreamSelection(DtDvbT2StreamSelPars& StreamSel); + DTAPI_RESULT SetStreamSelection(DtIsdbtStreamSelPars& StreamSel); + DTAPI_RESULT SetStreamSelection(DtT2MiStreamSelPars& StreamSel); + DTAPI_RESULT StatisticsPollingEnable(bool Enable); + DTAPI_RESULT SetTuningMode(int Mode); + DTAPI_RESULT SetTunerFrequency(__int64 FreqHz, int TunerId=-1); + DTAPI_RESULT SpectrumScan(DtSpsProgressFunc* pCallback, void* pOpaque, int ScanType, + __int64 FreqHzSteps=1000000LL, __int64 StartFreqHz=-1L, + __int64 EndFreqHz=-1L); + DTAPI_RESULT Tune(__int64 FreqHz, int ModType, + int ParXtra0, int ParXtra1, int ParXtra2); + DTAPI_RESULT Tune(__int64 FreqHz, DtDemodPars *pDemodPars); + + // Encapsulated data +private: + IXpMutex* m_pMTLock; // Multi-threading lock for Get/Read functions + void* m_pDetachLockCount; + int m_Port; + bool m_WantToDetach; + +public: // TODOSD should be protected + InpChannel* m_pInp; // Input channel implementation + +// Private helper functions +private: + DTAPI_RESULT DetachLock(void); + DTAPI_RESULT DetachUnlock(void); + DTAPI_RESULT ReadAccessLock(void); + DTAPI_RESULT ReadAccessUnlock(void); + DTAPI_RESULT ReadWithTimeOut(char* pBuf, int NumBytesToRead, int TimeOut = -1); +}; + +// Tuner freq has changed +#define DTAPI_EV_TUNE_FREQ_CHANGED 0x0000000000000001LL +// Tuning parameters have changed +#define DTAPI_EV_TUNE_PARS_CHANGED 0x0000000000000002LL + +#define DTAPI_ERRORSTATS_BER 0 // Bit error rate (default) +#define DTAPI_ERRORSTATS_RS 1 // Reed-Solomon packet errors + +// Feature not supported +#define DTAPI_NOT_SUPPORTED -1 + +// ASI Polarity-Control Status +#define DTAPI_ASIINV_NORMAL 0 +#define DTAPI_ASIINV_INVERT 1 + +// ASI Input-Clock Lock +#define DTAPI_ASI_NOLOCK 0 +#define DTAPI_ASI_INLOCK 1 + +// SDI Input-Clock Lock +#define DTAPI_GENLOCK_NOLOCK 0 +#define DTAPI_GENLOCK_INLOCK 1 + +// Clock Detector +#define DTAPI_CLKDET_FAIL 0 +#define DTAPI_CLKDET_OK 1 + +// Input Rate Ok +#define DTAPI_INPRATE_LOW 0 +#define DTAPI_INPRATE_OK 1 + +// #Invalid bytes per packet +#define DTAPI_NUMINV_NONE 0 +#define DTAPI_NUMINV_16 1 +#define DTAPI_NUMINV_OTHER 2 + +// Packet Size +#define DTAPI_PCKSIZE_INV 0 +#define DTAPI_PCKSIZE_188 2 +#define DTAPI_PCKSIZE_204 3 + +// SDI Mode +#define DTAPI_SDIMODE_INV 0 +#define DTAPI_SDIMODE_525 1 +#define DTAPI_SDIMODE_625 2 + +// Receive Control +#define DTAPI_RXCTRL_IDLE 0 +#define DTAPI_RXCTRL_RCV 1 + +// Receive mode for Transport Streams - Modes +#define DTAPI_RXMODE_TS 0x10 +#define DTAPI_RXMODE_TS_MODE_BITS 0x0F +#define DTAPI_RXMODE_ST188 (DTAPI_RXMODE_TS | 0x01) +#define DTAPI_RXMODE_ST204 (DTAPI_RXMODE_TS | 0x02) +#define DTAPI_RXMODE_STMP2 (DTAPI_RXMODE_TS | 0x03) +#define DTAPI_RXMODE_STRAW (DTAPI_RXMODE_TS | 0x04) +#define DTAPI_RXMODE_STL3 (DTAPI_RXMODE_TS | 0x05) +#define DTAPI_RXMODE_STL3FULL (DTAPI_RXMODE_TS | 0x06) +#define DTAPI_RXMODE_IPRAW (DTAPI_RXMODE_TS | 0x07) +#define DTAPI_RXMODE_RAWASI (DTAPI_RXMODE_TS | 0x08) +#define DTAPI_RXMODE_STTRP (DTAPI_RXMODE_TS | 0x09) +#define DTAPI_RXMODE_TS_MASK (DTAPI_RXMODE_TS | DTAPI_RXMODE_TS_MODE_BITS) + +// Receive mode for SDI - Modes +#define DTAPI_RXMODE_SDI 0x1000 +#define DTAPI_RXMODE_SDI_MODE_BITS 0x0F00 +#define DTAPI_RXMODE_SDI_FULL (DTAPI_RXMODE_SDI | 0x100) +#define DTAPI_RXMODE_SDI_ACTVID (DTAPI_RXMODE_SDI | 0x200) +#define DTAPI_RXMODE_SDI_MASK (DTAPI_RXMODE_SDI | DTAPI_RXMODE_SDI_MODE_BITS) +// Receive mode for SDI - Flags +#define DTAPI_RXMODE_SDI_HUFFMAN 0x00002000 +#define DTAPI_RXMODE_SDI_10B 0x00004000 +#define DTAPI_RXMODE_SDI_16B 0x00008000 +#define DTAPI_RXMODE_SDI_10B_NBO 0x00010000 +#define DTAPI_RXMODE_SDI_FRAMECOUNT 0x00020000 + +// Receive mode for SDI and Transport Streams - Common flags +#define DTAPI_RXMODE_TIMESTAMP32 0x01000000 +#define DTAPI_RXMODE_TIMESTAMP64 0x02000000 + +// Demodulation status flags - FEC lock +#define DTAPI_DEMOD_FECLOCK_FAIL 0 +#define DTAPI_DEMOD_FECLOCK_OK 1 +// Demodulation status flags - Receiver lock +#define DTAPI_DEMOD_RCVLOCK_FAIL 0 +#define DTAPI_DEMOD_RCVLOCK_OK 1 + +// Channel bands +#define DTAPI_BAND_BROADCAST_ONAIR 1 +#define DTAPI_BAND_FCC_CABLE 2 +#define DTAPI_BAND_IRC 3 +#define DTAPI_BAND_HRC 4 + +// RF level bandwith +#define DTAPI_RFLVL_CHANNEL 0 +#define DTAPI_RFLVL_NARROWBAND 1 + +// ADC sampling rates +#define DTAPI_ADCCLK_OFF 0 // Clock is off +#define DTAPI_ADCCLK_20M647 20647059 // 20.647059 MHz clock +#define DTAPI_ADCCLK_13M5 13500000 // 13.5 MHz clock +#define DTAPI_ADCCLK_27M 27000000 // 27.0 MHz clock + +// LNB control values +#define DTAPI_LNB_13V 0 // LNB power 13V +#define DTAPI_LNB_18V 1 // LNB power 18V +#define DTAPI_LNB_14V 2 // LNB power 14V +#define DTAPI_LNB_19V 3 // LNB power 19V + +// LNB burst types +#define DTAPI_LNB_BURST_A 0 // Burst A +#define DTAPI_LNB_BURST_B 1 // Burst B + +// Tuner Parameters - Tuner standard +#define DTAPI_TUNMOD_QAM 0x1 +#define DTAPI_TUNMOD_ATSC 0x2 +#define DTAPI_TUNMOD_ISDBT 0x3 +#define DTAPI_TUNMOD_DVBT 0x4 +#define DTAPI_TUNMOD_DMBT 0x5 + +// Tuner Parameters - DTA-2131 specific - Value for automatic computation of parameters +#define DTAPI_TUN31_AUTO -1 // According to tuner standard + +// Tuner Parameters - DTA-2131 specific - Low-pass filter cutoff frequency +#define DTAPI_TUN31_LPF_1_5MHZ 0 // 1.5 MHz low-pass filter +#define DTAPI_TUN31_LPF_6MHZ 1 // 6 MHz low-pass filter +#define DTAPI_TUN31_LPF_7MHZ 2 // 7 MHz low-pass filter +#define DTAPI_TUN31_LPF_8MHZ 3 // 8 MHz low-pass filter +#define DTAPI_TUN31_LPF_9MHZ 4 // 9 MHz low-pass filter + +// Tuner Parameters - DTA-2131 specific - Low-pass filter offset +#define DTAPI_TUN31_LPF_0PCT 0 // 0% low-pass filter offset +#define DTAPI_TUN31_LPF_4PCT 1 // 4% low-pass filter offset +#define DTAPI_TUN31_LPF_8PCT 2 // 8% low-pass filter offset +#define DTAPI_TUN31_LPF_12PCT 3 // 12% low-pass filter offset + +// Tuner Parameters - DTA-2131 specific - IF hi-pass filter +#define DTAPI_TUN31_HPF_DIS 0 // Disabled IF hi-pass filter +#define DTAPI_TUN31_HPF_0_4MHZ 1 // 0.4 MHz IF hi-pass filter +#define DTAPI_TUN31_HPF_0_85MHZ 2 // 0.85 MHz IF hi-pass filter +#define DTAPI_TUN31_HPF_1MHZ 3 // 1 MHz IF hi-pass filter +#define DTAPI_TUN31_HPF_1_5MHZ 4 // 1.5 MHz IF hi-pass filter + +// Tuner Parameters - DTA-2131 specific - Notch settings +#define DTAPI_TUN31_NOTCH_DIS 0 // Disable +#define DTAPI_TUN31_NOTCH_ENA 1 // Enable + +// Tuner Parameters - DTA-2139 specific - Agc specific +#define DTAPI_AGC1_FREE 0 +#define DTAPI_AGC1_FROZEN 1 + +// Tuning mode - DTU-236A/238 specific +#define DTAPI_TUNING_NORMAL 0 // Standard tuning mode +#define DTAPI_TUNING_INDEPENDENT 1 // Multiple tuners, tuned independently + +// Tuner ID - DTU-236A/238 specific +#define DTAPI_TUNERID_ALL -1 // ID for all tuners +#define DTAPI_TUNERID_MAIN 0 // ID for main tuner +#define DTAPI_TUNERID_MEASUREMENT 1 // ID for measurement tuner + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtOutpChannel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class to represent a transport-stream or SDI output channel +// +class DtOutpChannel +{ +public: + DtOutpChannel(); + virtual ~DtOutpChannel(); +private: + // No implementation is provided for the copy constructor + DtOutpChannel(const DtOutpChannel&); + +public: + DtHwFuncDesc m_HwFuncDesc; // Hardware function descriptor + + // Convenience functions +public: + int Category(void) { return m_HwFuncDesc.m_DvcDesc.m_Category; } + int FirmwareVersion(void) { return m_HwFuncDesc.m_DvcDesc.m_FirmwareVersion; } + bool IsAttached(void) { return m_pOutp != NULL; } + int TypeNumber(void) { return m_HwFuncDesc.m_DvcDesc.m_TypeNumber; } + bool HasCaps(const DtCaps Caps) const + { + return ((m_HwFuncDesc.m_Flags & Caps) == Caps); + } + +public: + virtual DTAPI_RESULT AttachToPort(DtDevice* pDtDvc, int Port, bool ProbeOnly=false); + virtual DTAPI_RESULT ClearFifo(void); + virtual DTAPI_RESULT ClearFlags(int Latched); + virtual DTAPI_RESULT ClearSfnErrors(); + virtual DTAPI_RESULT Detach(int DetachMode); + virtual DTAPI_RESULT GetAttribute(int AttrId, int& AttrValue); + virtual DTAPI_RESULT GetAttribute(int AttrId, DtModPars& ModParVals, int& AttrValue); + virtual DTAPI_RESULT GetDescriptor(DtHwFuncDesc& HwFunDesc); + virtual DTAPI_RESULT GetExtClkFreq(int& ExtClkFreq); + virtual DTAPI_RESULT GetFailsafeAlive(bool& Alive); + virtual DTAPI_RESULT GetFailsafeConfig(bool& Enable, int& Timeout); + virtual DTAPI_RESULT GetFifoLoad(int& FifoLoad, int SubChan=0); + virtual DTAPI_RESULT GetFifoSize(int& FifoSize); + virtual DTAPI_RESULT GetFifoSizeMax(int& FifoSizeMax); + virtual DTAPI_RESULT GetFifoSizeTyp(int& FifoSizeTyp); + virtual DTAPI_RESULT GetFlags(int& Status, int& Latched); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, + __int64& ParXtra0); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, + __int64& ParXtra0, __int64& ParXtra1); + virtual DTAPI_RESULT GetIpPars(DtIpPars* pIpPars); + virtual DTAPI_RESULT GetMaxFifoSize(int& MaxFifoSize); + virtual DTAPI_RESULT GetModControl(int& ModType, int& ParXtra0, int& ParXtra1, + int& ParXtra2, void*& pXtraPars); + virtual DTAPI_RESULT GetOutputLevel(int& LeveldBm); + virtual DTAPI_RESULT GetRfControl(__int64& RfFreq, int& LockStatus); + virtual DTAPI_RESULT GetRfControl(int& RfFreq, int& LockStatus); + virtual DTAPI_RESULT GetRfControl(double& RfFreq, int& LockStatus); + virtual DTAPI_RESULT GetSfnMaxTimeDiff(int& TimeDiff); + virtual DTAPI_RESULT GetSfnModDelay(int& ModDelay); + virtual DTAPI_RESULT GetSfnStatus(int& Status, int& Error); + virtual DTAPI_RESULT GetSpiClk(int& SpiClk); + virtual DTAPI_RESULT GetTargetId(int& Present, int& TargetId); + virtual DTAPI_RESULT GetTsRateBps(int& TsRate); + virtual DTAPI_RESULT GetTsRateBps(DtFractionInt& TsRate); + virtual DTAPI_RESULT GetTxControl(int& TxControl); + virtual DTAPI_RESULT GetTxMode(int& TxMode, int& TxStuffMode); + virtual DTAPI_RESULT LedControl(int LedControl); + virtual DTAPI_RESULT Reset(int ResetMode); + virtual DTAPI_RESULT SetChannelModelling(bool CmEnable, DtCmPars& CmPars); + virtual DTAPI_RESULT SetCustomRollOff(bool Enable, DtFilterPars& Filter); + virtual DTAPI_RESULT SetFailsafeAlive(); + virtual DTAPI_RESULT SetFailsafeConfig(bool Enable, int Timeout = 0); + virtual DTAPI_RESULT SetFifoSize(int FifoSize); + virtual DTAPI_RESULT SetFifoSizeMax(void); + virtual DTAPI_RESULT SetFifoSizeTyp(void); + virtual DTAPI_RESULT SetIoConfig(int Group, int Value, int SubValue = -1, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + virtual DTAPI_RESULT SetIpPars(DtIpPars* pIpPars); + virtual DTAPI_RESULT SetIsdbtCaptFile(void* IsdbtFile); + virtual DTAPI_RESULT SetModControl(DtCmmbPars&); + virtual DTAPI_RESULT SetModControl(DtDvbC2Pars&); + virtual DTAPI_RESULT SetModControl(DtDvbCidPars&); + virtual DTAPI_RESULT SetModControl(DtDvbS2Pars&); + virtual DTAPI_RESULT SetModControl(DtDvbT2Pars&); + virtual DTAPI_RESULT SetModControl(DtIqDirectPars&); + virtual DTAPI_RESULT SetModControl(DtIsdbsPars&); + virtual DTAPI_RESULT SetModControl(DtIsdbtPars&); + virtual DTAPI_RESULT SetModControl(DtIsdbTmmPars&); + virtual DTAPI_RESULT SetModControl(int ModType, int ParXtra0, int ParXtra1, + int ParXtra2); + virtual DTAPI_RESULT SetModControl(unsigned char*); + virtual DTAPI_RESULT SetMultiModConfig(int NumSubChan, int FreqSpacing); + virtual DTAPI_RESULT SetOutputLevel(int LeveldBm); + virtual DTAPI_RESULT SetPhaseNoiseControl(DtPhaseNoisePars& PnPars); + virtual DTAPI_RESULT SetPower(int Power); + virtual DTAPI_RESULT SetRfControl(__int64 RfFreq); + virtual DTAPI_RESULT SetRfControl(double RfFreq); + virtual DTAPI_RESULT SetRfControl(int RfFreq); + virtual DTAPI_RESULT SetRfMode(int RfMode); + virtual DTAPI_RESULT SetRfMode(int Sel, int Mode); + virtual DTAPI_RESULT SetSfnAllowedTimeDiff(int TimeDiff); + virtual DTAPI_RESULT SetSfnControl(int SnfMode, int TimeOffset); + virtual DTAPI_RESULT SetSnr(int Mode, int Snr); + virtual DTAPI_RESULT SetSpiClk(int SpiClk); + virtual DTAPI_RESULT SetTsRateBps(int TsRate); + virtual DTAPI_RESULT SetTsRateBps(DtFractionInt TsRate); + virtual DTAPI_RESULT SetTsRateRatio(int TsRate, int ClockRef); + virtual DTAPI_RESULT SetTxControl(int TxControl); + virtual DTAPI_RESULT SetTxMode(int TxMode, int StuffMode); + virtual DTAPI_RESULT SetTxPolarity(int TxPolarity); + virtual DTAPI_RESULT Write(char* pBuffer, int NumBytesToWrite, int SubChan=0); + // Undocumented + virtual DTAPI_RESULT GetModBufLoads(bool&, int&, int&, int&); + +public: // TODOSD should be protected + OutpChannel* m_pOutp; // Output channel implementation + +private: + void* m_pDetachLockCount; + bool m_WantToDetach; + DTAPI_RESULT DetachLock(void); + DTAPI_RESULT DetachUnlock(void); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMplpOutpChannel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMplpOutpChannel : public DtOutpChannel +{ +public: + DtMplpOutpChannel(); + virtual ~DtMplpOutpChannel(); +private: + // No implementation is provided for the copy constructor + DtMplpOutpChannel(const DtMplpOutpChannel&); + +public: + virtual bool IsAttached(void); + +public: + virtual DTAPI_RESULT AttachToPort(DtDevice* pDtDvc, int Port, bool ProbeOnly=false); + virtual DTAPI_RESULT ClearFifo(void); + virtual DTAPI_RESULT ClearFlags(int Latched); + virtual DTAPI_RESULT ClearSfnErrors(); + virtual DTAPI_RESULT Detach(int DetachMode); + virtual DTAPI_RESULT GetAttribute(int AttrId, int& AttrValue); + virtual DTAPI_RESULT GetAttribute(int AttrId, DtModPars& ModParVals, int& AttrValue); + virtual DTAPI_RESULT GetDescriptor(DtHwFuncDesc& HwFunDesc); + virtual DTAPI_RESULT GetExtClkFreq(int& ExtClkFreq); + virtual DTAPI_RESULT GetFailsafeAlive(bool& Alive); + virtual DTAPI_RESULT GetFailsafeConfig(bool& Enable, int& Timeout); + virtual DTAPI_RESULT GetFifoLoad(int& FifoLoad, int SubChan=0); + virtual DTAPI_RESULT GetFifoSize(int& FifoSize); + virtual DTAPI_RESULT GetFifoSizeMax(int& FifoSizeMax); + virtual DTAPI_RESULT GetFifoSizeTyp(int& FifoSizeTyp); + virtual DTAPI_RESULT GetFlags(int& Status, int& Latched); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, + __int64& ParXtra0); + virtual DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, + __int64& ParXtra0, __int64& ParXtra1); + virtual DTAPI_RESULT GetIpPars(DtIpPars* pIpPars); + virtual DTAPI_RESULT GetMaxFifoSize(int& MaxFifoSize); + virtual DTAPI_RESULT GetModControl(int& ModType, int& CodeRate, + int& ParXtra1, int& ParXtra2, void*& pXtraPars); + virtual DTAPI_RESULT GetOutputLevel(int& LeveldBm); + virtual DTAPI_RESULT GetRfControl(__int64& RfFreq, int& LockStatus); + virtual DTAPI_RESULT GetRfControl(int& RfFreq, int& LockStatus); + virtual DTAPI_RESULT GetRfControl(double& RfFreq, int& LockStatus); + virtual DTAPI_RESULT GetSfnMaxTimeDiff(int& TimeDiff); + virtual DTAPI_RESULT GetSfnModDelay(int& ModDelay); + virtual DTAPI_RESULT GetSfnStatus(int& Status, int& Error); + virtual DTAPI_RESULT GetSpiClk(int& SpiClk); + virtual DTAPI_RESULT GetTargetId(int& Present, int& TargetId); + virtual DTAPI_RESULT GetTsRateBps(int& TsRate); + virtual DTAPI_RESULT GetTsRateBps(DtFractionInt& TsRate); + virtual DTAPI_RESULT GetTxControl(int& TxControl); + virtual DTAPI_RESULT GetTxMode(int& TxMode, int& TxStuffMode); + virtual DTAPI_RESULT LedControl(int LedControl); + virtual DTAPI_RESULT Reset(int ResetMode); + virtual DTAPI_RESULT SetChannelModelling(bool CmEnable, DtCmPars& CmPars); + virtual DTAPI_RESULT SetCustomRollOff(bool Enable, DtFilterPars& Filter); + + virtual DTAPI_RESULT SetFailsafeConfig(bool Enable, int Timeout = 0); + virtual DTAPI_RESULT SetFailsafeAlive(); + virtual DTAPI_RESULT SetFifoSize(int FifoSize); + virtual DTAPI_RESULT SetFifoSizeMax(void); + virtual DTAPI_RESULT SetFifoSizeTyp(void); + virtual DTAPI_RESULT SetIoConfig(int Group, int Value, int SubValue = -1, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + virtual DTAPI_RESULT SetIpPars(DtIpPars* pIpPars); + virtual DTAPI_RESULT SetIsdbtCaptFile(void* IsdbtFile); + virtual DTAPI_RESULT SetModControl(DtCmmbPars&); + virtual DTAPI_RESULT SetModControl(DtDvbC2Pars&); + virtual DTAPI_RESULT SetModControl(DtDvbCidPars&); + virtual DTAPI_RESULT SetModControl(DtDvbS2Pars&); + virtual DTAPI_RESULT SetModControl(DtDvbT2Pars&); + virtual DTAPI_RESULT SetModControl(DtIqDirectPars&); + virtual DTAPI_RESULT SetModControl(DtIsdbsPars&); + virtual DTAPI_RESULT SetModControl(DtIsdbtPars&); + virtual DTAPI_RESULT SetModControl(DtIsdbTmmPars&); + virtual DTAPI_RESULT SetModControl(int ModType, int ParXtra0, int ParXtra1, + int ParXtra2); + virtual DTAPI_RESULT SetModControl(unsigned char*); + virtual DTAPI_RESULT SetMultiModConfig(int NumSubChan, int FreqSpacing); + virtual DTAPI_RESULT SetOutputLevel(int LeveldBm); + virtual DTAPI_RESULT SetPhaseNoiseControl(DtPhaseNoisePars& PnPars); + virtual DTAPI_RESULT SetPower(int Power); + virtual DTAPI_RESULT SetRfControl(__int64 RfFreq); + virtual DTAPI_RESULT SetRfControl(double RfFreq); + virtual DTAPI_RESULT SetRfControl(int RfFreq); + virtual DTAPI_RESULT SetRfMode(int RfMode); + virtual DTAPI_RESULT SetRfMode(int Sel, int Mode); + virtual DTAPI_RESULT SetSfnAllowedTimeDiff(int TimeDiff); + virtual DTAPI_RESULT SetSfnControl(int SnfMode, int TimeOffset); + virtual DTAPI_RESULT SetSnr(int Mode, int Snr); + virtual DTAPI_RESULT SetSpiClk(int SpiClk); + virtual DTAPI_RESULT SetTsRateBps(int TsRate); + virtual DTAPI_RESULT SetTsRateBps(DtFractionInt TsRate); + virtual DTAPI_RESULT SetTsRateRatio(int TsRate, int ClockRef); + virtual DTAPI_RESULT SetTxControl(int TxControl); + virtual DTAPI_RESULT SetTxMode(int TxMode, int TxStuffMode); + virtual DTAPI_RESULT SetTxPolarity(int TxPolarity); + virtual DTAPI_RESULT Write(char* pBuffer, int NumBytesToWrite, int SubChan=0); + // Undocumented + virtual DTAPI_RESULT GetModBufLoads(bool&, int&, int&, int&); + + // IMplpModulator interface implementation +public: + virtual DTAPI_RESULT AttachVirtual(DtDevice* pDtDvc, + bool (*pFunc)(void*, DtVirtualOutData*), void* pOpaque); + virtual DTAPI_RESULT GetMplpFifoFree(int FifoIdx, int& FifoFree); + virtual DTAPI_RESULT GetMplpFifoLoad(int FifoIdx, int& FifoLoad); + virtual DTAPI_RESULT GetMplpFifoSize(int FifoIdx, int& FifoSize); + virtual DTAPI_RESULT GetMplpModStatus(DtDvbC2ModStatus* pMplpModStat); + virtual DTAPI_RESULT GetMplpModStatus(DtDvbS2ModStatus* pMplpModStat); + virtual DTAPI_RESULT GetMplpModStatus(DtDvbT2ModStatus* pMplpModStat); + virtual DTAPI_RESULT GetMplpModStatus(DtDvbT2ModStatus* pMplpModStat1, + DtDvbT2ModStatus* pMplpModStat2); + virtual DTAPI_RESULT SetMplpChannelModelling(bool CmEnable, DtCmPars&, int Chan=0); + virtual DTAPI_RESULT WriteMplp(int FifoIdx, char* pBuffer, int NumBytesToWrite); + virtual DTAPI_RESULT WriteMplpPacket(int FifoIdx, char* pPacket, int PacketSize); + +private: + bool m_IsAttachedToVirtual; + MplpHelper* m_pMplpHelper; +}; + +// Detach mode flags +#define DTAPI_INSTANT_DETACH 1 +#define DTAPI_WAIT_UNTIL_SENT 2 + +// Equaliser settings +#define DTAPI_EQUALISER_OFF 0 +#define DTAPI_EQUALISER_ON 1 + +// LED control +#define DTAPI_LED_OFF 0 +#define DTAPI_LED_GREEN 1 +#define DTAPI_LED_RED 2 +#define DTAPI_LED_YELLOW 3 +#define DTAPI_LED_BLUE 4 +#define DTAPI_LED_HARDWARE 5 + +// Noise modes +#define DTAPI_NOISE_DISABLED 0 // No noise generation +#define DTAPI_NOISE_WNG_HW 1 // White noise generator (hardware) + +// Polarity control +#define DTAPI_POLARITY_AUTO 0 +#define DTAPI_POLARITY_NORMAL 2 +#define DTAPI_POLARITY_INVERT 3 + +// Power mode +#define DTAPI_POWER_OFF 0 +#define DTAPI_POWER_ON 1 + +// Reset mode +#define DTAPI_FIFO_RESET 0 +#define DTAPI_FULL_RESET 1 + +// RF PLL lock status +#define DTAPI_RFPLL_LOCK1 1 // RF PLL #1 is in lock +#define DTAPI_RFPLL_LOCK2 2 // RF PLL #2 is in lock +#define DTAPI_RFPLL_LOCK3 4 // RF PLL #3 is in lock + +// Receiver status flags +#define DTAPI_RX_FIFO_OVF 0x0002 +#define DTAPI_RX_SYNC_ERR 0x0004 +#define DTAPI_RX_RATE_OVF 0x0008 +#define DTAPI_RX_TARGET_ERR 0x0010 +#define DTAPI_RX_LINK_ERR 0x0040 +#define DTAPI_RX_DATA_ERR 0x0080 +#define DTAPI_RX_DRV_BUF_OVF 0x0100 +#define DTAPI_RX_SYNTAX_ERR 0x0200 + +// Single Frequency Network status andd error flags +#define DTAPI_SFN_IN_SYNC 0x0001 +#define DTAPI_SFN_TOO_EARLY_ERR 0x0001 +#define DTAPI_SFN_TOO_LATE_ERR 0x0002 +#define DTAPI_SFN_ABSTIME_ERR 0x0004 +#define DTAPI_SFN_DISCTIME_ERR 0x0008 +#define DTAPI_SFN_NOTIME_ERR 0x0010 +#define DTAPI_SFN_START_ERR 0x0020 + +// Single Frequency operation mode +#define DTAPI_SFN_MODE_DISABLED 0x0000 +#define DTAPI_SFN_MODE_AT_1PPS 0x0001 +#define DTAPI_SFN_MODE_IQPCK 0x0002 +#define DTAPI_SFN_MODE_DVBT_MIP 0x0003 +#define DTAPI_SFN_MODE_T2MI 0x0004 + +// Transmit status flags +#define DTAPI_TX_FIFO_UFL 0x0002 +#define DTAPI_TX_SYNC_ERR 0x0004 +#define DTAPI_TX_READBACK_ERR 0x0008 +#define DTAPI_TX_TARGET_ERR 0x0010 +#define DTAPI_TX_MUX_OVF 0x0020 +#define DTAPI_TX_FIFO_OVF 0x0020 +#define DTAPI_TX_LINK_ERR 0x0040 +#define DTAPI_TX_DATA_ERR 0x0080 +#define DTAPI_TX_CPU_UFL 0x0100 +#define DTAPI_TX_DMA_UFL 0x0200 + +// Target adapter present +#define DTAPI_NO_CONNECTION 0 +#define DTAPI_DVB_SPI_SINK 1 // For output channels +#define DTAPI_DVB_SPI_SOURCE 1 // For input channels +#define DTAPI_TARGET_PRESENT 2 +#define DTAPI_TARGET_UNKNOWN 3 + +// Transmit control +#define DTAPI_TXCTRL_IDLE 1 +#define DTAPI_TXCTRL_HOLD 2 +#define DTAPI_TXCTRL_SEND 3 + +// Transmit mode for Transport Streams - Modes +#define DTAPI_TXMODE_TS 0x10 +#define DTAPI_TXMODE_TS_MODE_BITS 0x0F +#define DTAPI_TXMODE_188 (DTAPI_TXMODE_TS | 0x01) +#define DTAPI_TXMODE_192 (DTAPI_TXMODE_TS | 0x02) +#define DTAPI_TXMODE_204 (DTAPI_TXMODE_TS | 0x03) +#define DTAPI_TXMODE_ADD16 (DTAPI_TXMODE_TS | 0x04) +#define DTAPI_TXMODE_MIN16 (DTAPI_TXMODE_TS | 0x05) +#define DTAPI_TXMODE_IPRAW (DTAPI_TXMODE_TS | 0x06) +#define DTAPI_TXMODE_RAW (DTAPI_TXMODE_TS | 0x07) +#define DTAPI_TXMODE_RAWASI (DTAPI_TXMODE_TS | 0x08) +#define DTAPI_TXMODE_TS_MASK (DTAPI_TXMODE_TS | DTAPI_TXMODE_TS_MODE_BITS) +// Transmit mode for Transport Streams - DVB-ASI flags +#define DTAPI_TXMODE_BURST 0x20 +#define DTAPI_TXMODE_TXONTIME 0x40 + +// Transmit mode for SDI - Modes +#define DTAPI_TXMODE_SDI 0x1000 +#define DTAPI_TXMODE_SDI_MODE_BITS 0x0F00 +#define DTAPI_TXMODE_SDI_FULL (DTAPI_TXMODE_SDI | 0x100) +#define DTAPI_TXMODE_SDI_ACTVID (DTAPI_TXMODE_SDI | 0x200) +#define DTAPI_TXMODE_SDI_MASK (DTAPI_TXMODE_SDI | DTAPI_TXMODE_SDI_MODE_BITS) +// Transmit mode for SDI - Flags +#define DTAPI_TXMODE_SDI_HUFFMAN 0x00002000 +#define DTAPI_TXMODE_SDI_10B 0x00004000 +#define DTAPI_TXMODE_SDI_16B 0x00008000 +#define DTAPI_TXMODE_SDI_10B_NBO 0x00010000 + +// Stuff mode - TS : Null-packet stuffing on/off; SDI: Black-frame stuffing on/off +#define DTAPI_TXSTUFF_MODE_OFF 0 +#define DTAPI_TXSTUFF_MODE_ON 1 + +// Transmit polarity +#define DTAPI_TXPOL_NORMAL 0 +#define DTAPI_TXPOL_INVERTED 1 + +// Upconverter RF modes +#define DTAPI_UPCONV_MODE 0 // Selects NORMAL/MUTE/CW/CWI/CWQ +#define DTAPI_UPCONV_MODE_MSK 0xF // Mask for mode field +#define DTAPI_UPCONV_NORMAL 0 +#define DTAPI_UPCONV_MUTE 1 +#define DTAPI_UPCONV_CW 2 +#define DTAPI_UPCONV_CWI 3 +#define DTAPI_UPCONV_CWQ 4 +#define DTAPI_UPCONV_SPECINV 0x100 // Can be OR-ed with other RF modes + +// USB speed modes +#define DTAPI_USB_FULL_SPEED 0 +#define DTAPI_USB_HIGH_SPEED 1 +#define DTAPI_USB_SUPER_SPEED 2 + +// PCIe standards +#define DTAPI_PCIE_GEN_UNKNOWN 0 // PCIe Gen is unknown +#define DTAPI_PCIE_GEN1 1 // PCIe Gen 1 (2.5Gbps per link) +#define DTAPI_PCIE_GEN2 2 // PCIe Gen 2 (5.0Gbps per link) +#define DTAPI_PCIE_GEN3 3 // PCIe Gen 3 (8.0Gbps per link) + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- Modulation Parameters -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- + +// Modulation types +#define DTAPI_MOD_DVBS_QPSK 0 // Native DVB-S on DTA-107 +#define DTAPI_MOD_DVBS_BPSK 1 +#define DTAPI_MOD_QAM4 3 +#define DTAPI_MOD_QAM16 4 +#define DTAPI_MOD_QAM32 5 +#define DTAPI_MOD_QAM64 6 +#define DTAPI_MOD_QAM128 7 +#define DTAPI_MOD_QAM256 8 +#define DTAPI_MOD_DVBT 9 +#define DTAPI_MOD_ATSC 10 +#define DTAPI_MOD_DVBT2 11 +#define DTAPI_MOD_ISDBT 12 +#define DTAPI_MOD_ISDBS 13 +#define DTAPI_MOD_IQDIRECT 15 +#define DTAPI_MOD_IQ_2131 16 // DTA-2131 specific (de)modulation +#define DTAPI_MOD_DVBS2_QPSK 32 +#define DTAPI_MOD_DVBS2_8PSK 33 +#define DTAPI_MOD_DVBS2_16APSK 34 +#define DTAPI_MOD_DVBS2_32APSK 35 +#define DTAPI_MOD_DVBS2_L3 36 +#define DTAPI_MOD_DVBS2 37 +#define DTAPI_MOD_DMBTH 48 +#define DTAPI_MOD_ADTBT 49 +#define DTAPI_MOD_CMMB 50 +#define DTAPI_MOD_T2MI 51 +#define DTAPI_MOD_DVBC2 52 +#define DTAPI_MOD_DAB 53 +#define DTAPI_MOD_QAM_AUTO 54 +#define DTAPI_MOD_ATSC_MH 55 +#define DTAPI_MOD_ISDBTMM 56 +// Modulation types DVB-S2X specific +#define DTAPI_MOD_S2X_QPSK_VLSNR 57 // DVB-S2X, QPSK, very low SNR +#define DTAPI_MOD_S2X_BPSK_VLSNR 58 // DVB-S2X, BPSK, very low SNR +#define DTAPI_MOD_S2X_BPSK_S_VLSNR 59 // DVB-S2X, BPSK-S, very low SNR +#define DTAPI_MOD_S2X_8APSK_L 60 // DVB-S2X, 8APSK-L +#define DTAPI_MOD_S2X_16APSK_L 61 // DVB-S2X, 16APSK-L +#define DTAPI_MOD_S2X_32APSK_L 62 // DVB-S2X, 32APSK-L +#define DTAPI_MOD_S2X_64APSK 63 // DVB-S2X, 64APSK +#define DTAPI_MOD_S2X_64APSK_L 64 // DVB-S2X, 64APSK-L +#define DTAPI_MOD_S2X_128APSK 65 // DVB-S2X, 128APSK +#define DTAPI_MOD_S2X_256APSK 66 // DVB-S2X, 256APSK-L +#define DTAPI_MOD_S2X_256APSK_L 67 // DVB-S2X, 256APSK +#define DTAPI_MOD_DVBS2X_L3 68 // L3 modulation with S2X support +#define DTAPI_MOD_TYPE_AUTO -1 // Auto detect modulation type +#define DTAPI_MOD_TYPE_UNK -1 // Unknown modulation type + +// Modulation parameters - Common - ParXtra2 +#define DTAPI_MOD_SYMRATE_AUTO -1 // Auto detect symbol rate +#define DTAPI_MOD_SYMRATE_UNK -1 // Symbol rate if unknown + +// Modulation parameters - ATSC - ParXtra0 +#define DTAPI_MOD_ATSC_VSB8 0x00000000 // 8-VSB, 10.762MBd, 19.392Mbps +#define DTAPI_MOD_ATSC_VSB16 0x00000001 // 16-VSB, 10.762MBd, 38.785Mbps +#define DTAPI_MOD_ATSC_VSB_AUTO 0x00000003 // Auto detect constellation +#define DTAPI_MOD_ATSC_VSB_UNK 0x00000003 // Unknown constellation +#define DTAPI_MOD_ATSC_VSB_MSK 0x00000003 // Constellation mask + +// Modulation parameters - DTMB - Bandwidth +#define DTAPI_MOD_DTMB_5MHZ 0x00000001 +#define DTAPI_MOD_DTMB_6MHZ 0x00000002 +#define DTAPI_MOD_DTMB_7MHZ 0x00000003 +#define DTAPI_MOD_DTMB_8MHZ 0x00000004 +#define DTAPI_MOD_DTMB_BW_AUTO 0x0000000F // Auto detect +#define DTAPI_MOD_DTMB_BW_UNK 0x0000000F // Unknown +#define DTAPI_MOD_DTMB_BW_MSK 0x0000000F + +// Modulation parameters - DTMB - Code rate +#define DTAPI_MOD_DTMB_0_4 0x00000100 // 0.4 +#define DTAPI_MOD_DTMB_0_6 0x00000200 // 0.6 +#define DTAPI_MOD_DTMB_0_8 0x00000300 // 0.8 +#define DTAPI_MOD_DTMB_RATE_AUTO 0x00000F00 // Auto detect +#define DTAPI_MOD_DTMB_RATE_UNK 0x00000F00 // Unknown +#define DTAPI_MOD_DTMB_RATE_MSK 0x00000F00 // Mask + +// Modulation parameters - DTMB - Constellation +#define DTAPI_MOD_DTMB_QAM4NR 0x00001000 // 4-QAM-NR +#define DTAPI_MOD_DTMB_QAM4 0x00002000 // 4-QAM +#define DTAPI_MOD_DTMB_QAM16 0x00003000 // 16-QAM +#define DTAPI_MOD_DTMB_QAM32 0x00004000 // 32-QAM +#define DTAPI_MOD_DTMB_QAM64 0x00005000 // 64-QAM +#define DTAPI_MOD_DTMB_CO_AUTO 0x0000F000 // Auto detect +#define DTAPI_MOD_DTMB_CO_UNK 0x0000F000 // Unknown +#define DTAPI_MOD_DTMB_CO_MSK 0x0000F000 // Mask + +// Modulation parameters - DTMB - Frame header mode +#define DTAPI_MOD_DTMB_PN420 0x00010000 // PN420 +#define DTAPI_MOD_DTMB_PN595 0x00020000 // PN595 +#define DTAPI_MOD_DTMB_PN945 0x00030000 // PN945 +#define DTAPI_MOD_DTMB_PN_AUTO 0x000F0000 // Auto detect +#define DTAPI_MOD_DTMB_PN_UNK 0x000F0000 // Unknown +#define DTAPI_MOD_DTMB_PN_MSK 0x000F0000 // Mask + +// Modulation parameters - DTMB - Interleaver mode +#define DTAPI_MOD_DTMB_IL_1 0x00100000 // Interleaver mode 1: B=54, M=240 +#define DTAPI_MOD_DTMB_IL_2 0x00200000 // Interleaver mode 2: B=54, M=720 +#define DTAPI_MOD_DTMB_IL_AUTO 0x00F00000 // Auto detect +#define DTAPI_MOD_DTMB_IL_UNK 0x00F00000 // Unknown +#define DTAPI_MOD_DTMB_IL_MSK 0x00F00000 // Mask + +// Modulation parameters - DTMB - pilots +#define DTAPI_MOD_DTMB_NO_PILOTS 0x01000000 // No pilots +#define DTAPI_MOD_DTMB_PILOTS 0x02000000 // Pilots, C=1 only +#define DTAPI_MOD_DTMB_PIL_AUTO 0x0F000000 // Auto detect +#define DTAPI_MOD_DTMB_PIL_UNK 0x0F000000 // Unknown +#define DTAPI_MOD_DTMB_PIL_MSK 0x0F000000 // Mask + +// Modulation parameters - DTMB - Use frame numbering +#define DTAPI_MOD_DTMB_NO_FRM_NO 0x10000000 // No frame numbering +#define DTAPI_MOD_DTMB_USE_FRM_NO 0x20000000 // Use frame numbers +#define DTAPI_MOD_DTMB_UFRM_AUTO 0xF0000000 // Auto detect +#define DTAPI_MOD_DTMB_UFRM_UNK 0xF0000000 // Unknown +#define DTAPI_MOD_DTMB_UFRM_MSK 0xF0000000 // Mask + +// Modulation parameters - DVB-S, DVB-S2 +#define DTAPI_MOD_1_2 0x0 // Code rate 1/2 +#define DTAPI_MOD_2_3 0x1 // Code rate 2/3 +#define DTAPI_MOD_3_4 0x2 // Code rate 3/4 +#define DTAPI_MOD_4_5 0x3 // Code rate 4/5 +#define DTAPI_MOD_5_6 0x4 // Code rate 5/6 +#define DTAPI_MOD_6_7 0x5 // Code rate 6/7 +#define DTAPI_MOD_7_8 0x6 // Code rate 7/8 +#define DTAPI_MOD_1_4 0x7 // Code rate 1/4 +#define DTAPI_MOD_1_3 0x8 // Code rate 1/3 +#define DTAPI_MOD_2_5 0x9 // Code rate 2/5 +#define DTAPI_MOD_3_5 0xA // Code rate 3/5 +#define DTAPI_MOD_8_9 0xB // Code rate 8/9 +#define DTAPI_MOD_9_10 0xC // Code rate 9/10 +#define DTAPI_MOD_CR_AUTO 0xF // Auto detect code rate +#define DTAPI_MOD_CR_UNK 0xF // Unknown code rate +//Coderates DVB-S2X specific +#define DTAPI_MOD_1_5 0x10 // Code rate 1/5 +#define DTAPI_MOD_2_9 0x11 // Code rate 2/9 +#define DTAPI_MOD_11_45 0x12 // Code rate 11/45 +#define DTAPI_MOD_4_15 0x13 // Code rate 4/15 +#define DTAPI_MOD_13_45 0x14 // Code rate 13/45 +#define DTAPI_MOD_14_45 0x15 // Code rate 14/45 +#define DTAPI_MOD_9_20 0x16 // Code rate 9/20 +#define DTAPI_MOD_7_15 0x17 // Code rate 7/15 +#define DTAPI_MOD_8_15 0x18 // Code rate 8/15 +#define DTAPI_MOD_11_20 0x19 // Code rate 11/20 +#define DTAPI_MOD_5_9 0x1A // Code rate 5/9 +#define DTAPI_MOD_26_45 0x1B // Code rate 26/45 +#define DTAPI_MOD_28_45 0x1C // Code rate 28/45 +#define DTAPI_MOD_23_36 0x1D // Code rate 23/36 +#define DTAPI_MOD_29_45 0x1E // Code rate 29/45 +#define DTAPI_MOD_31_45 0x1F // Code rate 31/45 +#define DTAPI_MOD_25_36 0x20 // Code rate 25/36 +#define DTAPI_MOD_32_45 0x21 // Code rate 32/45 +#define DTAPI_MOD_13_18 0x22 // Code rate 13/18 +#define DTAPI_MOD_11_15 0x23 // Code rate 11/15 +#define DTAPI_MOD_7_9 0x24 // Code rate 7/9 +#define DTAPI_MOD_77_90 0x25 // Code rate 77/90 + +// Modulation parameters - DVB-S, DVB-S2 - ParXtra1 +#define DTAPI_MOD_S_S2_SPECNONINV 0x00 // No spectrum inversion detected +#define DTAPI_MOD_S_S2_SPECINV 0x10 // Spectrum inversion detected +#define DTAPI_MOD_S_S2_SPECINV_AUTO 0x30 // Auto detect spectral inversion +#define DTAPI_MOD_S_S2_SPECINV_UNK 0x30 // Spectral inversion is unknown +#define DTAPI_MOD_S_S2_SPECINV_MSK 0x30 // Mask for spectrum inversion field + +// Modulation parameters - DVB-S2 - ParXtra1 - Pilots +#define DTAPI_MOD_S2_NOPILOTS 0x00 // Pilots disabled +#define DTAPI_MOD_S2_PILOTS 0x01 // Pilots enabled +#define DTAPI_MOD_S2_PILOTS_AUTO 0x03 // Auto detect pilots +#define DTAPI_MOD_S2_PILOTS_UNK 0x03 // State of pilots unknown +#define DTAPI_MOD_S2_PILOTS_MSK 0x03 // Mask for pilots field + +// Modulation parameters - DVB-S2 - ParXtra1 - FEC frame length +#define DTAPI_MOD_S2_LONGFRM 0x00 // Long FECFRAME +#define DTAPI_MOD_S2_MEDIUMFRM 0x04 // Medium FECFRAME +#define DTAPI_MOD_S2_SHORTFRM 0x08 // Short FECFRAME +#define DTAPI_MOD_S2_FRM_AUTO 0x0C // Auto detect frame size +#define DTAPI_MOD_S2_FRM_UNK 0x0C // Frame size unknown +#define DTAPI_MOD_S2_FRM_MSK 0x0C // Mask for FECFRAME field + +// Modulation parameters - DVB-S2(X) - ParXtra1 - Constellation amplitude for 16-, 32-APSK +#define DTAPI_MOD_S2_CONST_AUTO 0x00 // Default constellation amplitude +#define DTAPI_MOD_S2_CONST_E_1 0x40 // E=1; Average symbol energy is constant +#define DTAPI_MOD_S2_CONST_R_1 0x80 // R=1; Radius of outer ring is constant +#define DTAPI_MOD_S2_CONST_MSK 0xC0 // Mask for constellation shape + +// Modulation parameters - ISDB-S - Input stream +#define DTAPI_MOD_ISDBS_STREAMTYPE_RAW 0x00 // Raw stream with TMCC in sync bytes +#define DTAPI_MOD_ISDBS_STREAMTYPE_B15 0x01 // TMCC data following each TS packet +#define DTAPI_MOD_ISDBS_STREAMTYPE_AUTO 0x07 // Default (raw) isdb-s input stream +#define DTAPI_MOD_ISDBS_STREAMTYPE_MASK 0x07 // Mask for input stream type + +// Modulation parameters - DVB-T - Bandwidth +#define DTAPI_MOD_DVBT_5MHZ 0x00000001 +#define DTAPI_MOD_DVBT_6MHZ 0x00000002 +#define DTAPI_MOD_DVBT_7MHZ 0x00000003 +#define DTAPI_MOD_DVBT_8MHZ 0x00000004 +#define DTAPI_MOD_DVBT_BW_UNK 0x0000000F // Unknown bandwidth +#define DTAPI_MOD_DVBT_BW_MSK 0x0000000F + +// Modulation parameters - DVB-T - Constellation +#define DTAPI_MOD_DVBT_QPSK 0x00000010 +#define DTAPI_MOD_DVBT_QAM16 0x00000020 +#define DTAPI_MOD_DVBT_QAM64 0x00000030 +#define DTAPI_MOD_DVBT_CO_AUTO 0x000000F0 // Auto detect constellation +#define DTAPI_MOD_DVBT_CO_UNK 0x000000F0 // Unknown constellation +#define DTAPI_MOD_DVBT_CO_MSK 0x000000F0 + +// Modulation parameters - DVB-T - Guard interval +#define DTAPI_MOD_DVBT_G_1_32 0x00000100 +#define DTAPI_MOD_DVBT_G_1_16 0x00000200 +#define DTAPI_MOD_DVBT_G_1_8 0x00000300 +#define DTAPI_MOD_DVBT_G_1_4 0x00000400 +#define DTAPI_MOD_DVBT_GU_AUTO 0x00000F00 // Auto detect guard interval +#define DTAPI_MOD_DVBT_GU_UNK 0x00000F00 // Unknown guard interval +#define DTAPI_MOD_DVBT_GU_MSK 0x00000F00 + +// DVB-T TPS information - DVB-T Hierarchical layer +#define DTAPI_MOD_DVBT_HARCHY_NONE 0x00000000 +#define DTAPI_MOD_DVBT_HARCHY_A1 0x01000000 +#define DTAPI_MOD_DVBT_HARCHY_A2 0x02000000 +#define DTAPI_MOD_DVBT_HARCHY_A4 0x03000000 +#define DTAPI_MOD_DVBT_HARCHY_MSK 0x0F000000 +// Modulation parameters - DVB-T - Interleaver mode +#define DTAPI_MOD_DVBT_INDEPTH 0x00001000 +#define DTAPI_MOD_DVBT_NATIVE 0x00002000 +#define DTAPI_MOD_DVBT_IL_AUTO 0x0000F000 // Auto detect interleaver depth +#define DTAPI_MOD_DVBT_IL_UNK 0x0000F000 // Unknown interleaver depth +#define DTAPI_MOD_DVBT_IL_MSK 0x0000F000 + +// Modulation parameters - DVB-T - FFT size +#define DTAPI_MOD_DVBT_2K 0x00010000 +#define DTAPI_MOD_DVBT_4K 0x00020000 +#define DTAPI_MOD_DVBT_8K 0x00030000 +#define DTAPI_MOD_DVBT_MD_AUTO 0x000F0000 // Auto detect mode +#define DTAPI_MOD_DVBT_MD_UNK 0x000F0000 // Unknown mode +#define DTAPI_MOD_DVBT_MD_MSK 0x000F0000 + +// Modulation parameters - DVB-T - s48 +#define DTAPI_MOD_DVBT_S48_OFF 0x00000000 +#define DTAPI_MOD_DVBT_S48 0x00100000 +#define DTAPI_MOD_DVBT_S48_MSK 0x00100000 + +// Modulation parameters - DVB-T - s49 +#define DTAPI_MOD_DVBT_S49_OFF 0x00000000 +#define DTAPI_MOD_DVBT_S49 0x00200000 +#define DTAPI_MOD_DVBT_S49_MSK 0x00200000 + +// Modulation parameters - DVB-T - s48s49 +#define DTAPI_MOD_DVBT_ENA4849 0x00000000 +#define DTAPI_MOD_DVBT_DIS4849 0x00400000 +#define DTAPI_MOD_DVBT_4849_MSK 0x00400000 + +// Modulation parameters - IQ - ParXtra0 +#define DTAPI_MOD_INTERPOL_RAW 0 // Raw mode, no interpolation +#define DTAPI_MOD_INTERPOL_OFDM 1 // Use OFDM interpolation +#define DTAPI_MOD_INTERPOL_QAM 2 // Use QAM interpolation + +// Modulation parameters - IQ - ParXtra2 Packing +#define DTAPI_MOD_IQPCK_AUTO 0x00000000 // Auto IQ-sample packin +#define DTAPI_MOD_IQPCK_NONE 0x00000001 // No IQ-sample packing +#define DTAPI_MOD_IQPCK_PCKD 0x00000002 // IQ-samples are already packed +#define DTAPI_MOD_IQPCK_12B 0x00000003 // IQ-samples packed in 12-bit +#define DTAPI_MOD_IQPCK_10B 0x00000004 // IQ-samples packed in 10-bit +#define DTAPI_MOD_IQPCK_UNK 0x000000FF // Unknown (= use auto) +#define DTAPI_MOD_IQPCK_MSK 0x000000FF + +// Modulation parameters - Roll-off factor ParXtra1 (DVB-S2), ParXtra2 (IQ) and +// Low pass filters ParXtra2 (IQ) +#define DTAPI_MOD_ROLLOFF_AUTO 0x00000000 // Default roll-off factor +#define DTAPI_MOD_ROLLOFF_NONE 0x00000100 // No roll-off +#define DTAPI_MOD_ROLLOFF_5 0x00000200 // 5% roll-off for DVB-S2X +#define DTAPI_MOD_ROLLOFF_10 0x00000300 // 10% roll-off for DVB-S2X +#define DTAPI_MOD_ROLLOFF_15 0x00000400 // 15% roll-off for DVB-S2X +#define DTAPI_MOD_ROLLOFF_20 0x00000500 // 20% roll-off for DVB-S2 +#define DTAPI_MOD_ROLLOFF_25 0x00000600 // 25% roll-off for DVB-S2 +#define DTAPI_MOD_ROLLOFF_35 0x00000700 // 35% roll-off for DVB-S/S2 +// Pre-defined low pass filters +#define DTAPI_MOD_LPF_0_614 0x00000800 // Passband up to samplerate*0.614, + // used for 2MHz CMMB +#define DTAPI_MOD_LPF_0_686 0x00000900 // Passband up to samplerate*0.686, + // used for ISDB-T/Tmm/Tsb +#define DTAPI_MOD_LPF_0_754 0x00000A00 // Passband up to samplerate*0.754, + // used for 8MHz CMMB, DAB +#define DTAPI_MOD_LPF_0_833 0x00000B00 // Passband up to samplerate*0.833, + // used for DVB-C2/T/T2 +#define DTAPI_MOD_LPF_0_850 0x00000C00 // Passband up to samplerate*0.850, + // used for DVB-T2 extended bandwidth +#define DTAPI_MOD_ROLLOFF_UNK 0x0000FF00 // Unknown (= use default) +#define DTAPI_MOD_ROLLOFF_MSK 0x0000FF00 + +// Modulation parameters - DVB-T2-MI - ParXtra0 used for T2-MI bitrate + +// Modulation parameters - DVB-T2-MI - ParXtra1 +#define DTAPI_MOD_T2MI_PID1_MSK 0x1FFF +#define DTAPI_MOD_T2MI_PID1_SHFT 0 +#define DTAPI_MOD_T2MI_PID2_MSK 0x1FFF0000 +#define DTAPI_MOD_T2MI_PID2_SHFT 16 +#define DTAPI_MOD_T2MI_MULT_DIS 0x00000000 // Single Profile +#define DTAPI_MOD_T2MI_MULT_ENA 0x20000000 // Multi Profile +#define DTAPI_MOD_T2MI_MULT_MSK 0x20000000 // Multi Profile mask + +// Modulation parameters - QAM - ParXtra0 - J.83 Annex +#define DTAPI_MOD_J83_MSK 0x000F +#define DTAPI_MOD_J83_UNK 0x000F // Unknown annex +#define DTAPI_MOD_J83_AUTO 0x000F // Auto detect annex +#define DTAPI_MOD_J83_A 0x0002 // J.83 annex A (DVB-C) +#define DTAPI_MOD_J83_B 0x0003 // J.83 annex B (\93American QAM\94) +#define DTAPI_MOD_J83_C 0x0001 // J.83 annex C (\93Japanese QAM\94) + +// Modulation parameters - QAM - ParXtra1 - QAM-B interleaver mode +#define DTAPI_MOD_QAMB_I128_J1D 0x1 +#define DTAPI_MOD_QAMB_I64_J2 0x3 +#define DTAPI_MOD_QAMB_I32_J4 0x5 +#define DTAPI_MOD_QAMB_I16_J8 0x7 +#define DTAPI_MOD_QAMB_I8_J16 0x9 +#define DTAPI_MOD_QAMB_I128_J1 0x0 +#define DTAPI_MOD_QAMB_I128_J2 0x2 +#define DTAPI_MOD_QAMB_I128_J3 0x4 +#define DTAPI_MOD_QAMB_I128_J4 0x6 +#define DTAPI_MOD_QAMB_I128_J5 0x8 +#define DTAPI_MOD_QAMB_I128_J6 0xA +#define DTAPI_MOD_QAMB_I128_J7 0xC +#define DTAPI_MOD_QAMB_I128_J8 0xE +#define DTAPI_MOD_QAMB_IL_UNK 0xF // Unknown interleaver mode +#define DTAPI_MOD_QAMB_IL_AUTO 0xF // Auto detect interleaver mode +#define DTAPI_MOD_QAMB_IL_MSK 0xF + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ SDI +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +// DtSdi - Table-of-content entry types +#define DTAPI_SDI_TOC_ENTRY_UNKNOWN 0 +#define DTAPI_SDI_TOC_ENTRY_ACTVID 1 +#define DTAPI_SDI_TOC_ENTRY_HANC 2 +#define DTAPI_SDI_TOC_ENTRY_VANC 3 + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtSdiTocEntry -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtSdiTocEntry +{ + friend class DtSdiUtility; + +public: + inline int AncDataBlockNum() const + { + if (AncType() != 1) return -1; + else return m_SdidOrDbn; + } + inline int AncDataId() const { return m_Did; } + inline int AncNumUserWords() const { return m_NumUserWords; } + inline int AncSecDataId() const + { + if (AncType() != 2) return -1; + else return m_SdidOrDbn; + } + inline int AncType() const { return m_AncType; } + + inline int Field() const { return m_Field; } + inline int Line() const { return m_Line; } + inline int NumSymbols() const { return m_NumSymbols; } + inline int StartOffset() const { return m_StartOffset; } + inline int TocType() const { return m_TocType; } + + // Encapsulated data +protected: + int m_TocType; // Type of TOC entry + int m_Line; // Line number where data is located + int m_Field; // Field in where data is located + int m_StartOffset; // Symbol offset relative to start of line, first data + int m_NumSymbols; // Number of symbols + + // Following members are only valid if TOC type is DTAPI_SDI_TOC_ENTRY_HANC or + // DTAPI_SDI_TOC_ENTRY_VANC + int m_AncType; // Ancillery data packet type (DTAPI_SDI_ANC_TYPE1 or + // DTAPI_SDI_ANC_TYPE2) + int m_Did; // Ancillary packet data ID + int m_SdidOrDbn; // Ancillary packet data block number (type 1 packet) + // or secondary data ID (type 2 packet) + int m_NumUserWords; // Number of ancillary data packet user words + + // Constructor, destructor +public: + DtSdiTocEntry() : m_TocType(DTAPI_SDI_TOC_ENTRY_UNKNOWN), m_Line(0), m_Field(0), + m_StartOffset(0), m_NumSymbols(0) {} + virtual ~DtSdiTocEntry() {}; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtSdi -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// The DtSdi class provides helper functions for processing SDI data +// +class DtSdi +{ + friend class DtSdiUtility; + +public: + DtSdi(); + virtual ~DtSdi(); + +public: + DTAPI_RESULT ConvertFrame(unsigned int* pInFrame, int& InFrameSize, + int InFrameFormat, unsigned int* pOutFrame, int& OutFrameSize, int OutFrameFormat); + DTAPI_RESULT CreateBlackFrame(unsigned int* pFrame, int& FrameSize, int FrameFormat); + DTAPI_RESULT GetActiveVideo(const DtSdiTocEntry& TocEntry, + unsigned short* pVideo, int& NumSamples); + DTAPI_RESULT GetActiveVideo(unsigned short* pVideo, int& NumSamples, + int Field, int Stride=-1); + DTAPI_RESULT GetAncillaryData(const DtSdiTocEntry& TocEntry, + unsigned short* pData, int& NumSamples); + DTAPI_RESULT GetAudio(int AudioGroup, int& Channel, + unsigned short* pAudio, int& NumSamples); + DTAPI_RESULT GetTableOfContents(const DtSdiTocEntry** ppToc, int& NumTocEntries); + DTAPI_RESULT ParseFrame(const unsigned int* pFrame, int FrameSize, int FrameFormat, + int ParseFlags, const DtSdiTocEntry** ppToc, int& NumTocEntries); + +protected: + DtSdiUtility* m_pSdiUtil; // Internal utility class +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtSdi constants -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. + +// Ancillary data packet types +#define DTAPI_SDI_ANC_TYPE1 1 // Type 1 packet +#define DTAPI_SDI_ANC_TYPE2 2 // Type 2 packet + +// Parse flags +#define DTAPI_SDI_PARSE_ACTVID 0x0001 // Parse active video +#define DTAPI_SDI_PARSE_HBLANK 0x0002 // Parse horizontal blanking +#define DTAPI_SDI_PARSE_VBLANK 0x0004 // Parse vertical blanking + +#define DTAPI_SDI_PARSE_BLANK (DTAPI_SDI_PARSE_HBLANK | DTAPI_SDI_PARSE_VBLANK) +#define DTAPI_SDI_PARSE_ALL (DTAPI_SDI_PARSE_ACTVID | DTAPI_SDI_PARSE_BLANK) + +// Field flags +#define DTAPI_SDI_FIELD1 1 +#define DTAPI_SDI_FIELD2 2 + +// Audio groups +#define DTAPI_SDI_AUDIO_GROUP1 0x2FF +#define DTAPI_SDI_AUDIO_GROUP2 0x1FD +#define DTAPI_SDI_AUDIO_GROUP3 0x1FB +#define DTAPI_SDI_AUDIO_GROUP4 0x2F9 + +#define DTAPI_SDI_AUDIO_CHAN1 0x01 +#define DTAPI_SDI_AUDIO_CHAN2 0x02 +#define DTAPI_SDI_AUDIO_CHAN3 0x04 +#define DTAPI_SDI_AUDIO_CHAN4 0x08 + +#define DTAPI_SDI_AUDIO_CH_PAIR1 (DTAPI_SDI_AUDIO_CHAN1 | DTAPI_SDI_AUDIO_CHAN2) +#define DTAPI_SDI_AUDIO_CH_PAIR2 (DTAPI_SDI_AUDIO_CHAN3 | DTAPI_SDI_AUDIO_CHAN4) +#define DTAPI_SDI_AUDIO_CH_MASK (DTAPI_SDI_AUDIO_CH_PAIR1 | DTAPI_SDI_AUDIO_CH_PAIR2) + +// Conversions format +#define DTAPI_SDI_FULL 0x001 +#define DTAPI_SDI_ACTVID 0x002 +#define DTAPI_SDI_HUFFMAN 0x004 +#define DTAPI_SDI_625 0x008 +#define DTAPI_SDI_525 0x010 +#define DTAPI_SDI_8B 0x020 +#define DTAPI_SDI_10B 0x040 +#define DTAPI_SDI_16B 0x080 +#define DTAPI_SDI_10B_NBO 0x100 // 10-bit packed in network-byte-order + +#define DTAPI_SDI_BIT_MASK 0x1E0 + +// Video standards +#define DTAPI_VIDSTD_UNKNOWN -1 +#define DTAPI_VIDSTD_TS 0 +#define DTAPI_VIDSTD_525I59_94 DTAPI_IOCONFIG_525I59_94 +#define DTAPI_VIDSTD_625I50 DTAPI_IOCONFIG_625I50 +#define DTAPI_VIDSTD_720P23_98 DTAPI_IOCONFIG_720P23_98 +#define DTAPI_VIDSTD_720P24 DTAPI_IOCONFIG_720P24 +#define DTAPI_VIDSTD_720P25 DTAPI_IOCONFIG_720P25 +#define DTAPI_VIDSTD_720P29_97 DTAPI_IOCONFIG_720P29_97 +#define DTAPI_VIDSTD_720P30 DTAPI_IOCONFIG_720P30 +#define DTAPI_VIDSTD_720P50 DTAPI_IOCONFIG_720P50 +#define DTAPI_VIDSTD_720P59_94 DTAPI_IOCONFIG_720P59_94 +#define DTAPI_VIDSTD_720P60 DTAPI_IOCONFIG_720P60 +#define DTAPI_VIDSTD_1080P23_98 DTAPI_IOCONFIG_1080P23_98 +#define DTAPI_VIDSTD_1080P24 DTAPI_IOCONFIG_1080P24 +#define DTAPI_VIDSTD_1080P25 DTAPI_IOCONFIG_1080P25 +#define DTAPI_VIDSTD_1080P29_97 DTAPI_IOCONFIG_1080P29_97 +#define DTAPI_VIDSTD_1080P30 DTAPI_IOCONFIG_1080P30 +#define DTAPI_VIDSTD_1080PSF23_98 DTAPI_IOCONFIG_1080PSF23_98 +#define DTAPI_VIDSTD_1080PSF24 DTAPI_IOCONFIG_1080PSF24 +#define DTAPI_VIDSTD_1080PSF25 DTAPI_IOCONFIG_1080PSF25 +#define DTAPI_VIDSTD_1080PSF29_97 DTAPI_IOCONFIG_1080PSF29_97 +#define DTAPI_VIDSTD_1080PSF30 DTAPI_IOCONFIG_1080PSF30 +#define DTAPI_VIDSTD_1080I50 DTAPI_IOCONFIG_1080I50 +#define DTAPI_VIDSTD_1080I59_94 DTAPI_IOCONFIG_1080I59_94 +#define DTAPI_VIDSTD_1080I60 DTAPI_IOCONFIG_1080I60 +#define DTAPI_VIDSTD_1080P50 DTAPI_IOCONFIG_1080P50 +#define DTAPI_VIDSTD_1080P50B DTAPI_IOCONFIG_1080P50B +#define DTAPI_VIDSTD_1080P59_94 DTAPI_IOCONFIG_1080P59_94 +#define DTAPI_VIDSTD_1080P59_94B DTAPI_IOCONFIG_1080P59_94B +#define DTAPI_VIDSTD_1080P60 DTAPI_IOCONFIG_1080P60 +#define DTAPI_VIDSTD_1080P60B DTAPI_IOCONFIG_1080P60B +// The video standards above map 1-to-1 to an IOConfig value. The video formats below +// are used for multi-link video standards. Start at a high value to make sure there +// is no overlap. +#define DTAPI_VIDSTD_BASE 1000 +#define DTAPI_VIDSTD_2160P50 (DTAPI_VIDSTD_BASE + 0) +#define DTAPI_VIDSTD_2160P50B (DTAPI_VIDSTD_BASE + 1) +#define DTAPI_VIDSTD_2160P59_94 (DTAPI_VIDSTD_BASE + 2) +#define DTAPI_VIDSTD_2160P59_94B (DTAPI_VIDSTD_BASE + 3) +#define DTAPI_VIDSTD_2160P60 (DTAPI_VIDSTD_BASE + 4) +#define DTAPI_VIDSTD_2160P60B (DTAPI_VIDSTD_BASE + 5) +#define DTAPI_VIDSTD_2160P23_98 (DTAPI_VIDSTD_BASE + 6) +#define DTAPI_VIDSTD_2160P24 (DTAPI_VIDSTD_BASE + 7) +#define DTAPI_VIDSTD_2160P25 (DTAPI_VIDSTD_BASE + 8) +#define DTAPI_VIDSTD_2160P29_97 (DTAPI_VIDSTD_BASE + 9) +#define DTAPI_VIDSTD_2160P30 (DTAPI_VIDSTD_BASE + 10) + +// Video link standards. +#define DTAPI_VIDLNK_4K_SMPTE425 0 // 4K mapping according to SMPTE 425 +#define DTAPI_VIDLNK_4K_SMPTE425B 1 // 4K mapping acc. to SMPTE 425 annex B + +// Audio standard +#define DTAPI_SDI_AUDIO_SMPTE272A 1 // SMPTE-272 Level A, 48kHz, 20-bit audio + +// Audio formats +#define DTAPI_SDI_AUDIO_PCM16 0 +#define DTAPI_SDI_AUDIO_PCM24 1 +#define DTAPI_SDI_AUDIO_PCM32 2 + +// HANC/VANC/Video selection (can be OR-ed) +//#define DTAPI_SDI_ACTVID 0x01 +#define DTAPI_SDI_HANC 0x02 +#define DTAPI_SDI_VANC 0x04 +#define DTAPI_SDI_ANC_MASK (DTAPI_SDI_HANC | DTAPI_SDI_VANC) + +// Chrominace/luminance stream selection (can be OR-ed) +#define DTAPI_SDI_CHROM 0x01 +#define DTAPI_SDI_LUM 0x02 +#define DTAPI_SDI_STREAM_MASK (DTAPI_SDI_CHROM | DTAPI_SDI_LUM) + +// Anc-data operation mode +#define DTAPI_ANC_MARK 0x0001 +#define DTAPI_ANC_DELETE 0x0002 + +// Scalling factor +#define DTAPI_SCALING_OFF 1 +#define DTAPI_SCALING_1_4 2 +#define DTAPI_SCALING_1_16 3 + +// Symbol filter mode +#define DTAPI_SYMFLT_ALL 0 // YCbCr sample (CbYCrY order) +#define DTAPI_SYMFLT_LUM 1 // Luminance only (Y) +#define DTAPI_SYMFLT_CHROM 2 // Chrominance only (CbCr) +#define DTAPI_SYMFLT_SWAP 3 // Swap order of lum and chrom (i.e. YCbYCr) +#define DTAPI_SYMFLT_RGB 4 // Convert to/from RGB + +// Ancillary filter mode +#define DTAPI_ANCFLT_OFF 0 +#define DTAPI_ANCFLT_HANC_ALL 1 +#define DTAPI_ANCFLT_HANC_MIN 2 +#define DTAPI_ANCFLT_VANC_ALL 3 +#define DTAPI_ANCFLT_VANC_MIN 4 + +// Receive mode hints for USB3 devices +#define DTAPI_RXMODE_FRAMEBUFFER 0x10000 +#define DTAPI_RXMODE_ANC (DTAPI_RXMODE_FRAMEBUFFER | 1) +#define DTAPI_RXMODE_RAW (DTAPI_RXMODE_FRAMEBUFFER | 2) +#define DTAPI_RXMODE_FULL (DTAPI_RXMODE_FRAMEBUFFER | 3) +#define DTAPI_RXMODE_FULL8 (DTAPI_RXMODE_FRAMEBUFFER | 4) +#define DTAPI_RXMODE_FULL8_SCALED4 (DTAPI_RXMODE_FRAMEBUFFER | 5) +#define DTAPI_RXMODE_FULL8_SCALED16 (DTAPI_RXMODE_FRAMEBUFFER | 6) +#define DTAPI_RXMODE_VIDEO (DTAPI_RXMODE_FRAMEBUFFER | 7) +#define DTAPI_RXMODE_VIDEO8 (DTAPI_RXMODE_FRAMEBUFFER | 8) +#define DTAPI_RXMODE_VIDEO8_SCALED4 (DTAPI_RXMODE_FRAMEBUFFER | 9) +#define DTAPI_RXMODE_VIDEO8_SCALED16 (DTAPI_RXMODE_FRAMEBUFFER | 10) +#define DTAPI_RXMODE_RAW8 (DTAPI_RXMODE_FRAMEBUFFER | 15) +#define DTAPI_RXMODE_FRMBUF_MASK 0x0F + +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ HD-SDI CLASSES +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- AncPacket -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class AncPacket +{ +public: + AncPacket(); + AncPacket(const AncPacket& s); + virtual ~AncPacket(); + +public: + int m_Did; // Data identifier + int m_SdidOrDbn; // Secondary data identifier / Data block number + int m_Dc; // Data count + int m_Cs; // Check sum + unsigned short* m_pUdw; // User data words + int m_Line; // Line number in which packet was found + + // Operations +public: + void Create(unsigned short* pUserWords, int NumWords); + void Create(int NumWords=256); + void Destroy(); + int Type() const { return (m_Did & 0x80)==0 ? 2 : 1; } + int Size() const { return m_Size; } + + void operator = (const AncPacket& s); + +private: + int m_Size; // Size of user data buffer (in # of words) +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFrameBufTrPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtFrameBufTrPars +{ +public: + enum ParsType { PT_VIDEO, PT_ANC, PT_RAW }; + +protected: + DtFrameBufTrPars(ParsType Type); +public: + virtual ~DtFrameBufTrPars(); + + // Operations +public: + DTAPI_RESULT SetCommon(__int64 Frame, unsigned char* pBuf, int BufSize, + int DataFormat, int StartLine=1, int NumLines=-1); + + ParsType GetType() const { return m_Type; } + + virtual DtFrameBufTrPars* Clone() = 0; + +public: + __int64 m_Frame; // Frame to transfer + unsigned char* m_pBuf; // Transfer buffer + int m_BufSize; // [in] size of buffer / [out] actual #bytes transferred + int m_StartLine; // [in] 1st line to transfer / [out] actual first line + int m_NumLines; // [in] #lines to transfer / [out] actual #lines + int m_DataFormat; // Format of data (8-, 10-, 16-bit) + +private: + ParsType m_Type; // Parameter type +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFrameBufTrParsVideo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtFrameBufTrParsVideo : public DtFrameBufTrPars +{ +public: + DtFrameBufTrParsVideo(int Field, int Scaling=DTAPI_SCALING_OFF, int Stride=-1, + int SymFlt=DTAPI_SYMFLT_ALL); + virtual ~DtFrameBufTrParsVideo(); + + DtFrameBufTrParsVideo* Clone(); + +public: + int m_Field; // Field to transfer (DTAPI_SDI_FIELD*) + int m_Scaling; // Scaling mode (DTAPI_SCALING_*) + int m_Stride; // -1 means no stride + int m_SymFlt; // Symbol filter mode (DTAPI_SYMFLT_*) +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFrameBufTrParsAnc -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtFrameBufTrParsAnc : public DtFrameBufTrPars +{ +public: + DtFrameBufTrParsAnc(int HancVanc, int AncFlt=DTAPI_ANCFLT_OFF); + virtual ~DtFrameBufTrParsAnc(); + + DtFrameBufTrParsAnc* Clone(); + +public: + int m_HancVanc; // HANC or VANC + int m_AncFlt; // Anc filter mode (DTAPI_ANCFLT_*) +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFrameBufTrParsRaw -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtFrameBufTrParsRaw : public DtFrameBufTrPars +{ +public: + DtFrameBufTrParsRaw(int SymFlt=DTAPI_SYMFLT_ALL, int Stride=-1); + virtual ~DtFrameBufTrParsRaw(); + + DtFrameBufTrParsRaw* Clone(); + +public: + int m_SymFlt; // Symbol filter mode + int m_Stride; // -1 means no stride +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtFrameBuffer -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class to represent an frame buffer +// +class DtFrameBuffer +{ +public: + DtFrameBuffer(); + virtual ~DtFrameBuffer(); +private: + // No implementation is provided for the copy constructor + DtFrameBuffer(const DtFrameBuffer&); + +public: + virtual DTAPI_RESULT AncAddAudio(__int64 Frame, unsigned char* pBuf, + int& BufSize, int Format, int Channels, int AudioGroup); + virtual DTAPI_RESULT AncAddAudioStatusWord(__int64 Frame, unsigned char Status[24], + int Channels, int AudioGroup); + // Old declaration of the AncAddPacket function. The AncPacket class has been extended + // with a new m_Line member. + DTAPI_DEPRECATED(virtual DTAPI_RESULT AncAddPacket(__int64 Frame, + AncPacket& AncPacket, + int Line, int HancVanc, int Stream), + "Deprecated (will be removed!): use overloaded AncAddPacket without " + "line argument, use AncPacket::m_Line instead"); + virtual DTAPI_RESULT AncAddPacket(__int64 Frame, AncPacket& AncPacket, + int HancVanc, int Stream); + virtual DTAPI_RESULT AncClear(__int64 Frame, int HancVanc, int Stream); + virtual DTAPI_RESULT AncCommit(__int64 Frame); + virtual DTAPI_RESULT AncDelAudio(__int64 Frame, int AudioGroup, int Mode); + virtual DTAPI_RESULT AncDelPacket(__int64 Frame, int DID, int SDID, int StartLine, + int NumLines, int HancVanc, int Stream, int Mode); + virtual DTAPI_RESULT AncGetAudio(__int64 Frame, unsigned char* pBuf, + int& BufSize, int DataFormat, int& Channels, int AudioGroup); + virtual DTAPI_RESULT AncGetPacket(__int64 Frame, int DID, int SDID, + AncPacket*, int& NumPackets, int HancVanc, int Stream); + virtual DTAPI_RESULT AncReadRaw(__int64 Frame, unsigned char* pBuf, + int& BufSize, int DataFormat, int StartLine, + int NumLines, int HancVanc, bool EnableAncFilter = false); + virtual DTAPI_RESULT AncReadRaw(DtFrameBufTrParsAnc& TP); + virtual DTAPI_RESULT AncWriteRaw(__int64 Frame, unsigned char* pBuf, + int& BufSize, int Format, int StartLine, + int NumLines, int HancVanc, bool EnableAncFilter = false); + virtual DTAPI_RESULT AncWriteRaw(DtFrameBufTrParsAnc& TP); + virtual DTAPI_RESULT AttachToInput(DtDevice*, int Port); + virtual DTAPI_RESULT AttachToOutput(DtDevice*, int Port, int Delay); + virtual DTAPI_RESULT ClearFlags(int Latched); + virtual DTAPI_RESULT Detach(); + virtual DTAPI_RESULT DetectIoStd(int& Value, int& SubValue); + virtual DTAPI_RESULT GetBufferInfo(DtBufferInfo&); + virtual DTAPI_RESULT GetCurFrame(__int64& CurFrame); + virtual DTAPI_RESULT GetFlags(int& Flags, int& Latched); + virtual DTAPI_RESULT GetFrameInfo(__int64 Frame, DtFrameInfo&); + virtual DTAPI_RESULT GetStatistics(int Count, DtStatistic* pStatistics); + virtual DTAPI_RESULT GetStatistic(int Type, int& Statistic); + virtual DTAPI_RESULT ReadSdiLines(__int64 Frame, unsigned char* pBuf, + int& BufSize, int DataFormat, int StartLine, int& NumLines); + virtual DTAPI_RESULT ReadSdiLines(DtFrameBufTrParsRaw& TP); + virtual DTAPI_RESULT ReadSdiLines(__int64 Frame, unsigned char* pBuf, + int& BufSize, int DataFormat); + virtual DTAPI_RESULT ReadVideo(__int64 Frame, unsigned char* pBuf, + int& BufSize, int Field, int FullOrScaled, + int DataFormat, int StartLine, int& NumLines); + virtual DTAPI_RESULT ReadVideo(DtFrameBufTrParsVideo& TP); + virtual DTAPI_RESULT SetRxMode(int RxMode, __int64& FirstFrame); + virtual DTAPI_RESULT Start(bool Start=true); + virtual DTAPI_RESULT SetIoConfig(int Group, int Value, int SubValue = -1, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + virtual DTAPI_RESULT WaitFrame(__int64& LastFrame); + virtual DTAPI_RESULT WaitFrame(__int64& FirstFrame, __int64& LastFrame); + virtual DTAPI_RESULT WriteSdiLines(__int64 Frame, unsigned char* pBuf, + int& BufSize, int DataFormat); + virtual DTAPI_RESULT WriteSdiLines(__int64 Frame, unsigned char* pBuf, + int& BufSize, int DataFormat, int StartLine, int& NumLines); + virtual DTAPI_RESULT WriteSdiLines(DtFrameBufTrParsRaw& TP); + virtual DTAPI_RESULT WriteVideo(__int64 Frame, unsigned char* pBuf, int& BufSize, + int Field, int DataFormat, int StartLine, int& NumLines); + virtual DTAPI_RESULT WriteVideo(DtFrameBufTrParsVideo& TP); + +protected: + FrameBufImpl* m_pImpl; // Implementation class +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtSdiMatrix -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtSdiMatrix +{ +public: + DtSdiMatrix(); + virtual ~DtSdiMatrix(); +private: + // No implementation is provided for the copy constructor + DtSdiMatrix(const DtSdiMatrix&); + +public: + virtual DTAPI_RESULT Attach(DtDevice* pDvc, int& MaxNumRows); + virtual DTAPI_RESULT Detach(); + virtual DTAPI_RESULT GetMatrixInfo(DtMatrixInfo& Info); + virtual DtFrameBuffer& Row(int n); + virtual DTAPI_RESULT Start(bool Start=true); + virtual DTAPI_RESULT SetIoConfig(int Group, int Value, int SubValue = -1, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + virtual DTAPI_RESULT WaitFrame(__int64& LastFrame); + virtual DTAPI_RESULT WaitFrame(__int64& FirstFrame, __int64& LastFrame); + +private: + SdiMatrixImpl* m_pImpl; // Implementation class +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- Global DTAPI Functions -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. + +DTAPI_RESULT DtapiCheckDeviceDriverVersion(void); +DTAPI_RESULT DtapiCheckDeviceDriverVersion(int DeviceCategory); +DTAPI_RESULT DtapiDeviceScan(int NumEntries, int& NumEntriesResult, + DtDeviceDesc* DvcDescArr, bool InclDteDvcs=false, + int ScanOrder=DTAPI_SCANORDER_ORIG); +DTAPI_RESULT DtapiDtaPlusDeviceScan(int NumEntries, int& NumEntriesResult, + DtDtaPlusDeviceDesc* DvcDescArr); +DTAPI_RESULT DtapiDtDeviceDesc2String(DtDeviceDesc* pDvcDesc, int StringType, + char* pString, int StringLength); +DTAPI_RESULT DtapiDtDeviceDesc2String(DtDeviceDesc* pDvcDesc, int StringType, + wchar_t* pString, int StringLength); +DTAPI_RESULT DtapiDtHwFuncDesc2String(DtHwFuncDesc* pHwFunc, int StringType, + char* pString, int StringLength); +DTAPI_RESULT DtapiDtHwFuncDesc2String(DtHwFuncDesc* pHwFunc, int StringType, + wchar_t* pString, int StringLength); +DTAPI_RESULT DtapiGetDeviceDriverVersion(int, int&, int&, int&, int&); +DTAPI_RESULT DtapiGetDtapiServiceVersion(int&, int&, int&, int&); +DTAPI_RESULT DtapiGetVersion(int& Maj, int& Min, int& BugFix, int& Build); +DTAPI_RESULT DtapiHwFuncScan(int NumEntries, int& NumEntriesResult, + DtHwFuncDesc* pHwFuncs, bool InclDteDvcs=false, + int ScanOrder=DTAPI_SCANORDER_ORIG); +DTAPI_RESULT DtapiPower2Voltage(int dBm, int& dBmV, bool Is50Ohm=false); +const char* DtapiResult2Str(DTAPI_RESULT DtapiResult); +DTAPI_RESULT DtapiVoltage2Power(int dBmV, int& dBm, bool Is50Ohm=false); + +// Callbacks +DTAPI_RESULT DtapiRegisterCallback(pDtEventCallback Callback, void* pContext, + int EventTypes, void** pId = NULL); +DTAPI_RESULT DtapiUnregisterCallback(void* pId); + +// IP address conversion +DTAPI_RESULT DtapiInitDtIpParsFromIpString(DtIpPars& IpPars, + const char* pDstIp, const char* pSrcIp); +DTAPI_RESULT DtapiInitDtIpParsFromIpString(DtIpPars& IpPars, + const wchar_t* pDstIp, const wchar_t* pSrcIp); +DTAPI_RESULT DtapiIpAddr2ByteArray(const char* pIpStr, unsigned char* pIpByte, + int& Flags); +DTAPI_RESULT DtapiIpAddr2ByteArray(const wchar_t* pIpStr, + unsigned char* pIpByte, int& Flags); +DTAPI_RESULT DtapiIpAddr2Str(char* pStr, int Len, unsigned char* pIpAddr); +DTAPI_RESULT DtapiIpAddr2Str(wchar_t* pStr, int Len, unsigned char* pIpAddr); +DTAPI_RESULT DtapiStr2IpAddr(unsigned char* pIpAddr, const char* pStr); +DTAPI_RESULT DtapiStr2IpAddr(unsigned char* pIpAddr, const wchar_t* pStr); + +// Legacy +#define DtapiInitDtTsIpParsFromIpString DtapiInitDtIpParsFromIpString + +// Modulator functions +DTAPI_RESULT DtapiModPars2Bandwidth(int& ModBandwidth, int& TotalBandwidth, + int ModType, int ParXtra0, int ParXtra1, int ParXtra2, + void* pXtraPars, int SymRate); +DTAPI_RESULT DtapiModPars2SymRate(int& SymRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, int TsRate); +DTAPI_RESULT DtapiModPars2SymRate(int& SymRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, DtFractionInt TsRate); +DTAPI_RESULT DtapiModPars2SymRate(int& SymRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, void* pXtraPars, int TsRate); +DTAPI_RESULT DtapiModPars2SymRate(int& SymRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, void* pXtraPars, DtFractionInt TsRate); +DTAPI_RESULT DtapiModPars2TsRate(int& TsRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, int SymRate = -1); +DTAPI_RESULT DtapiModPars2TsRate(DtFractionInt& TsRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, int SymRate = -1); +DTAPI_RESULT DtapiModPars2TsRate(int& TsRate, DtDvbC2Pars&, int PlpIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(DtFractionInt& TsRate, DtDvbC2Pars&, int PlpIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(int& TsRate, DtDvbS2Pars&, int PlpIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(DtFractionInt& TsRate, DtDvbS2Pars&, int PlpIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(int& TsRate, DtDvbT2Pars&, int PlpIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(DtFractionInt& TsRate, DtDvbT2Pars&, int PlpIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(int& TsRate, DtIsdbTmmPars&, int TsIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(DtFractionInt& TsRate, DtIsdbTmmPars&, int TsIdx = 0); +DTAPI_RESULT DtapiModPars2TsRate(int& TsRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, void* pXtraPars, int SymRate); +DTAPI_RESULT DtapiModPars2TsRate(DtFractionInt& TsRate, int ModType, int ParXtra0, + int ParXtra1, int ParXtra2, void* pXtraPars, int SymRate); + +// HD-SDI functions +DTAPI_RESULT DtapiGetRequiredUsbBandwidth(int VidStd, int RxMode, long long& Bandwidth); +DTAPI_RESULT DtapiGetVidStdInfo(int VidStd, DtVidStdInfo& Info); +DTAPI_RESULT DtapiGetVidStdInfo(int VidStd, int LinkStd, DtVidStdInfo& Info); +DTAPI_RESULT DtapiIoStd2VidStd(int Value, int SubValue, int& VidStd); +DTAPI_RESULT DtapiVidStd2IoStd(int VidStd, int& Value, int& SubValue); +DTAPI_RESULT DtapiVidStd2IoStd(int VidStd, int LinkStd, int& Value, int& SubValue); +const char* DtapiVidStd2Str(int VidStd); +const char* DtapiLinkStd2Str(int LinkStd); + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- Return Codes -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// NOTE: ERROR CODES 0x1100-0x12FF ARE RESERVED FOR USE IN THE DTAPIplus +// +#define DTAPI_OK 0 +#define DTAPI_OK_FAILSAFE 1 +#define DTAPI_E 0x1000 +#define DTAPI_E_ATTACHED (DTAPI_E + 0) +#define DTAPI_E_BUF_TOO_SMALL (DTAPI_E + 1) +#define DTAPI_E_DEV_DRIVER (DTAPI_E + 2) +#define DTAPI_E_EEPROM_FULL (DTAPI_E + 3) +#define DTAPI_E_EEPROM_READ (DTAPI_E + 4) +#define DTAPI_E_EEPROM_WRITE (DTAPI_E + 5) +#define DTAPI_E_EEPROM_FORMAT (DTAPI_E + 6) +#define DTAPI_E_FIFO_FULL (DTAPI_E + 7) +#define DTAPI_E_IN_USE (DTAPI_E + 8) +#define DTAPI_E_INVALID_BUF (DTAPI_E + 9) +#define DTAPI_E_INVALID_FLAGS (DTAPI_E + 11) +#define DTAPI_E_INVALID_MODE (DTAPI_E + 12) +#define DTAPI_E_INVALID_RATE (DTAPI_E + 13) +#define DTAPI_E_INVALID_SIZE (DTAPI_E + 14) +#define DTAPI_E_KEYWORD (DTAPI_E + 15) +#define DTAPI_E_NO_DEVICE (DTAPI_E + 16) +#define DTAPI_E_NO_LOOPBACK (DTAPI_E + 17) +#define DTAPI_E_NO_SUCH_DEVICE (DTAPI_E + 18) +#define DTAPI_E_NO_SUCH_OUTPUT (DTAPI_E + 19) +#define DTAPI_E_NO_DT_OUTPUT (DTAPI_E + 20) +#define DTAPI_E_NO_TS_OUTPUT (DTAPI_E + 20) +#define DTAPI_E_NOT_ATTACHED (DTAPI_E + 21) +#define DTAPI_E_NOT_FOUND (DTAPI_E + 22) +#define DTAPI_E_NOT_SUPPORTED (DTAPI_E + 23) +#define DTAPI_E_DEVICE (DTAPI_E + 24) +#define DTAPI_E_TOO_LONG (DTAPI_E + 25) +#define DTAPI_E_UNDERFLOW (DTAPI_E + 26) +#define DTAPI_E_NO_SUCH_INPUT (DTAPI_E + 27) +#define DTAPI_E_NO_DT_INPUT (DTAPI_E + 28) +#define DTAPI_E_NO_TS_INPUT (DTAPI_E + 28) +#define DTAPI_E_DRIVER_INCOMP (DTAPI_E + 29) +#define DTAPI_E_INTERNAL (DTAPI_E + 30) +#define DTAPI_E_OUT_OF_MEM (DTAPI_E + 31) +#define DTAPI_E_INVALID_J83ANNEX (DTAPI_E + 32) +#define DTAPI_E_IDLE (DTAPI_E + 33) +#define DTAPI_E_INSUF_LOAD (DTAPI_E + 34) +#define DTAPI_E_INVALID_BANDWIDTH (DTAPI_E + 35) +#define DTAPI_E_INVALID_CONSTEL (DTAPI_E + 36) +#define DTAPI_E_INVALID_GUARD (DTAPI_E + 37) +#define DTAPI_E_INVALID_INTERLVNG (DTAPI_E + 38) +#define DTAPI_E_INVALID_TRANSMODE (DTAPI_E + 39) +#define DTAPI_E_INVALID_TSTYPE (DTAPI_E + 40) +#define DTAPI_E_NO_IPPARS (DTAPI_E + 41) +#define DTAPI_E_NO_TSRATE (DTAPI_E + 42) +#define DTAPI_E_NOT_IDLE (DTAPI_E + 43) +#define DTAPI_E_INVALID_ARG (DTAPI_E + 44) +#define DTAPI_E_NW_DRIVER (DTAPI_E + 45) +#define DTAPI_E_DST_MAC_ADDR (DTAPI_E + 46) +#define DTAPI_E_NO_SUCH_PORT (DTAPI_E + 47) +#define DTAPI_E_WINSOCK (DTAPI_E + 48) +#define DTAPI_E_MULTICASTJOIN (DTAPI_E + 49) +#define DTAPI_E_EMBEDDED (DTAPI_E + 50) +#define DTAPI_E_LOCKED (DTAPI_E + 51) +#define DTAPI_E_NO_VALID_CALDATA (DTAPI_E + 52) +#define DTAPI_E_NO_LINK (DTAPI_E + 53) +#define DTAPI_E_INVALID_HEADER (DTAPI_E + 54) +#define DTAPI_E_INVALID_PARS (DTAPI_E + 55) +#define DTAPI_E_NOT_SDI_MODE (DTAPI_E + 56) +#define DTAPI_E_INCOMP_FRAME (DTAPI_E + 57) +#define DTAPI_E_UNSUP_CONV (DTAPI_E + 58) +#define DTAPI_E_OUTBUF_TOO_SMALL (DTAPI_E + 59) +#define DTAPI_E_CONFIG (DTAPI_E + 60) +#define DTAPI_E_TIMEOUT (DTAPI_E + 61) +#define DTAPI_E_INVALID_TIMEOUT (DTAPI_E + 62) +#define DTAPI_E_INVALID_FHMODE (DTAPI_E + 63) +#define DTAPI_E_INVALID_PILOTS (DTAPI_E + 64) +#define DTAPI_E_INVALID_USEFRAMENO (DTAPI_E + 65) +#define DTAPI_E_SYMRATE_REQD (DTAPI_E + 66) +#define DTAPI_E_NO_SYMRATE (DTAPI_E + 67) +#define DTAPI_E_INVALID_NUMSEGM (DTAPI_E + 68) +#define DTAPI_E_INVALID_NUMTAPS (DTAPI_E + 69) +#define DTAPI_E_COMMUNICATION (DTAPI_E + 70) +#define DTAPI_E_BIND (DTAPI_E + 71) +#define DTAPI_E_FRAME_INTERVAL (DTAPI_E + 72) +#define DTAPI_E_INVALID_BWT_EXT (DTAPI_E + 73) +#define DTAPI_E_INVALID_FFTMODE (DTAPI_E + 74) +#define DTAPI_E_INVALID_NUMDTSYM (DTAPI_E + 75) +#define DTAPI_E_INVALID_NUMT2FRM (DTAPI_E + 76) +#define DTAPI_E_INVALID_SUBCH (DTAPI_E + 77) +#define DTAPI_E_INVALID_TIME_IL (DTAPI_E + 78) +#define DTAPI_E_NUM_PLP (DTAPI_E + 79) +#define DTAPI_E_PLP_NUMBLOCKS (DTAPI_E + 80) +#define DTAPI_E_NUMPLPS_MUSTBE_1 (DTAPI_E + 81) +#define DTAPI_E_INBAND (DTAPI_E + 82) +#define DTAPI_E_ISSY (DTAPI_E + 83) +#define DTAPI_E_OTHER_PLP_IN_BAND (DTAPI_E + 84) +#define DTAPI_E_CM_NUMPATHS (DTAPI_E + 85) +#define DTAPI_E_PILOT_PATTERN (DTAPI_E + 86) +#define DTAPI_E_SUBSLICES (DTAPI_E + 87) +#define DTAPI_E_NO_GENREF (DTAPI_E + 88) +#define DTAPI_E_TI_MEM_OVF (DTAPI_E + 89) +#define DTAPI_E_FEF (DTAPI_E + 90) +#define DTAPI_E_UNSUP_FORMAT (DTAPI_E + 91) +#define DTAPI_E_OUT_OF_SYNC (DTAPI_E + 92) +#define DTAPI_E_NO_FRAME (DTAPI_E + 93) +#define DTAPI_E_NO_SUCH_DATA (DTAPI_E + 94) +#define DTAPI_E_INVALID_TYPE (DTAPI_E + 95) +#define DTAPI_E_INVALID_MODPARS (DTAPI_E + 96) +#define DTAPI_E_BIAS_BAL_CELLS (DTAPI_E + 97) +#define DTAPI_E_COMMON_PLP_COUNT (DTAPI_E + 98) +#define DTAPI_E_PLP_ID (DTAPI_E + 99) +#define DTAPI_E_BUFS (DTAPI_E + 100) +#define DTAPI_E_FIXED_CELL_PARS (DTAPI_E + 101) +#define DTAPI_E_CM_CHANNEL (DTAPI_E + 102) +#define DTAPI_E_INVALID_FIFO_IDX (DTAPI_E + 103) +#define DTAPI_E_INVALID_INP_TYPE (DTAPI_E + 104) +#define DTAPI_E_INVALID_OUTP_TYPE (DTAPI_E + 105) +#define DTAPI_E_INVALID_START_FREQ (DTAPI_E + 106) +#define DTAPI_E_DSLICE_TUNE_POS (DTAPI_E + 107) +#define DTAPI_E_DSLICE_OFFSETS (DTAPI_E + 108) +#define DTAPI_E_DSLICE_OVERLAP (DTAPI_E + 109) +#define DTAPI_E_NOTCH_OFFSETS (DTAPI_E + 110) +#define DTAPI_E_PLP_BUNDLED (DTAPI_E + 111) +#define DTAPI_E_BROADBAND_NOTCH (DTAPI_E + 112) +#define DTAPI_E_L1_PART2_TOO_LONG (DTAPI_E + 113) +#define DTAPI_E_DSLICE_T1_NDP (DTAPI_E + 114) +#define DTAPI_E_DSLICE_T1_TSRATE (DTAPI_E + 115) +#define DTAPI_E_CONNECT_TO_SERVICE (DTAPI_E + 116) +#define DTAPI_E_INVALID_SYMRATE (DTAPI_E + 117) +#define DTAPI_E_MODPARS_NOT_SET (DTAPI_E + 118) +#define DTAPI_E_SERVICE_INCOMP (DTAPI_E + 119) +#define DTAPI_E_INVALID_LEVEL (DTAPI_E + 120) +#define DTAPI_E_MODTYPE_UNSUP (DTAPI_E + 121) +#define DTAPI_E_I2C_LOCK_TIMEOUT (DTAPI_E + 122) +#define DTAPI_E_INVALID_FREQ (DTAPI_E + 123) +#define DTAPI_E_INVALID_TSRATESEL (DTAPI_E + 124) +#define DTAPI_E_INVALID_SPICLKSEL (DTAPI_E + 125) +#define DTAPI_E_INVALID_SPIMODE (DTAPI_E + 126) +#define DTAPI_E_NOT_INITIALIZED (DTAPI_E + 127) +#define DTAPI_E_NOT_LOCKED (DTAPI_E + 128) +#define DTAPI_E_NO_PERMISSION (DTAPI_E + 129) +#define DTAPI_E_CANCELLED (DTAPI_E + 130) +#define DTAPI_E_OUT_OF_RESOURCES (DTAPI_E + 131) +#define DTAPI_E_LISTEN (DTAPI_E + 132) +#define DTAPI_E_INVALID_STREAMFMT (DTAPI_E + 133) +#define DTAPI_E_EVENT_POWER (DTAPI_E + 134) +#define DTAPI_E_EVENT_REMOVAL (DTAPI_E + 135) +#define DTAPI_E_UNSUP_ROLLOFF (DTAPI_E + 136) +#define DTAPI_E_T2_LITE (DTAPI_E + 137) +#define DTAPI_E_COMP_OVERLAP (DTAPI_E + 138) +#define DTAPI_E_MULTI_COMPS (DTAPI_E + 139) +#define DTAPI_E_INVALID_ISI (DTAPI_E + 140) +#define DTAPI_E_FIRMW_INCOMP (DTAPI_E + 141) +#define DTAPI_E_INVALID_MODTYPE (DTAPI_E + 142) +#define DTAPI_E_NO_VIDSTD (DTAPI_E + 143) +#define DTAPI_E_INVALID_VIDSTD (DTAPI_E + 144) +#define DTAPI_E_INVALID_AUDSTD (DTAPI_E + 145) +#define DTAPI_E_INVALID_SCALING (DTAPI_E + 146) +#define DTAPI_E_INVALID_ROW (DTAPI_E + 147) +#define DTAPI_E_NOT_STARTED (DTAPI_E + 148) +#define DTAPI_E_STARTED (DTAPI_E + 149) +#define DTAPI_E_INVALID_LINE (DTAPI_E + 150) +#define DTAPI_E_INVALID_STREAM (DTAPI_E + 151) +#define DTAPI_E_INVALID_ANC (DTAPI_E + 152) +#define DTAPI_E_INVALID_FRAME (DTAPI_E + 153) +#define DTAPI_E_NOT_IMPLEMENTED (DTAPI_E + 154) +#define DTAPI_E_INVALID_CHANNEL (DTAPI_E + 155) +#define DTAPI_E_INVALID_GROUP (DTAPI_E + 156) +#define DTAPI_E_INVALID_FORMAT (DTAPI_E + 157) +#define DTAPI_E_INVALID_FIELD (DTAPI_E + 158) +#define DTAPI_E_BUF_TOO_LARGE (DTAPI_E + 159) +#define DTAPI_E_INVALID_DELAY (DTAPI_E + 160) +#define DTAPI_E_EXCL_MANDATORY (DTAPI_E + 161) +#define DTAPI_E_INVALID_ROLLOFF (DTAPI_E + 162) +#define DTAPI_E_CM_UNSUP (DTAPI_E + 163) +#define DTAPI_E_I2C (DTAPI_E + 164) +#define DTAPI_E_STATE (DTAPI_E + 165) +#define DTAPI_E_NO_LOCK (DTAPI_E + 166) +#define DTAPI_E_RANGE (DTAPI_E + 167) +#define DTAPI_E_INVALID_T2PROFILE (DTAPI_E + 168) +#define DTAPI_E_DSLICE_ID (DTAPI_E + 169) +#define DTAPI_E_EXCL_ACCESS_REQD (DTAPI_E + 170) +#define DTAPI_E_CHAN_ALREADY_ADDED (DTAPI_E + 171) +#define DTAPI_E_LAYER_ID (DTAPI_E + 172) +#define DTAPI_E_INVALID_FECMODE (DTAPI_E + 173) +#define DTAPI_E_INVALID_PORT (DTAPI_E + 174) +#define DTAPI_E_INVALID_PROTOCOL (DTAPI_E + 175) +#define DTAPI_E_INVALID_FEC_MATRIX (DTAPI_E + 176) +#define DTAPI_E_INVALID_IP_ADDR (DTAPI_E + 177) +#define DTAPI_E_INVALID_SRCIP_ADDR (DTAPI_E + 178) +#define DTAPI_E_IPV6_NOT_SUPPORTED (DTAPI_E + 179) +#define DTAPI_E_INVALID_DIFFSERV (DTAPI_E + 180) +#define DTAPI_E_INVALID_FOR_ACM (DTAPI_E + 181) +#define DTAPI_E_NWAP_DRIVER (DTAPI_E + 182) +#define DTAPI_E_INIT_ERROR (DTAPI_E + 183) +#define DTAPI_E_NOT_USB3 (DTAPI_E + 184) +#define DTAPI_E_INSUF_BW (DTAPI_E + 185) +#define DTAPI_E_NO_ANC_DATA (DTAPI_E + 186) +#define DTAPI_E_MATRIX_HALTED (DTAPI_E + 187) +#define DTAPI_E_VLAN_NOT_FOUND (DTAPI_E + 188) +#define DTAPI_E_NO_ADAPTER_IP_ADDR (DTAPI_E + 189) +#define DTAPI_E_INVALID_BTYPE (DTAPI_E + 190) +#define DTAPI_E_INVALID_PARTIAL (DTAPI_E + 191) +#define DTAPI_E_INVALID_NUMTS (DTAPI_E + 192) +#define DTAPI_E_INVALID (DTAPI_E + 193) +#define DTAPI_E_NO_RS422 (DTAPI_E + 194) +#define DTAPI_E_FECFRAMESIZE (DTAPI_E + 195) +#define DTAPI_E_SFN_NOT_SUPPORTED (DTAPI_E + 196) +#define DTAPI_E_SFN_INVALID_MODE (DTAPI_E + 197) +#define DTAPI_E_SFN_INVALID_OFFSET (DTAPI_E + 198) +#define DTAPI_E_SFN_DISABLED (DTAPI_E + 199) +#define DTAPI_E_SFN_INVALID_TIMEDIFF (DTAPI_E + 200) +#define DTAPI_E_NO_GPSCLKREF (DTAPI_E + 201) +#define DTAPI_E_NO_GPSSYNC (DTAPI_E + 202) +#define DTAPI_E_INVALID_PROFILE (DTAPI_E + 203) +#define DTAPI_E_INVALID_LINKSTD (DTAPI_E + 204) +#define DTAPI_E_FRAMERATE_MISMATCH (DTAPI_E + 205) +#define DTAPI_E_CID_INVALID_ID (DTAPI_E + 206) +#define DTAPI_E_CID_INVALID_INFO (DTAPI_E + 207) +#define DTAPI_E_CID_INVALID_FORMAT (DTAPI_E + 208) +#define DTAPI_E_CID_NOT_SUPPORTED (DTAPI_E + 209) +#define DTAPI_E_INVALID_SAMPRATE (DTAPI_E + 210) +#define DTAPI_E_MULTIMOD_UNSUP (DTAPI_E + 211) +#define DTAPI_E_NUM_CHAN (DTAPI_E + 212) +#define DTAPI_E_INVALID_TIME (DTAPI_E + 213) +#define DTAPI_E_INVALID_LINK (DTAPI_E + 214) +#define DTAPI_E_MODE_VIDEOSTD (DTAPI_E + 215) + + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//=+=+=+=+=+=+=+=+ DVB-C2, DVB-S2, DVB-T2, ISDB-Tmm Multi PLP Parameters +=+=+=+=+=+=+=+=+ +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtBigTsSplitPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying 'Big TS' splitting +// +struct DtBigTsSplitPars +{ + bool m_Enabled; // Enable 'Big TS' splitting + bool m_IsCommonPlp; // Is Common PLP or Layer + bool m_SplitSdtIn; // SDT already split (e.g. BBC TS-files) + std::vector m_Pids; // Series of PIDs to include in the PLP + + // The parameters below are not used in case of a common PLP + int m_OnwId; // Original Network ID of the Big-TS + int m_TsId; // Transport Stream ID of the Big-TS + int m_ServiceId; // ID of service to include in PLP + int m_PmtPid; // PID of the PMT-table + int m_NewTsId; // New Transport Stream ID + int m_SdtLoopDataLength; // SDT loop data length. 0..168 + // Not used if m_SplitSdtIn == true + // The SDT-Actual loop data + unsigned char m_SdtLoopData[168]; + +public: + // Methods + void Init(void); + + // Operators + bool operator == (DtBigTsSplitPars& TsSplitPars); + bool operator != (DtBigTsSplitPars& TsSplitPars); + bool IsEqual(DtBigTsSplitPars& TsSplitPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtPlpInpPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying the PLP input +// +struct DtPlpInpPars +{ + // PLP input data types + enum InDataType + { + TS188, // 188-byte TS packets + TS204, // 204-byte TS packets + GSE // Generic Stream Encapsulation + }; + +public: + int m_FifoIdx; // Fifo index used for the PLP + // If Big TS file splitting is used, PLPs in a group + // can share the input FIFO + InDataType m_DataType; // TS188, TS204 byte or GSE packets + DtBigTsSplitPars m_BigTsSplit; // Big TS splitting (optional) + +public: + // Methods + void Init(int Idx = 0); + + // Operators + bool operator == (DtPlpInpPars& PlpInPars); + bool operator != (DtPlpInpPars& PlpInPars); + bool IsEqual(DtPlpInpPars& PlpInPars); +}; + +// Test point data format +#define DTAPI_TP_FORMAT_HEX 0 +#define DTAPI_TP_FORMAT_BIT 1 +#define DTAPI_TP_FORMAT_CFLOAT32 2 +#define DTAPI_TP_FORMAT_INT64 3 + +// Complex floating point type +struct DtComplexFloat +{ + float m_Re, m_Im; // Real, imaginary part +}; + +// Function to write test point data +typedef void DtTpWriteDataFunc(void* pOpaque, int TpIndex, int StreamIndex, + const void* Buffer, int Length, int Format, float Mult, int IsNewFrame); + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtTestPointOutPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for enabling the test point data output specifying a callback function +// +struct DtTestPointOutPars +{ +public: + bool m_Enabled; // Enable TP data output + void* m_pTpWriteDataOpaque; // Opaque data pointer passed to TpWriteData + + // Callback function for writing test data + DtTpWriteDataFunc* m_pTpWriteDataFunc; + +public: + // Methods + void Init(void); + + // Operators + bool operator == (DtTestPointOutPars& RbmPars); + bool operator != (DtTestPointOutPars& RbmPars); + bool IsEqual(DtTestPointOutPars& RbmPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtVirtualOutData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure describing and containing the output data for a virtual output channel +// +struct DtVirtualOutData +{ + // Virtual output data types + enum OutDataType + { + IQ_INT16, // 16-bit I/Q samples + IQ_FLOAT32, // 32 bit float I/Q samples + T2MI_TS188, // 188 byte T2MI TS-packets + DVBS2_L3, // L3 format for DVB-S2 + }; + OutDataType m_DataType; // Output data type + + // Output type dependent parameters + union { + // 16-bit int I/Q samples + struct { + // Array of buffers; Per output channel a buffer with samples + const unsigned char** m_pBuffer; + int m_NumBuffers; // Number of buffers + int m_NumBytes; // Number of bytes + } IqSamplesInt16; + + // 32-bit float I/Q samples + struct { + // Array of buffers. Per output channel a buffer with samples + const unsigned char** m_pBuffer; + int m_NumBuffers; // Number of buffers + int m_NumBytes; // Number of bytes + } IqSamplesFloat32; + + // 188-byte T2MI TS packets + struct { + // Pointer to T2MI TS-packet(s) + const unsigned char* m_pBuffer; + int m_NumBytes; // Number of bytes + __int64 m_T2MiFrameNr; // T2MI super frame number counter + } T2MiTs188; + + // L3 frames + struct { + // Pointer to L3 frame(s) + const unsigned char* m_pBuffer; + int m_NumBytes; // Number of bytes + } DvbS2L3; + + } u; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtVirtualOutPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying the output type and level for a virtual output. +// These parameters are only relevant when outputting to a virtual output channel. +// +struct DtVirtualOutPars +{ + bool m_Enabled; // Enable virtual output parameters + DtVirtualOutData::OutDataType m_DataType; + // Type of output data + double m_Gain; // The square root of the average power of + // the generated signal +public: + void Init(void); + bool IsEqual(DtVirtualOutPars& VirtOutPars); + bool operator == (DtVirtualOutPars& VirtOutPars); + bool operator != (DtVirtualOutPars& VirtOutPars); +}; + + + +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ DAB Parameters +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +// DAB error protection modes +#define DTAPI_DAB_UEP 0 // DAB unequal error protection +#define DTAPI_DAB_EEP 1 // DAB equal error protection + +// DAB data extraction mode +enum DtDabExtractionMode +{ + DAB_RAW, // Raw DAB stream, no extraction + DAB_EXTRACTION_AAC, // AAC/DAB+ stream extraction + DAB_EXTRACTION_DMB // DMB stream extraction +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabEtiStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for DAB Ensemble Transport Interface (ETI) selection +// +struct DtDabEtiStreamSelPars +{ + // No selection parameters yet +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for DAB selection +// +struct DtDabStreamSelPars +{ + int m_BitrateKbps; // Bitrate in kbps + int m_ErrProtLevel; // Error protection level: 1..5 (UEP); 1..4 (EEP) + int m_ErrProtMode; // Error protection mode: DTAPI_DAB_UEP/EEP + int m_ErrProtOption; // Error protection option (EEP only): 0 or 1 + int m_StartAddress; // Start address in DAB capacity units (64bits) + + // DAB data extraction mode: DAB_RAW, DAB_EXTRACTION_AAC or DAB_EXTRACTION_DMB + DtDabExtractionMode m_ExtractionMode; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabFicStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Selection parameters for a DAB Fast Information Channel (FIC) +// +struct DtDabFicStreamSelPars +{ + // Parameters below are passed in the WriteStreamFunc() callback function; + // the parameters are not used for selection + int m_CifIndex; // Index of the CIF in the DAB frame to which this + // FIB is associated + int m_FibIndex; // Index of this FIB in the group of FIBs that + // are associated to the same CIF +}; + +// Forward declarations +struct DtDabService; +struct DtDabSubChannel; +struct DtDabServiceComp; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabEnsembleInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Information about a DAB ensemble +// +struct DtDabEnsembleInfo +{ + int m_CountryId; // Country identifier + int m_EnsembleReference; // Indentifier of this ensemble in national area + int m_ExtCountryCode; // Extended country code + int m_InterTableId; // International table identifier + std::wstring m_Label; // Label identifying this ensemble + int m_LocalTimeOffset; // Local time offset in half hours from UTC + int m_LtoUnique; // Covers one(=0) or several(=1) time zones + int m_TransmissionMode; // Transmission mode: 1..4 + + // Services contained in this ensemble + std::vector m_Services; + + // Subchannels in this ensemble. Key: subchannel identifier + std::map m_SubChannels; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabService -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Information about a single service. Every service must have one primary service +// component and can have one or more non-primay service components +// +struct DtDabService +{ + int m_CondAccessId; // Conditional access identifier + int m_CountryId; // Country identifier + int m_ExtCountryCode; // Extended country code; -1 for program service + bool m_IsLocal; // True if local (partial) ensemble service area + std::wstring m_Label; // Label identifying this service + int m_ServiceReference; // Identifier of the service + + // Components in this service + std::vector m_Components; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabServiceComp -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Information about a single DAB service component +// +struct DtDabServiceComp +{ + int m_AudioServiceCompType; // Audio service component type; -1 if not applicable + int m_DataServiceCompType; // Data service component type; -1 if not applicable + int m_FidChannelId; // Fast information data channel identifier 0..63; + // -1 if not applicable + bool m_HasCondAccess; // True if access control applies + bool m_IsPrimary; // True if this is the primary component + std::wstring m_Label; // Label identifying this service component + int m_Language; // Service compoment language or -1 + int m_SubChannelId; // Subchannel identifier: 0..63; -1 if not applicable + int m_ServiceCompId; // Service component identifier; -1 if not applicable + int m_TransportMechanismId; // Transport mechanism identifier +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabSubChannel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// A DAB subchannel contains the data for a single audio or data stream. Every service +// component refers to a subchannel, but multiple service components can refer to the +// same subchannel. In that case more than one service can use the same audio stream. +// +struct DtDabSubChannel +{ + int m_BitrateKbps; // Bitrate in kbps + int m_ErrProtLevel; // Protection level UEP: 1..5; EEP: 1..4 + int m_ErrProtMode; // Error protection mode: DTAPI_DAB_UEP/EEP + int m_ErrProtOption; // Option for EEP; -1 for UEP + int m_FecScheme; // FEC scheme; -1 if not applicable + int m_StartAddress; // Start address in capacity units (64bits) + int m_SubChannelId; // Subchannel identifier: 0..63 + int m_SubChannelSize; // Size of subchannel in capacity units (64bits) + int m_UepTableIndex; // Index in UEP table; -1 if not applicable + int m_UepTableSwitch; // UEP table switch; -1 if not applicable +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabTransmitterId -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +struct DtDabTransmitterId +{ + int m_TxMainId; // Transmitter main identifier; + // 0...5 (for transmission mode 3) otherwise 0...69 + int m_TxSubId; // Transmitter sub-identifier; 0...23 + double m_RelativePowerdB;; // Transmitter power, relative to total power +}; + + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDabTransmitterIdInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Information about a DAB transmitter identification +// +struct DtDabTransmitterIdInfo +{ + std::vector m_Transmitters; +}; + +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ DVB-C2 Parameters +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +// Maxima +#define DTAPI_DVBC2_NUM_DSLICE_MAX 255 // Maximum number of data slices +#define DTAPI_DVBC2_NUM_PLP_MAX 255 // Maximum number of PLPs +#define DTAPI_DVBC2_NUM_NOTCH_MAX 16 // Maximum number of Notches + +// PLP IDs +#define DTAPI_DVBC2_PLP_ID_NONE -1 // No PLP selected +#define DTAPI_DVBC2_PLP_ID_AUTO -2 // Automatic PLP selection + +// Data slice IDs +#define DTAPI_DVBC2_DSLICE_ID_AUTO -2 // Automatic data slice selection + +// m_Bandwidth +#define DTAPI_DVBC2_6MHZ 6 // 6 MHz +#define DTAPI_DVBC2_8MHZ 8 // 8 MHz + +// m_Guard - Guard interval +#define DTAPI_DVBC2_GI_1_128 0 // 1/128 +#define DTAPI_DVBC2_GI_1_64 1 // 1/64 + +// m_L1TiMode - L1 time interleaving mode +#define DTAPI_DVBC2_L1TIMODE_NONE 0 // No time interleaving +#define DTAPI_DVBC2_L1TIMODE_BEST 1 // Best fit +#define DTAPI_DVBC2_L1TIMODE_4 2 // 4 OFDM symbols +#define DTAPI_DVBC2_L1TIMODE_8 3 // 8 OFDM symbols + +// m_Type - PLP type +#define DTAPI_DVBC2_PLP_TYPE_COMMON 0 // Common PLP +#define DTAPI_DVBC2_PLP_TYPE_GROUPED 1 // Grouped Data PLP +#define DTAPI_DVBC2_PLP_TYPE_NORMAL 2 // Normal Data PLP + +// m_FecType - PLP FEC type +#define DTAPI_DVBC2_LDPC_16K 0 // 16K LDPC +#define DTAPI_DVBC2_LDPC_64K 1 // 64K LDPC + +// m_CodeRate - PLP code rate +#define DTAPI_DVBC2_COD_2_3 1 // 2/3 +#define DTAPI_DVBC2_COD_3_4 2 // 3/4 +#define DTAPI_DVBC2_COD_4_5 3 // 4/5 +#define DTAPI_DVBC2_COD_5_6 4 // 5/6 +#define DTAPI_DVBC2_COD_8_9 5 // 8/9 (For 16K FEC) +#define DTAPI_DVBC2_COD_9_10 5 // 9/10 (For 64K FEC) + +// m_Modulation - PLP constellation +#define DTAPI_DVBC2_QAM16 1 // 16-QAM +#define DTAPI_DVBC2_QAM64 2 // 64-QAM +#define DTAPI_DVBC2_QAM256 3 // 256-QAM +#define DTAPI_DVBC2_QAM1024 4 // 1024-QAM +#define DTAPI_DVBC2_QAM4096 5 // 4096-QAM +#define DTAPI_DVBC2_QAM16384 6 // 16K-QAM non standard, but supported +#define DTAPI_DVBC2_QAM65536 7 // 64K-QAM non standard, but supported + +// m_C2Version - DVB-C2 specification version +#define DTAPI_DVBC2_VERSION_1_2_1 0 // DVB-C2 version 1.2.1 +#define DTAPI_DVBC2_VERSION_1_3_1 1 // DVB-C2 version 1.3.1 +// m_Issy - PLP ISSY +#define DTAPI_DVBC2_ISSY_NONE 0 // No ISSY field is used +#define DTAPI_DVBC2_ISSY_SHORT 1 // 2 byte ISSY field is used +#define DTAPI_DVBC2_ISSY_LONG 2 // 3 byte ISSY field is used + +// m_TiDepth - Data slice time interleaving depth +#define DTAPI_DVBC2_TIDEPTH_NONE 0 // No time interleaving +#define DTAPI_DVBC2_TIDEPTH_4 1 // 4 OFDM symbols +#define DTAPI_DVBC2_TIDEPTH_8 2 // 8 OFDM symbols +#define DTAPI_DVBC2_TIDEPTH_16 3 // 16 OFDM symbols + +// m_Type - Data slice type +#define DTAPI_DVBC2_DSLICE_TYPE_1 0 // Type 1 (Single PLP and fixed mod/cod) +#define DTAPI_DVBC2_DSLICE_TYPE_2 1 // Type 2 + +// m_FecHdrType - Data slice FEC frame header type +#define DTAPI_DVBC2_FECHDR_TYPE_ROBUST 0 // Robust mode +#define DTAPI_DVBC2_FECHDR_TYPE_HEM 1 // High efficiency mode + +// DVB-C2 Test points +enum { + DTAPI_DVBC2_TP07, // FEC frame + DTAPI_DVBC2_TP08, + DTAPI_DVBC2_TP10, + DTAPI_DVBC2_TP13, + DTAPI_DVBC2_TP15, // Data slice + DTAPI_DVBC2_TP18, // OFDM output + DTAPI_DVBC2_TP20, + DTAPI_DVBC2_TP22, // FEC header + DTAPI_DVBC2_TP26, + DTAPI_DVBC2_TP27, // L1 header + DTAPI_DVBC2_TP31, + DTAPI_DVBC2_TP32, // L1 part2 data + DTAPI_DVBC2_TP33, // L1 part2 + padding & CRC + DTAPI_DVBC2_TP37, + DTAPI_DVBC2_TP40, + DTAPI_DVBC2_TP41, + DTAPI_DVBC2_TP42, + DTAPI_DVBC2_TP01, + DTAPI_DVBC2_TP_COUNT, +}; + +// DVB-C2 test points +extern const int DTAPI_DVBC2_TESTPOINTS[DTAPI_DVBC2_TP_COUNT]; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2DSlicePars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying the data slice parameters +// +struct DtDvbC2DSlicePars +{ + int m_Id; // Data slice ID. 0..255 + int m_TunePosition; // Tune position relative to the start frequency in + // multiples of pilot carrier spacing. + // For guard interval 1/128: 0..8191 + // For guard interval 1/64: 0..16383 + int m_OffsetLeft; // Offset left in multiples of pilot carrier spacing. + // For guard interval 1/128: -128..127 + // For guard interval 1/64: -256..255 + int m_OffsetRight; // Offset right in multiples of pilot carrier spacing. + // For guard interval 1/128: -128..127 + // For guard interval 1/64: -256..255 + // If m_OffsetLeft = m_OffsetRight, the data slice is + // empty and no input streams are created for the PLPs + // of the data slice. + int m_TiDepth; // Time interleaving depth. See DTAPI_DVBC2_TIDEPTH_x + int m_Type; // Data slice type. See DTAPI_DVBC2_DSLICE_TYPE_x + int m_FecHdrType; // FEC header type. See DTAPI_DVBC2_FECHDR_TYPE_x + bool m_ConstConfig; // Constant data slice configuration + bool m_LeftNotch; // Left notch present + + // Data per PLP + std::vector m_Plps; + +public: + void Init(int Id=0); + bool IsEqual(DtDvbC2DSlicePars& DSlicePars); + bool operator == (DtDvbC2DSlicePars& DSlicePars); + bool operator != (DtDvbC2DSlicePars& DSlicePars); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2L1UpdatePlpPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// struct for L1 PLP parameter update support +// +struct DtDvbC2L1UpdatePlpPars +{ + bool m_Enable; // Enable or disable the PLP. + // Only PLPs with m_NoData = true can be disabled. +public: + void Init(); + bool IsEqual(DtDvbC2L1UpdatePlpPars& PlpUpdatePars); + bool operator == (DtDvbC2L1UpdatePlpPars& PlpUpdatePars); + bool operator != (DtDvbC2L1UpdatePlpPars& PlpUpdatePars); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2L1UpdateDSlicePars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// struct for L1 DSlice parameter update support +// +struct DtDvbC2L1UpdateDSlicePars +{ + bool m_Enable; // Enable or disable the DSlice. + // Only dummy data slices can be disabled. + // A data slice is considered as dummy if either: + // - m_OffsetLeft == m_OffsetRight in its + // global configuration; or + // - all its PLPs have m_NoData = true + // A dummy data slice is modulated with dummy data. + + int m_OffsetLeft; // Data slice left offset - 0..2^(8+g)-1 + int m_OffsetRight; // Data slice right offset - 0..2^(8+g)-1 + // If the data slice is not dummy: + // - For type 1 , no size change is accepted. + // - For type 2 , size change is accepted + // provided it is not zero (i.e. m_OffsetRight > + // m_OffsetLeft). It is up to the user to ensure that + // there is no bitrate overflow. + std::vector m_Plps; // L1 PLP updates + +public: + void Init(); + bool IsEqual(DtDvbC2L1UpdateDSlicePars& DSliceUpdatePars); + bool operator == (DtDvbC2L1UpdateDSlicePars& DSliceUpdatePars); + bool operator != (DtDvbC2L1UpdateDSlicePars& DSliceUpdatePars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2L1UpdatePars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// L1 update support +// +struct DtDvbC2L1UpdatePars +{ + int m_NumFrames; // The following parameters are used during + // 'm_NumFrames' C2 frames + // L1 DSlice updates + std::vector m_DSlices; + bool m_EarlyWarningSystem; // Early warning system + +public: + void Init(); + bool IsEqual(DtDvbC2L1UpdatePars& L1UpdatePars); + bool operator == (DtDvbC2L1UpdatePars& L1UpdatePars); + bool operator != (DtDvbC2L1UpdatePars& L1UpdatePars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2ModStatus -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for retrieving the DVB-C2 MPLP modulator status +// +struct DtDvbC2ModStatus +{ + int m_MplpModFlags; // Multi PLP modulator flags + __int64 m_DjbOverflows; // Count number of DJB overflows. If it happens, + // issy output delay must be decreased or "issy bufs" + // increased. + __int64 m_DjbUnderflows; // Count number of DJB underflows. If it happens, + // issy output delay must be increased. +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2NotchPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying the notch parameters +// +struct DtDvbC2NotchPars +{ + int m_Start; // Notch start in multiples of pilot carrier spacing. + // For guard interval 1/128: 0..8191 + // For guard interval 1/64: 0..16383 + int m_Width; // Notch width in multiples of pilot carrier spacing. + // For guard interval 1/128: 0..255 + // For guard interval 1/64: 0..511 +public: + void Init(void); + bool IsEqual(DtDvbC2NotchPars& NotchPars); + bool operator == (DtDvbC2NotchPars& NotchPars); + bool operator != (DtDvbC2NotchPars& NotchPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2PaprPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying and enabling the PAPR reduction parameters +// +struct DtDvbC2PaprPars +{ + bool m_TrEnabled; // TR enabled + double m_TrVclip; // TR clipping threshold 1..4.32 (Volt) + int m_TrMaxIter; // TR maximum number of iterations. Must be >= 1. + // Note: PAPR TR processing time is proportional + // to this parameter +public: + void Init(void); + bool IsEqual(DtDvbC2PaprPars& PaprPars); + bool operator == (DtDvbC2PaprPars& PaprPars); + bool operator != (DtDvbC2PaprPars& PaprPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2ParamInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// DVB-C2 parameter info +// +struct DtDvbC2ParamInfo +{ + int m_L1Part2Length; // #bits of the L1 part2 data (including CRC) + int m_NumL1Symbols; // Number of L1 symbols (LP) + int m_NumSymbols; // Total number of symbols per frame (LP + Ldata) + int m_PilotSpacing; // Distance between pilots (Dx) + int m_FftSize; // FFT size + int m_MinCarrierOffset; // Lowest used carrier offset (Koffset) + int m_CenterFrequency; // Center frequency in multiples of the carrier + // spacing +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2PlpPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying the parameters of a PLP. +// In case of bundled PLPs, only the mode adaptation parameters from the +// first PLP of the bundle are used. +// +struct DtDvbC2PlpPars +{ + bool m_Hem; // High Efficiency Mode + bool m_Npd; // Null Packet Deletion + int m_Issy; // Issy mode. See DTAPI_DVBC2_ISSY_x + int m_IssyBufs; // Issy BUFS + int m_IssyOutputDelay; // Delay (in T units) between the incoming data and + // the output TS in the receiver model. This value + // determines the minimum and maximum dejitter buffer + // usage and is used to compute the ISSY BUFSTAT field + int m_TsRate; // If 0 the rate is computed from the PLP parameters, + // only possible in case of single PLP and no ISSY + // is used + int m_Ccm; // ACM/CMM bit in the BBframe header 0 or 1 + int m_Id; // PLP ID. 0..255 + bool m_Bundled; // A bundled PLP can appear in several data slices. + // All the PLP instances have the same PLP ID. + // Only a single input stream results from the + // first PLP of the bundle. + int m_Type; // PLP Type. See DTAPI_DVBC2_PLP_TYPE_x + int m_GroupId; // Group ID. 0..255 + int m_FecType; // FEC Type. 0=16K, 1=64K + int m_CodeRate; // PLP Code rate. See DTAPI_DVBC2_COD_x + int m_Modulation; // PLP Modulation. See DTAPI_DVBC2_x + int m_HdrCntr; // Header counter #FECFrames following the + // FECFrame header. 0=1FF 1=2FF. + // Only used for DSlice type 2. + + // ACM test mode. Only available for type 2 data slices. If number ACM headers != 0, + // then the successive XFEC frames of this PLP use the modulation and coding + // parameters taken from the m_AcmHeaders array. After the last value is used, it + // loops again to the start of the array. + // So DtDvbC2PlpPars.m_FecType, m_Modulation, m_CodeRate and m_HdrCntr are ignored. + std::vector m_AcmHeaders; + + bool m_PsiSiReproc; // Indicates whether PSI/SI reprocessing is performed + int m_TsId; // Transport Stream ID (if m_PsiSiReproc=false) + int m_OnwId; // Original Network ID (if m_PsiSiReproc=false) + bool m_NoData; // No input data is provided for this PLP. + // It is implicitely true for all PLPs in a data slice + // with m_OffsetLeft = m_OffsetRight +public: + void Init(int PlpId = 0); + bool IsEqual(DtDvbC2PlpPars& PlpPars); + bool operator == (DtDvbC2PlpPars& PlpPars); + bool operator != (DtDvbC2PlpPars& PlpPars); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2XFecFrameHeader -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// DVBC2 FEC frame header for ACM test +// +struct DtDvbC2XFecFrameHeader +{ + int m_FecType; // PLP FEC Type. 0=16K, 1=64K + int m_Modulation; // PLP Modulation. See DTAPI_DVBC2_x + int m_CodeRate; // PLP Code rate. See DTAPI_DVBC2_COD_x + int m_HdrCntr; // Header counter #FEC frames following the + // FEC frame header. 0=1FF, 1=2FF + int m_XFecFrameCount; // 1..256: Number of successive XFEC frames using + // these parameters +public: + void Init(void); + bool IsEqual(DtDvbC2XFecFrameHeader& FecHeader); + bool operator == (DtDvbC2XFecFrameHeader& FecHeader); + bool operator != (DtDvbC2XFecFrameHeader& FecHeader); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2Pars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying the DVB-C2 modulation parameters +// + struct DtDvbC2Pars +{ +public: + // General C2 parameters + int m_Bandwidth; // Bandwidth. Defines the OFDM carrier spacing + // F=8e6*bandwidth/7/4096 Hz. See DVBC2_BW_x + int m_NetworkId; // Network ID. 0..0xFFFF + int m_C2SystemId; // C2 System ID. 0..0xFFFF + int m_StartFrequency; // Start frequency in multiple of carrier spacing + // 0..2^24 - 1 and multiples of dx. + // For guard interval 1/128 dx=24, otherwise dx=12 + int m_C2Bandwidth; // Bandwidth of the generated signal in + // multiples of pilot carrier spacing. 0..65535 + int m_GuardInterval; // Guard interval See DVBC2_GI_x + bool m_ReservedTone; // Reserved tone. When there are reserved carriers + // (e.g. PAPR TR is enabled) it shall be set to true; + // otherwise false + bool m_EarlyWarningSystem; // Early warning system + int m_C2Version; // DVB-C2 Version + int m_L1TiMode; // L1 time interleaving mode. See DVBC2_L1TIMODE_x + + // Data slices parameters + int m_NumDSlices; // Number of data slices + DtDvbC2DSlicePars m_DSlices[DTAPI_DVBC2_NUM_DSLICE_MAX]; + + // Notches + int m_NumNotches; // Number of notches + DtDvbC2NotchPars m_Notches[DTAPI_DVBC2_NUM_NOTCH_MAX]; + + // PLP input + int m_NumPlpInputs; // Number of PLPs + DtPlpInpPars m_PlpInputs[DTAPI_DVBC2_NUM_PLP_MAX]; // PLP inputs (Optional) + + DtDvbC2PaprPars m_PaprPars; // PAPR Params (Optional) + DtVirtualOutPars m_VirtOutput; // Virtual Output parameters(Optional) + DtTestPointOutPars m_TpOutput; // Test point data output parameters (Optional) + int m_OutpFreqOffset; // Output frequency offset from 'm_StartFrequency' + // in carriers of the generated spectrum. + // Must be multiple of dx. + int m_OutpBandwidth; // Output bandwidth in carriers and a multiple of dx. + // 0 means default output bandwidth. + // Note: for convenience, one more carrier is output + // if an edge carrier needs to be output. + + std::vector m_L1Updates; // L1 updates + + // Undocumented + int m_L1P2ChangeCtr; // Undocumented. For internal use only + bool m_NotchTestEnable; // Undocumented. For internal use only + int m_TimeWindowLength; // Undocumented. For internal use only + +public: + DTAPI_RESULT CheckValidity(void); + DTAPI_RESULT GetParamInfo(DtDvbC2ParamInfo& C2Info); + void Init(void); + bool IsEqual(DtDvbC2Pars& C2Pars); + bool operator == (DtDvbC2Pars& C2Pars); + bool operator != (DtDvbC2Pars& C2Pars); +}; + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ DVB-C2 Demodulation +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +// DtDvbC2DemodL1Part2Plp::m_PayloadType - The PLP payload type +#define DTAPI_DVBC2_PAYLOAD_GFPS 0 // Generic fixed-length packetized stream +#define DTAPI_DVBC2_PAYLOAD_GCS 1 // Generic continuous stream +#define DTAPI_DVBC2_PAYLOAD_GSE 2 // Generic stream encapsulation +#define DTAPI_DVBC2_PAYLOAD_TS 3 // Transport Stream + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2DemodL1PlpSigDataPlp -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. + // +// Struct for storing layer 1 PLP signalling information per PLP. +// For type 1 data slices this struct contains the PLP-signalling information +// from the layer 1 part 2 signalling. +// For type 2 data slices this struct contains the PLP-signalling information +// from the layer 1 part 1 (=FEC-frame header). +// +struct DtDvbC2DemodL1PlpSigDataPlp +{ + int m_Id; // PLP ID: 0..255 + int m_FecType; // PLP FEC type: 0=LDPC 16K, 1=LDPC 64K + int m_Modulation; // PLP modulation, see DTAPI_DVBC2_x + int m_CodeRate; // PLP modulation, see DTAPI_DVBC2_x + int m_HdrCntr; // Header counter #FEC frames following the + // FEC frame header. 0=1FF, 1=2FF. Only present for + // type 2 data slices + + DtDvbC2DemodL1PlpSigDataPlp(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2DemodL1PlpSigData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Struct for storing the DVB-C2 layer 1 PLP signalling data +// +struct DtDvbC2DemodL1PlpSigData +{ + int m_NumPlps; // Number of PLPs + std::vector m_Plps; + + DtDvbC2DemodL1PlpSigData(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); + +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2DemodL1Part2Plp -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Struct for storing Layer 1 part 2 information per PLP +// +struct DtDvbC2DemodL1Part2Plp +{ + int m_Id; // PLP ID: 0..255 + int m_Bundled; // Bundled PLP + int m_Type; // PLP type, see DTAPI_DVBC2_PLP_TYPE_x + int m_PayloadType; // PLP payload type: 0..3 + int m_GroupId; // Group ID: 0..255 + // Start, FecType, Modulation and CodeRate parameters are not present for type 2 data + // slices + int m_Start; // PLP start: Start of the first complete XFECframe + int m_FecType; // PLP FEC type: 0=LDPC 16K, 1=LDPC 64K + int m_Modulation; // PLP modulation, see DTAPI_DVBC2_x + int m_CodeRate; // PLP modulation, see DTAPI_DVBC2_x + int m_PsiSiReproc; // Indicates whether PSI/SI reprocessing is performed + int m_TsId; // Transport Stream ID (if m_PsiSiReproc=false) + int m_OnwId; // Original Network ID (if m_PsiSiReproc=false) + + DtDvbC2DemodL1Part2Plp(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2DemodL1Part2DSlice -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Struct for storing Layer 1 part 2 information per data slice +// +struct DtDvbC2DemodL1Part2DSlice +{ + int m_Id; // Data slice ID: 0..255 + int m_TunePosition; // Tune position relative to the start frequency in + // multiples of pilot carrier spacing. + // For guard interval 1/128: 0..8191 + // For guard interval 1/64: 0..16383 + int m_OffsetLeft; // Offset left in multiples of pilot carrier spacing. + // For guard interval 1/128: -128..127 + // For guard interval 1/64: -256..255 + int m_OffsetRight; // Offset right in multiples of pilot carrier spacing. + // For guard interval 1/128: -128..127 + // For guard interval 1/64: -256..255 + // If m_OffsetLeft = m_OffsetRight, the data slice is + // empty and no input streams are created for the PLPs + // of the data slice. + int m_TiDepth; // Time interleaving depth, see DTAPI_DVBC2_TIDEPTH_x + int m_Type; // Data slice type, see DTAPI_DVBC2_DSLICE_TYPE_x + int m_FecHdrType; // FEC header type, see DTAPI_DVBC2_FECHDR_TYPE_x + int m_ConstConfig; // Constant data slice configuration flag + int m_LeftNotch; // Left notch present flag + // PLPs + int m_NumPlps; // Number of PLPs + std::vector m_Plps; + + DtDvbC2DemodL1Part2DSlice(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2DemodL1Part2Data -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Struct for storing the DVB-C2 layer 1 part 2data +// +struct DtDvbC2DemodL1Part2Data +{ + int m_NetworkId; // Network ID: 0..0xFFFF + int m_C2SystemId; // C2 System ID: 0..0xFFFF + int m_StartFrequency; // Start frequency in multiple of carrier spacing: + // 0..2^24 - 1 + int m_C2Bandwidth; // Bandwidth of the generated signal in + // multiples of pilot carrier spacing: 0..65535 + int m_GuardInterval; // Guard interval. See DVBC2_GI_x + int m_C2FrameLength; // C2 frame length: #Data symbols per C2 frame + int m_L1P2ChangeCtr; // Value of the L1_PART2_CHANGE_COUNTER field + int m_ReservedTone; // Reserved tone + bool m_EarlyWarningSystem; // Early warning system + int m_C2Version; // DVB-C2 Version + + // Data slices + int m_NumDSlices; // Number of data slices + std::vector m_DSlices; + + // Notches + int m_NumNotches; // Number of notches + std::vector m_Notches; + + DtDvbC2DemodL1Part2Data(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbC2StreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for DVB-C2 PLP-stream selection +// +struct DtDvbC2StreamSelPars +{ + int m_DSliceId; // ID of the data slice or DTAPI_DVBC2_DSLICE_ID_AUTO + int m_PlpId; // ID of the data PLP or DTAPI_DVBC2_PLP_ID_xxx + int m_CommonPlpId; // ID of the common PLP or DTAPI_DVBC2_PLP_ID_xxx + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ DVB-S2 Parameters +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +#define DTAPI_DVBS2_NUM_PLP_MAX 255 // Maximum number of PLPs + +// m_Issy - PLP ISSY +#define DTAPI_DVBS2_ISSY_NONE 0 // No ISSY field is used +#define DTAPI_DVBS2_ISSY_SHORT 1 // 2 byte ISSY field is used +#define DTAPI_DVBS2_ISSY_LONG 2 // 3 byte ISSY field is used + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDvbS2ModStatus -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +struct DtDvbS2ModStatus +{ + int m_MplpModFlags; // Multi PLP modulator flags + __int64 m_DjbOverflows; // Count number of DJB overflows. If it happens, + // issy output delay must be decreased or "issy bufs" + // increased. + __int64 m_DjbUnderflows; // Count number of DJB underflows. If it happens, + // issy output delay must be increased. +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDvbS2FecFrameHeader -.-.-.-.-.-.-.-.-.-.-.-.-.-.- +struct DtDvbS2FecFrameHeader +{ + int m_Modulation; // PLP Modulation. See DTAPI_MOD_DVBS2_* + int m_CodeRate; // PLP Code rate. See DTAPI_MOD_x + int m_FecFrameSize; // Fec frame size. See DTAPI_MOD_S2_*FRM + bool m_HasPilots; // Enable pilots + int m_FecFrameCount; // Number of successive FEC frames using these + // parameters, 0 means infinite. +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDvbS2ModCod -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +struct DtDvbS2ModCod +{ + int m_ModType; // Modulation type, e.g. DTAPI_MOD_DVBS_QPSK + int m_CodeRate; // Code rate, e.g. DTAPI_MOD_1_2 + // Constructor + DtDvbS2ModCod(); + DtDvbS2ModCod(int ModType, int CodeRate); + bool operator < (const DtDvbS2ModCod& ModCod) const; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDvbS2PlpPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +struct DtDvbS2PlpPars +{ + bool m_Hem; // High Efficiency Mode + bool m_Npd; // Null Packet Deletion + int m_Issy; // Issy mode. See DTAPI_DVBS2_ISSY_x + int m_IssyBufs; // Issy BUFS + int m_IssyOutputDelay; // Delay (in T units) between the incoming data and + // the output TS in the receiver model. This value + // determines the minimum and maximum dejitter buffer + // usage and is used to compute the ISSY BUFSTAT field + int m_TsRate; // Ts rate + int m_Ccm; // ACM/CMM bit in the BBframe header 0 or 1 + int m_Id; // PLP ID. 0..255 + + // One or more fec frame headers. If there is only 1 the m_FecFrameCount member + // is ignored. Otherwise that specifies the number of frames to generate with those + // parameters. When that number of frames are generated, the next set of parameters + // is taken. After the last DtDvbS2FecFrameHeader the first one is used again. + std::vector m_AcmHeaders; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- struct DtDvbS2Pars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +struct DtDvbS2Pars +{ + DtVirtualOutPars m_VirtOutput; // Virtual-output parameters (Optional) + bool m_L3Output; // Set to true to enable L3 output + int m_SymRate; // Symbol rate + int m_RollOff; // Roll-off DTAPI_MOD_ROLLOFF_xxx + + // Data per PLP + std::vector m_Plps; + // PLP input + int m_NumPlpInputs; // Number of PLPs + DtPlpInpPars m_PlpInputs[DTAPI_DVBS2_NUM_PLP_MAX]; // PLP inputs (Optional) + + DtDvbS2Pars(); + DTAPI_RESULT CheckValidity(); +}; + +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ DVB-T2 Parameters +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +// Maxima +#define DTAPI_DVBT2_NUM_PLP_MAX 255 // Maximum number of PLPs +#define DTAPI_DVBT2_NUM_RF_MAX 7 // Maximum number of RF output signals + +// PLP IDs +#define DTAPI_DVBT2_PLP_ID_NONE -1 // No PLP selected +#define DTAPI_DVBT2_PLP_ID_AUTO -2 // Automatic PLP selection + +// m_Issy +#define DTAPI_DVBT2_ISSY_NONE 0 // No ISSY field is used +#define DTAPI_DVBT2_ISSY_SHORT 1 // 2-byte ISSY field is used +#define DTAPI_DVBT2_ISSY_LONG 2 // 3-byte ISSY field is used + +// m_Bandwidth +#define DTAPI_DVBT2_1_7MHZ 0 // 1.7 MHz +#define DTAPI_DVBT2_5MHZ 1 // 5 MHz +#define DTAPI_DVBT2_6MHZ 2 // 6 MHz +#define DTAPI_DVBT2_7MHZ 3 // 7 MHz +#define DTAPI_DVBT2_8MHZ 4 // 8 MHz +#define DTAPI_DVBT2_10MHZ 5 // 10 MHz +#define DTAPI_DVBT2_BW_UNK -1 // Unknown bandwith +#define DTAPI_DVBT2MI_BW_MSK 0xF // Mask for T2MI ParXtra2 +#define DTAPI_DVBT2MI_BW_UNK 0xF //Val in ParXtra2 if not set, map to 8MHz + +// m_FftMode +// Warning: the codes are different from the corresponding L1 field +#define DTAPI_DVBT2_FFT_1K 0 // 1K FFT +#define DTAPI_DVBT2_FFT_2K 1 // 2K FFT +#define DTAPI_DVBT2_FFT_4K 2 // 4K FFT +#define DTAPI_DVBT2_FFT_8K 3 // 8K FFT +#define DTAPI_DVBT2_FFT_16K 4 // 16K FFT +#define DTAPI_DVBT2_FFT_32K 5 // 32K FFT +#define DTAPI_DVBT2_FFT_UNK -1 // Unknown FFT mode + +// m_Miso +#define DTAPI_DVBT2_MISO_OFF 0 // No MISO +#define DTAPI_DVBT2_MISO_TX1 1 // TX1 only +#define DTAPI_DVBT2_MISO_TX2 2 // TX2 only +#define DTAPI_DVBT2_MISO_TX1TX2 3 // TX1+TX2 Legacy +#define DTAPI_DVBT2_MISO_SUM 3 // TX1+TX2 +#define DTAPI_DVBT2_MISO_BOTH 4 // TX1 and TX2 + +// m_Guard - Guard interval +// Warning: the codes are different from the corresponding L1 field +#define DTAPI_DVBT2_GI_1_128 0 // 1/128 +#define DTAPI_DVBT2_GI_1_32 1 // 1/32 +#define DTAPI_DVBT2_GI_1_16 2 // 1/16 +#define DTAPI_DVBT2_GI_19_256 3 // 19/256 +#define DTAPI_DVBT2_GI_1_8 4 // 1/8 +#define DTAPI_DVBT2_GI_19_128 5 // 19/128 +#define DTAPI_DVBT2_GI_1_4 6 // 1/4 +#define DTAPI_DVBT2_GI_UNK -1 // Unknown guard interval + +// m_Papr - PAPR - Peak to Average Power Reduction +#define DTAPI_DVBT2_PAPR_NONE 0 +#define DTAPI_DVBT2_PAPR_ACE 1 // ACE - Active Constellation Extension +#define DTAPI_DVBT2_PAPR_TR 2 // TR - PAPR using reserved carriers +#define DTAPI_DVBT2_PAPR_ACE_TR 3 // ACE and TR + +// m_BwtExt - Bandwidth extension +#define DTAPI_DVBT2_BWTEXT_OFF false // No bandwidth extension +#define DTAPI_DVBT2_BWTEXT_ON true // Bandwidth extension on + +// m_PilotPattern +// Warning: the codes are different from the corresponding L1 field +#define DTAPI_DVBT2_PP_1 1 // PP1 +#define DTAPI_DVBT2_PP_2 2 // PP2 +#define DTAPI_DVBT2_PP_3 3 // PP3 +#define DTAPI_DVBT2_PP_4 4 // PP4 +#define DTAPI_DVBT2_PP_5 5 // PP5 +#define DTAPI_DVBT2_PP_6 6 // PP6 +#define DTAPI_DVBT2_PP_7 7 // PP7 +#define DTAPI_DVBT2_PP_8 8 // PP8 + +// m_CodeRate - Code rate +#define DTAPI_DVBT2_COD_1_2 0 // 1/2 +#define DTAPI_DVBT2_COD_3_5 1 // 3/5 +#define DTAPI_DVBT2_COD_2_3 2 // 2/3 +#define DTAPI_DVBT2_COD_3_4 3 // 3/4 +#define DTAPI_DVBT2_COD_4_5 4 // 4/5 not for T2 lite +#define DTAPI_DVBT2_COD_5_6 5 // 5/6 not for T2 lite +#define DTAPI_DVBT2_COD_1_3 6 // 1/3 only for T2 lite +#define DTAPI_DVBT2_COD_2_5 7 // 2/5 only for T2 lite + +// m_FefSignal - Type of signal generated during the FEF period +#define DTAPI_DVBT2_FEF_ZERO 0 // Use zero I/Q samples during FEF +#define DTAPI_DVBT2_FEF_1K_OFDM 1 // 1K OFDM symbols with 852 active + // carriers containing BPSK symbols + // (same PRBS as the T2 dummy cells, + // not reset between symbols) +#define DTAPI_DVBT2_FEF_1K_OFDM_384 2 // 1K OFDM symbols with 384 active + // carriers containing BPSK symbols + +// m_PlpConstel and m_L1Constel - Modulation constellation +#define DTAPI_DVBT2_BPSK 0 // BPSK +#define DTAPI_DVBT2_QPSK 1 // QPSK +#define DTAPI_DVBT2_QAM16 2 // 16-QAM +#define DTAPI_DVBT2_QAM64 3 // 64-QAM +#define DTAPI_DVBT2_QAM256 4 // 256-QAM + +// m_Type - PLP type +#define DTAPI_DVBT2_PLP_TYPE_COMM 0 // Common PLP +#define DTAPI_DVBT2_PLP_TYPE_1 1 // PLP type 1 +#define DTAPI_DVBT2_PLP_TYPE_2 2 // PLP type 2 + +// m_FecType - PLP FEC type +#define DTAPI_DVBT2_LDPC_16K 0 // 16K LDPC +#define DTAPI_DVBT2_LDPC_64K 1 // 64K LDPC + +// m_TimeIlType - Time interleaving type +#define DTAPI_DVBT2_IL_ONETOONE 0 // Interleaving frame in one T2 frame +#define DTAPI_DVBT2_IL_MULTI 1 // Interleaving frame in multiple frames + +// m_TimeStamping - Type of timestamps in T2MI +#define DTAPI_DVBT2MI_TIMESTAMP_NULL 0 // No timestamping +#define DTAPI_DVBT2MI_TIMESTAMP_REL 1 // Relative timestamps. Use m_Subseconds +#define DTAPI_DVBT2MI_TIMESTAMP_ABS 2 // Absolute timestamps. Use m_T2miUtco, + // m_SecSince2000, m_Subseconds, + +// m_T2Version - DVB-T2 specification version +#define DTAPI_DVBT2_VERSION_1_1_1 0 // DVB-T2 version 1.1.1 +#define DTAPI_DVBT2_VERSION_1_2_1 1 // DVB-T2 version 1.2.1 +#define DTAPI_DVBT2_VERSION_1_3_1 2 // DVB-T2 version 1.3.1 + +// m_T2Profile - DVB-T2 profile +#define DTAPI_DVBT2_PROFILE_BASE 0 +#define DTAPI_DVBT2_PROFILE_LITE 1 // Requires DVB-T2 version 1.3.1 + +// m_BiasBalancing +#define DTAPI_DVBT2_BIAS_BAL_OFF 0 // No L1 bias compensation +#define DTAPI_DVBT2_BIAS_BAL_ON 1 // Modify L1 reserved fields and L1 ext. + // field padding to compensate L1 bias +// m_GseLabelType - DVB-T2 GSE Label size +#define DTAPI_DVBT2_GSE_LABEL_6BYTE 0 // 6 Byte GSE label +#define DTAPI_DVBT2_GSE_LABEL_3BYTE 1 // 3 Byte GSE label +#define DTAPI_DVBT2_GSE_LABEL_NONE 2 // No GSE label + +#define DTAPI_TXSIG_FEF_LEN_MIN 162212 // Min. FEF length for FEF TX sgnalling + +// DVB-T2 test point enum +enum { + DTAPI_DVBT2_TP00, + DTAPI_DVBT2_TP01, + DTAPI_DVBT2_TP03, + DTAPI_DVBT2_TP04, + DTAPI_DVBT2_TP06, + DTAPI_DVBT2_TP08, + DTAPI_DVBT2_TP09, + DTAPI_DVBT2_TP11, + DTAPI_DVBT2_TP12, + DTAPI_DVBT2_TP15, + DTAPI_DVBT2_TP16, + DTAPI_DVBT2_TP19, // Only usable if CFLOAT32 output format is selected + DTAPI_DVBT2_TP20, + DTAPI_DVBT2_TP21, + DTAPI_DVBT2_TP22, + DTAPI_DVBT2_TP23, + DTAPI_DVBT2_TP24, + DTAPI_DVBT2_TP25, + DTAPI_DVBT2_TP26, + DTAPI_DVBT2_TP27, + DTAPI_DVBT2_TP28, + DTAPI_DVBT2_TP29, + DTAPI_DVBT2_TP30, + DTAPI_DVBT2_TP32, + DTAPI_DVBT2_TP33, // T2MI output + DTAPI_DVBT2_TP34, // T2MI output + + // Receiver Buffer Model + DTAPI_DVBT2_TP50, // TDI size + DTAPI_DVBT2_TP51, // TDI write index, TDI read available + DTAPI_DVBT2_TP53, // DJB size + DTAPI_DVBT2_TP_COUNT, // Number of test points +}; + +extern const int DTAPI_DVBT2_TESTPOINTS[DTAPI_DVBT2_TP_COUNT]; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2AuxPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying the parameters of AUX streams +// +struct DtDvbT2AuxPars +{ + int m_NumDummyStreams; // Number of dummy AUX streams + +public: + void Init(void); + bool IsEqual(DtDvbT2AuxPars& AuxPars); + bool operator == (DtDvbT2AuxPars& AuxPars); + bool operator != (DtDvbT2AuxPars& AuxPars); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2MiPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for specifying the parametes for T2MI output streams +// +struct DtDvbT2MiPars +{ + bool m_Enabled; // Enable T2MI output. If enabled, a T2MI + // Transport Stream is generated and output + int m_Pid; // T2MI data PID + int m_StreamId; // stream ID for the first T2MI stream + int m_Pid2; // Second T2MI data PID + int m_StreamId2; // stream ID for the second T2MI stream + int m_PcrPid; // PCR PID. If -1, no PCR is included otherwise + // PCRs are inserted on the specified PID + int m_PmtPid; // PMT PID. If -1, no PMT-table and no PAT-table + // are included otherwise a PMT-table is inserted + // on the specified PID + int m_TsRate; // Rate in bps for the T2MI output + int m_TimeStamping; // T2MI timestamps: None, Absolute or Releative + // See DVBT2MI_TIMESTAMP_x + __int64 m_SecSince2000; // First T2MI output timestamp value. Next values + // are computed + int m_Subseconds; // The number of subseconds. See T2MI spec table 4 + int m_T2miUtco; // Offset in seconds between UTC and m_SecSince2000. + // As of February 2009 the value shall be 2 and + // shall change as a result of each new leap second. + bool m_EncodeFef; // If true, outputs a FEF part composite packet + // with the required subpart. Otherwise, only + // outputs a FEF part NULL packet when FEF is + // enabled. + bool m_SyncWithExtClock; // Undocumented. For internal use only. +public: + void Init(void); + bool IsEqual(DtDvbT2MiPars& T2MiPars); + bool operator == (DtDvbT2MiPars& T2MiPars); + bool operator != (DtDvbT2MiPars& T2MiPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2ModStatus -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure for retrieving the MPLP modulator status +// +struct DtDvbT2ModStatus +{ + int m_MplpModFlags; // Multi PLP modulator flags + // General MPLP status info + __int64 m_PlpNumBlocksOverflows; + // Counts the FEC frames for which the requested + // number of PLP blocks is bigger than NumBlocks + // (the receiver will get an invalid stream) + __int64 m_BitrateOverflows; // Counts the frames in which too many bits were + // allocated (the receiver will get an invalid stream) + __int64 m_TtoErrorCount; // Number of times the generated TTO value was + // invalid (typically from a too small T_design) + + // T2MI Specific status info + __int64 m_T2MiOutputRateOverFlows; + // Number of bit rate overflows(i.e. the T2MI output + // rate must be increased for reliable operation) + int m_T2MiOutputRate; // Current T2MI rate excluding null packets(in bps) +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2PaprPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying and enabling the PAPR reduction parameters +// +struct DtDvbT2PaprPars +{ + bool m_AceEnabled; // ACE enabled + double m_AceVclip; // ACE clipping threshold 1..4.32 (Volt) + double m_AceGain; // ACE gain 0..31 (steps of 1) + double m_AceLimit; // ACE limit 0.7..1.4 (steps of 0.1) + int m_AceInterpFactor; // ACE interpolation factor 1..4 + // Note: PAPR ACE processing time is proportional + // to this parameter (1 recommended for realtime) + int m_AcePlpIndex; // PLP used for the PAPR ACE + bool m_TrEnabled; // TR enabled + bool m_TrP2Only; // PAPR TR is only applied on the P2 symbol + double m_TrVclip; // TR clipping threshold 1..4.32 (Volt) + int m_TrMaxIter; // TR maximum number of iterations. Must be >= 1 + // Note: PAPR TR processing time is proportional + // to this parameter + int m_L1ExtLength; // L1 extension field length 0..65535 + bool m_L1AceEnabled; // L1 ACE enabled + double m_L1AceCMax; // L1 ACE maximum constellation extension value + bool m_L1Scrambling; // L1 post scrabling (requires T2-version 1.3.1) + + // Parameters below only apply if DVB-T2 V1.2.1 is selected + int m_NumBiasBalCells; // Dummy cells added to reduce the P2 PAPR + // 0..BiasBalancingCellsMax + int m_BiasBalancing; // Modify the L1 reserved fields and + // L1 ext padding to compensate the L1 bias. + // See DTAPI_DVBT2_BIAS_x + int m_TrAlgorithm; // Undocumented. Must be 1 (default) + +public: + void Init(void); + bool IsEqual(DtDvbT2PaprPars& PaprPars); + bool operator == (DtDvbT2PaprPars& PaprPars); + bool operator != (DtDvbT2PaprPars& PaprPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2ParamInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// DVB-T2 parameter info +// +struct DtDvbT2ParamInfo +{ + int m_TotalCellsPerFrame; // Total number of cells per frame + int m_L1CellsPerFrame; // Total #cells per frame used for L1 signaling + // Overhead: m_L1CellsPerFrame/m_TotalCellsPerFrame + int m_AuxCellsPerFrame; // Total number of auxiliary stream cells per frame + // (currently only used for TX signalling if enabled) + int m_BiasBalCellsPerFrame; // Total number of L1 bias balancing cells per frame + int m_BiasBalCellsMax; // Maximum number of L1 bias balancing cells per P2 + int m_DummyCellsPerFrame; // Total number of cells lost per frame. Dummy cells + // overhead: m_DummyCellsPerFrame/m_TotalCellsPerFrame + // It is computed in case no NDP is used for frame 0. + int m_SamplesPerFrame; // Total number of samples per frame +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2PlpPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying the parameters of a PLP +// +struct DtDvbT2PlpPars +{ + // Mode adaptation layer: TS input + bool m_Hem; // High Efficiency Mode: yes/no + bool m_Npd; // Null Packet Deletion: yes/no + int m_Issy; // ISSY mode. See DTAPI_DVBT2_ISSY_XXX + int m_IssyBufs; // ISSY BUFS + int m_IssyTDesign; // T-design value for TTO generation. + // Use 0 to have the modulator choose the value. + // T-design is defined as the delay (in samples) + // between the start of the first T2 frame in + // which the PLP is mapped (m_FirstFrameIdx) and + // the first output bit of the transport stream. + int m_CompensatingDelay; // Additional delay (in samples) before the TS + // data is sent. Use -1 to have the modulator + // choose the value + int m_TsRate; // If 0 the rate is computed from the PLP + // parameters. Only possible if no NPD is used. + // Mode adaptation layer: GSE input + int m_GseLabelType; // GSE-label type. See DTAPI_DVBT2_GSE_LABEL_XXX + + // DVB-T2 L1 parameters + int m_Id; // PLP ID: 0..255 + int m_GroupId; // PLP group ID: 0..255 + int m_Type; // PLP type: DTAPI_DVBT2_PLP_TYPE_XXX + int m_PayloadType; // PLP payload type: DTAPI_DVBT2_PAYLOAD_XXX + int m_CodeRate; // PLP code rate: DTAPI_DVBT2_COD_XXX + int m_Modulation; // PLP modulation: DTAPI_DVBT2_BPSK/... + bool m_Rotation; // Constellation rotation: yes/no + int m_FecType; // FEC Type. 0=16K, 1=64K; Must be 16K for T2 lite + int m_FrameInterval; // T2-frame interval for this PLP: 1..255 + int m_FirstFrameIdx; // First frame index: 0..m_FrameInterval-1 + int m_TimeIlLength; // Time interleaving length: 0..255 + int m_TimeIlType; // Time interleaving type: DTAPI_DVBT2_IL_XXX + bool m_InBandAFlag; // In band A signaling information: yes/no + bool m_InBandBFlag; // In band B Signaling information: yes/no + // Only useful if DVB-T2 V1.2.1 is selected + int m_NumBlocks; // Maximum number of FEC blocks contained in + // one interleaving frame + + // IDs of the other PLPs in the in-band signaling + int m_NumOtherPlpInBand; // Number of other PLPs in m_OtherPlpInBand + int m_OtherPlpInBand[DTAPI_DVBT2_NUM_PLP_MAX-1]; + + // The parameters below are only meaningful for type 1 PLPs in TFS case + bool m_FfFlag; // FF flag + int m_FirstRfIdx; // First TFS RF channel: 0..NumRf-1 + +public: + void Init(int PlpId = 0); + bool IsEqual(DtDvbT2PlpPars& PlpPars); + bool operator == (DtDvbT2PlpPars& PlpPars); + bool operator != (DtDvbT2PlpPars& PlpPars); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- RBM events -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// RBM events all are errors except plot +// +enum DtDvbT2RbmEventType +{ + // Plot event (only generated if m_PlotEnabled is true) + DTAPI_DVBT2_RBM_EVENT_PLOT, + // Dejitter buffer underflow + DTAPI_DVBT2_RBM_EVENT_DJB_UNDERFLOW, + // BUFS=[m_Bufs] gives too small dejitter buffer + DTAPI_DVBT2_RBM_EVENT_BUFS_TOO_SMALL, + // TTO=[m_Tto] gives time in the past + DTAPI_DVBT2_RBM_EVENT_TTO_IN_THE_PAST, + // DJB overflow (should never happen except if the model is buggy) + DTAPI_DVBT2_RBM_EVENT_DJB_OVERFLOW, + // BBFrame parser: CRC8 error in header (val=[m_Val]) + DTAPI_DVBT2_RBM_EVENT_CRC8_ERROR_HEADER, + // BBFrame parser: DFL too large + DTAPI_DVBT2_RBM_EVENT_DFL_TOO_LARGE, + // BBFrame parser: SYNCD too large (SYNCD=[m_SyncD] DFL=[m_Dfl]) + DTAPI_DVBT2_RBM_EVENT_SYNCD_TOO_LARGE, + // BBFrame parser: invalid UPL + DTAPI_DVBT2_RBM_EVENT_INVALID_UPL, + // BBFrame parser: invalid syncd (syncd=[m_SyncD] left=[m_Left]) + DTAPI_DVBT2_RBM_EVENT_INVALID_SYNCD, + // TDI overflow: write pointer ([m_TdiWriteIndex]) ahead of + // read pointer ([m_TdiReadIndex]) + DTAPI_DVBT2_RBM_EVENT_TDI_OVERFLOW, + // TDI overflow: too many TI blocks queued + DTAPI_DVBT2_RBM_EVENT_TOO_MANY_TI_BLOCKS, + // plp_start value gives overlap between PLP id=[m_PlpId1] and id=[m_PlpId2] + DTAPI_DVBT2_RBM_EVENT_INVALID_PLP_START, + // Frequency/L1 deinterleaver overflow + DTAPI_DVBT2_RBM_EVENT_FDI_OVERFLOW, + // Not enough ISCR data to estimate the TS rate + DTAPI_DVBT2_RBM_EVENT_NO_TS_RATE, + // ISCR error (delta=[m_Delta]) + DTAPI_DVBT2_RBM_EVENT_ISCR_ERROR, + // BUFS not constant (current=[m_CurBufs] new=[m_NewBufs]) + DTAPI_DVBT2_RBM_EVENT_BUFS_NOT_CONSTANT, + // ISSYI field cannot change its value + DTAPI_DVBT2_RBM_EVENT_ISSYI_NOT_CONSTANT, + // HEM field cannot change its value + DTAPI_DVBT2_RBM_EVENT_HEM_NOT_CONSTANT, + // plp_num_blocks for this interleaving frame is too small (plp_num_blocks=%d) + // At least 3 FEC block required in interleaving frame with HEM=1, + // at least 1 if HEM=0. + DTAPI_DVBT2_RBM_EVENT_PLP_NUM_BLOCKS_TOO_SMALL, +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2RbmEvent -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// RBM event parameters +// +struct DtDvbT2RbmEvent +{ + int m_DataPlpId; // Data plp ID identifiying the stream + int m_DataPlpIndex; // Data plp index + double m_Time; // Time in T units + int m_IsCommonPlp; // 1 = common PLP, 0 = data PLP, + // -1 = the event does not refer to a particular PLP + DtDvbT2RbmEventType m_EventType; + // Additional parameters + union { + // DTAPI_DVBT2_RBM_EVENT_PLOT parameters + struct { + int m_TdiWriteIndex; // TDI write index + int m_TdiReadIndex; // TDI read index + int m_TdiReadAvailable;// Available cells in the TDI read buffer + int m_DjbSize; // Dejitter buffer size in bits + } Plot; + + // DTAPI_DVBT2_RBM_EVENT_BUFS_TOO_SMALL parameters + struct { + int m_Bufs; // BUFS value + } BufsTooSmall; + + // DTAPI_DVBT2_RBM_EVENT_TTO_IN_THE_PAST parameters + struct { + int m_Tto; // TTO value + } TtoInThePast; + + // DTAPI_DVBT2_RBM_EVENT_DJB_OVERFLOW paraneters + struct { + int m_DjbSize; // Dejitter buffer size in bits + int m_DjbMaxSize; + } DjbOverflow; + + // DTAPI_DVBT2_RBM_EVENT_CRC8_ERROR_HEADER parameters + struct { + int m_Val; // CRC8 value + } Crc8ErrorHeader; + + // DTAPI_DVBT2_RBM_EVENT_DFL_TOO_LARGE parameters + struct { + int m_SyncD; // SYNCD + int m_Dfl; // DFL + } SyncDTooLarge; + + // DTAPI_DVBT2_RBM_EVENT_INVALID_SYNCD parameters + struct { + int m_Syncd; // SYNCD + int m_Left; // Left + } InvalidSyncD; + + // DTAPI_DVBT2_RBM_EVENT_TDI_OVERFLOW parameters + struct { + int m_TdiWriteIndex; // TDI write index + int m_TdiReadIndex; // TDI read index + } TdiOverflow; + + // DTAPI_DVBT2_RBM_EVENT_INVALID_PLP_START parameters + struct { + int m_PlpId1; // IDs of overlapping PLPs + int m_PlpId2; + } InvalidPlpStart; + + // DTAPI_DVBT2_RBM_EVENT_ISCR_ERROR parameters + struct { + int m_Delta; // Delta time in T units + } IscrError; + + // DTAPI_DVBT2_RBM_EVENT_BUFS_NOT_CONSTANT parameters + struct { + int m_CurBufs; // Different BUFS values + int m_newBufs; + } BufsNotConstant; + + // DTAPI_DVBT2_RBM_EVENT_PLP_NUM_BLOCKS_TOO_SMALL parameters + struct { + int m_PlpNumBlocks; // Number of blocks + } PlpNumBlocksTooSmall; + } u; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2RbmValidation -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for enabling the RBM validation and specifying a callback function +// +struct DtDvbT2RbmValidation +{ +public: + bool m_Enabled; // Enable RBM validation + bool m_PlotEnabled; // Enable RBM plotting events + int m_PlotPeriod; // Plot period + void* m_pCallbackOpaque; // RBM event callback function and environment + void (*m_pCallbackFunc)(void *pOpaque, const DtDvbT2RbmEvent* pRbmEvent); + +public: + void Init(void); + bool IsEqual(DtDvbT2RbmValidation& RbmPars); + bool operator == (DtDvbT2RbmValidation& RbmPars); + bool operator != (DtDvbT2RbmValidation& RbmPars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2TxSigPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying and enabling the Transmitter Signature +// +struct DtDvbT2TxSigPars +{ + // TX Signature through Auxiliary Streams + // The total number of possible TX IDs are M=3*(P+1) + // The number of cells used per transmitter is N=2^Q + // The number of of T2 frames per TX SIG frame is L=R+1 + bool m_TxSigAuxEnabled; // Enabled + int m_TxSigAuxId; // Transmitter ID. 0..3071 + int m_TxSigAuxP; // P 0..1023. The total number of possible + // TX IDs is M=3*(P+1). Hence M <= 3072 + int m_TxSigAuxQ; // Q 0..15. The number of cells used per + // transmitter is N=2^Q + int m_TxSigAuxR; // R 0..255. The number of T2 frames + // per TX SIG frame is L=R+1 + + // TX Signature through FEF. + // To use this FEF generation must be enabled and the FEF length + // must be >= DTAPI_TXSIG_FEF_LEN_MIN + bool m_TxSigFefEnabled; // Enabled + int m_TxSigFefId1; // TX ID for 1st signature period. 0..7 + int m_TxSigFefId2; // TX ID for 2nd signature period. 0..7 + +public: + void Init(void); + bool IsEqual(DtDvbT2TxSigPars& TxSigPars); + bool operator == (DtDvbT2TxSigPars& TxSigPars); + bool operator != (DtDvbT2TxSigPars& TxSigPars); +}; + +// Compare modes +#define DTAPI_DVBT2_COMPA_ALL 0 +#define DTAPI_DVBT2_COMPA_ESSENTIAL 1 + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2ComponentPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class for specifying the DVB-T2 component modulation parameters +// +class DtDvbT2ComponentPars +{ +public: + // General T2 parameters + int m_T2Version; // DVB-T2 spec. version. See DVBT2_VERSION_x + int m_T2Profile; // DVB-T2 profile. See DVBT2_PROFILE_x + bool m_T2BaseLite; // Indicates whether T2 lite is used in a base + // profile stream + int m_Bandwidth; // Bandwidth: DVBT2_BW_XXX + int m_FftMode; // FFT-mode: DVBT2_FFT_XXX + int m_Miso; // MISO. See DVBT2_MISO_x + int m_GuardInterval; // Guard interval. See DVBT2_GI_x + int m_Papr; // PAPR. See DVBT2_PAPR_x + bool m_BwtExt; // Bandwidth extention + int m_PilotPattern; // Pilot pattern. Pattern 1 .. 8. + int m_L1Modulation; // L1 modulation. See DVBT2_BPSK/... + int m_CellId; // Cell ID. 0..0xFFFF. + int m_NetworkId; // Network ID. 0..0xFFFF. + int m_T2SystemId; // T2 System ID. 0..0xFFFF. + bool m_L1Repetition; // L1 repetition + + // T2-Frame related parameters + int m_NumT2Frames; // #T2-frames per superframe. 1..255. + int m_NumDataSyms; // #Data symbols + int m_NumSubslices; // #Subslices per T2-frame (for type2 PLPs) + + // Component start time + int m_ComponentStartTime; // Offset in T unit at which the T2 component + // begins to be modulated. (0 in the first component) + // FEF parameters + bool m_FefEnable; // FEF enable + int m_FefType; // FEF type. 0..15 + int m_FefS1; // FEF S1. 2..7 + int m_FefS2; // FEF S2. 1, 3, 5, 7, 9 ,11, 13 or 15 + int m_FefSignal; // Selects the type of signal generated during + // the FEF period (see DTAPI_DVBT2_FEF_x) + int m_FefLength; // FEF Length in number of samples. + int m_FefInterval; // FEF Interval. + // Requires: (m_NumT2Frames % m_FefInterval) == 0 + // RF channels for TFS + int m_NumRfChans; // Number of RF channels 1..7 + int m_RfChanFreqs[DTAPI_DVBT2_NUM_RF_MAX]; + // Channel frequencis + int m_StartRfIdx; // First used RF channel + + // PLPs + int m_NumPlps; // Number of PLPs + DtDvbT2PlpPars m_Plps[DTAPI_DVBT2_NUM_PLP_MAX]; + // PLP parameters + DtPlpInpPars m_PlpInputs[DTAPI_DVBT2_NUM_PLP_MAX]; + // PLP inputs (Optional) + // Optional + DtDvbT2AuxPars m_Aux; // AUX Streams (Optional) + DtDvbT2PaprPars m_PaprPars; // PAPR Params (Optional) + DtDvbT2TxSigPars m_TxSignature;// TX-Signature (Optional) + DtDvbT2RbmValidation m_RbmValidation; + // RBM validation (Optional) + DtTestPointOutPars m_TpOutput; // Test point data output parameters (optional) + + int m_L1ChangeCounter; // Undocumented. For internal use only. + +public: + virtual void Init(void); + virtual bool IsEqual(DtDvbT2ComponentPars&, int CompareMode=DTAPI_DVBT2_COMPA_ALL); + virtual bool operator == (DtDvbT2ComponentPars& T2Pars); + virtual bool operator != (DtDvbT2ComponentPars& T2Pars); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2Pars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Class for specifying the DVB-T2 modulation parameters. +// +class DtDvbT2Pars : public DtDvbT2ComponentPars +{ +public: + // Optional + DtVirtualOutPars m_VirtOutput; // Virtual-output parameters (Optional) + DtDvbT2MiPars m_T2Mi; // T2MI output (Optional) + int m_NumFefComponents; // Number of other T2 stream transmitted in the + // FEF part of the first component. The parameters + // come from 'm_FefComponent'. + + // FEF components. Currently maximum 1 other component + DtDvbT2ComponentPars m_FefComponent[1]; + +public: + // Constructor + DtDvbT2Pars() { Init(); } + + // Methods + virtual void Init(void); + virtual DTAPI_RESULT CheckValidity(void); + virtual DTAPI_RESULT ComputeTDesign(); + virtual DTAPI_RESULT GetParamInfo(DtDvbT2ParamInfo& T2Info); + virtual DTAPI_RESULT GetParamInfo(DtDvbT2ParamInfo& T2Info1, + DtDvbT2ParamInfo& T2Info2); + + // Only usefull for single PLP + DTAPI_RESULT OptimisePlpNumBlocks(DtDvbT2ParamInfo&, int&); + DTAPI_RESULT OptimisePlpNumBlocks(DtDvbT2ParamInfo&, int&, int&); + + // Helper function to determine T2MI ts rate. + static DTAPI_RESULT RetrieveT2miTsRateFromTs(char* pBuffer, int NumBytes, + int Bandwidth, int& TsRate); + + // Operators + virtual bool operator == (DtDvbT2Pars& T2Pars); + virtual bool operator != (DtDvbT2Pars& T2Pars); + virtual bool IsEqual(DtDvbT2Pars& T2Pars, int CompareMode=DTAPI_DVBT2_COMPA_ALL); +}; + +//=+=+=+=+=+=+=+=+=+=+=+=+=+ DVB-T2 Demodulation layer 1 data +=+=+=+=+=+=+=+=+=+=+=+=+=+ + +// DtDvbT2DemodL1PostPlp::m_PayloadType - The PLP payload type +#define DTAPI_DVBT2_PAYLOAD_GFPS 0 // Generic Fixed-length Packetized Stream +#define DTAPI_DVBT2_PAYLOAD_GCS 1 // Generic Continuous Stream +#define DTAPI_DVBT2_PAYLOAD_GSE 2 // Generic Stream Encapsulation +#define DTAPI_DVBT2_PAYLOAD_TS 3 // Transport Stream + +// DtDvbT2DemodL1Pre::m_Type - The current T2 super-frame stream type +#define DTAPI_DVBT2_TYPE_TS 0 // Transport Stream (TS) only +#define DTAPI_DVBT2_TYPE_GS 1 // Generic Stream (GS) only +#define DTAPI_DVBT2_TYPE_TS_GS 2 // Mixed TS and GS + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2DemodAuxPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Struct for storing the Auxiliary stream information from Layer 1 Post +// +struct DtDvbT2DemodAuxPars +{ + int m_AuxStreamType; // Auxiliary stream type + int m_AuxPrivateConf; // Auxiliary stream info +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2DemodL1PostPlp -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Struct for storing Layer 1 Post per PLP +// +struct DtDvbT2DemodL1PostPlp +{ + int m_Id; // PLP ID: 0..255 + int m_Type; // PLP type, see DTAPI_DVBT2_PLP_TYPE_x + int m_PayloadType; // PLP payload type: 0..3 + int m_FfFlag; // FF flag + int m_FirstRfIdx; // 0..NumRf-1 + int m_FirstFrameIdx; // First frame in which PLP appears + int m_GroupId; // Group ID: 0..255 + int m_CodeRate; // PLP code rate, see DTAPI_DVBT2_COD_x + int m_Modulation; // PLP modulation, see DTAPI_DVBT2_BPSK/... + int m_Rotation; // PLP rotation yes/no + int m_FecType; // PLP FEC type: 0=LDPC 16K, 1=LDPC 64K + int m_NumBlocks; // PLP_NUM_BLOCKS_MAX: Maximum number of FEC blocks + // contained in one interleaving frame + int m_FrameInterval; // The PLP appears every m_FrameInterval frames + int m_TimeIlLength; // Time interleaver length: 0..255 + int m_TimeIlType; // Time interleaver type: 0 or 1 + int m_InBandAFlag; // IN_BAND_A_FLAG is used yes/no + // V1.2.1 spec revision + int m_InBandBFlag; // IN_BAND_B_FLAG is used yes/no + int m_Reserved1; // Reserved field, may be used for bias balancing + int m_PlpMode; // PLP mode: 0..3 + int m_Static; // Static flag: 0 or 1=Configuration changes only at + // super frame boundaries + int m_StaticPadding; // Static padding flag: 0 or 1=BBFRAME padding is not + // used + DtDvbT2DemodL1PostPlp(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2DemodRfPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Struct for storing the TFS RF channels information from Layer 1 Post +// +struct DtDvbT2DemodRfPars +{ + int m_RfIdx; // Index of the RF-frequency + int m_Frequency; // Centre frequency in Hz +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2DemodL1Data -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Struct for storing the DVB-T2 layer 1 data +// +struct DtDvbT2DemodL1Data +{ + // P1 Info + struct DtDvbT2DemodL1P1 + { + bool m_Valid; // True if P1 was found + int m_FftMode; // FFT mode, see DVBT2_FFT_x + int m_Miso; // MISO used + int m_Fef; // FEF used + int m_T2Profile; // DVB-T2 profile. See DVBT2_PROFILE_x + } m_P1; + + // L1-pre info + struct DtDvbT2DemodL1Pre + { + bool m_Valid; // True if L1 pre was correctly demodulated + + int m_Type; // Stream type within the current T2 super-frame + int m_BwtExt; // Bandwidth extension + int m_S1; // S1 signalling. P1 S1. + int m_S2; // S2 signalling. P1 S2. + int m_L1Repetition; // L1 repetition + int m_GuardInterval; // Guard interval, see DVBT2_GI_x + int m_Papr; // PAPR. see DVBT2_PAPR_x + int m_L1Modulation; // L1 modulation, see DVBT2_BPSK/... + int m_L1CodeRate; // L1 coderate, see DTAPI_DVBT2_COD_x + int m_L1FecType; // L1 FEC type: 0=LDPC 16K, 1=LDPC 64K + int m_L1PostSize; // Size of the L1-post in OFDM cells + int m_l1PostInfoSize; // L1-post info size = + // L1-post configurable+dynamic+extension + int m_PilotPattern; // Pilot pattern: 1..8 + int m_TxIdAvailability; // The Tx ID + int m_CellId; // Cell ID: 0..0xFFFF + int m_NetworkId; // Network ID: 0..0xFFFF + int m_T2SystemId; // T2 System ID: 0..0xFFFF + int m_NumT2Frames; // Number of T2-frames per superframe: 1..255 + int m_NumDataSyms; // Number of data symbols + int m_RegenFlag; // Regeneration count indicator + int m_L1PostExt; // L1-post extensions enabled + int m_NumRfChans; // Number of RF channels: 1..7 + int m_CurrentRfIdx; // Current RF index: 0..m_NumRfChans-1 + int m_T2Version; // DVB-T2 spec version, see DVBT2_VERSION_x + int m_L1PostScrambling; // L1 Post scrambling + int m_T2BaseLite; // Indicates whether T2 lite is used in a base + // profile stream + } m_L1Pre; + + // L1-post info + struct DtDvbT2DemodL1Post + { + bool m_Valid; // True if L1 post was correctly demodulated + int m_NumSubslices; // Number of subslices per T2-frame (for type2 PLPs) + int m_NumPlps; // Number of PLPs + int m_NumAux; // Number of auxiliary streams + + // TFS RF-channels + std::vector m_RfChanFreqs; + + // FEF info is meaningful if m_P1.m_Fef = true + int m_FefType; // FEF type: 0..15 + int m_FefLength; // FEF length in number of samples + int m_FefInterval; // FEF Interval + + // PLPs + std::vector m_Plps; + + // Auxiliary stream signalling information + std::vector m_AuxPars; + + } m_L1Post; + + DtDvbT2DemodL1Data(); + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ ISDBT-TMM +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +#define DTAPI_ISDBT_NUM_TS_MAX 14 +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbTmmPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// ISDB-Tmm parameters including per-layer parameters +// +struct DtIsdbTmmPars +{ + int m_Bandwidth; + int m_SubChannel; + int m_NumTss; + DtVirtualOutPars m_VirtOutput; // Virtual Output parameters(Optional) + DtIsdbtPars m_Tss[DTAPI_ISDBT_NUM_TS_MAX]; + DtPlpInpPars m_TsInputs[DTAPI_ISDBT_NUM_TS_MAX]; + + // Member function + DtIsdbTmmPars() { Init(); } + DTAPI_RESULT CheckValidity(); + int NumSegm(); + void Init(); + DTAPI_RESULT SetSegmentFormat(int TsIdx, int SegmFormat); + + bool operator == (DtIsdbTmmPars& Rhs); + bool operator != (DtIsdbTmmPars& Rhs); +}; + + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ Advanced Demodulator +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtStreamType -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Classifies the type of the stream +// +enum DtStreamType +{ + STREAM_CONSTEL, // Constellation points + STREAM_DAB, // DAB stream + STREAM_DABETI, // DAB Ensemble Transport Interface (NI, G.703) + STREAM_DABFIC, // DAB Fast Information Channel + STREAM_DVBC2, // DVB-C2 stream (Transport Stream packets) + STREAM_DVBC2_BBFRAME, // DVB-C2 stream base-band frames + STREAM_DVBT, // DVB-T stream + STREAM_DVBT2, // DVB-T2 stream (Transport Stream packets) + STREAM_DVBT2_BBFRAME, // DVB-T2 stream base band frames + STREAM_DVBT2_GSE, // DVB-T2 stream GSE-packets + STREAM_IMPRESP, // Impulse response + STREAM_ISDBT, // ISDB-T stream + STREAM_MER, // MER + STREAM_SPECTRUM, // Spectrum + STREAM_T2MI, // DVB-T2 stream + STREAM_TF_ABS, // Transfer function absolute + STREAM_TF_PHASE, // Transfer function phase + STREAM_TF_GROUPDELAY // Transfer function group delay +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtConstelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure specifies the parameters for a stream of constellation points +// +struct DtConstelPars +{ + int m_Period; // Minimum period between callbacks in ms + int m_ConstellationType; // 0: Constellation per PLP + // 1: Constellation per carrier (after equalization) + int m_Index; // Index of the PLP or carrier + int m_MaxNumPoints; // Maximum number of constellation points +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbTStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// This structure specifies the selection parameters for a DVB-T transport stream +// +struct DtDvbTStreamSelPars +{ + // No selection parameters yet +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbTTpsInfo -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// DVB-T Transmission Parameter Signalling (TPS) information structure +// +struct DtDvbTTpsInfo +{ + int m_LengthIndicator; // TPS length indicator + int m_Constellation; // Constellation (DTAPI_MOD_DVBT_xxx) + int m_HpCodeRate; // High Priority code rate (DTAPI_MOD_xxx) + int m_LpCodeRate; // Low Priority code rate(DTAPI_MOD_xxx) + int m_Guard; // Guard interval (DTAPI_MOD_DVBT_G_xx) + int m_Interleaving; // Interleaving (DTAPI_MOD_DVBT_xxx) + int m_Mode; // Transmission mode (DTAPI_MOD_DVBT_xK) + int m_Hierarchy; // Hierarchy (DTAPI_MOD_DVBT_HARCHY_xxx) + int m_CellId; // CellId or -1 when not present + int m_HpS48S49; // S48S49 of the odd frames (DTAPI_MOD_DVBT_Sxx) + int m_LpS48S49; // S48S49 of the even frames (DTAPI_MOD_DVBT_Sxx) + int m_OddS50_S53; // S50..S53 of the odd frames + int m_EvenS50_S53; // S50..S53 of the even frames + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDvbT2StreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure specifies the selection parameters for a DVB-T2 DVB-T2 GSE and +// DVB-T2 BBFRAME stream +// +struct DtDvbT2StreamSelPars +{ + int m_PlpId; // ID of the data PLP or DTAPI_DVBT2_PLP_ID_xxx + int m_CommonPlpId; // ID of the common PLP or DTAPI_DVBT2_PLP_ID_xxx + + // Serialisation + DTAPI_RESULT FromXml(const std::wstring& XmlString); + DTAPI_RESULT ToXml(std::wstring& XmlString); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtImpRespPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure specifies the parameters for an impulse-response stream +// +struct DtImpRespPars +{ + int m_Period; // Minimum period bewteen callbacks in ms + int m_Channel; // Channel used for MISO +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtIsdbtStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure specifies the selection parameters for an ISDB-T stream +// +struct DtIsdbtStreamSelPars +{ + // No additional selection parameters +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMeasurement -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Structure describing a set of measurement values. It used to pass measurements from +// the advanced demodulator to the user application through user-supplied +// DtWriteMeasFunc callback. +// +struct DtMeasurement +{ + DtStreamType m_MeasurementType;// Type of measurement values + __int64 m_TimeStamp; // Timestamp in number of samples + int m_NumValues; // Number of measurement values + DtComplexFloat* m_pMeasurement;// Measurement values +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMerPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// This structure specifies the parameters for a MER stream. +// +struct DtMerPars +{ + int m_Period; // Minimum period between callbacks in ms +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtSpectrumPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// This structure specifies the parameters for a spectrum stream. +// +struct DtSpectrumPars +{ + int m_Period; // Minimum time between callbacks in ms + int m_FftLength; // FFT length, must be a power of two + int m_AverageLength; // Number of FFT blocks on wich the average is done +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtT2MiStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// This structure specifies the selection parameters for a T2-MI transport stream +// containing a com-plete DVB-T2 stream. +// +struct DtT2MiStreamSelPars +{ + int m_T2MiOutPid; // T2-MI output PID + int m_T2MiTsRate; // Rate in bps for the T2MI output. + // If -1, output a variable bitrate T2MI stream + // (set_output_rate is not called in this case). + // Otherwise, use m_T2MiTsRate to set the rate. + // Padding null packets are used to reach the target + // bitrate. The maximum T2-MI bitrate is 72Mbps. +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtTransFuncPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// This structure specifies the parameters for a transfer-function stream. +// +struct DtTransFuncPars +{ + int m_Period; // Minimum time between callbacks in ms + int m_Channel; // Channel used for MISO +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtStreamSelPars -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Structure for streaming data selection +// +struct DtStreamSelPars +{ + intptr_t m_Id; // Unique stream identifier + DtStreamType m_StreamType; // Stream selection type + + union { + // Selection parameters for demodulated streams + DtDvbC2StreamSelPars m_DvbC2; + DtDvbTStreamSelPars m_DvbT; + DtDvbT2StreamSelPars m_DvbT2; + DtIsdbtStreamSelPars m_Isdbt; + DtT2MiStreamSelPars m_T2Mi; + DtDabStreamSelPars m_Dab; + DtDabEtiStreamSelPars m_DabEti; + DtDabFicStreamSelPars m_DabFic; + + // Parameters for streams of measurement values + DtConstelPars m_Constel; + DtImpRespPars m_ImpResp; + DtMerPars m_Mer; + DtSpectrumPars m_Spectrum; + DtTransFuncPars m_TransFunc; + } u; + + bool operator == (DtStreamSelPars& Rhs); + bool operator != (DtStreamSelPars& Rhs); +}; + +// Software demodulator callback functions +typedef void DtOutputRateChangedFunc(void *pOpaque, DtStreamSelPars&, int Bitrate); +typedef void DtReadIqFunc(void* pOpaque, + unsigned char* pIqBuf, int IqBufSize, int& IqLength); +typedef void DtWriteMeasFunc(void *pOpaque, DtStreamSelPars&, DtMeasurement*); +typedef void DtWriteStreamFunc(void* pOpaque, DtStreamSelPars& StreamSel, + const unsigned char* pData, int Length); + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtAdvDemod -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Class representing an advanced demodulator. +// DtAdvDemod can be considered a specialized in-put channel. +// +class DtAdvDemod +{ +public: + DtAdvDemod(); + virtual ~DtAdvDemod(); +private: + // No implementation is provided for the copy constructor + DtAdvDemod(const DtAdvDemod&); + +public: + DtHwFuncDesc m_HwFuncDesc; // Hardware function descriptor + + // Convenience functions +public: + int Category(void) { return m_HwFuncDesc.m_DvcDesc.m_Category; } + int FirmwareVersion(void) { return m_HwFuncDesc.m_DvcDesc.m_FirmwareVersion; } + bool IsAttached(void) { return m_pAdvDemod != NULL; } + int TypeNumber(void) { return m_HwFuncDesc.m_DvcDesc.m_TypeNumber; } + +public: + DTAPI_RESULT AttachToPort(DtDevice* pDtDvc, int Port, + bool Exclusive=true, bool ProbeOnly=false); + DTAPI_RESULT AttachVirtual(DtDevice* pDtDvc, + DtReadIqFunc* pReadIqFunc, void* pOpaque); + DTAPI_RESULT ClearFlags(int Latched); + DTAPI_RESULT CloseStream(intptr_t Id); + DTAPI_RESULT Detach(int DetachMode); + DTAPI_RESULT GetDemodControl(DtDemodPars* pDemodPars); + DTAPI_RESULT GetDescriptor(DtHwFuncDesc& HwFunDesc); + DTAPI_RESULT GetFlags(int& Flags, int& Latched); + DTAPI_RESULT GetIoConfig(int Group, int& Value); + DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue); + DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, __int64& ParXtra0); + DTAPI_RESULT GetIoConfig(int Group, int& Value, int& SubValue, + __int64& ParXtra0, __int64& ParXtra1); + DTAPI_RESULT GetPars(int Count, DtPar* pPars); + DTAPI_RESULT GetRxControl(int& RxControl); + DTAPI_RESULT GetStatistics(int Count, DtStatistic* pStatistics); + DTAPI_RESULT GetStatistic(int Type, int& Statistic); + DTAPI_RESULT GetStatistic(int Type, double& Statistic); + DTAPI_RESULT GetStatistic(int Type, bool& Statistic); + DTAPI_RESULT GetStreamSelection(std::vector& StreamSelList); + DTAPI_RESULT GetSupportedPars(int& NumPars, DtPar* pPars); + DTAPI_RESULT GetSupportedStatistics(int& Count, DtStatistic* pStatistics); + DTAPI_RESULT GetTsRateBps(intptr_t Id, int& TsRate); + DTAPI_RESULT GetTunerFrequency(__int64& FreqHz); + DTAPI_RESULT LedControl(int LedControl); + DTAPI_RESULT OpenStream(DtStreamSelPars StreamSel); + DTAPI_RESULT RegisterCallback(DtOutputRateChangedFunc* pCallback, void* pOpaque); + DTAPI_RESULT RegisterCallback(DtWriteStreamFunc* pCallback, void* pOpaque); + DTAPI_RESULT RegisterCallback(DtWriteMeasFunc* pCallback, void* pOpaque); + DTAPI_RESULT Reset(int ResetMode); + DTAPI_RESULT SetAntPower(int AntPower); + DTAPI_RESULT SetDemodControl(DtDemodPars *pDemodPars); + DTAPI_RESULT SetIoConfig(int Group, int Value, int SubValue, + __int64 ParXtra0 = -1, __int64 ParXtra1 = -1); + DTAPI_RESULT SetPars(int Count, DtPar* pPars); + DTAPI_RESULT SetRxControl(int RxControl); + DTAPI_RESULT SetTunerFrequency(__int64 FreqHz); + DTAPI_RESULT Tune(__int64 FreqHz, int ModType, + int ParXtra0, int ParXtra1, int ParXtra2); + DTAPI_RESULT Tune(__int64 FreqHz, DtDemodPars *pDemodPars); + +protected: + AdvDemod* m_pAdvDemod; // Advanced demodulation channel implementation + bool m_IsAttachedToVirtual; // Attached to virtual input port? + + // Encapsulated data +private: + IXpMutex* m_pMTLock; // Multi-threading lock for get/read functions + void* m_pDetachLockCount; + int m_Port; + bool m_WantToDetach; + +// Private helper functions +private: + DTAPI_RESULT DetachLock(void); + DTAPI_RESULT DetachUnlock(void); + DTAPI_RESULT ReadAccessLock(void); + DTAPI_RESULT ReadAccessUnlock(void); +}; + +// Forward declaration for use in DtRs422Channel +class Rs422Channel; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtRs422Channel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtRs422Channel +{ +public: + DtRs422Channel(); + virtual ~DtRs422Channel(); +private: + // No implementation is provided for the copy constructor + DtRs422Channel(const DtRs422Channel&); + +public: + DTAPI_RESULT AttachToPort(DtDevice* pDtDvc, int Port, + bool Exclusive=true, bool ProbeOnly=false); + DTAPI_RESULT Detach(); + DTAPI_RESULT Flush(); + DTAPI_RESULT Read(char* pBuffer, int NumBytesToRead, int Timeout, int& NumBytesRead); + DTAPI_RESULT Write(char* pBuffer, int NumBytesToWrite, bool Blocking=true); + +protected: + Rs422Channel* m_pRs422Channel; + void* m_pDetachLockCount; + bool m_WantToDetach; + +// Private helper functions +private: + DTAPI_RESULT DetachLock(void); + DTAPI_RESULT DetachUnlock(void); +}; + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ MATRIX CONFIGURATION +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxPixelFormat -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +enum DtMxPixelFormat +{ + DT_PXFMT_UYVY422_8B, // Packed CbYCrY, 8 bits per symbol + DT_PXFMT_UYVY422_10B, // Packed CbYCrY, 10 bits per symbol + DT_PXFMT_UYVY422_16B, // Packed CbYCrY, 16 bits per symbol (10 significant bits) + DT_PXFMT_UYVY422_10B_NBO, // Packed CbYCrY, 10 bits per symbol, network byte order + DT_PXFMT_YUYV422_8B, // Packed YCbYCr, symbol swap of DT_PXFMT_UYVY422_8B + DT_PXFMT_YUYV422_10B, // Packed YCbYCr, symbol swap of DT_PXFMT_UYVY422_10B + DT_PXFMT_YUYV422_16B, // Packed YCbYCr, symbol swap of DT_PXFMT_UYVY422_16B + DT_PXFMT_Y_8B, // Luminance plane only, 8 bits per symbol + DT_PXFMT_Y_16B, // Luminance plane only, 16 bits per symbol (10 sign bits) + DT_PXFMT_YUV422P_8B, // Planar YUV, 3 planes, 1 Cb & 1 Cr sample per 2 Y. 8BPS + DT_PXFMT_YUV422P_16B, // Planar YUV, 3 planes, 1 Cb & 1 Cr sample per 2 Y. 16BPS + DT_PXFMT_YUV422P2_8B, // Planar YUV, 2 planes, Y plane + Cb+Cr plane. 8BPS + DT_PXFMT_YUV422P2_16B, // Planar YUV, 2 planes, Y plane + Cb+Cr plane. 16BPS + DT_PXFMT_BGR_8B, // Packed RGB data. First B, then G, then R. 8 bits per ch + DT_PXFMT_V210, // Packed CbYCrY, 3 10-bit symbols per 32-bit + // Likely future extensions: + //DT_PXFMT_YUV420P, // Planar YUV, 3 planes, 1 Cb & 1 Cr sample per 2x2 Y.This + // is often used as decoder input/output. + //DT_PXFMT_RGBX, // Packed RGB data with a 4th dummy symbol per pixel. With + // 8-byte data this means 32-bit per pixel which is easy + // to process. + //DT_PXFMT_RGB_P, // Planar RGB data + + DT_PXFMT_INVALID = -1, +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxVideoConfig -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxVideoConfig +{ +public: + // m_StartLine1 / m_NumLines1 are for field 1, m_StartLine2 / m_NumLines2 are for + // field 2. For progressive input m_StartLine2 / m_NumLines2 are ignored. + // If no video input is required set m_NumLines1 and m_NumLines2 to 0. + int m_StartLine1; // 1st line to transfer (1-based relative to 1st field) + int m_NumLines1; // #lines to transfer (-1 for all lines) + + int m_StartLine2; // 1st line to transfer (1-based relative to 2nd field) + int m_NumLines2; // #lines to transfer (-1 for all lines) + + int m_Scaling; // Scaling mode (OFF, 1/4, 1/16). DTAPI_SCALING_* + int m_LineAlignment; // -1 if all symbols should directly follow eachother, + // otherwise the minimum alignment each line should + // have. HLM will chose a stride, usually + // n*m_LineAlignment for smallest n where the stride is + // equal or longer than the required number of bytes per + // line. HLM is allowed to pick larger stride for + // performance reasons. + // Common values will be -1 (no alignment), 1 (align + // each line at byte-boundary) and 16 (sse2 alignment). + DtMxPixelFormat m_PixelFormat; // Pixel format + bool m_UserBuffer; // When set to true the callback function is responsible + // for allocating the video sample buffers. When set to + // false the framework will allocate the buffers. Defaults + // to false. + + DtMxVideoConfig(); +}; + + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxRawConfigSdi -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxRawConfigSdi +{ +public: + DtMxPixelFormat m_PixelFormat; // Pixel format. Allowed are: UYVY422 or YUYV422 + int m_StartLine; // 1st line to transfer (1-based) + int m_NumLines; // #lines to transfer (-1 for all lines) + int m_LineAlignment; // See DtMxVideoConfig::m_LineAlignment +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxRawDataType -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +enum DtMxRawDataType +{ + DT_RAWDATA_SDI, +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxRawConfig -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxRawConfig +{ +public: + DtMxRawDataType m_Type; // Indicates which of the fields below is valid. + + union { + DtMxRawConfigSdi m_Sdi; + }; + + DtMxRawConfig(); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMuxAudioSampleType -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +enum DtMxAudioSampleType +{ + DT_AUDIO_SAMPLE_PCM, // 32-bit PCM samples + DT_AUDIO_SAMPLE_AES3, // AES samples +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxOutputMode -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +enum DtMxOutputMode +{ + DT_OUTPUT_MODE_ADD, + DT_OUTPUT_MODE_COPY, + DT_OUTPUT_MODE_DROP, +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAudioConfig -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxAudioConfig +{ +public: + int m_Index; // Identifies the corresponding audio channel. + bool m_DeEmbed; // If true, decode the input to data buffers per stream. + // m_DeEmbed is ignored for output rows. + DtMxOutputMode m_OutputMode; + // DROP: Audio group is not generated at output, whether + // or not it was available at input. Data buffers + // are available read-only if m_DeEmbed is true. + // COPY: Output for this group is directly copied from + // input, timing stays the same. Data buffers are + // available read-only if m_DeEmbed is true. For + // output rows this has the same effect as DROP: no + // generated output. + // ADD: Output is generated by framework from data + // buffers filled by callback. Data buffers are + // initialized with input data if m_DeEmbed is + // true, otherwise they're initially empty. + // m_OutputMode is ignored for input rows. + DtMxAudioSampleType m_Format; // Inidicate whether to (de-)embed PCM samples or + // AES subframes. Dolby E can be (de-)embedded as + // AES samples. + + DtMxAudioConfig(); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxAuxDataType -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +enum DtMxAuxDataType +{ + DT_AUXDATA_SDI, +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAuxObjConfig -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxAuxObjConfig +{ +public: + bool m_DeEmbed; // If true, decode this AuxData object. m_DeEmbed is + // ignored for output rows. + DtMxOutputMode m_OutputMode; + // DROP: AuxData object is not generated at output no + // matter whether or not it was available at the + // input. AuxData object is available read-only if + // m_DeEmbed is true. + // COPY: The embedded AuxData of this type in the input + // frame, if present, is copied one-to-one to the + // output, without re-embedding. If m_DeEmbed is + // true the data will be available in the callback. + // ADD: Output is generated by framework from data + // buffers filled by callback. Data buffers are + // initialized with input data if m_DeEmbed is + // true, otherwise they're initially empty. +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAuxConfigSdi -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxAuxConfigSdi +{ +public: + DtMxAuxObjConfig m_AncPackets; // Settings for ancillary data packets + //DtMxAuxObjConfig m_Rp188; + //DtMxAuxObjConfig m_Vitc; + //DtMxAuxObjConfig m_Eia608; + //DtMxAuxObjConfig m_Eia708; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAuxDataConfig -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxAuxDataConfig +{ +public: + bool m_DeEmbedAll; // De-embed all auxdata. Defaults to false. + DtMxAuxDataType m_DataType; // Indicates which of the following objects is valid. + + union + { + DtMxAuxConfigSdi m_Sdi; + }; + + DtMxAuxDataConfig(); +}; + + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxRowConfig -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxRowConfig +{ + // Constants +public: + static const int MAX_NUM_AUDIO_CHANNELS = 16; // Max. # audio channels supported + +public: + DtMxRowConfig(); + virtual ~DtMxRowConfig(); + +public: + bool m_Enable; // Global flag to enable/disable to the complete row. + // When disabled input rows will not provide data and all + // output ports will generate black frames. + // Wnen set to false all further configuration below + // is not taken into account. + + int m_RowSize; // Number of frame buffers available in the callback + // function. + + void* m_pOpaq; // Opaque user pointer. Framework itself will not change + // this value. This can be used if the row configuration + // is changed dynamically to detect the change. It can + // also be used to change the function of the callback + // frame-synchronous without implementing any locks + // on the user-side. + + // Each matrix row operates either in RAW mode or in "parsed data" mode. This means + // that m_RawDataEnable is mutually exclusive with m_VideoEnable, m_AudioEnable + // and m_AuxDataEnable. + + // Raw data + bool m_RawDataEnable; // Enable raw data processing. m_RawData is ignored when + // set to false. Defaults to false. + DtMxRawConfig m_RawData; // Configuration of raw input/output data. + + // Video + bool m_VideoEnable; // Enables video processing. m_Video is ignored when set + // to false. Defaults to true. + DtMxVideoConfig m_Video; // Configuration of video input/output. + + // Audio + bool m_AudioEnable; // Enables audio processing. m_AudioGen and m_Audio are + // ignored when set to false. Defaults to true. + DtMxAudioConfig m_AudioDef; // Default audio settings, can be used to de-embed all + // channels. These settings are used as defaults for + // all channels and can be overriden on a per-channel + // basis by the m_Audio vector. + std::vector m_Audio; // Configuration for each audio channel + + // AUX data + bool m_AuxDataEnable; // Enables auxiliary data processing. m_AuxData is ignored + // when set to false. Defaults to false. + DtMxAuxDataConfig m_AuxData; // Configuration of aux data input/output. +}; + + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+ MATRIX CALLBACK DATA STRUCTURES +=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxRawDataSdi -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxRawDataSdi +{ +public: + unsigned char* m_pBuf; + int m_BufSize; + int m_Stride; // Size of each line in bytes + int m_StartLine; // 1st line in buffer (1-based) + int m_NumLines; // #lines to transfer (-1 for all lines) + // Informational + DtMxPixelFormat m_PixelFormat; // Pixel format. Can be UYVY422 or YUVY422 + int m_Width; // Width in pixels + int m_Height; // Height in pixels +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxRawData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxRawData +{ +public: + DtMxRawDataType m_Type; // Indicates which of the fields below is valid. + + union { + DtMxRawDataSdi m_Sdi; + }; +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxVideoPlaneBuf -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxVideoPlaneBuf +{ +public: + unsigned char* m_pBuf; // Pointer to buffer + int m_BufSize; // Total size in bytes of buffer + int m_Stride; // Size of each line in bytes + int m_StartLine; // 1st line in buffer (1-based) + int m_NumLines; // Number of lines. Usually equal to + // DtMxVideoBuf::m_Height but might vary for some + // pixel formats, for 4:2:0 planar for example both + // chrominancy planes have m_NumLines twice as small + // as DtMatrixVideoBuf::m_Height. + + DtMxVideoPlaneBuf(); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxVidPattern -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +enum DtMxVidPattern +{ + DT_VIDPAT_BLACK_FRAME, + DT_VIDPAT_RED_FRAME, + DT_VIDPAT_GREEN_FRAME, + DT_VIDPAT_BLUE_FRAME, + DT_VIDPAT_WHITE_FRAME, +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxVideoBuf -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxVideoBuf +{ +public: + DtMxVideoPlaneBuf m_Planes[3]; + int m_NumPlanes; // The number of planes directly depends on the pixel + // format chosen. + DtMxPixelFormat m_PixelFormat; // See DtMxVideoConfig::m_PixelFormat + int m_Scaling; // Scaling mode (OFF, 1/4, 1/16). DTAPI_SCALING_* + int m_Width; // Width in pixels + int m_Height; // Height in pixels + + // Initialize the video buffers with a specific pattern in an efficient way. Can + // be used by the callback function for output rows if no useful data is available. + // Framework does not do this automatically because in normal operation it'd be + // a waste of resources to initialize buffers that will be overwritten later anyway. + DTAPI_RESULT InitBuf(DtMxVidPattern Pattern); + + DtMxVideoBuf(); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAuxData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxAuxData +{ +public: + // Teletext + // Closed captioning + + // Other anc data + bool m_AncTimeCodeValid; + __int64 m_AncTimeCode; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMxAncPacket -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxAncPacket +{ +public: + int m_Did; // Data identifier + int m_SdidOrDbn; // Secondary data identifier / Data block number + int m_Dc; // Data count + int m_Cs; // Check sum + unsigned short* m_pUdw; // User data words + int m_Line; // Line number in which packet was found + + // Operations +public: + int Type() const { return (m_Did & 0x80)==0 ? 2 : 1; } + +public: + DtMxAncPacket(); + virtual ~DtMxAncPacket(); +private: + DtMxAncPacket(const DtMxAncPacket&); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAudioChannelStatus -.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxAudioChannelStatus +{ +public: + // Get or set the sampling rate in Hz. + DTAPI_RESULT GetSampleRate(int& SampleRate); + DTAPI_RESULT SetSampleRate(int SampleRate); + // Get or set whether the channel contains linear audio PCM data or something else. + DTAPI_RESULT GetPcmAudio(bool& IsPcm); + DTAPI_RESULT SetPcmAudio(bool IsPcm); + // Get or set the the significant and maximum number of bits + DTAPI_RESULT GetPcmNumBits(int& NumBits, int& NumAuxBits); + DTAPI_RESULT SetPcmNumBits(int NumBits, int NumAuxBits=0); + + unsigned char m_Data[24]; // Raw AES3 channel-status word data. + bool m_Valid; // True, if channel status word has been initialised + + DtMxAudioChannelStatus(); + virtual ~DtMxAudioChannelStatus(); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAudioChannel -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxAudioChannel +{ +public: + int m_Index; // Index of this channel in underlaying AV format. + bool m_Present; // True if this channel was actually present in the + // input frame. + int m_Service; // Index in m_Services vector for the service this + // channel is a part of. + + unsigned int* m_pBuf; // Buffer with audio samples + int m_BufSizeSamples; // Total size of buffer (in #samples) + int m_NumValidSamples; // Number of valid samples inside buffer + + DtMxAudioChannelStatus m_Status; // AES3 status word; + + const int m_NumSamplesHint; // Suggested number of audio samples for this frame. + // This is based on the audio frame number. + const DtMxAudioSampleType m_Format; // Format of audio samples: PCM32 or AES + + // Constructor, destructor +public: + DtMxAudioChannel(); + virtual ~DtMxAudioChannel(); + DtMxAudioChannel& operator=(const DtMxAudioChannel& Other); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxAudioServiceType -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +enum DtMxAudioServiceType +{ + DT_AUDIOSERVICE_UNKNOWN, + DT_AUDIOSERVICE_MONO, + DT_AUDIOSERVICE_DUAL_MONO, + DT_AUDIOSERVICE_STEREO, + DT_AUDIOSERVICE_5_1, +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtFixedVector -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Represents a vector which has a fixed size (i.e. cannot add or remove elements) +// +template +class DtFixedVector +{ + // Operations +public: + bool empty() const { return m_Data.empty(); } + size_t size() const { return m_Data.size(); } + T& operator[](size_t n) { return m_Data[n]; } +protected: + // Cast to a "normal" std::vector. NOTE: Intended for internal DTAPI use only + inline operator typename std::vector& () { return m_Data; } + inline DtFixedVector& operator=(const DtFixedVector& Oth) + { + this->m_Data = Oth.m_Data; + return *this; + } + + // Data / Attributes +private: + std::vector m_Data; // Actual std::vector with the data + + // Constructor / Desstructor +public: + DtFixedVector() {} + virtual ~DtFixedVector() {} +protected: + DtFixedVector(size_t Size) { m_Data.resize(Size); } + DtFixedVector(const DtFixedVector& Oth) { *this= Oth; } + + // Friends +private: + friend class MxFrameImpl; + friend class MxCommonData; + friend class MxDecData; + friend class MxActionAncEnc; + friend class MxProcessImpl; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAudioService -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxAudioService +{ +public: + bool m_Valid; // Indicates whether or not this is a valid entry + DtMxAudioServiceType m_ServiceType; // Type of service: mono, stereo, 5.1 etc. + std::vector m_Channels; // Indices of channels that are part of this service + int m_PcmNumBits; // For PCM samples only: number of significant bits + bool m_ContainsData; // For AES only: true if data, false if PCM samples + int m_SampleRate; // Sample rate of audio channels + const int m_SamplesInFrame; // Number of samples in the current frame + //double m_SamplePhase; // Phase of the first audio sample + int m_AudioFrameNumber; // Indicates where we are in the audio frame + // sequence frame + + // Constructor, destructor +public: + DtMxAudioService(); + DtMxAudioService& operator=(const DtMxAudioService& Other); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxAudioData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +class DtMxAudioData +{ +public: + DtFixedVector m_Channels; + DtFixedVector m_Services; + + // Utility function to make the AES3 status word consistent with the members in this + // struct. It's recommended to call this after modifying any members to make sure + // the final output is consistent. + DTAPI_RESULT InitChannelStatus(); + DTAPI_RESULT InitChannelStatus(const DtMxAudioService& Service); +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxFrameStatus -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +enum DtMxFrameStatus +{ + DT_FRMSTATUS_OK, // Frame has been received and decoded without problems + DT_FRMSTATUS_SKIPPED, // Row has been received and decoded but the callback + // function was never called. This will only be set + // for historic buffers, never for the current + // frame buffer. + DT_FRMSTATUS_DISABLED, // Row has been disabled, buffers not available. + DT_FRMSTATUS_DUPLICATE, // Frame data is duplicated from previous frame + // because the input was too slow. + DT_FRMSTATUS_DROPPED, // Frame data was dropped because the input thread + // in the API was too slow. Data is not available. This + // should never happen under normal circumstances. + DT_FRMSTATUS_NO_SIGNAL, // No signal at input port. Frame data not available. + DT_FRMSTATUS_WRONG_VIDSTD, // Unconfigured video signal at input. Frame data + // not available. + DT_FRMSTATUS_DEV_DISCONNECTED, // Input (usb) device has been disconnected. Frame data + // not available. + DT_FRMSTATUS_ERROR_INTERNAL, // Internal error. Frame data is not available. +}; + +//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxFrame -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Data buffers for a single frame. Can be used for input, for output or be shared +// between input and output. +// +class DtMxFrame +{ +public: + const DtMxRowConfig* const m_Config; + // Row configuration at the time the frame processing + // was started by the HLM. + + // Status of this frame. DT_FRMSTATUS_DISABLED overrules all other status fields. + // For output-only rows this will always be DT_FRMSTATUS_OK or DT_FRMSTATUS_DISABLED. + // For input/output and output-only rows the data buffers requested will always be + // available if m_Status is not DT_FRMSTATUS_DISABLED. + DtMxFrameStatus m_Status; + + // Configured video standard, or for fixed-rate rows the actual received rate. + // For fixed rate output rows this has to be set by callback. + int m_VidStd; + + // For input and input/output rows this can contain a pointer to the data of an input + // frame that was received before this frame but not processed to maintain clock sync. + // Normally this is a NULL pointer, but if the input is faster than the HLM clock + // occasionally a frame needs to be dropped to keep the system in sync. By providing + // a pointer to the data of the dropped frame the callback might be able to prevent + // audio hickups. + // For each frame processed by the callback function there will be at most one + // dropped frame due to different clocks, so this->m_DroppedFrame->m_DroppedFrame is + // always NULL. + DtMxFrame* m_DroppedFrame; + + bool m_InpPhaseValid; // True if m_InpPhase contains a valid value. + double m_InpPhase; // Phase of this input relative to the HLM clock source. + // In a genlocked system this should be approximately + // zero. In a non-genlocked system the HLM will try + // to keep it between -1.25 and 0.05. A frame drop will + // increase this value by 1. + + bool m_RawTimestampValid; // True if m_RawTimestamp is valid + __int64 m_RawTimestamp; // 64-bit timestamp of the arrival of the SDI frame. + // Timestamps created by different hardware devices have + // no relation to eachother. + + // Raw data buffer + bool m_RawDataValid; // True, if the raw data is valid; False if invalid + DtMxRawData m_RawData; + // Video buffers for field 1 and 2 + bool m_VideoValid; // True, if the video data is valid; False if invalid + DtMxVideoBuf m_Video[2]; + // Audio data + bool m_AudioValid; // True, if the audio data is valid; False if invalid + DtMxAudioData m_Audio; + // Auxiliary data + bool m_AuxDataValid; // True, if the aux data is valid; False if invalid + DtMxAuxData m_AuxData; + + // Access functions for raw ANC packets + virtual DTAPI_RESULT AncAddPacket(DtMxAncPacket& AncPacket, int HancVanc, + int Stream, int Link=-1) = 0; + virtual DTAPI_RESULT AncDelPacket(int Did, int Sdid, int StartLine, + int NumLines, int HancVanc, int Stream, int Mode, int Link=-1) = 0; + virtual DTAPI_RESULT AncGetPacket(int Did, int Sdid, DtMxAncPacket*, int& NumPackets, + int HancVanc, int Stream, int Link=-1) = 0; + + // Constructor, destructor +protected: + DtMxFrame(); + virtual ~DtMxFrame(); +private: + // No implementation is provided for the copy constructor or for operator= + DtMxFrame(const DtMxFrame&); + DtMxFrame& operator=(const DtMxFrame&); +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxRowData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxRowData +{ +public: + // Pointer to current frame. This is the only read/write buffer, all other buffers + // are read-only. + DtMxFrame* m_CurFrame; + + // m_Hist.size() == RowSize-1 + // m_Hist[0] is the previous frame, m_Hist[1] the one before that etc. + std::vector m_Hist; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxData -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Top-level data class for the user callback function. +// +class DtMxData +{ +public: + __int64 m_Frame; // Frame counter. Increases by 1 for every frame the + // matrix clock source processes. + int m_Phase; // Current phase (0..NumPhases-1). Each callback function + // can run up to NumPhases time in parallel, each of them + // will be called with a different value in m_Phase. + int m_NumSkippedFrames; // Error counter, will normally be 0. If due to a timeout + // the matrix API has to skip the callback processing of + // a number of frames, it'll indicate it here in the data + // of the next processed frame. + DtFixedVector m_Rows; // Data per row + + // Constructor, destructor +public: + DtMxData(); + virtual ~DtMxData(); +}; + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ MATRIX CONTROL +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxPort -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// The DtMxPort is used as abstraction for one logical input or output. Often this +// maps 1-to-1 to one physical output port, but other mappings are possible as well. +// 4K-video over SDI can be transported over 4x3G links for example, creating +// a 1 logical to 4 physical ports mapping. +// +// Example for single-port: +// Matrix.AttachToInput(0, DtMxPort(&Dvc, 1)); +// +// Example for 4K (Assuming DtDevice Dvc; which is attached to DTA-2174): +// DtMxPort Port4k(DTAPI_VIDSTD_2160P60, DTAPI_LINK_4K_SMPTE425); +// Port4k.AddPhysicalPort(&Dvc, 1); +// Port4k.AddPhysicalPort(&Dvc, 2); +// Port4k.AddPhysicalPort(&Dvc, 3); +// Port4k.AddPhysicalPort(&Dvc, 4); +// Matrix.AttachToOutput(0, Port4k, 3); +// +// 3G over 1x3G-SDI link: +// DtMxPort Port3G1(DTAPI_VIDSTD_1080P60); +// Port3G1.AddPhysicalPort(&Dvc, 1); +// Alternatively "DtMxPort Port3G;" is enough, VidStd can be determined +// from the IoConfig. +// +// 3G over 2xHD-SDI links (NOT SUPPORTED): +// DtMxPort Port3G2(DTAPI_VIDSTD_1080P60, DTAPI_LINK_3G_SMPTE372); +// Port3G2.AddPhysicalPort(&Dvc, 1); +// Port3G2.AddPhysicalPort(&Dvc, 2); +// +// After Matrix.AttachToInput() / Matrix.AttachToOutput() it's completely transparent +// whether Port3G1 or Port3G2 is used. Both support exactly the same data and filtering, +// the matrix API will take care of splitting over 1 or multiple physical links. +// +class DtMxPort +{ +public: + // 1. Constructor that doesn't link to a physical port yet. + DtMxPort(); + // 2. Constructor that links to a single physical port. Video standard and + // link standard are not explicitly set and will be determined from IOConfig. + DtMxPort(DtDevice*, int Port, int ClockPriority=0); + // 3. Constructor that initializes the object for a multi-link structure. + DtMxPort(int VidStd, int LinkStd); + // 4. Copy constructor + DtMxPort(const DtMxPort&); + // Destructor + virtual ~DtMxPort(); + // Assignment operator + DtMxPort& operator=(const DtMxPort&); + + DTAPI_RESULT AddPhysicalPort(DtDevice*, int Port, int ClockPriority=0); + +private: + class MxPortImpl* m_pImpl; + friend class DtMxProcess; +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMxProcFrameFunc -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +// Signature of a user-defined matrix callback function. +// +typedef void DtMxProcFrameFunc(DtMxData* pData, void* pOpaque); + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtMxVidBufFreeCallback -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +// Signature of callback function that will be called by the HLM to free user-provided +// video buffers. +// +typedef void DtMxVidBufFreeCallback(void* pMem, void* pOpaque); + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- enum DtMxClockMode -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. +// +enum DtMxClockMode +{ + DT_MXCLOCK_AUTO, // Default, HLM internally picks a device as clock source + DT_MXCLOCK_PCR_TIME_ACC, // HLM changes internal clock source based on PCR samples + // provided by user. Each PCR sample is accurately + // timestamped (by using transparent input mode on + // a DekTec device). + DT_MXCLOCK_PCR_TIME_IP, // HLM changes internal clock source based on PCR samples + // provided by user. The PCR samples do not have an + // accurate timestamp, so HLM will adjust the internal + // clock very slowly. + DT_MXCLOCK_SW_FIFO, // User provides timestamped Fifo-loads. HLM controls the + // clock so that the average fifo load remains the same. +}; + + +// Affinity masks for several threads. Each can be set to 0 to disable them. +class DtMxCpuAffinity +{ +public: + unsigned int m_Default; // Mask for all other threads + unsigned int m_Dma; // Mask for DMA threads + unsigned int m_Decode; // Mask for decode threads + unsigned int m_Encode; // Mask for encode threads +}; + +//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- class DtMxProcess -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- +// +class DtMxProcess +{ +public: + // The matrix process has 2 states: IDLE and RUNNING. You can switch between those + // states by calling Start() and Stop(). Most functions can only be called in IDLE and + // will return immediately with an error if called in RUN mode. + + // Register a new callback function that will be called by the framework whenever + // a new frame is ready for processing. + DTAPI_RESULT AddMatrixCbFunc(DtMxProcFrameFunc* pFunc, void* pOpaque); + + // Reset complete matrix process. The following things will be done: + // 1. Detach all attached ports. + // 2. Set NumPhases to default value. + // 3. Clear any configuration done via SetRowConfig() + // 4. Set end-to-end delay to default. + // 5. Remove all callbacks. + DTAPI_RESULT Reset(); + + // The matrix can have any number of rows (limited by system resources). Row numbers + // start with 0 and go up to N-1 (where N=number of rows). Rows can be attached to + // ports in any order, it's not required to start with row 0. + // Each row can be attached to: + // - 1 input port + // - 1 or more output ports + // - 1 input port and 1 or more output ports + DTAPI_RESULT AttachRowToInput(int Row, const DtMxPort& Port); + DTAPI_RESULT AttachRowToOutput(int Row, const DtMxPort& Port, int ExtraOutDelay=0); + + // Change the way the HLM clock source is controlled. + DTAPI_RESULT SetClockControl(DtMxClockMode ClockMode, DtDevice* pDvc=NULL, + int AvgFifoLoad=-1); + + // Can be called by the user while the matrix process is running. HLM will keep + // track of a number of these samples and will adjust it's clock source so the + // output rate is matched to the provided samples. + DTAPI_RESULT NewClockSample(__int64 PcrOrFifoLoad, int RefClkCnt); + + // Changes the number of phases. Global setting per matrix. + DTAPI_RESULT SetNumPhases(int NumPhases); + + // SetRowConfig sets the configuration and validates if it is possible valid. Not all + // errors can be caught at this time since some depend on the video standard (for + // example DtMxVideoConfig::m_NumLines1 if not equal to -1). + // SetRowConfig(Row) is only valid after AttachToInput(Row)/AttachToOutput(Row) has + // been called and will return an error otherwise. + DTAPI_RESULT SetRowConfig(int Row, const DtMxRowConfig& Config); + + // Function to change the video standard for all ports attached to the given row. + DTAPI_RESULT SetVidStd(int Row, int VidStd); + + // Set a callback function the framework can use to free user-provided video buffers. + DTAPI_RESULT SetVidBufFreeCb(DtMxVidBufFreeCallback* pFunc); + + // Get the minimum/default end-to-end delay. CbFrames will be an approximation + // of the time the user callback function has relative to the time of a complete + // frame. GetDefEndToEndDelay() will return a value: CbFrames >= NumPhases. + // GetMinEndToEndDelay() will return a value: NumPhases-1 < CbFrames <= NumPhases. + DTAPI_RESULT GetMinEndToEndDelay(int& Delay, double& CbFrames); + DTAPI_RESULT GetDefEndToEndDelay(int& Delay, double& CbFrames); + DTAPI_RESULT SetEndToEndDelay(int Delay); + + // Makes sure the configuration of all rows and global matrix settings is consistent. + // If it is, start the matrix process. + DTAPI_RESULT Start(); + // Stop a runnig matrix process and return to IDLE. + DTAPI_RESULT Stop(); + + DTAPI_RESULT SetThreadAffinity(const DtMxCpuAffinity& Affinity); + + //TODO: add function to initialize "error-frame" for input/output and output rows. + // This error-frame can be played out during the first few frames when there is + // no data available yet and when the input is stalled and configuration requests it. + + // Print profiling information collected while the matrix was running + DTAPI_RESULT PrintProfilingInfo(); + + // Implementation data +private: + class MxProcessImpl* m_pImpl; + + // Constructor, destructor +public: + DtMxProcess(); + ~DtMxProcess(); +private: + // No implementation is provided for the copy constructor or for operator= + DtMxProcess(const DtMxProcess&); + DtMxProcess& operator=(const DtMxProcess&); +}; + + +} // namespace Dtapi + +#ifndef _NO_USING_NAMESPACE_DTAPI +using namespace Dtapi; +#endif + +#endif //#ifndef __DTAPI_H + diff --git a/extra_lib/include/ffmpeg_android/libavcodec/avcodec.h b/extra_lib/include/ffmpeg_android/libavcodec/avcodec.h index add4b10..fb1c9ca 100644 --- a/extra_lib/include/ffmpeg_android/libavcodec/avcodec.h +++ b/extra_lib/include/ffmpeg_android/libavcodec/avcodec.h @@ -22,33 +22,74 @@ #define AVCODEC_AVCODEC_H /** - * @file libavcodec/avcodec.h - * external API header + * @file + * @ingroup libavc + * Libavcodec external API header */ #include +#include "libavutil/samplefmt.h" +#include "libavutil/attributes.h" #include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/cpu.h" +#include "libavutil/channel_layout.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "version.h" + +#if FF_API_FAST_MALLOC +// to provide fast_*alloc +#include "libavutil/mem.h" +#endif -#define LIBAVCODEC_VERSION_MAJOR 52 -#define LIBAVCODEC_VERSION_MINOR 66 -#define LIBAVCODEC_VERSION_MICRO 0 - -#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ - LIBAVCODEC_VERSION_MINOR, \ - LIBAVCODEC_VERSION_MICRO) -#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ - LIBAVCODEC_VERSION_MINOR, \ - LIBAVCODEC_VERSION_MICRO) -#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT +/** + * @defgroup libavc Encoding/Decoding Library + * @{ + * + * @defgroup lavc_decoding Decoding + * @{ + * @} + * + * @defgroup lavc_encoding Encoding + * @{ + * @} + * + * @defgroup lavc_codec Codecs + * @{ + * @defgroup lavc_codec_native Native Codecs + * @{ + * @} + * @defgroup lavc_codec_wrappers External library wrappers + * @{ + * @} + * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge + * @{ + * @} + * @} + * @defgroup lavc_internal Internal + * @{ + * @} + * @} + * + */ -#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) +/** + * @defgroup lavc_core Core functions/structures. + * @ingroup libavc + * + * Basic definitions, functions for querying libavcodec capabilities, + * allocating core structures, etc. + * @{ + */ -#define AV_NOPTS_VALUE INT64_C(0x8000000000000000) -#define AV_TIME_BASE 1000000 -#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE} /** - * Identifies the syntax and semantics of the bitstream. + * Identify the syntax and semantics of the bitstream. * The principle is roughly: * Two decoders with the same ID can decode the same streams. * Two encoders with the same ID can encode compatible streams. @@ -57,387 +98,536 @@ * * If you add a codec ID to this list, add it so that * 1. no value of a existing codec ID changes (that would break ABI), - * 2. it is as close as possible to similar codecs. + * 2. Give it a value which when taken as ASCII is recognized uniquely by a human as this specific codec. + * This ensures that 2 forks can independently add AVCodecIDs without producing conflicts. + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. */ -enum CodecID { - CODEC_ID_NONE, +enum AVCodecID { + AV_CODEC_ID_NONE, /* video codecs */ - CODEC_ID_MPEG1VIDEO, - CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding - CODEC_ID_MPEG2VIDEO_XVMC, - CODEC_ID_H261, - CODEC_ID_H263, - CODEC_ID_RV10, - CODEC_ID_RV20, - CODEC_ID_MJPEG, - CODEC_ID_MJPEGB, - CODEC_ID_LJPEG, - CODEC_ID_SP5X, - CODEC_ID_JPEGLS, - CODEC_ID_MPEG4, - CODEC_ID_RAWVIDEO, - CODEC_ID_MSMPEG4V1, - CODEC_ID_MSMPEG4V2, - CODEC_ID_MSMPEG4V3, - CODEC_ID_WMV1, - CODEC_ID_WMV2, - CODEC_ID_H263P, - CODEC_ID_H263I, - CODEC_ID_FLV1, - CODEC_ID_SVQ1, - CODEC_ID_SVQ3, - CODEC_ID_DVVIDEO, - CODEC_ID_HUFFYUV, - CODEC_ID_CYUV, - CODEC_ID_H264, - CODEC_ID_INDEO3, - CODEC_ID_VP3, - CODEC_ID_THEORA, - CODEC_ID_ASV1, - CODEC_ID_ASV2, - CODEC_ID_FFV1, - CODEC_ID_4XM, - CODEC_ID_VCR1, - CODEC_ID_CLJR, - CODEC_ID_MDEC, - CODEC_ID_ROQ, - CODEC_ID_INTERPLAY_VIDEO, - CODEC_ID_XAN_WC3, - CODEC_ID_XAN_WC4, - CODEC_ID_RPZA, - CODEC_ID_CINEPAK, - CODEC_ID_WS_VQA, - CODEC_ID_MSRLE, - CODEC_ID_MSVIDEO1, - CODEC_ID_IDCIN, - CODEC_ID_8BPS, - CODEC_ID_SMC, - CODEC_ID_FLIC, - CODEC_ID_TRUEMOTION1, - CODEC_ID_VMDVIDEO, - CODEC_ID_MSZH, - CODEC_ID_ZLIB, - CODEC_ID_QTRLE, - CODEC_ID_SNOW, - CODEC_ID_TSCC, - CODEC_ID_ULTI, - CODEC_ID_QDRAW, - CODEC_ID_VIXL, - CODEC_ID_QPEG, -#if LIBAVCODEC_VERSION_MAJOR < 53 - CODEC_ID_XVID, -#endif - CODEC_ID_PNG, - CODEC_ID_PPM, - CODEC_ID_PBM, - CODEC_ID_PGM, - CODEC_ID_PGMYUV, - CODEC_ID_PAM, - CODEC_ID_FFVHUFF, - CODEC_ID_RV30, - CODEC_ID_RV40, - CODEC_ID_VC1, - CODEC_ID_WMV3, - CODEC_ID_LOCO, - CODEC_ID_WNV1, - CODEC_ID_AASC, - CODEC_ID_INDEO2, - CODEC_ID_FRAPS, - CODEC_ID_TRUEMOTION2, - CODEC_ID_BMP, - CODEC_ID_CSCD, - CODEC_ID_MMVIDEO, - CODEC_ID_ZMBV, - CODEC_ID_AVS, - CODEC_ID_SMACKVIDEO, - CODEC_ID_NUV, - CODEC_ID_KMVC, - CODEC_ID_FLASHSV, - CODEC_ID_CAVS, - CODEC_ID_JPEG2000, - CODEC_ID_VMNC, - CODEC_ID_VP5, - CODEC_ID_VP6, - CODEC_ID_VP6F, - CODEC_ID_TARGA, - CODEC_ID_DSICINVIDEO, - CODEC_ID_TIERTEXSEQVIDEO, - CODEC_ID_TIFF, - CODEC_ID_GIF, - CODEC_ID_FFH264, - CODEC_ID_DXA, - CODEC_ID_DNXHD, - CODEC_ID_THP, - CODEC_ID_SGI, - CODEC_ID_C93, - CODEC_ID_BETHSOFTVID, - CODEC_ID_PTX, - CODEC_ID_TXD, - CODEC_ID_VP6A, - CODEC_ID_AMV, - CODEC_ID_VB, - CODEC_ID_PCX, - CODEC_ID_SUNRAST, - CODEC_ID_INDEO4, - CODEC_ID_INDEO5, - CODEC_ID_MIMIC, - CODEC_ID_RL2, - CODEC_ID_8SVX_EXP, - CODEC_ID_8SVX_FIB, - CODEC_ID_ESCAPE124, - CODEC_ID_DIRAC, - CODEC_ID_BFI, - CODEC_ID_CMV, - CODEC_ID_MOTIONPIXELS, - CODEC_ID_TGV, - CODEC_ID_TGQ, - CODEC_ID_TQI, - CODEC_ID_AURA, - CODEC_ID_AURA2, - CODEC_ID_V210X, - CODEC_ID_TMV, - CODEC_ID_V210, - CODEC_ID_DPX, - CODEC_ID_MAD, - CODEC_ID_FRWU, - CODEC_ID_FLASHSV2, - CODEC_ID_CDGRAPHICS, - CODEC_ID_R210, - CODEC_ID_ANM, - CODEC_ID_BINKVIDEO, - CODEC_ID_IFF_ILBM, - CODEC_ID_IFF_BYTERUN1, - CODEC_ID_KGV1, - CODEC_ID_YOP, + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + AV_CODEC_ID_MPEG2VIDEO_XVMC, +#endif /* FF_API_XVMC */ + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, + AV_CODEC_ID_IFF_BYTERUN1, + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130_DEPRECATED, + AV_CODEC_ID_G2M_DEPRECATED, + AV_CODEC_ID_WEBP_DEPRECATED, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC_DEPRECATED, + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX_DEPRECATED, + AV_CODEC_ID_PAF_VIDEO_DEPRECATED, + AV_CODEC_ID_EXR_DEPRECATED, + AV_CODEC_ID_VP7_DEPRECATED, + AV_CODEC_ID_SANM_DEPRECATED, + AV_CODEC_ID_SGIRLE_DEPRECATED, + AV_CODEC_ID_MVC1_DEPRECATED, + AV_CODEC_ID_MVC2_DEPRECATED, + + AV_CODEC_ID_BRENDER_PIX= MKBETAG('B','P','I','X'), + AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), + AV_CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'), + AV_CODEC_ID_EXR = MKBETAG('0','E','X','R'), + AV_CODEC_ID_AVRP = MKBETAG('A','V','R','P'), + + AV_CODEC_ID_012V = MKBETAG('0','1','2','V'), + AV_CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'), + AV_CODEC_ID_AVUI = MKBETAG('A','V','U','I'), + AV_CODEC_ID_AYUV = MKBETAG('A','Y','U','V'), + AV_CODEC_ID_TARGA_Y216 = MKBETAG('T','2','1','6'), + AV_CODEC_ID_V308 = MKBETAG('V','3','0','8'), + AV_CODEC_ID_V408 = MKBETAG('V','4','0','8'), + AV_CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'), + AV_CODEC_ID_SANM = MKBETAG('S','A','N','M'), + AV_CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'), + AV_CODEC_ID_AVRN = MKBETAG('A','V','R','n'), + AV_CODEC_ID_CPIA = MKBETAG('C','P','I','A'), + AV_CODEC_ID_XFACE = MKBETAG('X','F','A','C'), + AV_CODEC_ID_SGIRLE = MKBETAG('S','G','I','R'), + AV_CODEC_ID_MVC1 = MKBETAG('M','V','C','1'), + AV_CODEC_ID_MVC2 = MKBETAG('M','V','C','2'), + AV_CODEC_ID_SNOW = MKBETAG('S','N','O','W'), + AV_CODEC_ID_WEBP = MKBETAG('W','E','B','P'), + AV_CODEC_ID_SMVJPEG = MKBETAG('S','M','V','J'), + AV_CODEC_ID_HEVC = MKBETAG('H','2','6','5'), +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_VP7 = MKBETAG('V','P','7','0'), /* various PCM "codecs" */ - CODEC_ID_PCM_S16LE= 0x10000, - CODEC_ID_PCM_S16BE, - CODEC_ID_PCM_U16LE, - CODEC_ID_PCM_U16BE, - CODEC_ID_PCM_S8, - CODEC_ID_PCM_U8, - CODEC_ID_PCM_MULAW, - CODEC_ID_PCM_ALAW, - CODEC_ID_PCM_S32LE, - CODEC_ID_PCM_S32BE, - CODEC_ID_PCM_U32LE, - CODEC_ID_PCM_U32BE, - CODEC_ID_PCM_S24LE, - CODEC_ID_PCM_S24BE, - CODEC_ID_PCM_U24LE, - CODEC_ID_PCM_U24BE, - CODEC_ID_PCM_S24DAUD, - CODEC_ID_PCM_ZORK, - CODEC_ID_PCM_S16LE_PLANAR, - CODEC_ID_PCM_DVD, - CODEC_ID_PCM_F32BE, - CODEC_ID_PCM_F32LE, - CODEC_ID_PCM_F64BE, - CODEC_ID_PCM_F64LE, - CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR_DEPRECATED, + AV_CODEC_ID_PCM_S32LE_PLANAR_DEPRECATED, + AV_CODEC_ID_PCM_S24LE_PLANAR = MKBETAG(24,'P','S','P'), + AV_CODEC_ID_PCM_S32LE_PLANAR = MKBETAG(32,'P','S','P'), + AV_CODEC_ID_PCM_S16BE_PLANAR = MKBETAG('P','S','P',16), /* various ADPCM codecs */ - CODEC_ID_ADPCM_IMA_QT= 0x11000, - CODEC_ID_ADPCM_IMA_WAV, - CODEC_ID_ADPCM_IMA_DK3, - CODEC_ID_ADPCM_IMA_DK4, - CODEC_ID_ADPCM_IMA_WS, - CODEC_ID_ADPCM_IMA_SMJPEG, - CODEC_ID_ADPCM_MS, - CODEC_ID_ADPCM_4XM, - CODEC_ID_ADPCM_XA, - CODEC_ID_ADPCM_ADX, - CODEC_ID_ADPCM_EA, - CODEC_ID_ADPCM_G726, - CODEC_ID_ADPCM_CT, - CODEC_ID_ADPCM_SWF, - CODEC_ID_ADPCM_YAMAHA, - CODEC_ID_ADPCM_SBPRO_4, - CODEC_ID_ADPCM_SBPRO_3, - CODEC_ID_ADPCM_SBPRO_2, - CODEC_ID_ADPCM_THP, - CODEC_ID_ADPCM_IMA_AMV, - CODEC_ID_ADPCM_EA_R1, - CODEC_ID_ADPCM_EA_R3, - CODEC_ID_ADPCM_EA_R2, - CODEC_ID_ADPCM_IMA_EA_SEAD, - CODEC_ID_ADPCM_IMA_EA_EACS, - CODEC_ID_ADPCM_EA_XAS, - CODEC_ID_ADPCM_EA_MAXIS_XA, - CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA_DEPRECATED, + AV_CODEC_ID_ADPCM_VIMA = MKBETAG('V','I','M','A'), + AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'), + AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '), + AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '), + AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '), + AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '), + AV_CODEC_ID_ADPCM_G726LE = MKBETAG('6','2','7','G'), /* AMR */ - CODEC_ID_AMR_NB= 0x12000, - CODEC_ID_AMR_WB, + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, /* RealAudio codecs*/ - CODEC_ID_RA_144= 0x13000, - CODEC_ID_RA_288, + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, /* various DPCM codecs */ - CODEC_ID_ROQ_DPCM= 0x14000, - CODEC_ID_INTERPLAY_DPCM, - CODEC_ID_XAN_DPCM, - CODEC_ID_SOL_DPCM, + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, /* audio codecs */ - CODEC_ID_MP2= 0x15000, - CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 - CODEC_ID_AAC, - CODEC_ID_AC3, - CODEC_ID_DTS, - CODEC_ID_VORBIS, - CODEC_ID_DVAUDIO, - CODEC_ID_WMAV1, - CODEC_ID_WMAV2, - CODEC_ID_MACE3, - CODEC_ID_MACE6, - CODEC_ID_VMDAUDIO, - CODEC_ID_SONIC, - CODEC_ID_SONIC_LS, - CODEC_ID_FLAC, - CODEC_ID_MP3ADU, - CODEC_ID_MP3ON4, - CODEC_ID_SHORTEN, - CODEC_ID_ALAC, - CODEC_ID_WESTWOOD_SND1, - CODEC_ID_GSM, ///< as in Berlin toast format - CODEC_ID_QDM2, - CODEC_ID_COOK, - CODEC_ID_TRUESPEECH, - CODEC_ID_TTA, - CODEC_ID_SMACKAUDIO, - CODEC_ID_QCELP, - CODEC_ID_WAVPACK, - CODEC_ID_DSICINAUDIO, - CODEC_ID_IMC, - CODEC_ID_MUSEPACK7, - CODEC_ID_MLP, - CODEC_ID_GSM_MS, /* as found in WAV */ - CODEC_ID_ATRAC3, - CODEC_ID_VOXWARE, - CODEC_ID_APE, - CODEC_ID_NELLYMOSER, - CODEC_ID_MUSEPACK8, - CODEC_ID_SPEEX, - CODEC_ID_WMAVOICE, - CODEC_ID_WMAPRO, - CODEC_ID_WMALOSSLESS, - CODEC_ID_ATRAC3P, - CODEC_ID_EAC3, - CODEC_ID_SIPR, - CODEC_ID_MP1, - CODEC_ID_TWINVQ, - CODEC_ID_TRUEHD, - CODEC_ID_MP4ALS, - CODEC_ID_ATRAC1, - CODEC_ID_BINKAUDIO_RDFT, - CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, +#if FF_API_VOXWARE + AV_CODEC_ID_VOXWARE, +#endif + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS_DEPRECATED, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK_DEPRECATED, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO_DEPRECATED, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'), + AV_CODEC_ID_SONIC = MKBETAG('S','O','N','C'), + AV_CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'), + AV_CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'), + AV_CODEC_ID_OPUS = MKBETAG('O','P','U','S'), + AV_CODEC_ID_TAK = MKBETAG('t','B','a','K'), + AV_CODEC_ID_EVRC = MKBETAG('s','e','v','c'), + AV_CODEC_ID_SMV = MKBETAG('s','s','m','v'), + AV_CODEC_ID_DSD_LSBF = MKBETAG('D','S','D','L'), + AV_CODEC_ID_DSD_MSBF = MKBETAG('D','S','D','M'), + AV_CODEC_ID_DSD_LSBF_PLANAR = MKBETAG('D','S','D','1'), + AV_CODEC_ID_DSD_MSBF_PLANAR = MKBETAG('D','S','D','8'), /* subtitle codecs */ - CODEC_ID_DVD_SUBTITLE= 0x17000, - CODEC_ID_DVB_SUBTITLE, - CODEC_ID_TEXT, ///< raw UTF-8 text - CODEC_ID_XSUB, - CODEC_ID_SSA, - CODEC_ID_MOV_TEXT, - CODEC_ID_HDMV_PGS_SUBTITLE, - CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + AV_CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'), + AV_CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'), + AV_CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'), + AV_CODEC_ID_SAMI = MKBETAG('S','A','M','I'), + AV_CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'), + AV_CODEC_ID_SUBVIEWER1 = MKBETAG('S','b','V','1'), + AV_CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'), + AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'), + AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'), + AV_CODEC_ID_MPL2 = MKBETAG('M','P','L','2'), + AV_CODEC_ID_VPLAYER = MKBETAG('V','P','l','r'), + AV_CODEC_ID_PJS = MKBETAG('P','h','J','S'), + AV_CODEC_ID_ASS = MKBETAG('A','S','S',' '), ///< ASS as defined in Matroska /* other specific kind of codecs (generally used for attachments) */ - CODEC_ID_TTF= 0x18000, + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + AV_CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'), + AV_CODEC_ID_XBIN = MKBETAG('X','B','I','N'), + AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), + AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), + AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'), + AV_CODEC_ID_DVD_NAV = MKBETAG('D','N','A','V'), + AV_CODEC_ID_TIMED_ID3 = MKBETAG('T','I','D','3'), + AV_CODEC_ID_BIN_DATA = MKBETAG('D','A','T','A'), - CODEC_ID_PROBE= 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it - CODEC_ID_MPEG2TS= 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS - * stream (only used by libavformat) */ -}; + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it -#if LIBAVCODEC_VERSION_MAJOR < 53 -#define CodecType AVMediaType + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. -#define CODEC_TYPE_UNKNOWN AVMEDIA_TYPE_UNKNOWN -#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO -#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO -#define CODEC_TYPE_DATA AVMEDIA_TYPE_DATA -#define CODEC_TYPE_SUBTITLE AVMEDIA_TYPE_SUBTITLE -#define CODEC_TYPE_ATTACHMENT AVMEDIA_TYPE_ATTACHMENT -#define CODEC_TYPE_NB AVMEDIA_TYPE_NB +#if FF_API_CODEC_ID +#include "old_codec_ids.h" #endif +}; /** - * all in native-endian format + * This struct describes the properties of a single codec described by an + * AVCodecID. + * @see avcodec_get_descriptor() */ -enum SampleFormat { - SAMPLE_FMT_NONE = -1, - SAMPLE_FMT_U8, ///< unsigned 8 bits - SAMPLE_FMT_S16, ///< signed 16 bits - SAMPLE_FMT_S32, ///< signed 32 bits - SAMPLE_FMT_FLT, ///< float - SAMPLE_FMT_DBL, ///< double - SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if dynamically linking to libavcodec -}; +typedef struct AVCodecDescriptor { + enum AVCodecID id; + enum AVMediaType type; + /** + * Name of the codec described by this descriptor. It is non-empty and + * unique for each codec descriptor. It should contain alphanumeric + * characters and '_' only. + */ + const char *name; + /** + * A more descriptive name for this codec. May be NULL. + */ + const char *long_name; + /** + * Codec properties, a combination of AV_CODEC_PROP_* flags. + */ + int props; -/* Audio channel masks */ -#define CH_FRONT_LEFT 0x00000001 -#define CH_FRONT_RIGHT 0x00000002 -#define CH_FRONT_CENTER 0x00000004 -#define CH_LOW_FREQUENCY 0x00000008 -#define CH_BACK_LEFT 0x00000010 -#define CH_BACK_RIGHT 0x00000020 -#define CH_FRONT_LEFT_OF_CENTER 0x00000040 -#define CH_FRONT_RIGHT_OF_CENTER 0x00000080 -#define CH_BACK_CENTER 0x00000100 -#define CH_SIDE_LEFT 0x00000200 -#define CH_SIDE_RIGHT 0x00000400 -#define CH_TOP_CENTER 0x00000800 -#define CH_TOP_FRONT_LEFT 0x00001000 -#define CH_TOP_FRONT_CENTER 0x00002000 -#define CH_TOP_FRONT_RIGHT 0x00004000 -#define CH_TOP_BACK_LEFT 0x00008000 -#define CH_TOP_BACK_CENTER 0x00010000 -#define CH_TOP_BACK_RIGHT 0x00020000 -#define CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. -#define CH_STEREO_RIGHT 0x40000000 ///< See CH_STEREO_LEFT. - -/** Channel mask value used for AVCodecContext.request_channel_layout - to indicate that the user requests the channel order of the decoder output - to be the native codec channel order. */ -#define CH_LAYOUT_NATIVE 0x8000000000000000LL - -/* Audio channel convenience macros */ -#define CH_LAYOUT_MONO (CH_FRONT_CENTER) -#define CH_LAYOUT_STEREO (CH_FRONT_LEFT|CH_FRONT_RIGHT) -#define CH_LAYOUT_2_1 (CH_LAYOUT_STEREO|CH_BACK_CENTER) -#define CH_LAYOUT_SURROUND (CH_LAYOUT_STEREO|CH_FRONT_CENTER) -#define CH_LAYOUT_4POINT0 (CH_LAYOUT_SURROUND|CH_BACK_CENTER) -#define CH_LAYOUT_2_2 (CH_LAYOUT_STEREO|CH_SIDE_LEFT|CH_SIDE_RIGHT) -#define CH_LAYOUT_QUAD (CH_LAYOUT_STEREO|CH_BACK_LEFT|CH_BACK_RIGHT) -#define CH_LAYOUT_5POINT0 (CH_LAYOUT_SURROUND|CH_SIDE_LEFT|CH_SIDE_RIGHT) -#define CH_LAYOUT_5POINT1 (CH_LAYOUT_5POINT0|CH_LOW_FREQUENCY) -#define CH_LAYOUT_5POINT0_BACK (CH_LAYOUT_SURROUND|CH_BACK_LEFT|CH_BACK_RIGHT) -#define CH_LAYOUT_5POINT1_BACK (CH_LAYOUT_5POINT0_BACK|CH_LOW_FREQUENCY) -#define CH_LAYOUT_7POINT0 (CH_LAYOUT_5POINT0|CH_BACK_LEFT|CH_BACK_RIGHT) -#define CH_LAYOUT_7POINT1 (CH_LAYOUT_5POINT1|CH_BACK_LEFT|CH_BACK_RIGHT) -#define CH_LAYOUT_7POINT1_WIDE (CH_LAYOUT_5POINT1_BACK|\ - CH_FRONT_LEFT_OF_CENTER|CH_FRONT_RIGHT_OF_CENTER) -#define CH_LAYOUT_STEREO_DOWNMIX (CH_STEREO_LEFT|CH_STEREO_RIGHT) - -/* in bytes */ -#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio + /** + * MIME type(s) associated with the codec. + * May be NULL; if not, a NULL-terminated array of MIME types. + * The first item is always non-NULL and is the preferred MIME type. + */ + const char *const *mime_types; +} AVCodecDescriptor; + +/** + * Codec uses only intra compression. + * Video codecs only. + */ +#define AV_CODEC_PROP_INTRA_ONLY (1 << 0) +/** + * Codec supports lossy compression. Audio and video codecs only. + * @note a codec may support both lossy and lossless + * compression modes + */ +#define AV_CODEC_PROP_LOSSY (1 << 1) +/** + * Codec supports lossless compression. Audio and video codecs only. + */ +#define AV_CODEC_PROP_LOSSLESS (1 << 2) +/** + * Codec supports frame reordering. That is, the coded order (the order in which + * the encoded packets are output by the encoders / stored / input to the + * decoders) may be different from the presentation order of the corresponding + * frames. + * + * For codecs that do not have this property set, PTS and DTS should always be + * equal. + */ +#define AV_CODEC_PROP_REORDER (1 << 3) +/** + * Subtitle codec is bitmap based + * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. + */ +#define AV_CODEC_PROP_BITMAP_SUB (1 << 16) +/** + * Subtitle codec is text based. + * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field. + */ +#define AV_CODEC_PROP_TEXT_SUB (1 << 17) /** + * @ingroup lavc_decoding * Required number of additionally allocated bytes at the end of the input bitstream for decoding. * This is mainly needed because some optimized bitstream readers read * 32 or 64 bit at once and could read over the end.
* Note: If the first 23 bits of the additional bytes are not 0, then damaged * MPEG bitstreams could cause overread and segfault. */ -#define FF_INPUT_BUFFER_PADDING_SIZE 8 +#define FF_INPUT_BUFFER_PADDING_SIZE 32 /** + * @ingroup lavc_encoding * minimum encoding buffer size * Used to avoid some checks during header writing. */ @@ -445,6 +635,7 @@ enum SampleFormat { /** + * @ingroup lavc_encoding * motion estimation type. */ enum Motion_Est_ID { @@ -456,74 +647,41 @@ enum Motion_Est_ID { ME_X1, ///< reserved for experiments ME_HEX, ///< hexagon based search ME_UMH, ///< uneven multi-hexagon search - ME_ITER, ///< iterative search ME_TESA, ///< transformed exhaustive search algorithm + ME_ITER=50, ///< iterative search }; +/** + * @ingroup lavc_decoding + */ enum AVDiscard{ /* We leave some space between them for extensions (drop some * keyframes for intra-only or drop just some bidir frames). */ - AVDISCARD_NONE =-16, ///< discard nothing - AVDISCARD_DEFAULT= 0, ///< discard useless packets like 0 size packets in avi - AVDISCARD_NONREF = 8, ///< discard all non reference - AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames - AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes - AVDISCARD_ALL = 48, ///< discard all -}; - -enum AVColorPrimaries{ - AVCOL_PRI_BT709 =1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B - AVCOL_PRI_UNSPECIFIED=2, - AVCOL_PRI_BT470M =4, - AVCOL_PRI_BT470BG =5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM - AVCOL_PRI_SMPTE170M =6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC - AVCOL_PRI_SMPTE240M =7, ///< functionally identical to above - AVCOL_PRI_FILM =8, - AVCOL_PRI_NB , ///< Not part of ABI + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONINTRA= 24, ///< discard all non intra frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all }; -enum AVColorTransferCharacteristic{ - AVCOL_TRC_BT709 =1, ///< also ITU-R BT1361 - AVCOL_TRC_UNSPECIFIED=2, - AVCOL_TRC_GAMMA22 =4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM - AVCOL_TRC_GAMMA28 =5, ///< also ITU-R BT470BG - AVCOL_TRC_NB , ///< Not part of ABI -}; - -enum AVColorSpace{ - AVCOL_SPC_RGB =0, - AVCOL_SPC_BT709 =1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B - AVCOL_SPC_UNSPECIFIED=2, - AVCOL_SPC_FCC =4, - AVCOL_SPC_BT470BG =5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 - AVCOL_SPC_SMPTE170M =6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above - AVCOL_SPC_SMPTE240M =7, - AVCOL_SPC_NB , ///< Not part of ABI -}; - -enum AVColorRange{ - AVCOL_RANGE_UNSPECIFIED=0, - AVCOL_RANGE_MPEG =1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges - AVCOL_RANGE_JPEG =2, ///< the normal 2^n-1 "JPEG" YUV ranges - AVCOL_RANGE_NB , ///< Not part of ABI +enum AVAudioServiceType { + AV_AUDIO_SERVICE_TYPE_MAIN = 0, + AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, + AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, + AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, + AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, + AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, + AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, + AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, + AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, + AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI }; /** - * X X 3 4 X X are luma samples, - * 1 2 1-6 are possible chroma positions - * X X 5 6 X 0 is undefined/unknown position + * @ingroup lavc_encoding */ -enum AVChromaLocation{ - AVCHROMA_LOC_UNSPECIFIED=0, - AVCHROMA_LOC_LEFT =1, ///< mpeg2/4, h264 default - AVCHROMA_LOC_CENTER =2, ///< mpeg1, jpeg, h263 - AVCHROMA_LOC_TOPLEFT =3, ///< DV - AVCHROMA_LOC_TOP =4, - AVCHROMA_LOC_BOTTOMLEFT =5, - AVCHROMA_LOC_BOTTOM =6, - AVCHROMA_LOC_NB , ///< Not part of ABI -}; - typedef struct RcOverride{ int start_frame; int end_frame; @@ -531,72 +689,85 @@ typedef struct RcOverride{ float quality_factor; } RcOverride; +#if FF_API_MAX_BFRAMES +/** + * @deprecated there is no libavcodec-wide limit on the number of B-frames + */ #define FF_MAX_B_FRAMES 16 +#endif /* encoding support These flags can be passed in AVCodecContext.flags before initialization. Note: Not everything is supported yet. */ +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define CODEC_FLAG_UNALIGNED 0x0001 #define CODEC_FLAG_QSCALE 0x0002 ///< Use fixed qscale. #define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / advanced prediction for H.263. +#define CODEC_FLAG_OUTPUT_CORRUPT 0x0008 ///< Output even those frames that might be corrupted #define CODEC_FLAG_QPEL 0x0010 ///< Use qpel MC. +#if FF_API_GMC +/** + * @deprecated use the "gmc" private option of the libxvid encoder + */ #define CODEC_FLAG_GMC 0x0020 ///< Use GMC. -#define CODEC_FLAG_MV0 0x0040 ///< Always try a MB with MV=<0,0>. -#define CODEC_FLAG_PART 0x0080 ///< Use data partitioning. +#endif +#if FF_API_MV0 +/** + * @deprecated use the flag "mv0" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_MV0 0x0040 +#endif +#if FF_API_INPUT_PRESERVED /** - * The parent program guarantees that the input for B-frames containing - * streams is not written to for at least s->max_b_frames+1 frames, if - * this is not set the input will be copied. + * @deprecated passing reference-counted frames to the encoders replaces this + * flag */ #define CODEC_FLAG_INPUT_PRESERVED 0x0100 +#endif #define CODEC_FLAG_PASS1 0x0200 ///< Use internal 2pass ratecontrol in first pass mode. #define CODEC_FLAG_PASS2 0x0400 ///< Use internal 2pass ratecontrol in second pass mode. -#define CODEC_FLAG_EXTERN_HUFF 0x1000 ///< Use external Huffman table (for MJPEG). #define CODEC_FLAG_GRAY 0x2000 ///< Only decode/encode grayscale. -#define CODEC_FLAG_EMU_EDGE 0x4000 ///< Don't draw edges. +#if FF_API_EMU_EDGE +/** + * @deprecated edges are not used/required anymore. I.e. this flag is now always + * set. + */ +#define CODEC_FLAG_EMU_EDGE 0x4000 +#endif #define CODEC_FLAG_PSNR 0x8000 ///< error[?] variables will be set during encoding. #define CODEC_FLAG_TRUNCATED 0x00010000 /** Input bitstream might be truncated at a random location instead of only at frame boundaries. */ -#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 ///< Normalize adaptive quantization. +#if FF_API_NORMALIZE_AQP +/** + * @deprecated use the flag "naq" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 +#endif #define CODEC_FLAG_INTERLACED_DCT 0x00040000 ///< Use interlaced DCT. #define CODEC_FLAG_LOW_DELAY 0x00080000 ///< Force low delay. -#define CODEC_FLAG_ALT_SCAN 0x00100000 ///< Use alternate scan. #define CODEC_FLAG_GLOBAL_HEADER 0x00400000 ///< Place global headers in extradata instead of every keyframe. #define CODEC_FLAG_BITEXACT 0x00800000 ///< Use only bitexact stuff (except (I)DCT). /* Fx : Flag for h263+ extra options */ #define CODEC_FLAG_AC_PRED 0x01000000 ///< H.263 advanced intra coding / MPEG-4 AC prediction -#define CODEC_FLAG_H263P_UMV 0x02000000 ///< unlimited motion vector -#define CODEC_FLAG_CBP_RD 0x04000000 ///< Use rate distortion optimization for cbp. -#define CODEC_FLAG_QP_RD 0x08000000 ///< Use rate distortion optimization for qp selectioon. -#define CODEC_FLAG_H263P_AIV 0x00000008 ///< H.263 alternative inter VLC -#define CODEC_FLAG_OBMC 0x00000001 ///< OBMC #define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter -#define CODEC_FLAG_H263P_SLICE_STRUCT 0x10000000 #define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation -#define CODEC_FLAG_SVCD_SCAN_OFFSET 0x40000000 ///< Will reserve space for SVCD scan offset user data. #define CODEC_FLAG_CLOSED_GOP 0x80000000 #define CODEC_FLAG2_FAST 0x00000001 ///< Allow non spec compliant speedup tricks. -#define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. #define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. -#define CODEC_FLAG2_BPYRAMID 0x00000010 ///< H.264 allow B-frames to be used as references. -#define CODEC_FLAG2_WPRED 0x00000020 ///< H.264 weighted biprediction for B-frames -#define CODEC_FLAG2_MIXED_REFS 0x00000040 ///< H.264 one reference per partition, as opposed to one reference per macroblock -#define CODEC_FLAG2_8X8DCT 0x00000080 ///< H.264 high profile 8x8 transform -#define CODEC_FLAG2_FASTPSKIP 0x00000100 ///< H.264 fast pskip -#define CODEC_FLAG2_AUD 0x00000200 ///< H.264 access unit delimiters -#define CODEC_FLAG2_BRDO 0x00000400 ///< B-frame rate-distortion optimization -#define CODEC_FLAG2_INTRA_VLC 0x00000800 ///< Use MPEG-2 intra VLC table. -#define CODEC_FLAG2_MEMC_ONLY 0x00001000 ///< Only do ME/MC (I frames -> ref, P frame -> ME+MC). -#define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format. -#define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skipping +#define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format. DEPRECATED!!!! +#define CODEC_FLAG2_IGNORE_CROP 0x00010000 ///< Discard cropping information from SPS. + #define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries. -#define CODEC_FLAG2_NON_LINEAR_QUANT 0x00010000 ///< Use MPEG-2 nonlinear quantizer. -#define CODEC_FLAG2_BIT_RESERVOIR 0x00020000 ///< Use a bit reservoir when encoding if possible -#define CODEC_FLAG2_MBTREE 0x00040000 ///< Use macroblock tree ratecontrol (x264 only) -#define CODEC_FLAG2_PSY 0x00080000 ///< Use psycho visual optimizations. -#define CODEC_FLAG2_SSIM 0x00100000 ///< Compute SSIM during encoding, error[] values are undefined. +#define CODEC_FLAG2_SHOW_ALL 0x00400000 ///< Show all frames before the first keyframe +#define CODEC_FLAG2_EXPORT_MVS 0x10000000 ///< Export motion vectors through frame side data /* Unsupported options : * Syntax Arithmetic coding (SAC) @@ -612,14 +783,39 @@ typedef struct RcOverride{ * assume the buffer was allocated by avcodec_default_get_buffer. */ #define CODEC_CAP_DR1 0x0002 -/* If 'parse_only' field is true, then avcodec_parse_frame() can be used. */ -#define CODEC_CAP_PARSE_ONLY 0x0004 #define CODEC_CAP_TRUNCATED 0x0008 -/* Codec can export data for HW decoding (XvMC). */ +#if FF_API_XVMC +/* Codec can export data for HW decoding. This flag indicates that + * the codec would call get_format() with list that might contain HW accelerated + * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them + * including raw image format. + * The application can use the passed context to determine bitstream version, + * chroma format, resolution etc. + */ #define CODEC_CAP_HWACCEL 0x0010 +#endif /* FF_API_XVMC */ /** - * Codec has a nonzero delay and needs to be fed with NULL at the end to get the delayed data. - * If this is not set, the codec is guaranteed to never be fed with NULL data. + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. */ #define CODEC_CAP_DELAY 0x0020 /** @@ -627,10 +823,12 @@ typedef struct RcOverride{ * This can be used to prevent truncation of the last audio samples. */ #define CODEC_CAP_SMALL_LAST_FRAME 0x0040 +#if FF_API_CAP_VDPAU /** * Codec can export data for HW decoding (VDPAU). */ #define CODEC_CAP_HWACCEL_VDPAU 0x0080 +#endif /** * Codec can output multiple frames per AVPacket * Normally demuxers return one frame at a time, demuxers which do not do @@ -643,7 +841,51 @@ typedef struct RcOverride{ * as a last resort. */ #define CODEC_CAP_SUBFRAMES 0x0100 +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define CODEC_CAP_EXPERIMENTAL 0x0200 +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define CODEC_CAP_CHANNEL_CONF 0x0400 +#if FF_API_NEG_LINESIZES +/** + * @deprecated no codecs use this capability + */ +#define CODEC_CAP_NEG_LINESIZES 0x0800 +#endif +/** + * Codec supports frame-level multithreading. + */ +#define CODEC_CAP_FRAME_THREADS 0x1000 +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define CODEC_CAP_SLICE_THREADS 0x2000 +/** + * Codec supports changed parameters at any point. + */ +#define CODEC_CAP_PARAM_CHANGE 0x4000 +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define CODEC_CAP_AUTO_THREADS 0x8000 +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define CODEC_CAP_VARIABLE_FRAME_SIZE 0x10000 +/** + * Codec is intra only. + */ +#define CODEC_CAP_INTRA_ONLY 0x40000000 +/** + * Codec is lossless. + */ +#define CODEC_CAP_LOSSLESS 0x80000000 +#if FF_API_MB_TYPE //The following defines may change, don't expect compatibility if you use them. #define MB_TYPE_INTRA4x4 0x0001 #define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific @@ -667,6 +909,7 @@ typedef struct RcOverride{ #define MB_TYPE_QUANT 0x00010000 #define MB_TYPE_CBP 0x00020000 //Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...) +#endif /** * Pan Scan area. @@ -697,259 +940,199 @@ typedef struct AVPanScan{ int16_t position[3][2]; }AVPanScan; -#define FF_COMMON_FRAME \ - /**\ - * pointer to the picture planes.\ - * This might be different from the first allocated byte\ - * - encoding: \ - * - decoding: \ - */\ - uint8_t *data[4];\ - int linesize[4];\ - /**\ - * pointer to the first allocated byte of the picture. Can be used in get_buffer/release_buffer.\ - * This isn't used by libavcodec unless the default get/release_buffer() is used.\ - * - encoding: \ - * - decoding: \ - */\ - uint8_t *base[4];\ - /**\ - * 1 -> keyframe, 0-> not\ - * - encoding: Set by libavcodec.\ - * - decoding: Set by libavcodec.\ - */\ - int key_frame;\ -\ - /**\ - * Picture type of the frame, see ?_TYPE below.\ - * - encoding: Set by libavcodec. for coded_picture (and set by user for input).\ - * - decoding: Set by libavcodec.\ - */\ - int pict_type;\ -\ - /**\ - * presentation timestamp in time_base units (time when frame should be shown to user)\ - * If AV_NOPTS_VALUE then frame_rate = 1/time_base will be assumed.\ - * - encoding: MUST be set by user.\ - * - decoding: Set by libavcodec.\ - */\ - int64_t pts;\ -\ - /**\ - * picture number in bitstream order\ - * - encoding: set by\ - * - decoding: Set by libavcodec.\ - */\ - int coded_picture_number;\ - /**\ - * picture number in display order\ - * - encoding: set by\ - * - decoding: Set by libavcodec.\ - */\ - int display_picture_number;\ -\ - /**\ - * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) \ - * - encoding: Set by libavcodec. for coded_picture (and set by user for input).\ - * - decoding: Set by libavcodec.\ - */\ - int quality; \ -\ - /**\ - * buffer age (1->was last buffer and dint change, 2->..., ...).\ - * Set to INT_MAX if the buffer has not been used yet.\ - * - encoding: unused\ - * - decoding: MUST be set by get_buffer().\ - */\ - int age;\ -\ - /**\ - * is this picture used as reference\ - * The values for this are the same as the MpegEncContext.picture_structure\ - * variable, that is 1->top field, 2->bottom field, 3->frame/both fields.\ - * Set to 4 for delayed, non-reference frames.\ - * - encoding: unused\ - * - decoding: Set by libavcodec. (before get_buffer() call)).\ - */\ - int reference;\ -\ - /**\ - * QP table\ - * - encoding: unused\ - * - decoding: Set by libavcodec.\ - */\ - int8_t *qscale_table;\ - /**\ - * QP store stride\ - * - encoding: unused\ - * - decoding: Set by libavcodec.\ - */\ - int qstride;\ -\ - /**\ - * mbskip_table[mb]>=1 if MB didn't change\ - * stride= mb_width = (width+15)>>4\ - * - encoding: unused\ - * - decoding: Set by libavcodec.\ - */\ - uint8_t *mbskip_table;\ -\ - /**\ - * motion vector table\ - * @code\ - * example:\ - * int mv_sample_log2= 4 - motion_subsample_log2;\ - * int mb_width= (width+15)>>4;\ - * int mv_stride= (mb_width << mv_sample_log2) + 1;\ - * motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];\ - * @endcode\ - * - encoding: Set by user.\ - * - decoding: Set by libavcodec.\ - */\ - int16_t (*motion_val[2])[2];\ -\ - /**\ - * macroblock type table\ - * mb_type_base + mb_width + 2\ - * - encoding: Set by user.\ - * - decoding: Set by libavcodec.\ - */\ - uint32_t *mb_type;\ -\ - /**\ - * log2 of the size of the block which a single vector in motion_val represents: \ - * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2)\ - * - encoding: unused\ - * - decoding: Set by libavcodec.\ - */\ - uint8_t motion_subsample_log2;\ -\ - /**\ - * for some private data of the user\ - * - encoding: unused\ - * - decoding: Set by user.\ - */\ - void *opaque;\ -\ - /**\ - * error\ - * - encoding: Set by libavcodec. if flags&CODEC_FLAG_PSNR.\ - * - decoding: unused\ - */\ - uint64_t error[4];\ -\ - /**\ - * type of the buffer (to keep track of who has to deallocate data[*])\ - * - encoding: Set by the one who allocates it.\ - * - decoding: Set by the one who allocates it.\ - * Note: User allocated (direct rendering) & internal buffers cannot coexist currently.\ - */\ - int type;\ - \ - /**\ - * When decoding, this signals how much the picture must be delayed.\ - * extra_delay = repeat_pict / (2*fps)\ - * - encoding: unused\ - * - decoding: Set by libavcodec.\ - */\ - int repeat_pict;\ - \ - /**\ - * \ - */\ - int qscale_type;\ - \ - /**\ - * The content of the picture is interlaced.\ - * - encoding: Set by user.\ - * - decoding: Set by libavcodec. (default 0)\ - */\ - int interlaced_frame;\ - \ - /**\ - * If the content is interlaced, is top field displayed first.\ - * - encoding: Set by user.\ - * - decoding: Set by libavcodec.\ - */\ - int top_field_first;\ - \ - /**\ - * Pan scan.\ - * - encoding: Set by user.\ - * - decoding: Set by libavcodec.\ - */\ - AVPanScan *pan_scan;\ - \ - /**\ - * Tell user application that palette has changed from previous frame.\ - * - encoding: ??? (no palette-enabled encoder yet)\ - * - decoding: Set by libavcodec. (default 0).\ - */\ - int palette_has_changed;\ - \ - /**\ - * codec suggestion on buffer type if != 0\ - * - encoding: unused\ - * - decoding: Set by libavcodec. (before get_buffer() call)).\ - */\ - int buffer_hints;\ -\ - /**\ - * DCT coefficients\ - * - encoding: unused\ - * - decoding: Set by libavcodec.\ - */\ - short *dct_coeff;\ -\ - /**\ - * motion reference frame index\ - * the order in which these are stored can depend on the codec.\ - * - encoding: Set by user.\ - * - decoding: Set by libavcodec.\ - */\ - int8_t *ref_index[2];\ -\ - /**\ - * reordered opaque 64bit number (generally a PTS) from AVCodecContext.reordered_opaque\ - * output in AVFrame.reordered_opaque\ - * - encoding: unused\ - * - decoding: Read by user.\ - */\ - int64_t reordered_opaque;\ -\ - /**\ - * hardware accelerator private data (FFmpeg allocated)\ - * - encoding: unused\ - * - decoding: Set by libavcodec\ - */\ - void *hwaccel_picture_private;\ - - +#if FF_API_QSCALE_TYPE #define FF_QSCALE_TYPE_MPEG1 0 #define FF_QSCALE_TYPE_MPEG2 1 #define FF_QSCALE_TYPE_H264 2 #define FF_QSCALE_TYPE_VP56 3 +#endif +#if FF_API_GET_BUFFER #define FF_BUFFER_TYPE_INTERNAL 1 #define FF_BUFFER_TYPE_USER 2 ///< direct rendering buffers (image is (de)allocated by user) #define FF_BUFFER_TYPE_SHARED 4 ///< Buffer from somewhere else; don't deallocate image (data/base), all other tables are not shared. #define FF_BUFFER_TYPE_COPY 8 ///< Just a (modified) copy of some other buffer, don't deallocate anything. - -#define FF_I_TYPE 1 ///< Intra -#define FF_P_TYPE 2 ///< Predicted -#define FF_B_TYPE 3 ///< Bi-dir predicted -#define FF_S_TYPE 4 ///< S(GMC)-VOP MPEG4 -#define FF_SI_TYPE 5 ///< Switching Intra -#define FF_SP_TYPE 6 ///< Switching Predicted -#define FF_BI_TYPE 7 - #define FF_BUFFER_HINTS_VALID 0x01 // Buffer hints value is meaningful (if 0 ignore). #define FF_BUFFER_HINTS_READABLE 0x02 // Codec will read from buffer. #define FF_BUFFER_HINTS_PRESERVE 0x04 // User must not alter buffer content. #define FF_BUFFER_HINTS_REUSABLE 0x08 // Codec will reuse the buffer (update). +#endif + +/** + * The decoder will keep a reference to the frame and may reuse it later. + */ +#define AV_GET_BUFFER_FLAG_REF (1 << 0) + +/** + * @defgroup lavc_packet AVPacket + * + * Types and functions for working with AVPacket. + * @{ + */ +enum AVPacketSideDataType { + AV_PKT_DATA_PALETTE, + AV_PKT_DATA_NEW_EXTRADATA, + + /** + * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: + * @code + * u32le param_flags + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) + * s32le channel_count + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) + * u64le channel_layout + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) + * s32le sample_rate + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) + * s32le width + * s32le height + * @endcode + */ + AV_PKT_DATA_PARAM_CHANGE, + + /** + * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of + * structures with info about macroblocks relevant to splitting the + * packet into smaller packets on macroblock edges (e.g. as for RFC 2190). + * That is, it does not necessarily contain info about all macroblocks, + * as long as the distance between macroblocks in the info is smaller + * than the target payload size. + * Each MB info structure is 12 bytes, and is laid out as follows: + * @code + * u32le bit offset from the start of the packet + * u8 current quantizer at the start of the macroblock + * u8 GOB number + * u16le macroblock address within the GOB + * u8 horizontal MV predictor + * u8 vertical MV predictor + * u8 horizontal MV predictor for block number 3 + * u8 vertical MV predictor for block number 3 + * @endcode + */ + AV_PKT_DATA_H263_MB_INFO, + + /** + * This side data should be associated with an audio stream and contains + * ReplayGain information in form of the AVReplayGain struct. + */ + AV_PKT_DATA_REPLAYGAIN, + + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the decoded video frames for + * correct presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_PKT_DATA_DISPLAYMATRIX, + + /** + * This side data should be associated with a video stream and contains + * Stereoscopic 3D information in form of the AVStereo3D struct. + */ + AV_PKT_DATA_STEREO3D, + + /** + * Recommmends skipping the specified number of samples + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_PKT_DATA_SKIP_SAMPLES=70, + + /** + * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that + * the packet may contain "dual mono" audio specific to Japanese DTV + * and if it is true, recommends only the selected channel to be used. + * @code + * u8 selected channels (0=mail/left, 1=sub/right, 2=both) + * @endcode + */ + AV_PKT_DATA_JP_DUALMONO, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. + */ + AV_PKT_DATA_STRINGS_METADATA, + /** + * Subtitle event position + * @code + * u32le x1 + * u32le y1 + * u32le x2 + * u32le y2 + * @endcode + */ + AV_PKT_DATA_SUBTITLE_POSITION, + + /** + * Data found in BlockAdditional element of matroska container. There is + * no end marker for the data, so it is required to rely on the side data + * size to recognize the end. 8 byte id (as found in BlockAddId) followed + * by data. + */ + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + + /** + * The optional first identifier line of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_IDENTIFIER, + + /** + * The optional settings (rendering instructions) that immediately + * follow the timestamp specifier of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_SETTINGS, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. This + * side data includes updated metadata which appeared in the stream. + */ + AV_PKT_DATA_METADATA_UPDATE, +}; + +typedef struct AVPacketSideData { + uint8_t *data; + int size; + enum AVPacketSideDataType type; +} AVPacketSideData; + +/** + * This structure stores compressed data. It is typically exported by demuxers + * and then passed as input to decoders, or received as output from encoders and + * then passed to muxers. + * + * For video, it should typically contain one compressed frame. For audio it may + * contain several compressed frames. + * + * AVPacket is one of the few structs in FFmpeg, whose size is a part of public + * ABI. Thus it may be allocated on stack and no new fields can be added to it + * without libavcodec and libavformat major bump. + * + * The semantics of data ownership depends on the buf or destruct (deprecated) + * fields. If either is set, the packet data is dynamically allocated and is + * valid indefinitely until av_free_packet() is called (which in turn calls + * av_buffer_unref()/the destruct callback to free the data). If neither is set, + * the packet data is typically backed by some static buffer somewhere and is + * only valid for a limited time (e.g. until the next read call when demuxing). + * + * The side data is always allocated with av_malloc() and is freed in + * av_free_packet(). + */ typedef struct AVPacket { + /** + * A reference to the reference-counted buffer where the packet data is + * stored. + * May be NULL, then the packet data is not reference-counted. + */ + AVBufferRef *buf; /** * Presentation timestamp in AVStream->time_base units; the time at which * the decompressed packet will be presented to the user. @@ -969,14 +1152,28 @@ typedef struct AVPacket { uint8_t *data; int size; int stream_index; + /** + * A combination of AV_PKT_FLAG values + */ int flags; + /** + * Additional packet data that can be provided by the container. + * Packet can contain several types of side information. + */ + AVPacketSideData *side_data; + int side_data_elems; + /** * Duration of this packet in AVStream->time_base units, 0 if unknown. * Equals next_pts - this_pts in presentation order. */ int duration; +#if FF_API_DESTRUCT_PACKET + attribute_deprecated void (*destruct)(struct AVPacket *); + attribute_deprecated void *priv; +#endif int64_t pos; ///< byte position in stream, -1 if unknown /** @@ -987,6 +1184,8 @@ typedef struct AVPacket { * the very first frame or from this keyframe. * Is AV_NOPTS_VALUE if unknown. * This field is not the display duration of the current packet. + * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY + * set. * * The purpose of this field is to allow seeking in streams that have no * keyframes in the conventional sense. It corresponds to the @@ -996,37 +1195,98 @@ typedef struct AVPacket { */ int64_t convergence_duration; } AVPacket; -#define AV_PKT_FLAG_KEY 0x0001 -#if LIBAVCODEC_VERSION_MAJOR < 53 -#define PKT_FLAG_KEY AV_PKT_FLAG_KEY -#endif - +#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe +#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted + +enum AVSideDataParamChangeFlags { + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002, + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004, + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008, +}; /** - * Audio Video Frame. - * New fields can be added to the end of FF_COMMON_FRAME with minor version - * bumps. - * Removal, reordering and changes to existing fields require a major - * version bump. No fields should be added into AVFrame before or after - * FF_COMMON_FRAME! - * sizeof(AVFrame) must not be used outside libav*. + * @} */ -typedef struct AVFrame { - FF_COMMON_FRAME -} AVFrame; + +struct AVCodecInternal; + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, //< Top coded_first, top displayed first + AV_FIELD_BB, //< Bottom coded first, bottom displayed first + AV_FIELD_TB, //< Top coded first, bottom displayed first + AV_FIELD_BT, //< Bottom coded first, top displayed first +}; /** * main external API structure. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. + * Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user + * applications. * sizeof(AVCodecContext) must not be used outside libav*. */ typedef struct AVCodecContext { /** * information on struct for av_log - * - set by avcodec_alloc_context + * - set by avcodec_alloc_context3 */ const AVClass *av_class; + int log_level_offset; + + enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ + const struct AVCodec *codec; +#if FF_API_CODEC_NAME + /** + * @deprecated this field is not used for anything in libavcodec + */ + attribute_deprecated + char codec_name[32]; +#endif + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * A demuxer should set this to what is stored in the field used to identify the codec. + * If there are multiple such fields in a container then the demuxer should choose the one + * which maximizes the information about the used codec. + * If the codec tag field in a container is larger than 32 bits then the demuxer should + * remap the longer ID to 32 bits with a table or other structure. Alternatively a new + * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated + * first. + * - encoding: Set by user, if not then the default based on codec_id will be used. + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int codec_tag; + + /** + * fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * - encoding: unused + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int stream_codec_tag; + + void *priv_data; + + /** + * Private context used for internal data. + * + * Unlike priv_data, this is not codec-specific. It is used in general + * libavcodec functions. + */ + struct AVCodecInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + * - encoding: Set by user. + * - decoding: Set by user. + */ + void *opaque; + /** * the average bitrate * - encoding: Set by user; unused for constant quantizer encoding. @@ -1043,30 +1303,33 @@ typedef struct AVCodecContext { int bit_rate_tolerance; /** - * CODEC_FLAG_*. + * Global quality for codecs which cannot change it per frame. + * This should be proportional to MPEG-1/2/4 qscale. * - encoding: Set by user. - * - decoding: Set by user. + * - decoding: unused */ - int flags; + int global_quality; /** - * Some codecs need additional format info. It is stored here. - * If any muxer uses this then ALL demuxers/parsers AND encoders for the - * specific codec MUST set it correctly otherwise stream copy breaks. - * In general use of this field by muxers is not recommanded. - * - encoding: Set by libavcodec. - * - decoding: Set by libavcodec. (FIXME: Is this OK?) + * - encoding: Set by user. + * - decoding: unused */ - int sub_id; + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 /** - * Motion estimation algorithm used for video coding. - * 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex), - * 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific] - * - encoding: MUST be set by user. - * - decoding: unused + * CODEC_FLAG_*. + * - encoding: Set by user. + * - decoding: Set by user. */ - int me_method; + int flags; + + /** + * CODEC_FLAG2_* + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags2; /** * some codecs need / can use extradata like Huffman tables. @@ -1074,7 +1337,7 @@ typedef struct AVCodecContext { * rv10: additional flags * mpeg4: global headers (they can be in the bitstream or here) * The allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger - * than extradata_size to avoid prolems if it is read with the bitstream reader. + * than extradata_size to avoid problems if it is read with the bitstream reader. * The bytewise contents of extradata must not depend on the architecture or CPU endianness. * - encoding: Set/allocated/freed by libavcodec. * - decoding: Set/allocated/freed by user. @@ -1092,45 +1355,108 @@ typedef struct AVCodecContext { */ AVRational time_base; - /* video only */ /** - * picture width / height. - * - encoding: MUST be set by user. - * - decoding: Set by libavcodec. - * Note: For compatibility it is possible to set this instead of - * coded_width/height before decoding. + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. */ - int width, height; - -#define FF_ASPECT_EXTENDED 15 + int ticks_per_frame; /** - * the number of pictures in a group of pictures, or 0 for intra_only - * - encoding: Set by user. - * - decoding: unused - */ - int gop_size; - + * Codec delay. + * + * Encoding: Number of frames delay there will be from the encoder input to + * the decoder output. (we assume the decoder matches the spec) + * Decoding: Number of frames delay in addition to what a standard decoder + * as specified in the spec would produce. + * + * Video: + * Number of frames the decoded output will be delayed relative to the + * encoded input. + * + * Audio: + * For encoding, this is the number of "priming" samples added by the + * encoder to the beginning of the stream. The decoded output will be + * delayed by this many samples relative to the input to the encoder (or + * more, if the decoder adds its own padding). + * The timestamps on the output packets are adjusted by the encoder so + * that they always refer to the first sample of the data actually + * contained in the packet, including any added padding. + * E.g. if the timebase is 1/samplerate and the timestamp of the first + * input sample is 0, the timestamp of the first output packet will be + * -delay. + * + * For decoding, this is the number of samples the decoder needs to + * output before the decoder's output is valid. When seeking, you should + * start decoding this many samples prior to your desired seek point. + * + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int delay; + + + /* video only */ + /** + * picture width / height. + * - encoding: MUST be set by user. + * - decoding: May be set by the user before opening the decoder if known e.g. + * from the container. Some decoders will require the dimensions + * to be set by the caller. During decoding, the decoder may + * overwrite those values as required. + */ + int width, height; + + /** + * Bitstream width / height, may be different from width/height e.g. when + * the decoded frame is cropped before being output or lowres is enabled. + * - encoding: unused + * - decoding: May be set by the user before opening the decoder if known + * e.g. from the container. During decoding, the decoder may + * overwrite those values as required. + */ + int coded_width, coded_height; + +#if FF_API_ASPECT_EXTENDED +#define FF_ASPECT_EXTENDED 15 +#endif + /** - * Pixel format, see PIX_FMT_xxx. + * the number of pictures in a group of pictures, or 0 for intra_only * - encoding: Set by user. - * - decoding: Set by libavcodec. + * - decoding: unused */ - enum PixelFormat pix_fmt; + int gop_size; /** - * Frame rate emulation. If not zero, the lower layer (i.e. format handler) - * has to read frames at native frame rate. + * Pixel format, see AV_PIX_FMT_xxx. + * May be set by the demuxer if known from headers. + * May be overridden by the decoder if it knows better. * - encoding: Set by user. + * - decoding: Set by user if known, overridden by libavcodec if known + */ + enum AVPixelFormat pix_fmt; + + /** + * Motion estimation algorithm used for video coding. + * 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex), + * 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific] + * - encoding: MUST be set by user. * - decoding: unused */ - int rate_emu; + int me_method; /** * If non NULL, 'draw_horiz_band' is called by the libavcodec * decoder to draw a horizontal band. It improves cache usage. Not * all codecs can do that. You must check the codec capabilities * beforehand. + * When multithreading is used, it may be called from multiple threads + * at the same time; threads might draw different parts of the same AVFrame, + * or multiple AVFrames, and there is no guarantee that slices will be drawn + * in order. * The function is also used by hardware acceleration APIs. * It is called at least once during frame decoding to pass * the data needed for hardware render. @@ -1146,62 +1472,19 @@ typedef struct AVCodecContext { * @param offset offset into the AVFrame.data from which the slice should be read */ void (*draw_horiz_band)(struct AVCodecContext *s, - const AVFrame *src, int offset[4], + const AVFrame *src, int offset[AV_NUM_DATA_POINTERS], int y, int type, int height); - /* audio only */ - int sample_rate; ///< samples per second - int channels; ///< number of audio channels - - /** - * audio sample format - * - encoding: Set by user. - * - decoding: Set by libavcodec. - */ - enum SampleFormat sample_fmt; ///< sample format - - /* The following data should not be initialized. */ - /** - * Samples per packet, initialized when calling 'init'. - */ - int frame_size; - int frame_number; ///< audio or video frame number -#if LIBAVCODEC_VERSION_MAJOR < 53 - int real_pict_num; ///< Returns the real picture number of previous encoded frame. -#endif - - /** - * Number of frames the decoded output will be delayed relative to - * the encoded input. - * - encoding: Set by libavcodec. - * - decoding: unused - */ - int delay; - - /* - encoding parameters */ - float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) - float qblur; ///< amount of qscale smoothing over time (0.0-1.0) - /** - * minimum quantizer - * - encoding: Set by user. - * - decoding: unused - */ - int qmin; - - /** - * maximum quantizer - * - encoding: Set by user. - * - decoding: unused - */ - int qmax; - - /** - * maximum quantizer difference between frames - * - encoding: Set by user. - * - decoding: unused + * callback to negotiate the pixelFormat + * @param fmt is the list of formats which are supported by the codec, + * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. + * The first is always the native one. + * @return the chosen format + * - encoding: unused + * - decoding: Set by user, if not set the native format will be chosen. */ - int max_qdiff; + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); /** * maximum number of B-frames between non-B-frames @@ -1227,957 +1510,884 @@ typedef struct AVCodecContext { int b_frame_strategy; /** - * hurry up amount - * - encoding: unused - * - decoding: Set by user. 1-> Skip B-frames, 2-> Skip IDCT/dequant too, 5-> Skip everything except header - * @deprecated Deprecated in favor of skip_idct and skip_frame. + * qscale offset between IP and B-frames + * - encoding: Set by user. + * - decoding: unused */ - int hurry_up; - - struct AVCodec *codec; - - void *priv_data; - - int rtp_payload_size; /* The size of the RTP payload: the coder will */ - /* do its best to deliver a chunk with size */ - /* below rtp_payload_size, the chunk will start */ - /* with a start code on some codecs like H.263. */ - /* This doesn't take account of any particular */ - /* headers inside the transmitted RTP payload. */ - - - /* The RTP callback: This function is called */ - /* every time the encoder has a packet to send. */ - /* It depends on the encoder if the data starts */ - /* with a Start Code (it should). H.263 does. */ - /* mb_nb contains the number of macroblocks */ - /* encoded in the RTP payload. */ - void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); - - /* statistics, used for 2-pass encoding */ - int mv_bits; - int header_bits; - int i_tex_bits; - int p_tex_bits; - int i_count; - int p_count; - int skip_count; - int misc_bits; + float b_quant_offset; /** - * number of bits used for the previously encoded frame + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. * - encoding: Set by libavcodec. - * - decoding: unused + * - decoding: Set by libavcodec. */ - int frame_bits; + int has_b_frames; /** - * Private data of the user, can be used to carry app specific stuff. + * 0-> h263 quant 1-> mpeg quant * - encoding: Set by user. - * - decoding: Set by user. + * - decoding: unused */ - void *opaque; - - char codec_name[32]; - enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ - enum CodecID codec_id; /* see CODEC_ID_xxx */ + int mpeg_quant; /** - * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). - * This is used to work around some encoder bugs. - * A demuxer should set this to what is stored in the field used to identify the codec. - * If there are multiple such fields in a container then the demuxer should choose the one - * which maximizes the information about the used codec. - * If the codec tag field in a container is larger then 32 bits then the demuxer should - * remap the longer ID to 32 bits with a table or other structure. Alternatively a new - * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated - * first. - * - encoding: Set by user, if not then the default based on codec_id will be used. - * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + * qscale factor between P and I-frames + * If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused */ - unsigned int codec_tag; + float i_quant_factor; /** - * Work around bugs in encoders which sometimes cannot be detected automatically. - * - encoding: Set by user - * - decoding: Set by user + * qscale offset between P and I-frames + * - encoding: Set by user. + * - decoding: unused */ - int workaround_bugs; -#define FF_BUG_AUTODETECT 1 ///< autodetection -#define FF_BUG_OLD_MSMPEG4 2 -#define FF_BUG_XVID_ILACE 4 -#define FF_BUG_UMP4 8 -#define FF_BUG_NO_PADDING 16 -#define FF_BUG_AMV 32 -#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. -#define FF_BUG_QPEL_CHROMA 64 -#define FF_BUG_STD_QPEL 128 -#define FF_BUG_QPEL_CHROMA2 256 -#define FF_BUG_DIRECT_BLOCKSIZE 512 -#define FF_BUG_EDGE 1024 -#define FF_BUG_HPEL_CHROMA 2048 -#define FF_BUG_DC_CLIP 4096 -#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. -#define FF_BUG_TRUNCATED 16384 -//#define FF_BUG_FAKE_SCALABILITY 16 //Autodetection should work 100%. + float i_quant_offset; /** - * luma single coefficient elimination threshold + * luminance masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ - int luma_elim_threshold; + float lumi_masking; /** - * chroma single coeff elimination threshold + * temporary complexity masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ - int chroma_elim_threshold; + float temporal_cplx_masking; /** - * strictly follow the standard (MPEG4, ...). + * spatial complexity masking (0-> disabled) * - encoding: Set by user. - * - decoding: Set by user. - * Setting this to STRICT or higher means the encoder and decoder will - * generally do stupid things. While setting it to inofficial or lower - * will mean the encoder might use things that are not supported by all - * spec compliant decoders. Decoders make no difference between normal, - * inofficial and experimental, that is they always try to decode things - * when they can unless they are explicitly asked to behave stupid - * (=strictly conform to the specs) + * - decoding: unused */ - int strict_std_compliance; -#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to a older more strict version of the spec or reference software. -#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. -#define FF_COMPLIANCE_NORMAL 0 -#define FF_COMPLIANCE_INOFFICIAL -1 ///< Allow inofficial extensions. -#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. + float spatial_cplx_masking; /** - * qscale offset between IP and B-frames + * p block masking (0-> disabled) * - encoding: Set by user. * - decoding: unused */ - float b_quant_offset; + float p_masking; /** - * Error recognization; higher values will detect more errors but may - * misdetect some more or less valid parts as errors. - * - encoding: unused - * - decoding: Set by user. + * darkness masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused */ - int error_recognition; -#define FF_ER_CAREFUL 1 -#define FF_ER_COMPLIANT 2 -#define FF_ER_AGGRESSIVE 3 -#define FF_ER_VERY_AGGRESSIVE 4 + float dark_masking; /** - * Called at the beginning of each frame to get a buffer for it. - * If pic.reference is set then the frame will be read later by libavcodec. - * avcodec_align_dimensions2() should be used to find the required width and - * height, as they normally need to be rounded up to the next multiple of 16. - * if CODEC_CAP_DR1 is not set then get_buffer() must call - * avcodec_default_get_buffer() instead of providing buffers allocated by - * some other means. - * - encoding: unused - * - decoding: Set by libavcodec., user can override. + * slice count + * - encoding: Set by libavcodec. + * - decoding: Set by user (or 0). */ - int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic); - + int slice_count; /** - * Called to release buffers which were allocated with get_buffer. - * A released buffer can be reused in get_buffer(). - * pic.data[*] must be set to NULL. - * - encoding: unused - * - decoding: Set by libavcodec., user can override. + * prediction method (needed for huffyuv) + * - encoding: Set by user. + * - decoding: unused */ - void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic); + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 /** - * Size of the frame reordering buffer in the decoder. - * For MPEG-2 it is 1 IPB or 0 low delay IP. - * - encoding: Set by libavcodec. - * - decoding: Set by libavcodec. + * slice offsets in the frame in bytes + * - encoding: Set/allocated by libavcodec. + * - decoding: Set/allocated by user (or NULL). */ - int has_b_frames; + int *slice_offset; /** - * number of bytes per packet if constant and known or 0 - * Used by some WAV based audio codecs. + * sample aspect ratio (0 if unknown) + * That is the width of a pixel divided by the height of the pixel. + * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * - encoding: Set by user. + * - decoding: Set by libavcodec. */ - int block_align; - - int parse_only; /* - decoding only: If true, only parsing is done - (function avcodec_parse_frame()). The frame - data is returned. Only MPEG codecs support this now. */ + AVRational sample_aspect_ratio; /** - * 0-> h263 quant 1-> mpeg quant + * motion estimation comparison function * - encoding: Set by user. * - decoding: unused */ - int mpeg_quant; - + int me_cmp; /** - * pass1 encoding statistics output buffer - * - encoding: Set by libavcodec. + * subpixel motion estimation comparison function + * - encoding: Set by user. * - decoding: unused */ - char *stats_out; - + int me_sub_cmp; /** - * pass2 encoding statistics input buffer - * Concatenated stuff from stats_out of pass1 should be placed here. - * - encoding: Allocated/set/freed by user. + * macroblock comparison function (not supported yet) + * - encoding: Set by user. * - decoding: unused */ - char *stats_in; - + int mb_cmp; /** - * ratecontrol qmin qmax limiting method - * 0-> clipping, 1-> use a nice continous function to limit qscale wthin qmin/qmax. + * interlaced DCT comparison function * - encoding: Set by user. * - decoding: unused */ - float rc_qsquish; - - float rc_qmod_amp; - int rc_qmod_freq; + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_CHROMA 256 /** - * ratecontrol override, see RcOverride - * - encoding: Allocated/set/freed by user. + * ME diamond size & shape + * - encoding: Set by user. * - decoding: unused */ - RcOverride *rc_override; - int rc_override_count; + int dia_size; /** - * rate control equation - * - encoding: Set by user + * amount of previous MV predictors (2a+1 x 2a+1 square) + * - encoding: Set by user. * - decoding: unused */ - const char *rc_eq; + int last_predictor_count; /** - * maximum bitrate + * prepass for motion estimation * - encoding: Set by user. * - decoding: unused */ - int rc_max_rate; + int pre_me; /** - * minimum bitrate + * motion estimation prepass comparison function * - encoding: Set by user. * - decoding: unused */ - int rc_min_rate; + int me_pre_cmp; /** - * decoder bitstream buffer size + * ME prepass diamond size & shape * - encoding: Set by user. * - decoding: unused */ - int rc_buffer_size; - float rc_buffer_aggressivity; + int pre_dia_size; /** - * qscale factor between P and I-frames - * If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset). - * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * subpel ME quality * - encoding: Set by user. * - decoding: unused */ - float i_quant_factor; + int me_subpel_quality; +#if FF_API_AFD /** - * qscale offset between P and I-frames - * - encoding: Set by user. - * - decoding: unused + * DTG active format information (additional aspect ratio + * information only used in DVB MPEG-2 transport streams) + * 0 if not set. + * + * - encoding: unused + * - decoding: Set by decoder. + * @deprecated Deprecated in favor of AVSideData */ - float i_quant_offset; + attribute_deprecated int dtg_active_format; +#define FF_DTG_AFD_SAME 8 +#define FF_DTG_AFD_4_3 9 +#define FF_DTG_AFD_16_9 10 +#define FF_DTG_AFD_14_9 11 +#define FF_DTG_AFD_4_3_SP_14_9 13 +#define FF_DTG_AFD_16_9_SP_14_9 14 +#define FF_DTG_AFD_SP_4_3 15 +#endif /* FF_API_AFD */ /** - * initial complexity for pass1 ratecontrol + * maximum motion estimation search range in subpel units + * If 0 then no limit. + * * - encoding: Set by user. * - decoding: unused */ - float rc_initial_cplx; + int me_range; /** - * DCT algorithm, see FF_DCT_* below + * intra quantizer bias * - encoding: Set by user. * - decoding: unused */ - int dct_algo; -#define FF_DCT_AUTO 0 -#define FF_DCT_FASTINT 1 -#define FF_DCT_INT 2 -#define FF_DCT_MMX 3 -#define FF_DCT_MLIB 4 -#define FF_DCT_ALTIVEC 5 -#define FF_DCT_FAAN 6 + int intra_quant_bias; +#define FF_DEFAULT_QUANT_BIAS 999999 /** - * luminance masking (0-> disabled) + * inter quantizer bias * - encoding: Set by user. * - decoding: unused */ - float lumi_masking; + int inter_quant_bias; /** - * temporary complexity masking (0-> disabled) + * slice flags + * - encoding: unused + * - decoding: Set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + +#if FF_API_XVMC + /** + * XVideo Motion Acceleration + * - encoding: forbidden + * - decoding: set by decoder + * @deprecated XvMC doesn't need it anymore. + */ + attribute_deprecated int xvmc_acceleration; +#endif /* FF_API_XVMC */ + + /** + * macroblock decision mode * - encoding: Set by user. * - decoding: unused */ - float temporal_cplx_masking; + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distortion /** - * spatial complexity masking (0-> disabled) + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *inter_matrix; + + /** + * scene change detection threshold + * 0 is default, larger means fewer detected scene changes. * - encoding: Set by user. * - decoding: unused */ - float spatial_cplx_masking; + int scenechange_threshold; /** - * p block masking (0-> disabled) + * noise reduction strength * - encoding: Set by user. * - decoding: unused */ - float p_masking; + int noise_reduction; /** - * darkness masking (0-> disabled) + * Motion estimation threshold below which no motion estimation is + * performed, but instead the user specified motion vectors are used. + * * - encoding: Set by user. * - decoding: unused */ - float dark_masking; + int me_threshold; /** - * IDCT algorithm, see FF_IDCT_* below. + * Macroblock threshold below which the user specified macroblock types will be used. * - encoding: Set by user. - * - decoding: Set by user. + * - decoding: unused */ - int idct_algo; -#define FF_IDCT_AUTO 0 -#define FF_IDCT_INT 1 -#define FF_IDCT_SIMPLE 2 -#define FF_IDCT_SIMPLEMMX 3 -#define FF_IDCT_LIBMPEG2MMX 4 -#define FF_IDCT_PS2 5 -#define FF_IDCT_MLIB 6 -#define FF_IDCT_ARM 7 -#define FF_IDCT_ALTIVEC 8 -#define FF_IDCT_SH4 9 -#define FF_IDCT_SIMPLEARM 10 -#define FF_IDCT_H264 11 -#define FF_IDCT_VP3 12 -#define FF_IDCT_IPP 13 -#define FF_IDCT_XVIDMMX 14 -#define FF_IDCT_CAVS 15 -#define FF_IDCT_SIMPLEARMV5TE 16 -#define FF_IDCT_SIMPLEARMV6 17 -#define FF_IDCT_SIMPLEVIS 18 -#define FF_IDCT_WMV2 19 -#define FF_IDCT_FAAN 20 -#define FF_IDCT_EA 21 -#define FF_IDCT_SIMPLENEON 22 -#define FF_IDCT_SIMPLEALPHA 23 -#define FF_IDCT_BINK 24 + int mb_threshold; /** - * slice count - * - encoding: Set by libavcodec. - * - decoding: Set by user (or 0). + * precision of the intra DC coefficient - 8 + * - encoding: Set by user. + * - decoding: unused */ - int slice_count; + int intra_dc_precision; + /** - * slice offsets in the frame in bytes - * - encoding: Set/allocated by libavcodec. - * - decoding: Set/allocated by user (or NULL). + * Number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: Set by user. */ - int *slice_offset; + int skip_top; /** - * error concealment flags + * Number of macroblock rows at the bottom which are skipped. * - encoding: unused * - decoding: Set by user. */ - int error_concealment; -#define FF_EC_GUESS_MVS 1 -#define FF_EC_DEBLOCK 2 + int skip_bottom; /** - * dsp_mask could be add used to disable unwanted CPU features - * CPU features (i.e. MMX, SSE. ...) - * - * With the FORCE flag you may instead enable given CPU features. - * (Dangerous: Usable in case of misdetection, improper usage however will - * result into program crash.) + * Border processing masking, raises the quantizer for mbs on the borders + * of the picture. + * - encoding: Set by user. + * - decoding: unused */ - unsigned dsp_mask; -#define FF_MM_FORCE 0x80000000 /* Force usage of selected flags (OR) */ - /* lower 16 bits - CPU features */ -#define FF_MM_MMX 0x0001 ///< standard MMX -#define FF_MM_3DNOW 0x0004 ///< AMD 3DNOW -#if LIBAVCODEC_VERSION_MAJOR < 53 -#define FF_MM_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext -#endif -#define FF_MM_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext -#define FF_MM_SSE 0x0008 ///< SSE functions -#define FF_MM_SSE2 0x0010 ///< PIV SSE2 functions -#define FF_MM_3DNOWEXT 0x0020 ///< AMD 3DNowExt -#define FF_MM_SSE3 0x0040 ///< Prescott SSE3 functions -#define FF_MM_SSSE3 0x0080 ///< Conroe SSSE3 functions -#define FF_MM_SSE4 0x0100 ///< Penryn SSE4.1 functions -#define FF_MM_SSE42 0x0200 ///< Nehalem SSE4.2 functions -#define FF_MM_IWMMXT 0x0100 ///< XScale IWMMXT -#define FF_MM_ALTIVEC 0x0001 ///< standard AltiVec + float border_masking; /** - * bits per sample/pixel from the demuxer (needed for huffyuv). - * - encoding: Set by libavcodec. - * - decoding: Set by user. + * minimum MB lagrange multipler + * - encoding: Set by user. + * - decoding: unused */ - int bits_per_coded_sample; + int mb_lmin; /** - * prediction method (needed for huffyuv) + * maximum MB lagrange multipler * - encoding: Set by user. * - decoding: unused */ - int prediction_method; -#define FF_PRED_LEFT 0 -#define FF_PRED_PLANE 1 -#define FF_PRED_MEDIAN 2 + int mb_lmax; /** - * sample aspect ratio (0 if unknown) - * That is the width of a pixel divided by the height of the pixel. - * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * * - encoding: Set by user. - * - decoding: Set by libavcodec. + * - decoding: unused */ - AVRational sample_aspect_ratio; + int me_penalty_compensation; /** - * the picture in the bitstream - * - encoding: Set by libavcodec. - * - decoding: Set by libavcodec. + * + * - encoding: Set by user. + * - decoding: unused */ - AVFrame *coded_frame; + int bidir_refine; /** - * debug + * * - encoding: Set by user. - * - decoding: Set by user. + * - decoding: unused */ - int debug; -#define FF_DEBUG_PICT_INFO 1 -#define FF_DEBUG_RC 2 -#define FF_DEBUG_BITSTREAM 4 -#define FF_DEBUG_MB_TYPE 8 -#define FF_DEBUG_QP 16 -#define FF_DEBUG_MV 32 -#define FF_DEBUG_DCT_COEFF 0x00000040 -#define FF_DEBUG_SKIP 0x00000080 -#define FF_DEBUG_STARTCODE 0x00000100 -#define FF_DEBUG_PTS 0x00000200 -#define FF_DEBUG_ER 0x00000400 -#define FF_DEBUG_MMCO 0x00000800 -#define FF_DEBUG_BUGS 0x00001000 -#define FF_DEBUG_VIS_QP 0x00002000 -#define FF_DEBUG_VIS_MB_TYPE 0x00004000 -#define FF_DEBUG_BUFFERS 0x00008000 + int brd_scale; /** - * debug + * minimum GOP size * - encoding: Set by user. - * - decoding: Set by user. - */ - int debug_mv; -#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames -#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames -#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames - - /** - * error - * - encoding: Set by libavcodec if flags&CODEC_FLAG_PSNR. * - decoding: unused */ - uint64_t error[4]; + int keyint_min; /** - * minimum MB quantizer - * - encoding: unused - * - decoding: unused + * number of reference frames + * - encoding: Set by user. + * - decoding: Set by lavc. */ - int mb_qmin; + int refs; /** - * maximum MB quantizer - * - encoding: unused + * chroma qp offset from luma + * - encoding: Set by user. * - decoding: unused */ - int mb_qmax; + int chromaoffset; +#if FF_API_UNUSED_MEMBERS /** - * motion estimation comparison function + * Multiplied by qscale for each frame and added to scene_change_score. * - encoding: Set by user. * - decoding: unused */ - int me_cmp; + attribute_deprecated int scenechange_factor; +#endif + /** - * subpixel motion estimation comparison function + * + * Note: Value depends upon the compare function used for fullpel ME. * - encoding: Set by user. * - decoding: unused */ - int me_sub_cmp; + int mv0_threshold; + /** - * macroblock comparison function (not supported yet) + * Adjust sensitivity of b_frame_strategy 1. * - encoding: Set by user. * - decoding: unused */ - int mb_cmp; + int b_sensitivity; + /** - * interlaced DCT comparison function - * - encoding: Set by user. - * - decoding: unused + * Chromaticity coordinates of the source primaries. + * - encoding: Set by user + * - decoding: Set by libavcodec */ - int ildct_cmp; -#define FF_CMP_SAD 0 -#define FF_CMP_SSE 1 -#define FF_CMP_SATD 2 -#define FF_CMP_DCT 3 -#define FF_CMP_PSNR 4 -#define FF_CMP_BIT 5 -#define FF_CMP_RD 6 -#define FF_CMP_ZERO 7 -#define FF_CMP_VSAD 8 -#define FF_CMP_VSSE 9 -#define FF_CMP_NSSE 10 -#define FF_CMP_W53 11 -#define FF_CMP_W97 12 -#define FF_CMP_DCTMAX 13 -#define FF_CMP_DCT264 14 -#define FF_CMP_CHROMA 256 + enum AVColorPrimaries color_primaries; /** - * ME diamond size & shape - * - encoding: Set by user. - * - decoding: unused + * Color Transfer Characteristic. + * - encoding: Set by user + * - decoding: Set by libavcodec */ - int dia_size; + enum AVColorTransferCharacteristic color_trc; /** - * amount of previous MV predictors (2a+1 x 2a+1 square) - * - encoding: Set by user. - * - decoding: unused + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec */ - int last_predictor_count; + enum AVColorSpace colorspace; /** - * prepass for motion estimation - * - encoding: Set by user. - * - decoding: unused + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec */ - int pre_me; + enum AVColorRange color_range; /** - * motion estimation prepass comparison function - * - encoding: Set by user. - * - decoding: unused + * This defines the location of chroma samples. + * - encoding: Set by user + * - decoding: Set by libavcodec */ - int me_pre_cmp; + enum AVChromaLocation chroma_sample_location; /** - * ME prepass diamond size & shape - * - encoding: Set by user. + * Number of slices. + * Indicates number of picture subdivisions. Used for parallelized + * decoding. + * - encoding: Set by user * - decoding: unused */ - int pre_dia_size; + int slices; - /** - * subpel ME quality - * - encoding: Set by user. - * - decoding: unused + /** Field order + * - encoding: set by libavcodec + * - decoding: Set by user. */ - int me_subpel_quality; + enum AVFieldOrder field_order; + + /* audio only */ + int sample_rate; ///< samples per second + int channels; ///< number of audio channels /** - * callback to negotiate the pixelFormat - * @param fmt is the list of formats which are supported by the codec, - * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. - * The first is always the native one. - * @return the chosen format - * - encoding: unused - * - decoding: Set by user, if not set the native format will be chosen. + * audio sample format + * - encoding: Set by user. + * - decoding: Set by libavcodec. */ - enum PixelFormat (*get_format)(struct AVCodecContext *s, const enum PixelFormat * fmt); + enum AVSampleFormat sample_fmt; ///< sample format + /* The following data should not be initialized. */ /** - * DTG active format information (additional aspect ratio - * information only used in DVB MPEG-2 transport streams) - * 0 if not set. + * Number of samples per channel in an audio frame. * - * - encoding: unused - * - decoding: Set by decoder. + * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame + * except the last must contain exactly frame_size samples per channel. + * May be 0 when the codec has CODEC_CAP_VARIABLE_FRAME_SIZE set, then the + * frame size is not restricted. + * - decoding: may be set by some decoders to indicate constant frame size */ - int dtg_active_format; -#define FF_DTG_AFD_SAME 8 -#define FF_DTG_AFD_4_3 9 -#define FF_DTG_AFD_16_9 10 -#define FF_DTG_AFD_14_9 11 -#define FF_DTG_AFD_4_3_SP_14_9 13 -#define FF_DTG_AFD_16_9_SP_14_9 14 -#define FF_DTG_AFD_SP_4_3 15 + int frame_size; /** - * maximum motion estimation search range in subpel units - * If 0 then no limit. + * Frame counter, set by libavcodec. * - * - encoding: Set by user. - * - decoding: unused + * - decoding: total number of frames returned from the decoder so far. + * - encoding: total number of frames passed to the encoder so far. + * + * @note the counter is not incremented if encoding/decoding resulted in + * an error. */ - int me_range; + int frame_number; /** - * intra quantizer bias - * - encoding: Set by user. - * - decoding: unused + * number of bytes per packet if constant and known or 0 + * Used by some WAV based audio codecs. */ - int intra_quant_bias; -#define FF_DEFAULT_QUANT_BIAS 999999 + int block_align; /** - * inter quantizer bias + * Audio cutoff bandwidth (0 means "automatic") * - encoding: Set by user. * - decoding: unused */ - int inter_quant_bias; + int cutoff; +#if FF_API_REQUEST_CHANNELS /** - * color table ID + * Decoder should decode to this many channels if it can (0 for default) * - encoding: unused - * - decoding: Which clrtable should be used for 8bit RGB images. - * Tables have to be stored somewhere. FIXME + * - decoding: Set by user. + * @deprecated Deprecated in favor of request_channel_layout. */ - int color_table_id; + attribute_deprecated int request_channels; +#endif /** - * internal_buffer count - * Don't touch, used by libavcodec default_get_buffer(). + * Audio channel layout. + * - encoding: set by user. + * - decoding: set by user, may be overwritten by libavcodec. */ - int internal_buffer_count; + uint64_t channel_layout; /** - * internal_buffers - * Don't touch, used by libavcodec default_get_buffer(). + * Request decoder to use this channel layout if it can (0 for default) + * - encoding: unused + * - decoding: Set by user. */ - void *internal_buffer; - -#define FF_LAMBDA_SHIFT 7 -#define FF_LAMBDA_SCALE (1< ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). - * This is used to work around some encoder bugs. - * - encoding: unused - * - decoding: Set by user, will be converted to uppercase by libavcodec during init. - */ - unsigned int stream_codec_tag; + int qmin; /** - * scene change detection threshold - * 0 is default, larger means fewer detected scene changes. + * maximum quantizer * - encoding: Set by user. * - decoding: unused */ - int scenechange_threshold; + int qmax; /** - * minimum Lagrange multipler + * maximum quantizer difference between frames * - encoding: Set by user. * - decoding: unused */ - int lmin; + int max_qdiff; /** - * maximum Lagrange multipler + * ratecontrol qmin qmax limiting method + * 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. * - encoding: Set by user. * - decoding: unused */ - int lmax; + float rc_qsquish; - /** - * palette control structure - * - encoding: ??? (no palette-enabled encoder yet) - * - decoding: Set by user. - */ - struct AVPaletteControl *palctrl; + float rc_qmod_amp; + int rc_qmod_freq; /** - * noise reduction strength + * decoder bitstream buffer size * - encoding: Set by user. * - decoding: unused */ - int noise_reduction; - - /** - * Called at the beginning of a frame to get cr buffer for it. - * Buffer type (size, hints) must be the same. libavcodec won't check it. - * libavcodec will pass previous buffer in pic, function should return - * same buffer or new buffer with old frame "painted" into it. - * If pic.data[0] == NULL must behave like get_buffer(). - * if CODEC_CAP_DR1 is not set then reget_buffer() must call - * avcodec_default_reget_buffer() instead of providing buffers allocated by - * some other means. - * - encoding: unused - * - decoding: Set by libavcodec., user can override - */ - int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic); + int rc_buffer_size; /** - * Number of bits which should be loaded into the rc buffer before decoding starts. - * - encoding: Set by user. + * ratecontrol override, see RcOverride + * - encoding: Allocated/set/freed by user. * - decoding: unused */ - int rc_initial_buffer_occupancy; + int rc_override_count; + RcOverride *rc_override; /** - * - * - encoding: Set by user. + * rate control equation + * - encoding: Set by user * - decoding: unused */ - int inter_threshold; + const char *rc_eq; /** - * CODEC_FLAG2_* + * maximum bitrate * - encoding: Set by user. - * - decoding: Set by user. + * - decoding: Set by libavcodec. */ - int flags2; + int rc_max_rate; /** - * Simulates errors in the bitstream to test error concealment. + * minimum bitrate * - encoding: Set by user. * - decoding: unused */ - int error_rate; + int rc_min_rate; + + float rc_buffer_aggressivity; /** - * MP3 antialias algorithm, see FF_AA_* below. - * - encoding: unused - * - decoding: Set by user. - */ - int antialias_algo; -#define FF_AA_AUTO 0 -#define FF_AA_FASTINT 1 //not implemented yet -#define FF_AA_INT 2 -#define FF_AA_FLOAT 3 - /** - * quantizer noise shaping + * initial complexity for pass1 ratecontrol * - encoding: Set by user. * - decoding: unused */ - int quantizer_noise_shaping; + float rc_initial_cplx; /** - * thread count - * is used to decide how many independent tasks should be passed to execute() + * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. * - encoding: Set by user. - * - decoding: Set by user. - */ - int thread_count; - - /** - * The codec may call this to execute several independent things. - * It will return only after finishing all tasks. - * The user may replace this with some multithreaded implementation, - * the default implementation will execute the parts serially. - * @param count the number of things to execute - * - encoding: Set by libavcodec, user can override. - * - decoding: Set by libavcodec, user can override. - */ - int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); - - /** - * thread opaque - * Can be used by execute() to store some per AVCodecContext stuff. - * - encoding: set by execute() - * - decoding: set by execute() + * - decoding: unused. */ - void *thread_opaque; + float rc_max_available_vbv_use; /** - * Motion estimation threshold below which no motion estimation is - * performed, but instead the user specified motion vectors are used. - * + * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. * - encoding: Set by user. - * - decoding: unused + * - decoding: unused. */ - int me_threshold; + float rc_min_vbv_overflow_use; /** - * Macroblock threshold below which the user specified macroblock types will be used. + * Number of bits which should be loaded into the rc buffer before decoding starts. * - encoding: Set by user. * - decoding: unused */ - int mb_threshold; + int rc_initial_buffer_occupancy; +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 +#define FF_CODER_TYPE_RAW 2 +#define FF_CODER_TYPE_RLE 3 +#if FF_API_UNUSED_MEMBERS +#define FF_CODER_TYPE_DEFLATE 4 +#endif /* FF_API_UNUSED_MEMBERS */ /** - * precision of the intra DC coefficient - 8 + * coder type * - encoding: Set by user. * - decoding: unused */ - int intra_dc_precision; + int coder_type; /** - * noise vs. sse weight for the nsse comparsion function + * context model * - encoding: Set by user. * - decoding: unused */ - int nsse_weight; - - /** - * Number of macroblock rows at the top which are skipped. - * - encoding: unused - * - decoding: Set by user. - */ - int skip_top; - - /** - * Number of macroblock rows at the bottom which are skipped. - * - encoding: unused - * - decoding: Set by user. - */ - int skip_bottom; + int context_model; /** - * profile + * minimum Lagrange multiplier * - encoding: Set by user. - * - decoding: Set by libavcodec. + * - decoding: unused */ - int profile; -#define FF_PROFILE_UNKNOWN -99 - -#define FF_PROFILE_AAC_MAIN 0 -#define FF_PROFILE_AAC_LOW 1 -#define FF_PROFILE_AAC_SSR 2 -#define FF_PROFILE_AAC_LTP 3 - -#define FF_PROFILE_H264_BASELINE 66 -#define FF_PROFILE_H264_MAIN 77 -#define FF_PROFILE_H264_EXTENDED 88 -#define FF_PROFILE_H264_HIGH 100 -#define FF_PROFILE_H264_HIGH_10 110 -#define FF_PROFILE_H264_HIGH_422 122 -#define FF_PROFILE_H264_HIGH_444 244 -#define FF_PROFILE_H264_CAVLC_444 44 + int lmin; /** - * level + * maximum Lagrange multiplier * - encoding: Set by user. - * - decoding: Set by libavcodec. - */ - int level; -#define FF_LEVEL_UNKNOWN -99 - - /** - * low resolution decoding, 1-> 1/2 size, 2->1/4 size - * - encoding: unused - * - decoding: Set by user. - */ - int lowres; - - /** - * Bitstream width / height, may be different from width/height if lowres - * or other things are used. - * - encoding: unused - * - decoding: Set by user before init if known. Codec should override / dynamically change if needed. + * - decoding: unused */ - int coded_width, coded_height; + int lmax; /** * frame skip threshold @@ -2208,445 +2418,695 @@ typedef struct AVCodecContext { int frame_skip_cmp; /** - * Border processing masking, raises the quantizer for mbs on the borders - * of the picture. + * trellis RD quantization * - encoding: Set by user. * - decoding: unused */ - float border_masking; + int trellis; /** - * minimum MB lagrange multipler * - encoding: Set by user. * - decoding: unused */ - int mb_lmin; + int min_prediction_order; /** - * maximum MB lagrange multipler * - encoding: Set by user. * - decoding: unused */ - int mb_lmax; + int max_prediction_order; /** - * - * - encoding: Set by user. - * - decoding: unused + * GOP timecode frame start number + * - encoding: Set by user, in non drop frame format + * - decoding: Set by libavcodec (timecode in the 25 bits format, -1 if unset) */ - int me_penalty_compensation; + int64_t timecode_frame_start; - /** - * - * - encoding: unused - * - decoding: Set by user. - */ - enum AVDiscard skip_loop_filter; + /* The RTP callback: This function is called */ + /* every time the encoder has a packet to send. */ + /* It depends on the encoder if the data starts */ + /* with a Start Code (it should). H.263 does. */ + /* mb_nb contains the number of macroblocks */ + /* encoded in the RTP payload. */ + void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); - /** - * - * - encoding: unused - * - decoding: Set by user. - */ - enum AVDiscard skip_idct; + int rtp_payload_size; /* The size of the RTP payload: the coder will */ + /* do its best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263. */ + /* This doesn't take account of any particular */ + /* headers inside the transmitted RTP payload. */ - /** - * - * - encoding: unused - * - decoding: Set by user. - */ - enum AVDiscard skip_frame; + /* statistics, used for 2-pass encoding */ + int mv_bits; + int header_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int p_count; + int skip_count; + int misc_bits; /** - * - * - encoding: Set by user. + * number of bits used for the previously encoded frame + * - encoding: Set by libavcodec. * - decoding: unused */ - int bidir_refine; + int frame_bits; /** - * - * - encoding: Set by user. + * pass1 encoding statistics output buffer + * - encoding: Set by libavcodec. * - decoding: unused */ - int brd_scale; + char *stats_out; /** - * constant rate factor - quality-based VBR - values ~correspond to qps - * - encoding: Set by user. + * pass2 encoding statistics input buffer + * Concatenated stuff from stats_out of pass1 should be placed here. + * - encoding: Allocated/set/freed by user. * - decoding: unused */ - float crf; + char *stats_in; /** - * constant quantization parameter rate control method - * - encoding: Set by user. - * - decoding: unused - */ - int cqp; + * Work around bugs in encoders which sometimes cannot be detected automatically. + * - encoding: Set by user + * - decoding: Set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#if FF_API_OLD_MSMPEG4 +#define FF_BUG_OLD_MSMPEG4 2 +#endif +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#if FF_API_AC_VLC +#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. +#endif +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. +#define FF_BUG_TRUNCATED 16384 /** - * minimum GOP size + * strictly follow the standard (MPEG4, ...). * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. + * Setting this to STRICT or higher means the encoder and decoder will + * generally do stupid things, whereas setting it to unofficial or lower + * will mean the encoder might produce output that is not supported by all + * spec-compliant decoders. Decoders don't differentiate between normal, + * unofficial and experimental (that is, they always try to decode things + * when they can) unless they are explicitly asked to behave stupidly + * (=strictly conform to the specs) */ - int keyint_min; + int strict_std_compliance; +#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. +#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. /** - * number of reference frames - * - encoding: Set by user. - * - decoding: Set by lavc. + * error concealment flags + * - encoding: unused + * - decoding: Set by user. */ - int refs; + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 +#define FF_EC_FAVOR_INTER 256 /** - * chroma qp offset from luma + * debug * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. */ - int chromaoffset; + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#if FF_API_DEBUG_MV +/** + * @deprecated this option does nothing + */ +#define FF_DEBUG_MV 32 +#endif +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#if FF_API_UNUSED_MEMBERS +#define FF_DEBUG_PTS 0x00000200 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#if FF_API_DEBUG_MV +#define FF_DEBUG_VIS_QP 0x00002000 ///< only access through AVOptions from outside libavcodec +#define FF_DEBUG_VIS_MB_TYPE 0x00004000 ///< only access through AVOptions from outside libavcodec +#endif +#define FF_DEBUG_BUFFERS 0x00008000 +#define FF_DEBUG_THREADS 0x00010000 +#define FF_DEBUG_NOMC 0x01000000 +#if FF_API_DEBUG_MV /** - * Influences how often B-frames are used. + * debug + * Code outside libavcodec should access this field using AVOptions * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. */ - int bframebias; + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif /** - * trellis RD quantization - * - encoding: Set by user. - * - decoding: unused + * Error recognition; may misdetect some more or less valid parts as errors. + * - encoding: unused + * - decoding: Set by user. */ - int trellis; + int err_recognition; + +/** + * Verify checksums embedded in the bitstream (could be of either encoded or + * decoded data, depending on the codec) and print an error message on mismatch. + * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the + * decoder returning an error. + */ +#define AV_EF_CRCCHECK (1<<0) +#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations +#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length +#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection + +#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue +#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors +#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors +#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error + /** - * Reduce fluctuations in qp (before curve compression). - * - encoding: Set by user. - * - decoding: unused + * opaque 64bit number (generally a PTS) that will be reordered and + * output in AVFrame.reordered_opaque + * - encoding: unused + * - decoding: Set by user. */ - float complexityblur; + int64_t reordered_opaque; /** - * in-loop deblocking filter alphac0 parameter - * alpha is in the range -6...6 - * - encoding: Set by user. - * - decoding: unused + * Hardware accelerator in use + * - encoding: unused. + * - decoding: Set by libavcodec */ - int deblockalpha; + struct AVHWAccel *hwaccel; /** - * in-loop deblocking filter beta parameter - * beta is in the range -6...6 - * - encoding: Set by user. - * - decoding: unused + * Hardware accelerator context. + * For some hardware accelerators, a global context needs to be + * provided by the user. In that case, this holds display-dependent + * data FFmpeg cannot instantiate itself. Please refer to the + * FFmpeg HW accelerator documentation to know how to fill this + * is. e.g. for VA API, this is a struct vaapi_context. + * - encoding: unused + * - decoding: Set by user */ - int deblockbeta; + void *hwaccel_context; /** - * macroblock subpartition sizes to consider - p8x8, p4x4, b8x8, i8x8, i4x4 - * - encoding: Set by user. + * error + * - encoding: Set by libavcodec if flags&CODEC_FLAG_PSNR. * - decoding: unused */ - int partitions; -#define X264_PART_I4X4 0x001 /* Analyze i4x4 */ -#define X264_PART_I8X8 0x002 /* Analyze i8x8 (requires 8x8 transform) */ -#define X264_PART_P8X8 0x010 /* Analyze p16x8, p8x16 and p8x8 */ -#define X264_PART_P4X4 0x020 /* Analyze p8x4, p4x8, p4x4 */ -#define X264_PART_B8X8 0x100 /* Analyze b16x8, b8x16 and b8x8 */ + uint64_t error[AV_NUM_DATA_POINTERS]; /** - * direct MV prediction mode - 0 (none), 1 (spatial), 2 (temporal), 3 (auto) + * DCT algorithm, see FF_DCT_* below * - encoding: Set by user. * - decoding: unused */ - int directpred; + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#if FF_API_UNUSED_MEMBERS +#define FF_DCT_INT 2 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_DCT_MMX 3 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 /** - * Audio cutoff bandwidth (0 means "automatic") + * IDCT algorithm, see FF_IDCT_* below. * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. */ - int cutoff; + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#if FF_API_ARCH_SH4 +#define FF_IDCT_SH4 9 +#endif +#define FF_IDCT_SIMPLEARM 10 +#if FF_API_UNUSED_MEMBERS +#define FF_IDCT_IPP 13 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_IDCT_XVID 14 +#if FF_API_IDCT_XVIDMMX +#define FF_IDCT_XVIDMMX 14 +#endif /* FF_API_IDCT_XVIDMMX */ +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 +#if FF_API_ARCH_SPARC +#define FF_IDCT_SIMPLEVIS 18 +#endif +#define FF_IDCT_FAAN 20 +#define FF_IDCT_SIMPLENEON 22 +#if FF_API_ARCH_ALPHA +#define FF_IDCT_SIMPLEALPHA 23 +#endif +#define FF_IDCT_SIMPLEAUTO 128 /** - * Multiplied by qscale for each frame and added to scene_change_score. - * - encoding: Set by user. - * - decoding: unused + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: Set by libavcodec. + * - decoding: Set by user. */ - int scenechange_factor; + int bits_per_coded_sample; /** - * - * Note: Value depends upon the compare function used for fullpel ME. - * - encoding: Set by user. - * - decoding: unused + * Bits per sample/pixel of internal libavcodec pixel/sample format. + * - encoding: set by user. + * - decoding: set by libavcodec. */ - int mv0_threshold; + int bits_per_raw_sample; +#if FF_API_LOWRES /** - * Adjusts sensitivity of b_frame_strategy 1. - * - encoding: Set by user. - * - decoding: unused + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_lowres(avctx) */ - int b_sensitivity; + int lowres; +#endif /** - * - encoding: Set by user. + * the picture in the bitstream + * - encoding: Set by libavcodec. * - decoding: unused */ - int compression_level; -#define FF_COMPRESSION_DEFAULT -1 + AVFrame *coded_frame; /** - * Sets whether to use LPC mode - used by FLAC encoder. + * thread count + * is used to decide how many independent tasks should be passed to execute() * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. */ - int use_lpc; + int thread_count; /** - * LPC coefficient precision - used by FLAC encoder - * - encoding: Set by user. - * - decoding: unused + * Which multithreading methods to use. + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, + * so clients which cannot provide future frames should not use it. + * + * - encoding: Set by user, otherwise the default is used. + * - decoding: Set by user, otherwise the default is used. */ - int lpc_coeff_precision; + int thread_type; +#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once +#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once /** - * - encoding: Set by user. - * - decoding: unused + * Which multithreading methods are in use by the codec. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. */ - int min_prediction_order; + int active_thread_type; /** + * Set by the client if its custom get_buffer() callback can be called + * synchronously from another thread, which allows faster multithreaded decoding. + * draw_horiz_band() will be called from other threads regardless of this setting. + * Ignored if the default get_buffer() is used. * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. */ - int max_prediction_order; + int thread_safe_callbacks; /** - * search method for selecting prediction order - * - encoding: Set by user. - * - decoding: unused + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param count the number of things to execute + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. + * @param c context passed also to func + * @param count the number of things to execute + * @param arg2 argument passed unchanged to func + * @param ret return values of executed functions, must have space for "count" values. May be NULL. + * @param func function that will be called count times, with jobnr from 0 to count-1. + * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no + * two instances of func executing at the same time will have the same threadnr. + * @return always 0 currently, but code should handle a future improvement where when any call to func + * returns < 0 no further calls to func may be done and < 0 is returned. + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + +#if FF_API_THREAD_OPAQUE + /** + * @deprecated this field should not be used from outside of lavc */ - int prediction_order_method; + attribute_deprecated + void *thread_opaque; +#endif /** + * noise vs. sse weight for the nsse comparison function * - encoding: Set by user. * - decoding: unused */ - int min_partition_order; + int nsse_weight; /** + * profile * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by libavcodec. */ - int max_partition_order; + int profile; +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +#define FF_PROFILE_AAC_MAIN 0 +#define FF_PROFILE_AAC_LOW 1 +#define FF_PROFILE_AAC_SSR 2 +#define FF_PROFILE_AAC_LTP 3 +#define FF_PROFILE_AAC_HE 4 +#define FF_PROFILE_AAC_HE_V2 28 +#define FF_PROFILE_AAC_LD 22 +#define FF_PROFILE_AAC_ELD 38 +#define FF_PROFILE_MPEG2_AAC_LOW 128 +#define FF_PROFILE_MPEG2_AAC_HE 131 + +#define FF_PROFILE_DTS 20 +#define FF_PROFILE_DTS_ES 30 +#define FF_PROFILE_DTS_96_24 40 +#define FF_PROFILE_DTS_HD_HRA 50 +#define FF_PROFILE_DTS_HD_MA 60 + +#define FF_PROFILE_MPEG2_422 0 +#define FF_PROFILE_MPEG2_HIGH 1 +#define FF_PROFILE_MPEG2_SS 2 +#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 +#define FF_PROFILE_MPEG2_MAIN 4 +#define FF_PROFILE_MPEG2_SIMPLE 5 + +#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define FF_PROFILE_H264_BASELINE 66 +#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) +#define FF_PROFILE_H264_MAIN 77 +#define FF_PROFILE_H264_EXTENDED 88 +#define FF_PROFILE_H264_HIGH 100 +#define FF_PROFILE_H264_HIGH_10 110 +#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_HIGH_422 122 +#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_HIGH_444 144 +#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_CAVLC_444 44 + +#define FF_PROFILE_VC1_SIMPLE 0 +#define FF_PROFILE_VC1_MAIN 1 +#define FF_PROFILE_VC1_COMPLEX 2 +#define FF_PROFILE_VC1_ADVANCED 3 + +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 0 +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 1 +#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 2 +#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 +#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 + + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 /** - * GOP timecode frame start number, in non drop frame format + * level * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by libavcodec. */ - int64_t timecode_frame_start; + int level; +#define FF_LEVEL_UNKNOWN -99 -#if LIBAVCODEC_VERSION_MAJOR < 53 /** - * Decoder should decode to this many channels if it can (0 for default) + * Skip loop filtering for selected frames. * - encoding: unused * - decoding: Set by user. - * @deprecated Deprecated in favor of request_channel_layout. */ - int request_channels; -#endif + enum AVDiscard skip_loop_filter; /** - * Percentage of dynamic range compression to be applied by the decoder. - * The default value is 1.0, corresponding to full compression. + * Skip IDCT/dequantization for selected frames. * - encoding: unused * - decoding: Set by user. */ - float drc_scale; + enum AVDiscard skip_idct; /** - * opaque 64bit number (generally a PTS) that will be reordered and - * output in AVFrame.reordered_opaque + * Skip decoding for selected frames. * - encoding: unused * - decoding: Set by user. */ - int64_t reordered_opaque; + enum AVDiscard skip_frame; /** - * Bits per sample/pixel of internal libavcodec pixel/sample format. - * This field is applicable only when sample_fmt is SAMPLE_FMT_S32. - * - encoding: set by user. - * - decoding: set by libavcodec. + * Header containing style information for text subtitles. + * For SUBTITLE_ASS subtitle type, it should contain the whole ASS + * [Script Info] and [V4+ Styles] section, plus the [Events] line and + * the Format line following. It shouldn't include any Dialogue line. + * - encoding: Set/allocated/freed by user (before avcodec_open2()) + * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) */ - int bits_per_raw_sample; + uint8_t *subtitle_header; + int subtitle_header_size; +#if FF_API_ERROR_RATE /** - * Audio channel layout. - * - encoding: set by user. - * - decoding: set by libavcodec. + * @deprecated use the 'error_rate' private AVOption of the mpegvideo + * encoders */ - int64_t channel_layout; + attribute_deprecated + int error_rate; +#endif +#if FF_API_CODEC_PKT /** - * Request decoder to use this channel layout if it can (0 for default) - * - encoding: unused - * - decoding: Set by user. + * @deprecated this field is not supposed to be accessed from outside lavc */ - int64_t request_channel_layout; + attribute_deprecated + AVPacket *pkt; +#endif /** - * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. - * - encoding: Set by user. + * VBV delay coded in the last frame (in periods of a 27 MHz clock). + * Used for compliant TS muxing. + * - encoding: Set by libavcodec. * - decoding: unused. */ - float rc_max_available_vbv_use; + uint64_t vbv_delay; /** - * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. - * - encoding: Set by user. - * - decoding: unused. + * Encoding only. Allow encoders to output packets that do not contain any + * encoded data, only side data. + * + * Some encoders need to output such packets, e.g. to update some stream + * parameters at the end of encoding. + * + * All callers are strongly recommended to set this option to 1 and update + * their code to deal with such packets, since this behaviour may become + * always enabled in the future (then this option will be deprecated and + * later removed). To avoid ABI issues when this happens, the callers should + * use AVOptions to set this field. */ - float rc_min_vbv_overflow_use; + int side_data_only_packets; /** - * Hardware accelerator in use - * - encoding: unused. - * - decoding: Set by libavcodec + * Timebase in which pkt_dts/pts and AVPacket.dts/pts are. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_pkt_timebase(avctx) + * - encoding unused. + * - decoding set by user. */ - struct AVHWAccel *hwaccel; + AVRational pkt_timebase; /** - * For some codecs, the time base is closer to the field rate than the frame rate. - * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration - * if no telecine is used ... - * - * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + * AVCodecDescriptor + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_codec_descriptor(avctx) + * - encoding: unused. + * - decoding: set by libavcodec. */ - int ticks_per_frame; + const AVCodecDescriptor *codec_descriptor; +#if !FF_API_LOWRES /** - * Hardware accelerator context. - * For some hardware accelerators, a global context needs to be - * provided by the user. In that case, this holds display-dependent - * data FFmpeg cannot instantiate itself. Please refer to the - * FFmpeg HW accelerator documentation to know how to fill this - * is. e.g. for VA API, this is a struct vaapi_context. + * low resolution decoding, 1-> 1/2 size, 2->1/4 size * - encoding: unused - * - decoding: Set by user - */ - void *hwaccel_context; - - /** - * Chromaticity coordinates of the source primaries. - * - encoding: Set by user - * - decoding: Set by libavcodec + * - decoding: Set by user. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_lowres(avctx) */ - enum AVColorPrimaries color_primaries; + int lowres; +#endif /** - * Color Transfer Characteristic. - * - encoding: Set by user - * - decoding: Set by libavcodec + * Current statistics for PTS correction. + * - decoding: maintained and used by libavcodec, not intended to be used by user apps + * - encoding: unused */ - enum AVColorTransferCharacteristic color_trc; + int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far + int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far + int64_t pts_correction_last_pts; /// PTS of the last frame + int64_t pts_correction_last_dts; /// DTS of the last frame /** - * YUV colorspace type. - * - encoding: Set by user - * - decoding: Set by libavcodec + * Character encoding of the input subtitles file. + * - decoding: set by user + * - encoding: unused */ - enum AVColorSpace colorspace; + char *sub_charenc; /** - * MPEG vs JPEG YUV range. - * - encoding: Set by user - * - decoding: Set by libavcodec + * Subtitles character encoding mode. Formats or codecs might be adjusting + * this setting (if they are doing the conversion themselves for instance). + * - decoding: set by libavcodec + * - encoding: unused */ - enum AVColorRange color_range; + int sub_charenc_mode; +#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) +#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself +#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv /** - * This defines the location of chroma samples. - * - encoding: Set by user - * - decoding: Set by libavcodec + * Skip processing alpha if supported by codec. + * Note that if the format uses pre-multiplied alpha (common with VP6, + * and recommended due to better video quality/compression) + * the image will look as if alpha-blended onto a black background. + * However for formats that do not use pre-multiplied alpha + * there might be serious artefacts (though e.g. libswscale currently + * assumes pre-multiplied alpha anyway). + * Code outside libavcodec should access this field using AVOptions + * + * - decoding: set by user + * - encoding: unused */ - enum AVChromaLocation chroma_sample_location; + int skip_alpha; /** - * The codec may call this to execute several independent things. - * It will return only after finishing all tasks. - * The user may replace this with some multithreaded implementation, - * the default implementation will execute the parts serially. - * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. - * @param c context passed also to func - * @param count the number of things to execute - * @param arg2 argument passed unchanged to func - * @param ret return values of executed functions, must have space for "count" values. May be NULL. - * @param func function that will be called count times, with jobnr from 0 to count-1. - * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no - * two instances of func executing at the same time will have the same threadnr. - * @return always 0 currently, but code should handle a future improvement where when any call to func - * returns < 0 no further calls to func may be done and < 0 is returned. - * - encoding: Set by libavcodec, user can override. - * - decoding: Set by libavcodec, user can override. + * Number of samples to skip after a discontinuity + * - decoding: unused + * - encoding: set by libavcodec */ - int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + int seek_preroll; +#if !FF_API_DEBUG_MV /** - * explicit P-frame weighted prediction analysis method - * 0: off - * 1: fast blind weighting (one reference duplicate with -1 offset) - * 2: smart weighting (full fade detection analysis) + * debug motion vectors + * Code outside libavcodec should access this field using AVOptions * - encoding: Set by user. - * - decoding: unused + * - decoding: Set by user. */ - int weighted_p_pred; + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif /** - * AQ mode - * 0: Disabled - * 1: Variance AQ (complexity mask) - * 2: Auto-variance AQ (experimental) - * - encoding: Set by user - * - decoding: unused + * custom intra quantization matrix + * Code outside libavcodec should access this field using av_codec_g/set_chroma_intra_matrix() + * - encoding: Set by user, can be NULL. + * - decoding: unused. */ - int aq_mode; + uint16_t *chroma_intra_matrix; +} AVCodecContext; - /** - * AQ strength - * Reduces blocking and blurring in flat and textured areas. - * - encoding: Set by user - * - decoding: unused - */ - float aq_strength; +AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); +void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val); - /** - * PSY RD - * Strength of psychovisual optimization - * - encoding: Set by user - * - decoding: unused - */ - float psy_rd; +const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx); +void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc); - /** - * PSY trellis - * Strength of psychovisual optimization - * - encoding: Set by user - * - decoding: unused - */ - float psy_trellis; +int av_codec_get_lowres(const AVCodecContext *avctx); +void av_codec_set_lowres(AVCodecContext *avctx, int val); - /** - * RC lookahead - * Number of frames for frametype and ratecontrol lookahead - * - encoding: Set by user - * - decoding: unused - */ - int rc_lookahead; -} AVCodecContext; +int av_codec_get_seek_preroll(const AVCodecContext *avctx); +void av_codec_set_seek_preroll(AVCodecContext *avctx, int val); + +uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx); +void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val); + +/** + * AVProfile. + */ +typedef struct AVProfile { + int profile; + const char *name; ///< short name for the profile +} AVProfile; + +typedef struct AVCodecDefault AVCodecDefault; + +struct AVSubtitle; /** * AVCodec. @@ -2659,36 +3119,96 @@ typedef struct AVCodec { * This is the primary way to find a codec from the user perspective. */ const char *name; + /** + * Descriptive name for the codec, meant to be more human readable than name. + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *long_name; enum AVMediaType type; - enum CodecID id; - int priv_data_size; - int (*init)(AVCodecContext *); - int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data); - int (*close)(AVCodecContext *); - int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + enum AVCodecID id; /** * Codec capabilities. * see CODEC_CAP_* */ int capabilities; + const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} + const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 + const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 + const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 + const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 +#if FF_API_LOWRES + uint8_t max_lowres; ///< maximum value for lowres supported by the decoder, no direct access, use av_codec_get_max_lowres() +#endif + const AVClass *priv_class; ///< AVClass for the private context + const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int priv_data_size; struct AVCodec *next; + /** + * @name Frame-level threading support functions + * @{ + */ + /** + * If defined, called on thread contexts when they are created. + * If the codec allocates writable tables in init(), re-allocate them here. + * priv_data will be set to a copy of the original. + */ + int (*init_thread_copy)(AVCodecContext *); + /** + * Copy necessary context variables from a previous thread context to the current one. + * If not defined, the next thread will start automatically; otherwise, the codec + * must call ff_thread_finish_setup(). + * + * dst and src will (rarely) point to the same context, in which case memcpy should be skipped. + */ + int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); + /** @} */ + + /** + * Private codec-specific defaults. + */ + const AVCodecDefault *defaults; + + /** + * Initialize codec static data, called from avcodec_register(). + */ + void (*init_static_data)(struct AVCodec *codec); + + int (*init)(AVCodecContext *); + int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, + const struct AVSubtitle *sub); + /** + * Encode data to an AVPacket. + * + * @param avctx codec context + * @param avpkt output AVPacket (may contain a user-provided buffer) + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in avpkt. + * @return 0 on success, negative error code on failure + */ + int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, + int *got_packet_ptr); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + int (*close)(AVCodecContext *); /** * Flush buffers. * Will be called when seeking */ void (*flush)(AVCodecContext *); - const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} - const enum PixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 - /** - * Descriptive name for the codec, meant to be more human readable than name. - * You should use the NULL_IF_CONFIG_SMALL() macro to define it. - */ - const char *long_name; - const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 - const enum SampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 - const int64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 } AVCodec; +int av_codec_get_max_lowres(const AVCodec *codec); + +struct MpegEncContext; + /** * AVHWAccel. */ @@ -2710,16 +3230,16 @@ typedef struct AVHWAccel { /** * Codec implemented by the hardware accelerator. * - * See CODEC_ID_xxx + * See AV_CODEC_ID_xxx */ - enum CodecID id; + enum AVCodecID id; /** * Supported pixel format. * * Only hardware accelerated formats are supported here. */ - enum PixelFormat pix_fmt; + enum AVPixelFormat pix_fmt; /** * Hardware accelerated codec capabilities. @@ -2727,8 +3247,20 @@ typedef struct AVHWAccel { */ int capabilities; + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ struct AVHWAccel *next; + /** + * Allocate a custom buffer + */ + int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame); + /** * Called at the beginning of each frame or field picture. * @@ -2750,6 +3282,7 @@ typedef struct AVHWAccel { * * Meaningful slice information (codec specific) is guaranteed to * be parsed at this point. This function is mandatory. + * The only exception is XvMC, that works on MB level. * * @param avctx the codec context * @param buf the slice data buffer base @@ -2770,49 +3303,70 @@ typedef struct AVHWAccel { int (*end_frame)(AVCodecContext *avctx); /** - * Size of HW accelerator private data. + * Size of per-frame hardware accelerator private data. * * Private data is allocated with av_mallocz() before * AVCodecContext.get_buffer() and deallocated after * AVCodecContext.release_buffer(). */ + int frame_priv_data_size; + + /** + * Called for every Macroblock in a slice. + * + * XvMC uses it to replace the ff_mpv_decode_mb(). + * Instead of decoding to raw picture, MB parameters are + * stored in an array provided by the video driver. + * + * @param s the mpeg context + */ + void (*decode_mb)(struct MpegEncContext *s); + + /** + * Initialize the hwaccel private data. + * + * This will be called from ff_get_format(), after hwaccel and + * hwaccel_context are set and the hwaccel private data in AVCodecInternal + * is allocated. + */ + int (*init)(AVCodecContext *avctx); + + /** + * Uninitialize the hwaccel private data. + * + * This will be called from get_format() or avcodec_close(), after hwaccel + * and hwaccel_context are already uninitialized. + */ + int (*uninit)(AVCodecContext *avctx); + + /** + * Size of the private data to allocate in + * AVCodecInternal.hwaccel_priv_data. + */ int priv_data_size; } AVHWAccel; /** - * four components are given, that's all. - * the last component is alpha + * @defgroup lavc_picture AVPicture + * + * Functions for working with AVPicture + * @{ */ -typedef struct AVPicture { - uint8_t *data[4]; - int linesize[4]; ///< number of bytes per line -} AVPicture; -#if LIBAVCODEC_VERSION_MAJOR < 53 /** - * AVPaletteControl - * This structure defines a method for communicating palette changes - * between and demuxer and a decoder. + * Picture data structure. * - * @deprecated Use AVPacket to send palette changes instead. - * This is totally broken. + * Up to four components can be stored into it, the last component is + * alpha. */ -#define AVPALETTE_SIZE 1024 -#define AVPALETTE_COUNT 256 -typedef struct AVPaletteControl { - - /* Demuxer sets this to 1 to indicate the palette has changed; - * decoder resets to 0. */ - int palette_changed; - - /* 4-byte ARGB palette entries, stored in native byte order; note that - * the individual palette components should be on a 8-bit scale; if - * the palette data comes from an IBM VGA native format, the component - * data is probably 6 bits in size and needs to be scaled. */ - unsigned int palette[AVPALETTE_COUNT]; +typedef struct AVPicture { + uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes + int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line +} AVPicture; -} AVPaletteControl attribute_deprecated; -#endif +/** + * @} + */ enum AVSubtitleType { SUBTITLE_NONE, @@ -2832,6 +3386,8 @@ enum AVSubtitleType { SUBTITLE_ASS, }; +#define AV_SUBTITLE_FLAG_FORCED 0x00000001 + typedef struct AVSubtitleRect { int x; ///< top left corner of pict, undefined when pict is not set int y; ///< top left corner of pict, undefined when pict is not set @@ -2850,10 +3406,12 @@ typedef struct AVSubtitleRect { /** * 0 terminated ASS/SSA compatible event line. - * The pressentation of this is unaffected by the other values in this + * The presentation of this is unaffected by the other values in this * struct. */ char *ass; + + int flags; } AVSubtitleRect; typedef struct AVSubtitle { @@ -2865,521 +3423,535 @@ typedef struct AVSubtitle { int64_t pts; ///< Same as packet pts, in AV_TIME_BASE } AVSubtitle; -/* packet functions */ +/** + * If c is NULL, returns the first registered codec, + * if c is non-NULL, returns the next registered codec after c, + * or NULL if c is the last one. + */ +AVCodec *av_codec_next(const AVCodec *c); + +/** + * Return the LIBAVCODEC_VERSION_INT constant. + */ +unsigned avcodec_version(void); /** - * @deprecated use NULL instead + * Return the libavcodec build-time configuration. */ -attribute_deprecated void av_destruct_packet_nofree(AVPacket *pkt); +const char *avcodec_configuration(void); /** - * Default packet destructor. + * Return the libavcodec license. */ -void av_destruct_packet(AVPacket *pkt); +const char *avcodec_license(void); /** - * Initialize optional fields of a packet with default values. + * Register the codec codec and initialize libavcodec. * - * @param pkt packet + * @warning either this function or avcodec_register_all() must be called + * before any other libavcodec functions. + * + * @see avcodec_register_all() */ -void av_init_packet(AVPacket *pkt); +void avcodec_register(AVCodec *codec); /** - * Allocate the payload of a packet and initialize its fields with - * default values. + * Register all the codecs, parsers and bitstream filters which were enabled at + * configuration time. If you do not call this function you can select exactly + * which formats you want to support, by using the individual registration + * functions. * - * @param pkt packet - * @param size wanted payload size - * @return 0 if OK, AVERROR_xxx otherwise + * @see avcodec_register + * @see av_register_codec_parser + * @see av_register_bitstream_filter */ -int av_new_packet(AVPacket *pkt, int size); +void avcodec_register_all(void); /** - * Reduce packet size, correctly zeroing padding + * Allocate an AVCodecContext and set its fields to default values. The + * resulting struct should be freed with avcodec_free_context(). * - * @param pkt packet - * @param size new size + * @param codec if non-NULL, allocate private data and initialize defaults + * for the given codec. It is illegal to then call avcodec_open2() + * with a different codec. + * If NULL, then the codec-specific defaults won't be initialized, + * which may result in suboptimal default settings (this is + * important mainly for encoders, e.g. libx264). + * + * @return An AVCodecContext filled with default values or NULL on failure. + * @see avcodec_get_context_defaults */ -void av_shrink_packet(AVPacket *pkt, int size); +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); /** - * @warning This is a hack - the packet memory allocation stuff is broken. The - * packet is allocated if it was not really allocated. + * Free the codec context and everything associated with it and write NULL to + * the provided pointer. */ -int av_dup_packet(AVPacket *pkt); +void avcodec_free_context(AVCodecContext **avctx); /** - * Free a packet. + * Set the fields of the given AVCodecContext to default values corresponding + * to the given codec (defaults may be codec-dependent). * - * @param pkt packet to free + * Do not call this function if a non-NULL codec has been passed + * to avcodec_alloc_context3() that allocated this AVCodecContext. + * If codec is non-NULL, it is illegal to call avcodec_open2() with a + * different codec on this AVCodecContext. */ -void av_free_packet(AVPacket *pkt); - -/* resample.c */ - -struct ReSampleContext; -struct AVResampleContext; - -typedef struct ReSampleContext ReSampleContext; +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec); -#if LIBAVCODEC_VERSION_MAJOR < 53 /** - * @deprecated Use av_audio_resample_init() instead. + * Get the AVClass for AVCodecContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). */ -attribute_deprecated ReSampleContext *audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate); -#endif +const AVClass *avcodec_get_class(void); + /** - * Initializes audio resampling context + * Get the AVClass for AVFrame. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. * - * @param output_channels number of output channels - * @param input_channels number of input channels - * @param output_rate output sample rate - * @param input_rate input sample rate - * @param sample_fmt_out requested output sample format - * @param sample_fmt_in input sample format - * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq - * @param log2_phase_count log2 of the number of entries in the polyphase filterbank - * @param linear If 1 then the used FIR filter will be linearly interpolated - between the 2 closest, if 0 the closest will be used - * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate - * @return allocated ReSampleContext, NULL if error occured + * @see av_opt_find(). */ -ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate, - enum SampleFormat sample_fmt_out, - enum SampleFormat sample_fmt_in, - int filter_length, int log2_phase_count, - int linear, double cutoff); +const AVClass *avcodec_get_frame_class(void); -int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); -void audio_resample_close(ReSampleContext *s); +/** + * Get the AVClass for AVSubtitleRect. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_subtitle_rect_class(void); +/** + * Copy the settings of the source AVCodecContext into the destination + * AVCodecContext. The resulting destination codec context will be + * unopened, i.e. you are required to call avcodec_open2() before you + * can use this AVCodecContext to decode/encode video/audio data. + * + * @param dest target codec context, should be initialized with + * avcodec_alloc_context3(NULL), but otherwise uninitialized + * @param src source codec context + * @return AVERROR() on error (e.g. memory allocation error), 0 on success + */ +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); +#if FF_API_AVFRAME_LAVC /** - * Initializes an audio resampler. - * Note, if either rate is not an integer then simply scale both rates up so they are. - * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq - * @param log2_phase_count log2 of the number of entries in the polyphase filterbank - * @param linear If 1 then the used FIR filter will be linearly interpolated - between the 2 closest, if 0 the closest will be used - * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + * @deprecated use av_frame_alloc() */ -struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); +attribute_deprecated +AVFrame *avcodec_alloc_frame(void); /** - * resamples. - * @param src an array of unconsumed samples - * @param consumed the number of samples of src which have been consumed are returned here - * @param src_size the number of unconsumed samples available - * @param dst_size the amount of space in samples available in dst - * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. - * @return the number of samples written in dst or -1 if an error occurred + * Set the fields of the given AVFrame to default values. + * + * @param frame The AVFrame of which the fields should be set to default values. + * + * @deprecated use av_frame_unref() */ -int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); +attribute_deprecated +void avcodec_get_frame_defaults(AVFrame *frame); +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. + * + * @param frame frame to be freed. The pointer will be set to NULL. + * + * @warning this function does NOT free the data buffers themselves + * (it does not know how, since they might have been allocated with + * a custom get_buffer()). + * + * @deprecated use av_frame_free() + */ +attribute_deprecated +void avcodec_free_frame(AVFrame **frame); +#endif /** - * Compensates samplerate/timestamp drift. The compensation is done by changing - * the resampler parameters, so no audible clicks or similar distortions occur - * @param compensation_distance distance in output samples over which the compensation should be performed - * @param sample_delta number of output samples which should be output less + * Initialize the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated with avcodec_alloc_context3(). * - * example: av_resample_compensate(c, 10, 500) - * here instead of 510 samples only 500 samples would be output + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. * - * note, due to rounding the actual compensation might be slightly different, - * especially if the compensation_distance is large and the in_rate used during init is small + * @warning This function is not thread safe! + * + * @code + * avcodec_register_all(); + * av_dict_set(&opts, "b", "2.5M", 0); + * codec = avcodec_find_decoder(AV_CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context3(codec); + * + * if (avcodec_open2(context, codec, opts) < 0) + * exit(1); + * @endcode + * + * @param avctx The context to initialize. + * @param codec The codec to open this context for. If a non-NULL codec has been + * previously passed to avcodec_alloc_context3() or + * avcodec_get_context_defaults3() for this context, then this + * parameter MUST be either NULL or equal to the previously passed + * codec. + * @param options A dictionary filled with AVCodecContext and codec-private options. + * On return this object will be filled with options that were not found. + * + * @return zero on success, a negative value on error + * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), + * av_dict_set(), av_opt_find(). */ -void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); -void av_resample_close(struct AVResampleContext *c); +int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); /** - * Allocate memory for a picture. Call avpicture_free to free it. + * Close a given AVCodecContext and free all the data associated with it + * (but not the AVCodecContext itself). * - * @param picture the picture to be filled in - * @param pix_fmt the format of the picture - * @param width the width of the picture - * @param height the height of the picture - * @return zero if successful, a negative value if not + * Calling this function on an AVCodecContext that hasn't been opened will free + * the codec-specific data allocated in avcodec_alloc_context3() / + * avcodec_get_context_defaults3() with a non-NULL codec. Subsequent calls will + * do nothing. */ -int avpicture_alloc(AVPicture *picture, enum PixelFormat pix_fmt, int width, int height); +int avcodec_close(AVCodecContext *avctx); /** - * Free a picture previously allocated by avpicture_alloc(). + * Free all allocated data in the given subtitle struct. * - * @param picture the AVPicture to be freed + * @param sub AVSubtitle to free. */ -void avpicture_free(AVPicture *picture); +void avsubtitle_free(AVSubtitle *sub); /** - * Fill in the AVPicture fields. - * The fields of the given AVPicture are filled in by using the 'ptr' address - * which points to the image data buffer. Depending on the specified picture - * format, one or multiple image data pointers and line sizes will be set. - * If a planar format is specified, several pointers will be set pointing to - * the different picture planes and the line sizes of the different planes - * will be stored in the lines_sizes array. - * Call with ptr == NULL to get the required size for the ptr buffer. - * - * @param picture AVPicture whose fields are to be filled in - * @param ptr Buffer which will contain or contains the actual image data - * @param pix_fmt The format in which the picture data is stored. - * @param width the width of the image in pixels - * @param height the height of the image in pixels - * @return size of the image data in bytes - */ -int avpicture_fill(AVPicture *picture, uint8_t *ptr, - enum PixelFormat pix_fmt, int width, int height); -int avpicture_layout(const AVPicture* src, enum PixelFormat pix_fmt, int width, int height, - unsigned char *dest, int dest_size); + * @} + */ /** - * Calculate the size in bytes that a picture of the given width and height - * would occupy if stored in the given picture format. - * Note that this returns the size of a compact representation as generated - * by avpicture_layout, which can be smaller than the size required for e.g. - * avpicture_fill. - * - * @param pix_fmt the given picture format - * @param width the width of the image - * @param height the height of the image - * @return Image data size in bytes or -1 on error (e.g. too large dimensions). - */ -int avpicture_get_size(enum PixelFormat pix_fmt, int width, int height); -void avcodec_get_chroma_sub_sample(enum PixelFormat pix_fmt, int *h_shift, int *v_shift); -const char *avcodec_get_pix_fmt_name(enum PixelFormat pix_fmt); -void avcodec_set_dimensions(AVCodecContext *s, int width, int height); + * @addtogroup lavc_packet + * @{ + */ -#if LIBAVCODEC_VERSION_MAJOR < 53 +#if FF_API_DESTRUCT_PACKET /** - * Returns the pixel format corresponding to the name name. - * - * If there is no pixel format with name name, then looks for a - * pixel format with the name corresponding to the native endian - * format of name. - * For example in a little-endian system, first looks for "gray16", - * then for "gray16le". - * - * Finally if no pixel format has been found, returns PIX_FMT_NONE. - * - * @deprecated Deprecated in favor of av_get_pix_fmt(). + * Default packet destructor. + * @deprecated use the AVBuffer API instead */ -attribute_deprecated enum PixelFormat avcodec_get_pix_fmt(const char* name); +attribute_deprecated +void av_destruct_packet(AVPacket *pkt); #endif /** - * Returns a value representing the fourCC code associated to the - * pixel format pix_fmt, or 0 if no associated fourCC code can be - * found. + * Initialize optional fields of a packet with default values. + * + * Note, this does not touch the data and size members, which have to be + * initialized separately. + * + * @param pkt packet */ -unsigned int avcodec_pix_fmt_to_codec_tag(enum PixelFormat pix_fmt); - -#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ -#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ -#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ -#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ -#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ -#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ +void av_init_packet(AVPacket *pkt); /** - * Computes what kind of losses will occur when converting from one specific - * pixel format to another. - * When converting from one pixel format to another, information loss may occur. - * For example, when converting from RGB24 to GRAY, the color information will - * be lost. Similarly, other losses occur when converting from some formats to - * other formats. These losses can involve loss of chroma, but also loss of - * resolution, loss of color depth, loss due to the color space conversion, loss - * of the alpha bits or loss due to color quantization. - * avcodec_get_fix_fmt_loss() informs you about the various types of losses - * which will occur when converting from one pixel format to another. + * Allocate the payload of a packet and initialize its fields with + * default values. * - * @param[in] dst_pix_fmt destination pixel format - * @param[in] src_pix_fmt source pixel format - * @param[in] has_alpha Whether the source pixel format alpha channel is used. - * @return Combination of flags informing you what kind of losses will occur. + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK, AVERROR_xxx otherwise */ -int avcodec_get_pix_fmt_loss(enum PixelFormat dst_pix_fmt, enum PixelFormat src_pix_fmt, - int has_alpha); +int av_new_packet(AVPacket *pkt, int size); /** - * Finds the best pixel format to convert to given a certain source pixel - * format. When converting from one pixel format to another, information loss - * may occur. For example, when converting from RGB24 to GRAY, the color - * information will be lost. Similarly, other losses occur when converting from - * some formats to other formats. avcodec_find_best_pix_fmt() searches which of - * the given pixel formats should be used to suffer the least amount of loss. - * The pixel formats from which it chooses one, are determined by the - * pix_fmt_mask parameter. - * - * @code - * src_pix_fmt = PIX_FMT_YUV420P; - * pix_fmt_mask = (1 << PIX_FMT_YUV422P) || (1 << PIX_FMT_RGB24); - * dst_pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src_pix_fmt, alpha, &loss); - * @endcode + * Reduce packet size, correctly zeroing padding * - * @param[in] pix_fmt_mask bitmask determining which pixel format to choose from - * @param[in] src_pix_fmt source pixel format - * @param[in] has_alpha Whether the source pixel format alpha channel is used. - * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. - * @return The best pixel format to convert to or -1 if none was found. + * @param pkt packet + * @param size new size */ -enum PixelFormat avcodec_find_best_pix_fmt(int64_t pix_fmt_mask, enum PixelFormat src_pix_fmt, - int has_alpha, int *loss_ptr); - +void av_shrink_packet(AVPacket *pkt, int size); /** - * Print in buf the string corresponding to the pixel format with - * number pix_fmt, or an header if pix_fmt is negative. + * Increase packet size, correctly zeroing padding * - * @param[in] buf the buffer where to write the string - * @param[in] buf_size the size of buf - * @param[in] pix_fmt the number of the pixel format to print the corresponding info string, or - * a negative value to print the corresponding header. - * Meaningful values for obtaining a pixel format info vary from 0 to PIX_FMT_NB -1. + * @param pkt packet + * @param grow_by number of bytes by which to increase the size of the packet */ -void avcodec_pix_fmt_string (char *buf, int buf_size, enum PixelFormat pix_fmt); - -#define FF_ALPHA_TRANSP 0x0001 /* image has some totally transparent pixels */ -#define FF_ALPHA_SEMI_TRANSP 0x0002 /* image has some transparent pixels */ +int av_grow_packet(AVPacket *pkt, int grow_by); /** - * Tell if an image really has transparent alpha values. - * @return ored mask of FF_ALPHA_xxx constants + * Initialize a reference-counted packet from av_malloc()ed data. + * + * @param pkt packet to be initialized. This function will set the data, size, + * buf and destruct fields, all others are left untouched. + * @param data Data allocated by av_malloc() to be used as packet data. If this + * function returns successfully, the data is owned by the underlying AVBuffer. + * The caller may not access the data through other means. + * @param size size of data in bytes, without the padding. I.e. the full buffer + * size is assumed to be size + FF_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error */ -int img_get_alpha_info(const AVPicture *src, - enum PixelFormat pix_fmt, int width, int height); - -/* deinterlace a picture */ -/* deinterlace - if not supported return -1 */ -int avpicture_deinterlace(AVPicture *dst, const AVPicture *src, - enum PixelFormat pix_fmt, int width, int height); - -/* external high level API */ +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); /** - * If c is NULL, returns the first registered codec, - * if c is non-NULL, returns the next registered codec after c, - * or NULL if c is the last one. + * @warning This is a hack - the packet memory allocation stuff is broken. The + * packet is allocated if it was not really allocated. */ -AVCodec *av_codec_next(AVCodec *c); +int av_dup_packet(AVPacket *pkt); /** - * Returns the LIBAVCODEC_VERSION_INT constant. + * Copy packet, including contents + * + * @return 0 on success, negative AVERROR on fail */ -unsigned avcodec_version(void); +int av_copy_packet(AVPacket *dst, const AVPacket *src); /** - * Returns the libavcodec build-time configuration. + * Copy packet side data + * + * @return 0 on success, negative AVERROR on fail */ -const char *avcodec_configuration(void); +int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src); /** - * Returns the libavcodec license. + * Free a packet. + * + * @param pkt packet to free */ -const char *avcodec_license(void); +void av_free_packet(AVPacket *pkt); /** - * Initializes libavcodec. + * Allocate new information of a packet. * - * @warning This function must be called before any other libavcodec - * function. + * @param pkt packet + * @param type side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise */ -void avcodec_init(void); +uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); -#if LIBAVCODEC_VERSION_MAJOR < 53 /** - * @deprecated Deprecated in favor of avcodec_register(). + * Shrink the already allocated side data buffer + * + * @param pkt packet + * @param type side information type + * @param size new side information size + * @return 0 on success, < 0 on failure */ -attribute_deprecated void register_avcodec(AVCodec *codec); -#endif +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); /** - * Register the codec codec and initialize libavcodec. + * Get side information from packet. * - * @see avcodec_init() + * @param pkt packet + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise */ -void avcodec_register(AVCodec *codec); +uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int *size); + +int av_packet_merge_side_data(AVPacket *pkt); + +int av_packet_split_side_data(AVPacket *pkt); /** - * Finds a registered encoder with a matching codec ID. + * Pack a dictionary for use in side_data. * - * @param id CodecID of the requested encoder - * @return An encoder if one was found, NULL otherwise. + * @param dict The dictionary to pack. + * @param size pointer to store the size of the returned data + * @return pointer to data if successful, NULL otherwise + */ +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size); +/** + * Unpack a dictionary from side_data. + * + * @param data data from side_data + * @param size size of the data + * @param dict the metadata storage dictionary + * @return 0 on success, < 0 on failure */ -AVCodec *avcodec_find_encoder(enum CodecID id); +int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict); + /** - * Finds a registered encoder with the specified name. + * Convenience function to free all the side data stored. + * All the other fields stay untouched. * - * @param name name of the requested encoder - * @return An encoder if one was found, NULL otherwise. + * @param pkt packet */ -AVCodec *avcodec_find_encoder_by_name(const char *name); +void av_packet_free_side_data(AVPacket *pkt); /** - * Finds a registered decoder with a matching codec ID. + * Setup a new reference to the data described by a given packet * - * @param id CodecID of the requested decoder - * @return A decoder if one was found, NULL otherwise. + * If src is reference-counted, setup dst as a new reference to the + * buffer in src. Otherwise allocate a new buffer in dst and copy the + * data from src into it. + * + * All the other fields are copied from src. + * + * @see av_packet_unref + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success, a negative AVERROR on error. */ -AVCodec *avcodec_find_decoder(enum CodecID id); +int av_packet_ref(AVPacket *dst, const AVPacket *src); /** - * Finds a registered decoder with the specified name. + * Wipe the packet. * - * @param name name of the requested decoder - * @return A decoder if one was found, NULL otherwise. + * Unreference the buffer referenced by the packet and reset the + * remaining packet fields to their default values. + * + * @param pkt The packet to be unreferenced. */ -AVCodec *avcodec_find_decoder_by_name(const char *name); -void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); +void av_packet_unref(AVPacket *pkt); /** - * Sets the fields of the given AVCodecContext to default values. + * Move every field in src to dst and reset src. + * + * @see av_packet_unref * - * @param s The AVCodecContext of which the fields should be set to default values. + * @param src Source packet, will be reset + * @param dst Destination packet */ -void avcodec_get_context_defaults(AVCodecContext *s); +void av_packet_move_ref(AVPacket *dst, AVPacket *src); -/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! - * we WILL change its arguments and name a few times! */ -void avcodec_get_context_defaults2(AVCodecContext *s, enum AVMediaType); +/** + * Copy only "properties" fields from src to dst. + * + * Properties for the purpose of this function are all the fields + * beside those related to the packet data (buf, data, size) + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success AVERROR on failure. + * + */ +int av_packet_copy_props(AVPacket *dst, const AVPacket *src); /** - * Allocates an AVCodecContext and sets its fields to default values. The - * resulting struct can be deallocated by simply calling av_free(). + * Convert valid timing fields (timestamps / durations) in a packet from one + * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be + * ignored. * - * @return An AVCodecContext filled with default values or NULL on failure. - * @see avcodec_get_context_defaults + * @param pkt packet on which the conversion will be performed + * @param tb_src source timebase, in which the timing fields in pkt are + * expressed + * @param tb_dst destination timebase, to which the timing fields will be + * converted */ -AVCodecContext *avcodec_alloc_context(void); +void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); -/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! - * we WILL change its arguments and name a few times! */ -AVCodecContext *avcodec_alloc_context2(enum AVMediaType); +/** + * @} + */ /** - * Copy the settings of the source AVCodecContext into the destination - * AVCodecContext. The resulting destination codec context will be - * unopened, i.e. you are required to call avcodec_open() before you - * can use this AVCodecContext to decode/encode video/audio data. - * - * @param dest target codec context, should be initialized with - * avcodec_alloc_context(), but otherwise uninitialized - * @param src source codec context - * @return AVERROR() on error (e.g. memory allocation error), 0 on success + * @addtogroup lavc_decoding + * @{ */ -int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); /** - * Sets the fields of the given AVFrame to default values. + * Find a registered decoder with a matching codec ID. * - * @param pic The AVFrame of which the fields should be set to default values. + * @param id AVCodecID of the requested decoder + * @return A decoder if one was found, NULL otherwise. */ -void avcodec_get_frame_defaults(AVFrame *pic); +AVCodec *avcodec_find_decoder(enum AVCodecID id); /** - * Allocates an AVFrame and sets its fields to default values. The resulting - * struct can be deallocated by simply calling av_free(). + * Find a registered decoder with the specified name. * - * @return An AVFrame filled with default values or NULL on failure. - * @see avcodec_get_frame_defaults + * @param name name of the requested decoder + * @return A decoder if one was found, NULL otherwise. */ -AVFrame *avcodec_alloc_frame(void); +AVCodec *avcodec_find_decoder_by_name(const char *name); + +#if FF_API_GET_BUFFER +attribute_deprecated int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); +attribute_deprecated void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); +attribute_deprecated int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic); +#endif -int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); -void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); -int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic); +/** + * The default callback for AVCodecContext.get_buffer2(). It is made public so + * it can be called by custom get_buffer2() implementations for decoders without + * CODEC_CAP_DR1 set. + */ +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); +#if FF_API_EMU_EDGE /** - * Returns the amount of padding in pixels which the get_buffer callback must + * Return the amount of padding in pixels which the get_buffer callback must * provide around the edge of the image for codecs which do not have the * CODEC_FLAG_EMU_EDGE flag. * * @return Required padding in pixels. + * + * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer + * needed */ +attribute_deprecated unsigned avcodec_get_edge_width(void); +#endif + /** - * Modifies width and height values so that they will result in a memory + * Modify width and height values so that they will result in a memory * buffer that is acceptable for the codec if you do not use any horizontal * padding. + * + * May only be used if a codec with CODEC_CAP_DR1 has been opened. */ void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + /** - * Modifies width and height values so that they will result in a memory + * Modify width and height values so that they will result in a memory * buffer that is acceptable for the codec if you also ensure that all * line sizes are a multiple of the respective linesize_align[i]. + * + * May only be used if a codec with CODEC_CAP_DR1 has been opened. */ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, - int linesize_align[4]); + int linesize_align[AV_NUM_DATA_POINTERS]); /** - * Checks if the given dimension of a picture is valid, meaning that all - * bytes of the picture can be addressed with a signed int. + * Converts AVChromaLocation to swscale x/y chroma position. * - * @param[in] w Width of the picture. - * @param[in] h Height of the picture. - * @return Zero if valid, a negative value if invalid. + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position */ -int avcodec_check_dimensions(void *av_log_ctx, unsigned int w, unsigned int h); -enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt); - -int avcodec_thread_init(AVCodecContext *s, int thread_count); -void avcodec_thread_free(AVCodecContext *s); -int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); -int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); -//FIXME func typedef +int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos); /** - * Initializes the AVCodecContext to use the given AVCodec. Prior to using this - * function the context has to be allocated. - * - * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), - * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for - * retrieving a codec. - * - * @warning This function is not thread safe! - * - * @code - * avcodec_register_all(); - * codec = avcodec_find_decoder(CODEC_ID_H264); - * if (!codec) - * exit(1); + * Converts swscale x/y chroma position to AVChromaLocation. * - * context = avcodec_alloc_context(); + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 * - * if (avcodec_open(context, codec) < 0) - * exit(1); - * @endcode - * - * @param avctx The context which will be set up to use the given codec. - * @param codec The codec to use within the context. - * @return zero on success, a negative value on error - * @see avcodec_alloc_context, avcodec_find_decoder, avcodec_find_encoder + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position */ -int avcodec_open(AVCodecContext *avctx, AVCodec *codec); +enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos); -#if LIBAVCODEC_VERSION_MAJOR < 53 +#if FF_API_OLD_DECODE_AUDIO /** - * Decodes an audio frame from buf into samples. - * Wrapper function which calls avcodec_decode_audio3. + * Wrapper function which calls avcodec_decode_audio4. * - * @deprecated Use avcodec_decode_audio3 instead. - * @param avctx the codec context - * @param[out] samples the output buffer - * @param[in,out] frame_size_ptr the output buffer size in bytes - * @param[in] buf the input buffer - * @param[in] buf_size the input buffer size in bytes - * @return On error a negative value is returned, otherwise the number of bytes - * used or zero if no frame could be decompressed. - */ -attribute_deprecated int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *samples, - int *frame_size_ptr, - const uint8_t *buf, int buf_size); -#endif - -/** - * Decodes the audio frame of size avpkt->size from avpkt->data into samples. + * @deprecated Use avcodec_decode_audio4 instead. + * + * Decode the audio frame of size avpkt->size from avpkt->data into samples. * Some decoders may support multiple frames in a single AVPacket, such * decoders would then just decode the first frame. In this case, * avcodec_decode_audio3 has to be called again with an AVPacket that contains @@ -3398,6 +3970,11 @@ attribute_deprecated int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *s * @warning The end of the input buffer avpkt->data should be set to 0 to ensure that * no overreading happens for damaged MPEG streams. * + * @warning You must not provide a custom get_buffer() when using + * avcodec_decode_audio3(). Doing so will override it with + * avcodec_default_get_buffer. Use avcodec_decode_audio4() instead, + * which does allow the application to provide a custom get_buffer(). + * * @note You might have to align the input buffer avpkt->data and output buffer * samples. The alignment requirements depend on the CPU: On some CPUs it isn't * necessary at all, on others it won't work at all if not aligned and on others @@ -3407,8 +3984,14 @@ attribute_deprecated int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *s * samples should be 16 byte aligned unless the CPU doesn't need it * (AltiVec and SSE do). * + * @note Codecs which have the CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. + * * @param avctx the codec context * @param[out] samples the output buffer, sample type in avctx->sample_fmt + * If the sample format is planar, each channel plane will + * be the same size, with no padding between channels. * @param[in,out] frame_size_ptr the output buffer size in bytes * @param[in] avpkt The input AVPacket containing the input buffer. * You can create such packet with av_init_packet() and by then setting @@ -3417,31 +4000,64 @@ attribute_deprecated int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *s * @return On error a negative value is returned, otherwise the number of bytes * used or zero if no frame data was decompressed (used) from the input AVPacket. */ -int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, +attribute_deprecated int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, AVPacket *avpkt); +#endif -#if LIBAVCODEC_VERSION_MAJOR < 53 /** - * Decodes a video frame from buf into picture. - * Wrapper function which calls avcodec_decode_video2. + * Decode the audio frame of size avpkt->size from avpkt->data into frame. * - * @deprecated Use avcodec_decode_video2 instead. - * @param avctx the codec context - * @param[out] picture The AVFrame in which the decoded video frame will be stored. - * @param[in] buf the input buffer - * @param[in] buf_size the size of the input buffer in bytes - * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero. - * @return On error a negative value is returned, otherwise the number of bytes - * used or zero if no frame could be decompressed. - */ -attribute_deprecated int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, - int *got_picture_ptr, - const uint8_t *buf, int buf_size); -#endif + * Some decoders may support multiple frames in a single AVPacket. Such + * decoders would then just decode the first frame and the return value would be + * less than the packet size. In this case, avcodec_decode_audio4 has to be + * called again with an AVPacket containing the remaining data in order to + * decode the second frame, etc... Even if no frames are returned, the packet + * needs to be fed to the decoder with remaining data until it is completely + * consumed or an error occurs. + * + * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning samples. It is safe to flush even those decoders that are not + * marked with CODEC_CAP_DELAY, then no samples will be returned. + * + * @warning The input buffer, avpkt->data must be FF_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @param avctx the codec context + * @param[out] frame The AVFrame in which to store decoded audio samples. + * The decoder will allocate a buffer for the decoded frame by + * calling the AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is + * non-zero. Note that this field being set to zero + * does not mean that an error has occurred. For + * decoders with CODEC_CAP_DELAY set, no given decode + * call is guaranteed to produce a frame. + * @param[in] avpkt The input AVPacket containing the input buffer. + * At least avpkt->data and avpkt->size should be set. Some + * decoders might also require additional fields to be set. + * @return A negative error code is returned if an error occurred during + * decoding, otherwise the number of bytes consumed from the input + * AVPacket is returned. + */ +int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, const AVPacket *avpkt); /** - * Decodes the video frame of size avpkt->size from avpkt->data into picture. + * Decode the video frame of size avpkt->size from avpkt->data into picture. * Some decoders may support multiple frames in a single AVPacket, such * decoders would then just decode the first frame. * @@ -3452,19 +4068,26 @@ attribute_deprecated int avcodec_decode_video(AVCodecContext *avctx, AVFrame *pi * @warning The end of the input buffer buf should be set to 0 to ensure that * no overreading happens for damaged MPEG streams. * - * @note You might have to align the input buffer avpkt->data. - * The alignment requirements depend on the CPU: on some CPUs it isn't - * necessary at all, on others it won't work at all if not aligned and on others - * it will work but it will have an impact on performance. - * - * In practice, avpkt->data should have 4 byte alignment at minimum. - * - * @note Some codecs have a delay between input and output, these need to be - * fed with avpkt->data=NULL, avpkt->size=0 at the end to return the remaining frames. + * @note Codecs which have the CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. * * @param avctx the codec context * @param[out] picture The AVFrame in which the decoded video frame will be stored. - * @param[in] avpkt The input AVpacket containing the input buffer. + * Use av_frame_alloc() to get an AVFrame. The codec will + * allocate memory for the actual bitmap by calling the + * AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * + * @param[in] avpkt The input AVPacket containing the input buffer. * You can create such packet with av_init_packet() and by then setting * data and size, some decoders might in addition need other fields like * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least @@ -3475,42 +4098,303 @@ attribute_deprecated int avcodec_decode_video(AVCodecContext *avctx, AVFrame *pi */ int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, - AVPacket *avpkt); - -#if LIBAVCODEC_VERSION_MAJOR < 53 -/* Decode a subtitle message. Return -1 if error, otherwise return the - * number of bytes used. If no subtitle could be decompressed, - * got_sub_ptr is zero. Otherwise, the subtitle is stored in *sub. */ -attribute_deprecated int avcodec_decode_subtitle(AVCodecContext *avctx, AVSubtitle *sub, - int *got_sub_ptr, - const uint8_t *buf, int buf_size); -#endif + const AVPacket *avpkt); /** - * Decodes a subtitle message. - * Returns a negative value on error, otherwise returns the number of bytes used. + * Decode a subtitle message. + * Return a negative value on error, otherwise return the number of bytes used. * If no subtitle could be decompressed, got_sub_ptr is zero. * Otherwise, the subtitle is stored in *sub. + * Note that CODEC_CAP_DR1 is not available for subtitle codecs. This is for + * simplicity, because the performance difference is expect to be negligible + * and reusing a get_buffer written for video codecs would probably perform badly + * due to a potentially very different allocation pattern. + * + * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning subtitles. It is safe to flush even those decoders that are not + * marked with CODEC_CAP_DELAY, then no subtitles will be returned. * * @param avctx the codec context - * @param[out] sub The AVSubtitle in which the decoded subtitle will be stored. + * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored, + * must be freed with avsubtitle_free if *got_sub_ptr is set. * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. * @param[in] avpkt The input AVPacket containing the input buffer. */ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt); -int avcodec_parse_frame(AVCodecContext *avctx, uint8_t **pdata, - int *data_size_ptr, - uint8_t *buf, int buf_size); /** - * Encodes an audio frame from samples into buf. + * @defgroup lavc_parsing Frame parsing + * @{ + */ + +enum AVPictureStructure { + AV_PICTURE_STRUCTURE_UNKNOWN, //< unknown + AV_PICTURE_STRUCTURE_TOP_FIELD, //< coded as top field + AV_PICTURE_STRUCTURE_BOTTOM_FIELD, //< coded as bottom field + AV_PICTURE_STRUCTURE_FRAME, //< coded as frame +}; + +typedef struct AVCodecParserContext { + void *priv_data; + struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t next_frame_offset; /* offset of the next frame */ + /* video info */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + /** + * This field is used for proper frame duration computation in lavf. + * It signals, how much longer the frame duration of the current frame + * is compared to normal frame duration. + * + * frame_duration = (1 + repeat_pict) * time_base + * + * It is used by codecs like H.264 to display telecined material. + */ + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +#define PARSER_FLAG_ONCE 0x0002 +/// Set if the parser has a valid file offset +#define PARSER_FLAG_FETCHED_OFFSET 0x0004 +#define PARSER_FLAG_USE_CODEC_TS 0x1000 + + int64_t offset; ///< byte offset from starting packet start + int64_t cur_frame_end[AV_PARSER_PTS_NB]; + + /** + * Set by parser to 1 for key frames and 0 for non-key frames. + * It is initialized to -1, so if the parser doesn't set this flag, + * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames + * will be used. + */ + int key_frame; + + /** + * Time difference in stream time base units from the pts of this + * packet to the point at which the output from the decoder has converged + * independent from the availability of previous frames. That is, the + * frames are virtually identical no matter if decoding started from + * the very first frame or from this keyframe. + * Is AV_NOPTS_VALUE if unknown. + * This field is not the display duration of the current frame. + * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY + * set. + * + * The purpose of this field is to allow seeking in streams that have no + * keyframes in the conventional sense. It corresponds to the + * recovery point SEI in H.264 and match_time_delta in NUT. It is also + * essential for some types of subtitle streams to ensure that all + * subtitles are correctly displayed after seeking. + */ + int64_t convergence_duration; + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; + + /** + * Position of the packet in file. + * + * Analogous to cur_frame_pts/dts + */ + int64_t cur_frame_pos[AV_PARSER_PTS_NB]; + + /** + * Byte position of currently parsed frame in stream. + */ + int64_t pos; + + /** + * Previous frame byte position. + */ + int64_t last_pos; + + /** + * Duration of the current frame. + * For audio, this is in units of 1 / AVCodecContext.sample_rate. + * For all other types, this is in units of AVCodecContext.time_base. + */ + int duration; + + enum AVFieldOrder field_order; + + /** + * Indicate whether a picture is coded as a frame, top field or bottom field. + * + * For example, H.264 field_pic_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag + * equal to 1 and bottom_field_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_TOP_FIELD. + */ + enum AVPictureStructure picture_structure; + + /** + * Picture number incremented in presentation or output order. + * This field may be reinitialized at the first picture of a new sequence. + * + * For example, this corresponds to H.264 PicOrderCnt. + */ + int output_picture_number; +} AVCodecParserContext; + +typedef struct AVCodecParser { + int codec_ids[5]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + struct AVCodecParser *next; +} AVCodecParser; + +AVCodecParser *av_parser_next(const AVCodecParser *c); + +void av_register_codec_parser(AVCodecParser *parser); +AVCodecParserContext *av_parser_init(int codec_id); + +/** + * Parse a packet. + * + * @param s parser context. + * @param avctx codec context. + * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. + * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. + * @param buf input buffer. + * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output). + * @param pts input presentation timestamp. + * @param dts input decoding timestamp. + * @param pos input byte position in stream. + * @return the number of bytes of the input bitstream used. + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts, pos); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse2(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, + int64_t pos); + +/** + * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed + * @deprecated use AVBitStreamFilter + */ +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_parser_close(AVCodecParserContext *s); + +/** + * @} + * @} + */ + +/** + * @addtogroup lavc_encoding + * @{ + */ + +/** + * Find a registered encoder with a matching codec ID. + * + * @param id AVCodecID of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder(enum AVCodecID id); + +/** + * Find a registered encoder with the specified name. + * + * @param name name of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder_by_name(const char *name); + +#if FF_API_OLD_ENCODE_AUDIO +/** + * Encode an audio frame from samples into buf. + * + * @deprecated Use avcodec_encode_audio2 instead. * * @note The output buffer should be at least FF_MIN_BUFFER_SIZE bytes large. - * However, for PCM audio the user will know how much space is needed - * because it depends on the value passed in buf_size as described - * below. In that case a lower value can be used. + * However, for codecs with avctx->frame_size equal to 0 (e.g. PCM) the user + * will know how much space is needed because it depends on the value passed + * in buf_size as described below. In that case a lower value can be used. * * @param avctx the codec context * @param[out] buf the output buffer @@ -3518,16 +4402,66 @@ int avcodec_parse_frame(AVCodecContext *avctx, uint8_t **pdata, * @param[in] samples the input buffer containing the samples * The number of samples read from this buffer is frame_size*channels, * both of which are defined in avctx. - * For PCM audio the number of samples read from samples is equal to - * buf_size * input_sample_size / output_sample_size. + * For codecs which have avctx->frame_size equal to 0 (e.g. PCM) the number of + * samples read from samples is equal to: + * buf_size * 8 / (avctx->channels * av_get_bits_per_sample(avctx->codec_id)) + * This also implies that av_get_bits_per_sample() must not return 0 for these + * codecs. * @return On error a negative value is returned, on success zero or the number * of bytes used to encode the data read from the input buffer. */ -int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, - const short *samples); +int attribute_deprecated avcodec_encode_audio(AVCodecContext *avctx, + uint8_t *buf, int buf_size, + const short *samples); +#endif /** - * Encodes a video frame from pict into buf. + * Encode a frame of audio. + * + * Takes input samples from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay, split, and combine input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. If avpkt->data and + * avpkt->size are set, avpkt->destruct must also be set. All + * other AVPacket fields will be reset by the encoder using + * av_init_packet(). If avpkt->data is NULL, the encoder will + * allocate it. The encoder will set avpkt->size to the size + * of the output packet. + * + * If this function fails or produces no output, avpkt will be + * freed using av_free_packet() (i.e. avpkt->destruct will be + * called to free the user supplied buffer). + * @param[in] frame AVFrame containing the raw audio data to be encoded. + * May be NULL when flushing an encoder that has the + * CODEC_CAP_DELAY capability set. + * If CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + */ +int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +#if FF_API_OLD_ENCODE_VIDEO +/** + * @deprecated use avcodec_encode_video2() instead. + * + * Encode a video frame from pict into buf. * The input picture should be * stored using a specific format, namely avctx.pix_fmt. * @@ -3538,249 +4472,474 @@ int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, * @return On error a negative value is returned, on success zero or the number * of bytes used from the output buffer. */ +attribute_deprecated int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVFrame *pict); +#endif + +/** + * Encode a frame of video. + * + * Takes input raw video data from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay and reorder input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. All other AVPacket fields + * will be reset by the encoder using av_init_packet(). If + * avpkt->data is NULL, the encoder will allocate it. + * The encoder will set avpkt->size to the size of the + * output packet. The returned data (if any) belongs to the + * caller, he is responsible for freeing it. + * + * If this function fails or produces no output, avpkt will be + * freed using av_free_packet() (i.e. avpkt->destruct will be + * called to free the user supplied buffer). + * @param[in] frame AVFrame containing the raw video data to be encoded. + * May be NULL when flushing an encoder that has the + * CODEC_CAP_DELAY capability set. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + */ +int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVSubtitle *sub); -int avcodec_close(AVCodecContext *avctx); /** - * Register all the codecs, parsers and bitstream filters which were enabled at - * configuration time. If you do not call this function you can select exactly - * which formats you want to support, by using the individual registration - * functions. + * @} + */ + +#if FF_API_AVCODEC_RESAMPLE +/** + * @defgroup lavc_resample Audio resampling + * @ingroup libavc + * @deprecated use libswresample instead * - * @see avcodec_register - * @see av_register_codec_parser - * @see av_register_bitstream_filter + * @{ */ -void avcodec_register_all(void); +struct ReSampleContext; +struct AVResampleContext; + +typedef struct ReSampleContext ReSampleContext; + +/** + * Initialize audio resampling context. + * + * @param output_channels number of output channels + * @param input_channels number of input channels + * @param output_rate output sample rate + * @param input_rate input sample rate + * @param sample_fmt_out requested output sample format + * @param sample_fmt_in input sample format + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear if 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + * @return allocated ReSampleContext, NULL if error occurred + */ +attribute_deprecated +ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, + int output_rate, int input_rate, + enum AVSampleFormat sample_fmt_out, + enum AVSampleFormat sample_fmt_in, + int filter_length, int log2_phase_count, + int linear, double cutoff); + +attribute_deprecated +int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); /** - * Flush buffers, should be called when seeking or when switching to a different stream. + * Free resample context. + * + * @param s a non-NULL pointer to a resample context previously + * created with av_audio_resample_init() */ -void avcodec_flush_buffers(AVCodecContext *avctx); +attribute_deprecated +void audio_resample_close(ReSampleContext *s); + + +/** + * Initialize an audio resampler. + * Note, if either rate is not an integer then simply scale both rates up so they are. + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear If 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + */ +attribute_deprecated +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); + +/** + * Resample an array of samples using a previously configured context. + * @param src an array of unconsumed samples + * @param consumed the number of samples of src which have been consumed are returned here + * @param src_size the number of unconsumed samples available + * @param dst_size the amount of space in samples available in dst + * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. + * @return the number of samples written in dst or -1 if an error occurred + */ +attribute_deprecated +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); + + +/** + * Compensate samplerate/timestamp drift. The compensation is done by changing + * the resampler parameters, so no audible clicks or similar distortions occur + * @param compensation_distance distance in output samples over which the compensation should be performed + * @param sample_delta number of output samples which should be output less + * + * example: av_resample_compensate(c, 10, 500) + * here instead of 510 samples only 500 samples would be output + * + * note, due to rounding the actual compensation might be slightly different, + * especially if the compensation_distance is large and the in_rate used during init is small + */ +attribute_deprecated +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +attribute_deprecated +void av_resample_close(struct AVResampleContext *c); -void avcodec_default_free_buffers(AVCodecContext *s); +/** + * @} + */ +#endif -/* misc useful functions */ +/** + * @addtogroup lavc_picture + * @{ + */ /** - * Returns a single letter to describe the given picture type pict_type. + * Allocate memory for the pixels of a picture and setup the AVPicture + * fields for it. + * + * Call avpicture_free() to free it. + * + * @param picture the picture structure to be filled in + * @param pix_fmt the pixel format of the picture + * @param width the width of the picture + * @param height the height of the picture + * @return zero if successful, a negative error code otherwise * - * @param[in] pict_type the picture type - * @return A single character representing the picture type. + * @see av_image_alloc(), avpicture_fill() */ -char av_get_pict_type_char(int pict_type); +int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height); /** - * Returns codec bits per sample. + * Free a picture previously allocated by avpicture_alloc(). + * The data buffer used by the AVPicture is freed, but the AVPicture structure + * itself is not. * - * @param[in] codec_id the codec - * @return Number of bits per sample or zero if unknown for the given codec. + * @param picture the AVPicture to be freed */ -int av_get_bits_per_sample(enum CodecID codec_id); +void avpicture_free(AVPicture *picture); /** - * Returns sample format bits per sample. + * Setup the picture fields based on the specified image parameters + * and the provided image data buffer. + * + * The picture fields are filled in by using the image data buffer + * pointed to by ptr. + * + * If ptr is NULL, the function will fill only the picture linesize + * array and return the required size for the image buffer. * - * @param[in] sample_fmt the sample format - * @return Number of bits per sample or zero if unknown for the given sample format. + * To allocate an image buffer and fill the picture data in one call, + * use avpicture_alloc(). + * + * @param picture the picture to be filled in + * @param ptr buffer where the image data is stored, or NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @return the size in bytes required for src, a negative error code + * in case of failure + * + * @see av_image_fill_arrays() */ -int av_get_bits_per_sample_format(enum SampleFormat sample_fmt); +int avpicture_fill(AVPicture *picture, const uint8_t *ptr, + enum AVPixelFormat pix_fmt, int width, int height); -/* frame parsing */ -typedef struct AVCodecParserContext { - void *priv_data; - struct AVCodecParser *parser; - int64_t frame_offset; /* offset of the current frame */ - int64_t cur_offset; /* current offset - (incremented by each av_parser_parse()) */ - int64_t next_frame_offset; /* offset of the next frame */ - /* video info */ - int pict_type; /* XXX: Put it back in AVCodecContext. */ - /** - * This field is used for proper frame duration computation in lavf. - * It signals, how much longer the frame duration of the current frame - * is compared to normal frame duration. - * - * frame_duration = (1 + repeat_pict) * time_base - * - * It is used by codecs like H.264 to display telecined material. - */ - int repeat_pict; /* XXX: Put it back in AVCodecContext. */ - int64_t pts; /* pts of the current frame */ - int64_t dts; /* dts of the current frame */ +/** + * Copy pixel data from an AVPicture into a buffer. + * + * avpicture_get_size() can be used to compute the required size for + * the buffer to fill. + * + * @param src source picture with filled data + * @param pix_fmt picture pixel format + * @param width picture width + * @param height picture height + * @param dest destination buffer + * @param dest_size destination buffer size in bytes + * @return the number of bytes written to dest, or a negative value + * (error code) on error, for example if the destination buffer is not + * big enough + * + * @see av_image_copy_to_buffer() + */ +int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt, + int width, int height, + unsigned char *dest, int dest_size); - /* private data */ - int64_t last_pts; - int64_t last_dts; - int fetch_timestamp; +/** + * Calculate the size in bytes that a picture of the given width and height + * would occupy if stored in the given picture format. + * + * @param pix_fmt picture pixel format + * @param width picture width + * @param height picture height + * @return the computed picture buffer size or a negative error code + * in case of error + * + * @see av_image_get_buffer_size(). + */ +int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height); -#define AV_PARSER_PTS_NB 4 - int cur_frame_start_index; - int64_t cur_frame_offset[AV_PARSER_PTS_NB]; - int64_t cur_frame_pts[AV_PARSER_PTS_NB]; - int64_t cur_frame_dts[AV_PARSER_PTS_NB]; +#if FF_API_DEINTERLACE +/** + * deinterlace - if not supported return -1 + * + * @deprecated - use yadif (in libavfilter) instead + */ +attribute_deprecated +int avpicture_deinterlace(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); +#endif +/** + * Copy image src to dst. Wraps av_image_copy(). + */ +void av_picture_copy(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); - int flags; -#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +/** + * Crop image top and left side. + */ +int av_picture_crop(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int top_band, int left_band); + +/** + * Pad image. + */ +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum AVPixelFormat pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); + +/** + * @} + */ + +/** + * @defgroup lavc_misc Utility functions + * @ingroup libavc + * + * Miscellaneous utility functions related to both encoding and decoding + * (or neither). + * @{ + */ + +/** + * @defgroup lavc_misc_pixfmt Pixel formats + * + * Functions for working with pixel formats. + * @{ + */ + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * This function asserts that pix_fmt is valid. See av_pix_fmt_get_chroma_sub_sample + * for one that returns a failure code and continues in case of invalid + * pix_fmts. + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @see av_pix_fmt_get_chroma_sub_sample + */ + +void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift); + +/** + * Return a value representing the fourCC code associated to the + * pixel format pix_fmt, or 0 if no associated fourCC code can be + * found. + */ +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt); - int64_t offset; ///< byte offset from starting packet start - int64_t cur_frame_end[AV_PARSER_PTS_NB]; +/** + * @deprecated see av_get_pix_fmt_loss() + */ +int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt, + int has_alpha); - /*! - * Set by parser to 1 for key frames and 0 for non-key frames. - * It is initialized to -1, so if the parser doesn't set this flag, - * old-style fallback using FF_I_TYPE picture type as key frames - * will be used. - */ - int key_frame; +/** + * Find the best pixel format to convert to given a certain source pixel + * format. When converting from one pixel format to another, information loss + * may occur. For example, when converting from RGB24 to GRAY, the color + * information will be lost. Similarly, other losses occur when converting from + * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of + * the given pixel formats should be used to suffer the least amount of loss. + * The pixel formats from which it chooses one, are determined by the + * pix_fmt_list parameter. + * + * + * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); - /** - * Time difference in stream time base units from the pts of this - * packet to the point at which the output from the decoder has converged - * independent from the availability of previous frames. That is, the - * frames are virtually identical no matter if decoding started from - * the very first frame or from this keyframe. - * Is AV_NOPTS_VALUE if unknown. - * This field is not the display duration of the current frame. - * - * The purpose of this field is to allow seeking in streams that have no - * keyframes in the conventional sense. It corresponds to the - * recovery point SEI in H.264 and match_time_delta in NUT. It is also - * essential for some types of subtitle streams to ensure that all - * subtitles are correctly displayed after seeking. - */ - int64_t convergence_duration; +/** + * @deprecated see av_find_best_pix_fmt_of_2() + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); - // Timestamp generation support: - /** - * Synchronization point for start of timestamp generation. - * - * Set to >0 for sync point, 0 for no sync point and <0 for undefined - * (default). - * - * For example, this corresponds to presence of H.264 buffering period - * SEI message. - */ - int dts_sync_point; +attribute_deprecated +#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI +enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); +#else +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); +#endif - /** - * Offset of the current timestamp against last timestamp sync point in - * units of AVCodecContext.time_base. - * - * Set to INT_MIN when dts_sync_point unused. Otherwise, it must - * contain a valid timestamp offset. - * - * Note that the timestamp of sync point has usually a nonzero - * dts_ref_dts_delta, which refers to the previous sync point. Offset of - * the next frame after timestamp sync point will be usually 1. - * - * For example, this corresponds to H.264 cpb_removal_delay. - */ - int dts_ref_dts_delta; - /** - * Presentation delay of current frame in units of AVCodecContext.time_base. - * - * Set to INT_MIN when dts_sync_point unused. Otherwise, it must - * contain valid non-negative timestamp delta (presentation time of a frame - * must not lie in the past). - * - * This delay represents the difference between decoding and presentation - * time of the frame. - * - * For example, this corresponds to H.264 dpb_output_delay. - */ - int pts_dts_delta; +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt); - /** - * Position of the packet in file. - * - * Analogous to cur_frame_pts/dts - */ - int64_t cur_frame_pos[AV_PARSER_PTS_NB]; +/** + * @} + */ - /** - * Byte position of currently parsed frame in stream. - */ - int64_t pos; +#if FF_API_SET_DIMENSIONS +/** + * @deprecated this function is not supposed to be used from outside of lavc + */ +attribute_deprecated +void avcodec_set_dimensions(AVCodecContext *s, int width, int height); +#endif - /** - * Previous frame byte position. - */ - int64_t last_pos; -} AVCodecParserContext; +/** + * Put a string representing the codec tag codec_tag in buf. + * + * @param buf buffer to place codec tag in + * @param buf_size size in bytes of buf + * @param codec_tag codec tag to assign + * @return the length of the string that would have been generated if + * enough space had been available, excluding the trailing null + */ +size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag); -typedef struct AVCodecParser { - int codec_ids[5]; /* several codec IDs are permitted */ - int priv_data_size; - int (*parser_init)(AVCodecParserContext *s); - int (*parser_parse)(AVCodecParserContext *s, - AVCodecContext *avctx, - const uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size); - void (*parser_close)(AVCodecParserContext *s); - int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); - struct AVCodecParser *next; -} AVCodecParser; +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); -AVCodecParser *av_parser_next(AVCodecParser *c); +/** + * Return a name for the specified profile, if available. + * + * @param codec the codec that is searched for the given profile + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + */ +const char *av_get_profile_name(const AVCodec *codec, int profile); -void av_register_codec_parser(AVCodecParser *parser); -AVCodecParserContext *av_parser_init(int codec_id); +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); +//FIXME func typedef -#if LIBAVCODEC_VERSION_MAJOR < 53 -attribute_deprecated -int av_parser_parse(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int64_t pts, int64_t dts); -#endif +/** + * Fill AVFrame audio data and linesize pointers. + * + * The buffer buf must be a preallocated buffer with a size big enough + * to contain the specified samples amount. The filled AVFrame data + * pointers will point to this buffer. + * + * AVFrame extended_data channel pointers are allocated if necessary for + * planar audio. + * + * @param frame the AVFrame + * frame->nb_samples must be set prior to calling the + * function. This function fills in frame->data, + * frame->extended_data, frame->linesize[0]. + * @param nb_channels channel count + * @param sample_fmt sample format + * @param buf buffer to use for frame data + * @param buf_size size of buffer + * @param align plane size sample alignment (0 = default) + * @return >=0 on success, negative error code on failure + * @todo return the size in bytes required to store the samples in + * case of success, at the next libavutil bump + */ +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align); /** - * Parse a packet. + * Reset the internal decoder state / flush internal buffers. Should be called + * e.g. when seeking or when switching to a different stream. * - * @param s parser context. - * @param avctx codec context. - * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. - * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. - * @param buf input buffer. - * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output). - * @param pts input presentation timestamp. - * @param dts input decoding timestamp. - * @param pos input byte position in stream. - * @return the number of bytes of the input bitstream used. + * @note when refcounted frames are not used (i.e. avctx->refcounted_frames is 0), + * this invalidates the frames previously returned from the decoder. When + * refcounted frames are used, the decoder just releases any references it might + * keep internally, but the caller's reference remains valid. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +/** + * Return codec bits per sample. * - * Example: - * @code - * while(in_len){ - * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, - * in_data, in_len, - * pts, dts, pos); - * in_data += len; - * in_len -= len; + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. * - * if(size) - * decode_frame(data, size); - * } - * @endcode + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. */ -int av_parser_parse2(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int64_t pts, int64_t dts, - int64_t pos); +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); -int av_parser_change(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe); -void av_parser_close(AVCodecParserContext *s); +/** + * Return audio frame duration. + * + * @param avctx codec context + * @param frame_bytes size of the frame, or 0 if unknown + * @return frame duration, in samples, if known. 0 if not able to + * determine. + */ +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); typedef struct AVBitStreamFilterContext { @@ -3802,60 +4961,99 @@ typedef struct AVBitStreamFilter { struct AVBitStreamFilter *next; } AVBitStreamFilter; +/** + * Register a bitstream filter. + * + * The filter will be accessible to the application code through + * av_bitstream_filter_next() or can be directly initialized with + * av_bitstream_filter_init(). + * + * @see avcodec_register_all() + */ void av_register_bitstream_filter(AVBitStreamFilter *bsf); + +/** + * Create and initialize a bitstream filter context given a bitstream + * filter name. + * + * The returned context must be freed with av_bitstream_filter_close(). + * + * @param name the name of the bitstream filter + * @return a bitstream filter context if a matching filter was found + * and successfully initialized, NULL otherwise + */ AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); + +/** + * Filter bitstream. + * + * This function filters the buffer buf with size buf_size, and places the + * filtered buffer in the buffer pointed to by poutbuf. + * + * The output buffer must be freed by the caller. + * + * @param bsfc bitstream filter context created by av_bitstream_filter_init() + * @param avctx AVCodecContext accessed by the filter, may be NULL. + * If specified, this must point to the encoder context of the + * output stream the packet is sent to. + * @param args arguments which specify the filter configuration, may be NULL + * @param poutbuf pointer which is updated to point to the filtered buffer + * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes + * @param buf buffer containing the data to filter + * @param buf_size size in bytes of buf + * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data + * @return >= 0 in case of success, or a negative error code in case of failure + * + * If the return value is positive, an output buffer is allocated and + * is available in *poutbuf, and is distinct from the input buffer. + * + * If the return value is 0, the output buffer is not allocated and + * should be considered identical to the input buffer, or in case + * *poutbuf was set it points to the input buffer (not necessarily to + * its starting address). + */ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe); -void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); - -AVBitStreamFilter *av_bitstream_filter_next(AVBitStreamFilter *f); - -/* memory */ /** - * Reallocates the given block if it is not large enough, otherwise it - * does nothing. + * Release bitstream filter context. * - * @see av_realloc + * @param bsf the bitstream filter context created with + * av_bitstream_filter_init(), can be NULL */ -void *av_fast_realloc(void *ptr, unsigned int *size, unsigned int min_size); +void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); /** - * Allocates a buffer, reusing the given one if large enough. - * - * Contrary to av_fast_realloc the current buffer contents might not be - * preserved and on error the old buffer is freed, thus no special - * handling to avoid memleaks is necessary. + * If f is NULL, return the first registered bitstream filter, + * if f is non-NULL, return the next registered bitstream filter + * after f, or NULL if f is the last one. * - * @param ptr pointer to pointer to already allocated buffer, overwritten with pointer to new buffer - * @param size size of the buffer *ptr points to - * @param min_size minimum size of *ptr buffer after returning, *ptr will be NULL and - * *size 0 if an error occurred. + * This function can be used to iterate over all registered bitstream + * filters. */ -void av_fast_malloc(void *ptr, unsigned int *size, unsigned int min_size); +AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); -/** - * Copy image 'src' to 'dst'. - */ -void av_picture_copy(AVPicture *dst, const AVPicture *src, - enum PixelFormat pix_fmt, int width, int height); +/* memory */ /** - * Crop image top and left side. + * Same behaviour av_fast_malloc but the buffer has additional + * FF_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0. + * + * In addition the whole buffer will initially and after resizes + * be 0-initialized so that no uninitialized data will ever appear. */ -int av_picture_crop(AVPicture *dst, const AVPicture *src, - enum PixelFormat pix_fmt, int top_band, int left_band); +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); /** - * Pad image. + * Same behaviour av_fast_padded_malloc except that buffer will always + * be 0-initialized after call. */ -int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum PixelFormat pix_fmt, - int padtop, int padbottom, int padleft, int padright, int *color); +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); /** - * Encodes extradata length to a buffer. Used by xiph codecs. + * Encode extradata length to a buffer. Used by xiph codecs. * * @param s buffer to write to; must be at least (v/255+1) bytes long * @param v size of extradata in bytes @@ -3863,32 +5061,9 @@ int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, */ unsigned int av_xiphlacing(unsigned char *s, unsigned int v); +#if FF_API_MISSING_SAMPLE /** - * Parses str and put in width_ptr and height_ptr the detected values. - * - * @return 0 in case of a successful parsing, a negative value otherwise - * @param[in] str the string to parse: it has to be a string in the format - * x or a valid video frame size abbreviation. - * @param[in,out] width_ptr pointer to the variable which will contain the detected - * frame width value - * @param[in,out] height_ptr pointer to the variable which will contain the detected - * frame height value - */ -int av_parse_video_frame_size(int *width_ptr, int *height_ptr, const char *str); - -/** - * Parses str and put in frame_rate the detected values. - * - * @return 0 in case of a successful parsing, a negative value otherwise - * @param[in] str the string to parse: it has to be a string in the format - * /, a float number or a valid video rate abbreviation - * @param[in,out] frame_rate pointer to the AVRational which will contain the detected - * frame rate - */ -int av_parse_video_frame_rate(AVRational *frame_rate, const char *str); - -/** - * Logs a generic warning message about a missing feature. This function is + * Log a generic warning message about a missing feature. This function is * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) * only, and would normally not be used by applications. * @param[in] avc a pointer to an arbitrary struct of which the first field is @@ -3898,21 +5073,26 @@ int av_parse_video_frame_rate(AVRational *frame_rate, const char *str); * If want_sample is non-zero, additional verbage will be added to the log * message which tells the user how to report samples to the development * mailing list. + * @deprecated Use avpriv_report_missing_feature() instead. */ +attribute_deprecated void av_log_missing_feature(void *avc, const char *feature, int want_sample); /** - * Logs a generic warning message asking for a sample. This function is + * Log a generic warning message asking for a sample. This function is * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) * only, and would normally not be used by applications. * @param[in] avc a pointer to an arbitrary struct of which the first field is * a pointer to an AVClass struct * @param[in] msg string containing an optional message, or NULL if no message + * @deprecated Use avpriv_request_sample() instead. */ -void av_log_ask_for_sample(void *avc, const char *msg); +attribute_deprecated +void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); +#endif /* FF_API_MISSING_SAMPLE */ /** - * Registers the hardware accelerator hwaccel. + * Register the hardware accelerator hwaccel. */ void av_register_hwaccel(AVHWAccel *hwaccel); @@ -3921,7 +5101,7 @@ void av_register_hwaccel(AVHWAccel *hwaccel); * if hwaccel is non-NULL, returns the next registered hardware accelerator * after hwaccel, or NULL if hwaccel is the last one. */ -AVHWAccel *av_hwaccel_next(AVHWAccel *hwaccel); +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel); /** @@ -3949,4 +5129,55 @@ enum AVLockOp { */ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * @return a positive value if s is open (i.e. avcodec_open2() was called on it + * with no corresponding avcodec_close()), 0 otherwise. + */ +int avcodec_is_open(AVCodecContext *s); + +/** + * @return a non-zero number if codec is an encoder, zero otherwise + */ +int av_codec_is_encoder(const AVCodec *codec); + +/** + * @return a non-zero number if codec is a decoder, zero otherwise + */ +int av_codec_is_decoder(const AVCodec *codec); + +/** + * @return descriptor for given codec ID or NULL if no descriptor exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id); + +/** + * Iterate over all codec descriptors known to libavcodec. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev); + +/** + * @return codec descriptor with the given name or NULL if no such descriptor + * exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name); + +/** + * @} + */ + #endif /* AVCODEC_AVCODEC_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/avfft.h b/extra_lib/include/ffmpeg_android/libavcodec/avfft.h new file mode 100644 index 0000000..f5fddfc --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/avfft.h @@ -0,0 +1,236 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVFFT_H +#define AVCODEC_AVFFT_H + +/** + * @file + * @ingroup lavc_fft + * FFT functions + */ + +/** + * @defgroup lavc_fft FFT functions + * @ingroup lavc_misc + * + * @{ + */ + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + */ +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void av_fft_calc(FFTContext *s, FFTComplex *z); + +void av_fft_end(FFTContext *s); + +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +void av_rdft_calc(RDFTContext *s, FFTSample *data); +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * @param type the type of transform + * + * @note the first element of the input of DST-I is ignored + */ +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +void av_dct_calc(DCTContext *s, FFTSample *data); +void av_dct_end (DCTContext *s); + +/** + * @} + */ + +#endif /* AVCODEC_AVFFT_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVFFT_H +#define AVCODEC_AVFFT_H + +/** + * @file + * @ingroup lavc_fft + * FFT functions + */ + +/** + * @defgroup lavc_fft FFT functions + * @ingroup lavc_misc + * + * @{ + */ + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + */ +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void av_fft_calc(FFTContext *s, FFTComplex *z); + +void av_fft_end(FFTContext *s); + +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +void av_rdft_calc(RDFTContext *s, FFTSample *data); +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * @param type the type of transform + * + * @note the first element of the input of DST-I is ignored + */ +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +void av_dct_calc(DCTContext *s, FFTSample *data); +void av_dct_end (DCTContext *s); + +/** + * @} + */ + +#endif /* AVCODEC_AVFFT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/dv_profile.h b/extra_lib/include/ffmpeg_android/libavcodec/dv_profile.h new file mode 100644 index 0000000..af2e20c --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/dv_profile.h @@ -0,0 +1,160 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DV_PROFILE_H +#define AVCODEC_DV_PROFILE_H + +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" +#include "avcodec.h" + +/* minimum number of bytes to read from a DV stream in order to + * determine the profile */ +#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */ + + +/* + * AVDVProfile is used to express the differences between various + * DV flavors. For now it's primarily used for differentiating + * 525/60 and 625/50, but the plans are to use it for various + * DV specs as well (e.g. SMPTE314M vs. IEC 61834). + */ +typedef struct AVDVProfile { + int dsf; /* value of the dsf in the DV header */ + int video_stype; /* stype for VAUX source pack */ + int frame_size; /* total size of one frame in bytes */ + int difseg_size; /* number of DIF segments per DIF channel */ + int n_difchan; /* number of DIF channels per frame */ + AVRational time_base; /* 1/framerate */ + int ltc_divisor; /* FPS from the LTS standpoint */ + int height; /* picture height in pixels */ + int width; /* picture width in pixels */ + AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */ + enum AVPixelFormat pix_fmt; /* picture pixel format */ + int bpm; /* blocks per macroblock */ + const uint8_t *block_sizes; /* AC block sizes, in bits */ + int audio_stride; /* size of audio_shuffle table */ + int audio_min_samples[3]; /* min amount of audio samples */ + /* for 48kHz, 44.1kHz and 32kHz */ + int audio_samples_dist[5]; /* how many samples are supposed to be */ + /* in each frame in a 5 frames window */ + const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */ +} AVDVProfile; + +const AVDVProfile* avpriv_dv_frame_profile2(AVCodecContext* codec, const AVDVProfile *sys, + const uint8_t* frame, unsigned buf_size); + +/** + * Get a DV profile for the provided compressed frame. + * + * @param sys the profile used for the previous frame, may be NULL + * @param frame the compressed data buffer + * @param buf_size size of the buffer in bytes + * @return the DV profile for the supplied data or NULL on failure + */ +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +/** + * Get a DV profile for the provided stream parameters. + */ +const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt); + +#endif /* AVCODEC_DV_PROFILE_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DV_PROFILE_H +#define AVCODEC_DV_PROFILE_H + +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" +#include "avcodec.h" + +/* minimum number of bytes to read from a DV stream in order to + * determine the profile */ +#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */ + + +/* + * AVDVProfile is used to express the differences between various + * DV flavors. For now it's primarily used for differentiating + * 525/60 and 625/50, but the plans are to use it for various + * DV specs as well (e.g. SMPTE314M vs. IEC 61834). + */ +typedef struct AVDVProfile { + int dsf; /* value of the dsf in the DV header */ + int video_stype; /* stype for VAUX source pack */ + int frame_size; /* total size of one frame in bytes */ + int difseg_size; /* number of DIF segments per DIF channel */ + int n_difchan; /* number of DIF channels per frame */ + AVRational time_base; /* 1/framerate */ + int ltc_divisor; /* FPS from the LTS standpoint */ + int height; /* picture height in pixels */ + int width; /* picture width in pixels */ + AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */ + enum AVPixelFormat pix_fmt; /* picture pixel format */ + int bpm; /* blocks per macroblock */ + const uint8_t *block_sizes; /* AC block sizes, in bits */ + int audio_stride; /* size of audio_shuffle table */ + int audio_min_samples[3]; /* min amount of audio samples */ + /* for 48kHz, 44.1kHz and 32kHz */ + int audio_samples_dist[5]; /* how many samples are supposed to be */ + /* in each frame in a 5 frames window */ + const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */ +} AVDVProfile; + +const AVDVProfile* avpriv_dv_frame_profile2(AVCodecContext* codec, const AVDVProfile *sys, + const uint8_t* frame, unsigned buf_size); + +/** + * Get a DV profile for the provided compressed frame. + * + * @param sys the profile used for the previous frame, may be NULL + * @param frame the compressed data buffer + * @param buf_size size of the buffer in bytes + * @return the DV profile for the supplied data or NULL on failure + */ +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +/** + * Get a DV profile for the provided stream parameters. + */ +const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt); + +#endif /* AVCODEC_DV_PROFILE_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/dxva2.h b/extra_lib/include/ffmpeg_android/libavcodec/dxva2.h new file mode 100644 index 0000000..228f5bf --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/dxva2.h @@ -0,0 +1,186 @@ +/* + * DXVA2 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DXVA_H +#define AVCODEC_DXVA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_dxva2 + * Public libavcodec DXVA2 header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif + +#include +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_dxva2 DXVA2 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for DXVA2 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for DXVA2 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the DXVA2 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct dxva_context { + /** + * DXVA2 decoder object + */ + IDirectXVideoDecoder *decoder; + + /** + * DXVA2 configuration used to create the decoder + */ + const DXVA2_ConfigPictureDecode *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + LPDIRECT3DSURFACE9 *surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; +}; + +/** + * @} + */ + +#endif /* AVCODEC_DXVA_H */ +/* + * DXVA2 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DXVA_H +#define AVCODEC_DXVA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_dxva2 + * Public libavcodec DXVA2 header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif + +#include +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_dxva2 DXVA2 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for DXVA2 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for DXVA2 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the DXVA2 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct dxva_context { + /** + * DXVA2 decoder object + */ + IDirectXVideoDecoder *decoder; + + /** + * DXVA2 configuration used to create the decoder + */ + const DXVA2_ConfigPictureDecode *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + LPDIRECT3DSURFACE9 *surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; +}; + +/** + * @} + */ + +#endif /* AVCODEC_DXVA_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/old_codec_ids.h b/extra_lib/include/ffmpeg_android/libavcodec/old_codec_ids.h new file mode 100644 index 0000000..fa6d1a2 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/old_codec_ids.h @@ -0,0 +1,794 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OLD_CODEC_IDS_H +#define AVCODEC_OLD_CODEC_IDS_H + +/* + * This header exists to prevent new codec IDs from being accidentally added to + * the deprecated list. + * Do not include it directly. It will be removed on next major bump + * + * Do not add new items to this list. Use the AVCodecID enum instead. + */ + + CODEC_ID_NONE = AV_CODEC_ID_NONE, + + /* video codecs */ + CODEC_ID_MPEG1VIDEO, + CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + CODEC_ID_MPEG2VIDEO_XVMC, +#endif + CODEC_ID_H261, + CODEC_ID_H263, + CODEC_ID_RV10, + CODEC_ID_RV20, + CODEC_ID_MJPEG, + CODEC_ID_MJPEGB, + CODEC_ID_LJPEG, + CODEC_ID_SP5X, + CODEC_ID_JPEGLS, + CODEC_ID_MPEG4, + CODEC_ID_RAWVIDEO, + CODEC_ID_MSMPEG4V1, + CODEC_ID_MSMPEG4V2, + CODEC_ID_MSMPEG4V3, + CODEC_ID_WMV1, + CODEC_ID_WMV2, + CODEC_ID_H263P, + CODEC_ID_H263I, + CODEC_ID_FLV1, + CODEC_ID_SVQ1, + CODEC_ID_SVQ3, + CODEC_ID_DVVIDEO, + CODEC_ID_HUFFYUV, + CODEC_ID_CYUV, + CODEC_ID_H264, + CODEC_ID_INDEO3, + CODEC_ID_VP3, + CODEC_ID_THEORA, + CODEC_ID_ASV1, + CODEC_ID_ASV2, + CODEC_ID_FFV1, + CODEC_ID_4XM, + CODEC_ID_VCR1, + CODEC_ID_CLJR, + CODEC_ID_MDEC, + CODEC_ID_ROQ, + CODEC_ID_INTERPLAY_VIDEO, + CODEC_ID_XAN_WC3, + CODEC_ID_XAN_WC4, + CODEC_ID_RPZA, + CODEC_ID_CINEPAK, + CODEC_ID_WS_VQA, + CODEC_ID_MSRLE, + CODEC_ID_MSVIDEO1, + CODEC_ID_IDCIN, + CODEC_ID_8BPS, + CODEC_ID_SMC, + CODEC_ID_FLIC, + CODEC_ID_TRUEMOTION1, + CODEC_ID_VMDVIDEO, + CODEC_ID_MSZH, + CODEC_ID_ZLIB, + CODEC_ID_QTRLE, + CODEC_ID_TSCC, + CODEC_ID_ULTI, + CODEC_ID_QDRAW, + CODEC_ID_VIXL, + CODEC_ID_QPEG, + CODEC_ID_PNG, + CODEC_ID_PPM, + CODEC_ID_PBM, + CODEC_ID_PGM, + CODEC_ID_PGMYUV, + CODEC_ID_PAM, + CODEC_ID_FFVHUFF, + CODEC_ID_RV30, + CODEC_ID_RV40, + CODEC_ID_VC1, + CODEC_ID_WMV3, + CODEC_ID_LOCO, + CODEC_ID_WNV1, + CODEC_ID_AASC, + CODEC_ID_INDEO2, + CODEC_ID_FRAPS, + CODEC_ID_TRUEMOTION2, + CODEC_ID_BMP, + CODEC_ID_CSCD, + CODEC_ID_MMVIDEO, + CODEC_ID_ZMBV, + CODEC_ID_AVS, + CODEC_ID_SMACKVIDEO, + CODEC_ID_NUV, + CODEC_ID_KMVC, + CODEC_ID_FLASHSV, + CODEC_ID_CAVS, + CODEC_ID_JPEG2000, + CODEC_ID_VMNC, + CODEC_ID_VP5, + CODEC_ID_VP6, + CODEC_ID_VP6F, + CODEC_ID_TARGA, + CODEC_ID_DSICINVIDEO, + CODEC_ID_TIERTEXSEQVIDEO, + CODEC_ID_TIFF, + CODEC_ID_GIF, + CODEC_ID_DXA, + CODEC_ID_DNXHD, + CODEC_ID_THP, + CODEC_ID_SGI, + CODEC_ID_C93, + CODEC_ID_BETHSOFTVID, + CODEC_ID_PTX, + CODEC_ID_TXD, + CODEC_ID_VP6A, + CODEC_ID_AMV, + CODEC_ID_VB, + CODEC_ID_PCX, + CODEC_ID_SUNRAST, + CODEC_ID_INDEO4, + CODEC_ID_INDEO5, + CODEC_ID_MIMIC, + CODEC_ID_RL2, + CODEC_ID_ESCAPE124, + CODEC_ID_DIRAC, + CODEC_ID_BFI, + CODEC_ID_CMV, + CODEC_ID_MOTIONPIXELS, + CODEC_ID_TGV, + CODEC_ID_TGQ, + CODEC_ID_TQI, + CODEC_ID_AURA, + CODEC_ID_AURA2, + CODEC_ID_V210X, + CODEC_ID_TMV, + CODEC_ID_V210, + CODEC_ID_DPX, + CODEC_ID_MAD, + CODEC_ID_FRWU, + CODEC_ID_FLASHSV2, + CODEC_ID_CDGRAPHICS, + CODEC_ID_R210, + CODEC_ID_ANM, + CODEC_ID_BINKVIDEO, + CODEC_ID_IFF_ILBM, + CODEC_ID_IFF_BYTERUN1, + CODEC_ID_KGV1, + CODEC_ID_YOP, + CODEC_ID_VP8, + CODEC_ID_PICTOR, + CODEC_ID_ANSI, + CODEC_ID_A64_MULTI, + CODEC_ID_A64_MULTI5, + CODEC_ID_R10K, + CODEC_ID_MXPEG, + CODEC_ID_LAGARITH, + CODEC_ID_PRORES, + CODEC_ID_JV, + CODEC_ID_DFA, + CODEC_ID_WMV3IMAGE, + CODEC_ID_VC1IMAGE, + CODEC_ID_UTVIDEO, + CODEC_ID_BMV_VIDEO, + CODEC_ID_VBLE, + CODEC_ID_DXTORY, + CODEC_ID_V410, + CODEC_ID_XWD, + CODEC_ID_CDXL, + CODEC_ID_XBM, + CODEC_ID_ZEROCODEC, + CODEC_ID_MSS1, + CODEC_ID_MSA1, + CODEC_ID_TSCC2, + CODEC_ID_MTS2, + CODEC_ID_CLLC, + CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), + CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'), + CODEC_ID_EXR = MKBETAG('0','E','X','R'), + CODEC_ID_AVRP = MKBETAG('A','V','R','P'), + + CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'), + CODEC_ID_AVUI = MKBETAG('A','V','U','I'), + CODEC_ID_AYUV = MKBETAG('A','Y','U','V'), + CODEC_ID_V308 = MKBETAG('V','3','0','8'), + CODEC_ID_V408 = MKBETAG('V','4','0','8'), + CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'), + CODEC_ID_SANM = MKBETAG('S','A','N','M'), + CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'), + CODEC_ID_SNOW = AV_CODEC_ID_SNOW, + + /* various PCM "codecs" */ + CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + CODEC_ID_PCM_S16LE = 0x10000, + CODEC_ID_PCM_S16BE, + CODEC_ID_PCM_U16LE, + CODEC_ID_PCM_U16BE, + CODEC_ID_PCM_S8, + CODEC_ID_PCM_U8, + CODEC_ID_PCM_MULAW, + CODEC_ID_PCM_ALAW, + CODEC_ID_PCM_S32LE, + CODEC_ID_PCM_S32BE, + CODEC_ID_PCM_U32LE, + CODEC_ID_PCM_U32BE, + CODEC_ID_PCM_S24LE, + CODEC_ID_PCM_S24BE, + CODEC_ID_PCM_U24LE, + CODEC_ID_PCM_U24BE, + CODEC_ID_PCM_S24DAUD, + CODEC_ID_PCM_ZORK, + CODEC_ID_PCM_S16LE_PLANAR, + CODEC_ID_PCM_DVD, + CODEC_ID_PCM_F32BE, + CODEC_ID_PCM_F32LE, + CODEC_ID_PCM_F64BE, + CODEC_ID_PCM_F64LE, + CODEC_ID_PCM_BLURAY, + CODEC_ID_PCM_LXF, + CODEC_ID_S302M, + CODEC_ID_PCM_S8_PLANAR, + + /* various ADPCM codecs */ + CODEC_ID_ADPCM_IMA_QT = 0x11000, + CODEC_ID_ADPCM_IMA_WAV, + CODEC_ID_ADPCM_IMA_DK3, + CODEC_ID_ADPCM_IMA_DK4, + CODEC_ID_ADPCM_IMA_WS, + CODEC_ID_ADPCM_IMA_SMJPEG, + CODEC_ID_ADPCM_MS, + CODEC_ID_ADPCM_4XM, + CODEC_ID_ADPCM_XA, + CODEC_ID_ADPCM_ADX, + CODEC_ID_ADPCM_EA, + CODEC_ID_ADPCM_G726, + CODEC_ID_ADPCM_CT, + CODEC_ID_ADPCM_SWF, + CODEC_ID_ADPCM_YAMAHA, + CODEC_ID_ADPCM_SBPRO_4, + CODEC_ID_ADPCM_SBPRO_3, + CODEC_ID_ADPCM_SBPRO_2, + CODEC_ID_ADPCM_THP, + CODEC_ID_ADPCM_IMA_AMV, + CODEC_ID_ADPCM_EA_R1, + CODEC_ID_ADPCM_EA_R3, + CODEC_ID_ADPCM_EA_R2, + CODEC_ID_ADPCM_IMA_EA_SEAD, + CODEC_ID_ADPCM_IMA_EA_EACS, + CODEC_ID_ADPCM_EA_XAS, + CODEC_ID_ADPCM_EA_MAXIS_XA, + CODEC_ID_ADPCM_IMA_ISS, + CODEC_ID_ADPCM_G722, + CODEC_ID_ADPCM_IMA_APC, + CODEC_ID_VIMA = MKBETAG('V','I','M','A'), + + /* AMR */ + CODEC_ID_AMR_NB = 0x12000, + CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + CODEC_ID_RA_144 = 0x13000, + CODEC_ID_RA_288, + + /* various DPCM codecs */ + CODEC_ID_ROQ_DPCM = 0x14000, + CODEC_ID_INTERPLAY_DPCM, + CODEC_ID_XAN_DPCM, + CODEC_ID_SOL_DPCM, + + /* audio codecs */ + CODEC_ID_MP2 = 0x15000, + CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + CODEC_ID_AAC, + CODEC_ID_AC3, + CODEC_ID_DTS, + CODEC_ID_VORBIS, + CODEC_ID_DVAUDIO, + CODEC_ID_WMAV1, + CODEC_ID_WMAV2, + CODEC_ID_MACE3, + CODEC_ID_MACE6, + CODEC_ID_VMDAUDIO, + CODEC_ID_FLAC, + CODEC_ID_MP3ADU, + CODEC_ID_MP3ON4, + CODEC_ID_SHORTEN, + CODEC_ID_ALAC, + CODEC_ID_WESTWOOD_SND1, + CODEC_ID_GSM, ///< as in Berlin toast format + CODEC_ID_QDM2, + CODEC_ID_COOK, + CODEC_ID_TRUESPEECH, + CODEC_ID_TTA, + CODEC_ID_SMACKAUDIO, + CODEC_ID_QCELP, + CODEC_ID_WAVPACK, + CODEC_ID_DSICINAUDIO, + CODEC_ID_IMC, + CODEC_ID_MUSEPACK7, + CODEC_ID_MLP, + CODEC_ID_GSM_MS, /* as found in WAV */ + CODEC_ID_ATRAC3, + CODEC_ID_VOXWARE, + CODEC_ID_APE, + CODEC_ID_NELLYMOSER, + CODEC_ID_MUSEPACK8, + CODEC_ID_SPEEX, + CODEC_ID_WMAVOICE, + CODEC_ID_WMAPRO, + CODEC_ID_WMALOSSLESS, + CODEC_ID_ATRAC3P, + CODEC_ID_EAC3, + CODEC_ID_SIPR, + CODEC_ID_MP1, + CODEC_ID_TWINVQ, + CODEC_ID_TRUEHD, + CODEC_ID_MP4ALS, + CODEC_ID_ATRAC1, + CODEC_ID_BINKAUDIO_RDFT, + CODEC_ID_BINKAUDIO_DCT, + CODEC_ID_AAC_LATM, + CODEC_ID_QDMC, + CODEC_ID_CELT, + CODEC_ID_G723_1, + CODEC_ID_G729, + CODEC_ID_8SVX_EXP, + CODEC_ID_8SVX_FIB, + CODEC_ID_BMV_AUDIO, + CODEC_ID_RALF, + CODEC_ID_IAC, + CODEC_ID_ILBC, + CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'), + CODEC_ID_SONIC = MKBETAG('S','O','N','C'), + CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'), + CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'), + CODEC_ID_OPUS = MKBETAG('O','P','U','S'), + + /* subtitle codecs */ + CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + CODEC_ID_DVD_SUBTITLE = 0x17000, + CODEC_ID_DVB_SUBTITLE, + CODEC_ID_TEXT, ///< raw UTF-8 text + CODEC_ID_XSUB, + CODEC_ID_SSA, + CODEC_ID_MOV_TEXT, + CODEC_ID_HDMV_PGS_SUBTITLE, + CODEC_ID_DVB_TELETEXT, + CODEC_ID_SRT, + CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'), + CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'), + CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'), + CODEC_ID_SAMI = MKBETAG('S','A','M','I'), + CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'), + CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'), + + /* other specific kind of codecs (generally used for attachments) */ + CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + CODEC_ID_TTF = 0x18000, + CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'), + CODEC_ID_XBIN = MKBETAG('X','B','I','N'), + CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), + CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), + + CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it + + CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + +#endif /* AVCODEC_OLD_CODEC_IDS_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OLD_CODEC_IDS_H +#define AVCODEC_OLD_CODEC_IDS_H + +/* + * This header exists to prevent new codec IDs from being accidentally added to + * the deprecated list. + * Do not include it directly. It will be removed on next major bump + * + * Do not add new items to this list. Use the AVCodecID enum instead. + */ + + CODEC_ID_NONE = AV_CODEC_ID_NONE, + + /* video codecs */ + CODEC_ID_MPEG1VIDEO, + CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + CODEC_ID_MPEG2VIDEO_XVMC, +#endif + CODEC_ID_H261, + CODEC_ID_H263, + CODEC_ID_RV10, + CODEC_ID_RV20, + CODEC_ID_MJPEG, + CODEC_ID_MJPEGB, + CODEC_ID_LJPEG, + CODEC_ID_SP5X, + CODEC_ID_JPEGLS, + CODEC_ID_MPEG4, + CODEC_ID_RAWVIDEO, + CODEC_ID_MSMPEG4V1, + CODEC_ID_MSMPEG4V2, + CODEC_ID_MSMPEG4V3, + CODEC_ID_WMV1, + CODEC_ID_WMV2, + CODEC_ID_H263P, + CODEC_ID_H263I, + CODEC_ID_FLV1, + CODEC_ID_SVQ1, + CODEC_ID_SVQ3, + CODEC_ID_DVVIDEO, + CODEC_ID_HUFFYUV, + CODEC_ID_CYUV, + CODEC_ID_H264, + CODEC_ID_INDEO3, + CODEC_ID_VP3, + CODEC_ID_THEORA, + CODEC_ID_ASV1, + CODEC_ID_ASV2, + CODEC_ID_FFV1, + CODEC_ID_4XM, + CODEC_ID_VCR1, + CODEC_ID_CLJR, + CODEC_ID_MDEC, + CODEC_ID_ROQ, + CODEC_ID_INTERPLAY_VIDEO, + CODEC_ID_XAN_WC3, + CODEC_ID_XAN_WC4, + CODEC_ID_RPZA, + CODEC_ID_CINEPAK, + CODEC_ID_WS_VQA, + CODEC_ID_MSRLE, + CODEC_ID_MSVIDEO1, + CODEC_ID_IDCIN, + CODEC_ID_8BPS, + CODEC_ID_SMC, + CODEC_ID_FLIC, + CODEC_ID_TRUEMOTION1, + CODEC_ID_VMDVIDEO, + CODEC_ID_MSZH, + CODEC_ID_ZLIB, + CODEC_ID_QTRLE, + CODEC_ID_TSCC, + CODEC_ID_ULTI, + CODEC_ID_QDRAW, + CODEC_ID_VIXL, + CODEC_ID_QPEG, + CODEC_ID_PNG, + CODEC_ID_PPM, + CODEC_ID_PBM, + CODEC_ID_PGM, + CODEC_ID_PGMYUV, + CODEC_ID_PAM, + CODEC_ID_FFVHUFF, + CODEC_ID_RV30, + CODEC_ID_RV40, + CODEC_ID_VC1, + CODEC_ID_WMV3, + CODEC_ID_LOCO, + CODEC_ID_WNV1, + CODEC_ID_AASC, + CODEC_ID_INDEO2, + CODEC_ID_FRAPS, + CODEC_ID_TRUEMOTION2, + CODEC_ID_BMP, + CODEC_ID_CSCD, + CODEC_ID_MMVIDEO, + CODEC_ID_ZMBV, + CODEC_ID_AVS, + CODEC_ID_SMACKVIDEO, + CODEC_ID_NUV, + CODEC_ID_KMVC, + CODEC_ID_FLASHSV, + CODEC_ID_CAVS, + CODEC_ID_JPEG2000, + CODEC_ID_VMNC, + CODEC_ID_VP5, + CODEC_ID_VP6, + CODEC_ID_VP6F, + CODEC_ID_TARGA, + CODEC_ID_DSICINVIDEO, + CODEC_ID_TIERTEXSEQVIDEO, + CODEC_ID_TIFF, + CODEC_ID_GIF, + CODEC_ID_DXA, + CODEC_ID_DNXHD, + CODEC_ID_THP, + CODEC_ID_SGI, + CODEC_ID_C93, + CODEC_ID_BETHSOFTVID, + CODEC_ID_PTX, + CODEC_ID_TXD, + CODEC_ID_VP6A, + CODEC_ID_AMV, + CODEC_ID_VB, + CODEC_ID_PCX, + CODEC_ID_SUNRAST, + CODEC_ID_INDEO4, + CODEC_ID_INDEO5, + CODEC_ID_MIMIC, + CODEC_ID_RL2, + CODEC_ID_ESCAPE124, + CODEC_ID_DIRAC, + CODEC_ID_BFI, + CODEC_ID_CMV, + CODEC_ID_MOTIONPIXELS, + CODEC_ID_TGV, + CODEC_ID_TGQ, + CODEC_ID_TQI, + CODEC_ID_AURA, + CODEC_ID_AURA2, + CODEC_ID_V210X, + CODEC_ID_TMV, + CODEC_ID_V210, + CODEC_ID_DPX, + CODEC_ID_MAD, + CODEC_ID_FRWU, + CODEC_ID_FLASHSV2, + CODEC_ID_CDGRAPHICS, + CODEC_ID_R210, + CODEC_ID_ANM, + CODEC_ID_BINKVIDEO, + CODEC_ID_IFF_ILBM, + CODEC_ID_IFF_BYTERUN1, + CODEC_ID_KGV1, + CODEC_ID_YOP, + CODEC_ID_VP8, + CODEC_ID_PICTOR, + CODEC_ID_ANSI, + CODEC_ID_A64_MULTI, + CODEC_ID_A64_MULTI5, + CODEC_ID_R10K, + CODEC_ID_MXPEG, + CODEC_ID_LAGARITH, + CODEC_ID_PRORES, + CODEC_ID_JV, + CODEC_ID_DFA, + CODEC_ID_WMV3IMAGE, + CODEC_ID_VC1IMAGE, + CODEC_ID_UTVIDEO, + CODEC_ID_BMV_VIDEO, + CODEC_ID_VBLE, + CODEC_ID_DXTORY, + CODEC_ID_V410, + CODEC_ID_XWD, + CODEC_ID_CDXL, + CODEC_ID_XBM, + CODEC_ID_ZEROCODEC, + CODEC_ID_MSS1, + CODEC_ID_MSA1, + CODEC_ID_TSCC2, + CODEC_ID_MTS2, + CODEC_ID_CLLC, + CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), + CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'), + CODEC_ID_EXR = MKBETAG('0','E','X','R'), + CODEC_ID_AVRP = MKBETAG('A','V','R','P'), + + CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'), + CODEC_ID_AVUI = MKBETAG('A','V','U','I'), + CODEC_ID_AYUV = MKBETAG('A','Y','U','V'), + CODEC_ID_V308 = MKBETAG('V','3','0','8'), + CODEC_ID_V408 = MKBETAG('V','4','0','8'), + CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'), + CODEC_ID_SANM = MKBETAG('S','A','N','M'), + CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'), + CODEC_ID_SNOW = AV_CODEC_ID_SNOW, + + /* various PCM "codecs" */ + CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + CODEC_ID_PCM_S16LE = 0x10000, + CODEC_ID_PCM_S16BE, + CODEC_ID_PCM_U16LE, + CODEC_ID_PCM_U16BE, + CODEC_ID_PCM_S8, + CODEC_ID_PCM_U8, + CODEC_ID_PCM_MULAW, + CODEC_ID_PCM_ALAW, + CODEC_ID_PCM_S32LE, + CODEC_ID_PCM_S32BE, + CODEC_ID_PCM_U32LE, + CODEC_ID_PCM_U32BE, + CODEC_ID_PCM_S24LE, + CODEC_ID_PCM_S24BE, + CODEC_ID_PCM_U24LE, + CODEC_ID_PCM_U24BE, + CODEC_ID_PCM_S24DAUD, + CODEC_ID_PCM_ZORK, + CODEC_ID_PCM_S16LE_PLANAR, + CODEC_ID_PCM_DVD, + CODEC_ID_PCM_F32BE, + CODEC_ID_PCM_F32LE, + CODEC_ID_PCM_F64BE, + CODEC_ID_PCM_F64LE, + CODEC_ID_PCM_BLURAY, + CODEC_ID_PCM_LXF, + CODEC_ID_S302M, + CODEC_ID_PCM_S8_PLANAR, + + /* various ADPCM codecs */ + CODEC_ID_ADPCM_IMA_QT = 0x11000, + CODEC_ID_ADPCM_IMA_WAV, + CODEC_ID_ADPCM_IMA_DK3, + CODEC_ID_ADPCM_IMA_DK4, + CODEC_ID_ADPCM_IMA_WS, + CODEC_ID_ADPCM_IMA_SMJPEG, + CODEC_ID_ADPCM_MS, + CODEC_ID_ADPCM_4XM, + CODEC_ID_ADPCM_XA, + CODEC_ID_ADPCM_ADX, + CODEC_ID_ADPCM_EA, + CODEC_ID_ADPCM_G726, + CODEC_ID_ADPCM_CT, + CODEC_ID_ADPCM_SWF, + CODEC_ID_ADPCM_YAMAHA, + CODEC_ID_ADPCM_SBPRO_4, + CODEC_ID_ADPCM_SBPRO_3, + CODEC_ID_ADPCM_SBPRO_2, + CODEC_ID_ADPCM_THP, + CODEC_ID_ADPCM_IMA_AMV, + CODEC_ID_ADPCM_EA_R1, + CODEC_ID_ADPCM_EA_R3, + CODEC_ID_ADPCM_EA_R2, + CODEC_ID_ADPCM_IMA_EA_SEAD, + CODEC_ID_ADPCM_IMA_EA_EACS, + CODEC_ID_ADPCM_EA_XAS, + CODEC_ID_ADPCM_EA_MAXIS_XA, + CODEC_ID_ADPCM_IMA_ISS, + CODEC_ID_ADPCM_G722, + CODEC_ID_ADPCM_IMA_APC, + CODEC_ID_VIMA = MKBETAG('V','I','M','A'), + + /* AMR */ + CODEC_ID_AMR_NB = 0x12000, + CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + CODEC_ID_RA_144 = 0x13000, + CODEC_ID_RA_288, + + /* various DPCM codecs */ + CODEC_ID_ROQ_DPCM = 0x14000, + CODEC_ID_INTERPLAY_DPCM, + CODEC_ID_XAN_DPCM, + CODEC_ID_SOL_DPCM, + + /* audio codecs */ + CODEC_ID_MP2 = 0x15000, + CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + CODEC_ID_AAC, + CODEC_ID_AC3, + CODEC_ID_DTS, + CODEC_ID_VORBIS, + CODEC_ID_DVAUDIO, + CODEC_ID_WMAV1, + CODEC_ID_WMAV2, + CODEC_ID_MACE3, + CODEC_ID_MACE6, + CODEC_ID_VMDAUDIO, + CODEC_ID_FLAC, + CODEC_ID_MP3ADU, + CODEC_ID_MP3ON4, + CODEC_ID_SHORTEN, + CODEC_ID_ALAC, + CODEC_ID_WESTWOOD_SND1, + CODEC_ID_GSM, ///< as in Berlin toast format + CODEC_ID_QDM2, + CODEC_ID_COOK, + CODEC_ID_TRUESPEECH, + CODEC_ID_TTA, + CODEC_ID_SMACKAUDIO, + CODEC_ID_QCELP, + CODEC_ID_WAVPACK, + CODEC_ID_DSICINAUDIO, + CODEC_ID_IMC, + CODEC_ID_MUSEPACK7, + CODEC_ID_MLP, + CODEC_ID_GSM_MS, /* as found in WAV */ + CODEC_ID_ATRAC3, + CODEC_ID_VOXWARE, + CODEC_ID_APE, + CODEC_ID_NELLYMOSER, + CODEC_ID_MUSEPACK8, + CODEC_ID_SPEEX, + CODEC_ID_WMAVOICE, + CODEC_ID_WMAPRO, + CODEC_ID_WMALOSSLESS, + CODEC_ID_ATRAC3P, + CODEC_ID_EAC3, + CODEC_ID_SIPR, + CODEC_ID_MP1, + CODEC_ID_TWINVQ, + CODEC_ID_TRUEHD, + CODEC_ID_MP4ALS, + CODEC_ID_ATRAC1, + CODEC_ID_BINKAUDIO_RDFT, + CODEC_ID_BINKAUDIO_DCT, + CODEC_ID_AAC_LATM, + CODEC_ID_QDMC, + CODEC_ID_CELT, + CODEC_ID_G723_1, + CODEC_ID_G729, + CODEC_ID_8SVX_EXP, + CODEC_ID_8SVX_FIB, + CODEC_ID_BMV_AUDIO, + CODEC_ID_RALF, + CODEC_ID_IAC, + CODEC_ID_ILBC, + CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'), + CODEC_ID_SONIC = MKBETAG('S','O','N','C'), + CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'), + CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'), + CODEC_ID_OPUS = MKBETAG('O','P','U','S'), + + /* subtitle codecs */ + CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + CODEC_ID_DVD_SUBTITLE = 0x17000, + CODEC_ID_DVB_SUBTITLE, + CODEC_ID_TEXT, ///< raw UTF-8 text + CODEC_ID_XSUB, + CODEC_ID_SSA, + CODEC_ID_MOV_TEXT, + CODEC_ID_HDMV_PGS_SUBTITLE, + CODEC_ID_DVB_TELETEXT, + CODEC_ID_SRT, + CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'), + CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'), + CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'), + CODEC_ID_SAMI = MKBETAG('S','A','M','I'), + CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'), + CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'), + + /* other specific kind of codecs (generally used for attachments) */ + CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + CODEC_ID_TTF = 0x18000, + CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'), + CODEC_ID_XBIN = MKBETAG('X','B','I','N'), + CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'), + CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'), + + CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it + + CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + +#endif /* AVCODEC_OLD_CODEC_IDS_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/vaapi.h b/extra_lib/include/ffmpeg_android/libavcodec/vaapi.h new file mode 100644 index 0000000..87d5d1e --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/vaapi.h @@ -0,0 +1,346 @@ +/* + * Video Acceleration API (shared data between FFmpeg and the video player) + * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1 + * + * Copyright (C) 2008-2009 Splitted-Desktop Systems + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VAAPI_H +#define AVCODEC_VAAPI_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vaapi + * Public libavcodec VA API header. + */ + +#include + +/** + * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding + * @ingroup lavc_codec_hwaccel + * @{ + */ + +/** + * This structure is used to share data between the FFmpeg library and + * the client video application. + * This shall be zero-allocated and available as + * AVCodecContext.hwaccel_context. All user members can be set once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + */ +struct vaapi_context { + /** + * Window system dependent data + * + * - encoding: unused + * - decoding: Set by user + */ + void *display; + + /** + * Configuration ID + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t config_id; + + /** + * Context ID (video decode pipeline) + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t context_id; + + /** + * VAPictureParameterBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t pic_param_buf_id; + + /** + * VAIQMatrixBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t iq_matrix_buf_id; + + /** + * VABitPlaneBuffer ID (for VC-1 decoding) + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t bitplane_buf_id; + + /** + * Slice parameter/data buffer IDs + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t *slice_buf_ids; + + /** + * Number of effective slice buffer IDs to send to the HW + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int n_slice_buf_ids; + + /** + * Size of pre-allocated slice_buf_ids + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_buf_ids_alloc; + + /** + * Pointer to VASliceParameterBuffers + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + void *slice_params; + + /** + * Size of a VASliceParameterBuffer element + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_param_size; + + /** + * Size of pre-allocated slice_params + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_params_alloc; + + /** + * Number of slices currently filled in + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_count; + + /** + * Pointer to slice data buffer base + * - encoding: unused + * - decoding: Set by libavcodec + */ + const uint8_t *slice_data; + + /** + * Current size of slice data + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t slice_data_size; +}; + +/* @} */ + +#endif /* AVCODEC_VAAPI_H */ +/* + * Video Acceleration API (shared data between FFmpeg and the video player) + * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1 + * + * Copyright (C) 2008-2009 Splitted-Desktop Systems + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VAAPI_H +#define AVCODEC_VAAPI_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vaapi + * Public libavcodec VA API header. + */ + +#include + +/** + * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding + * @ingroup lavc_codec_hwaccel + * @{ + */ + +/** + * This structure is used to share data between the FFmpeg library and + * the client video application. + * This shall be zero-allocated and available as + * AVCodecContext.hwaccel_context. All user members can be set once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + */ +struct vaapi_context { + /** + * Window system dependent data + * + * - encoding: unused + * - decoding: Set by user + */ + void *display; + + /** + * Configuration ID + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t config_id; + + /** + * Context ID (video decode pipeline) + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t context_id; + + /** + * VAPictureParameterBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t pic_param_buf_id; + + /** + * VAIQMatrixBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t iq_matrix_buf_id; + + /** + * VABitPlaneBuffer ID (for VC-1 decoding) + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t bitplane_buf_id; + + /** + * Slice parameter/data buffer IDs + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t *slice_buf_ids; + + /** + * Number of effective slice buffer IDs to send to the HW + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int n_slice_buf_ids; + + /** + * Size of pre-allocated slice_buf_ids + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_buf_ids_alloc; + + /** + * Pointer to VASliceParameterBuffers + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + void *slice_params; + + /** + * Size of a VASliceParameterBuffer element + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_param_size; + + /** + * Size of pre-allocated slice_params + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_params_alloc; + + /** + * Number of slices currently filled in + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + unsigned int slice_count; + + /** + * Pointer to slice data buffer base + * - encoding: unused + * - decoding: Set by libavcodec + */ + const uint8_t *slice_data; + + /** + * Current size of slice data + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + uint32_t slice_data_size; +}; + +/* @} */ + +#endif /* AVCODEC_VAAPI_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/vda.h b/extra_lib/include/ffmpeg_android/libavcodec/vda.h new file mode 100644 index 0000000..91b21c2 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/vda.h @@ -0,0 +1,426 @@ +/* + * VDA HW acceleration + * + * copyright (c) 2011 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDA_H +#define AVCODEC_VDA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vda + * Public libavcodec VDA header. + */ + +#include "libavcodec/avcodec.h" + +#include + +// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes +// http://openradar.appspot.com/8026390 +#undef __GNUC_STDC_INLINE__ + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/version.h" + +// extra flags not defined in VDADecoder.h +enum { + kVDADecodeInfo_Asynchronous = 1UL << 0, + kVDADecodeInfo_FrameDropped = 1UL << 1 +}; + +/** + * @defgroup lavc_codec_hwaccel_vda VDA + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +/** + * This structure is used to provide the necessary configurations and data + * to the VDA FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct vda_context { + /** + * VDA decoder object. + * + * - encoding: unused + * - decoding: Set/Unset by libavcodec. + */ + VDADecoder decoder; + + /** + * The Core Video pixel buffer that contains the current image data. + * + * encoding: unused + * decoding: Set by libavcodec. Unset by user. + */ + CVPixelBufferRef cv_buffer; + + /** + * Use the hardware decoder in synchronous mode. + * + * encoding: unused + * decoding: Set by user. + */ + int use_sync_decoding; + + /** + * The frame width. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int width; + + /** + * The frame height. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int height; + + /** + * The frame format. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int format; + + /** + * The pixel format for output image buffers. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + OSType cv_pix_fmt_type; + + /** + * unused + */ + uint8_t *priv_bitstream; + + /** + * unused + */ + int priv_bitstream_size; + + /** + * unused + */ + int priv_allocated_size; + + /** + * Use av_buffer to manage buffer. + * When the flag is set, the CVPixelBuffers returned by the decoder will + * be released automatically, so you have to retain them if necessary. + * Not setting this flag may cause memory leak. + * + * encoding: unused + * decoding: Set by user. + */ + int use_ref_buffer; +}; + +/** Create the video decoder. */ +int ff_vda_create_decoder(struct vda_context *vda_ctx, + uint8_t *extradata, + int extradata_size); + +/** Destroy the video decoder. */ +int ff_vda_destroy_decoder(struct vda_context *vda_ctx); + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing VDA decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_vda_alloc_context() and freed with av_free(). + */ +typedef struct AVVDAContext { + /** + * VDA decoder object. Created and freed by the caller. + */ + VDADecoder decoder; + + /** + * The output callback that must be passed to VDADecoderCreate. + * Set by av_vda_alloc_context(). + */ + VDADecoderOutputCallback output_callback; +} AVVDAContext; + +/** + * Allocate and initialize a VDA context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder + * object (using the output callback provided by libavcodec) that will be used + * for VDA-accelerated decoding. + * + * When decoding with VDA is finished, the caller must destroy the decoder + * object and free the VDA context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVDAContext *av_vda_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the VDA context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_vda_default_init(AVCodecContext *avctx); + +/** + * This function must be called to free the VDA context initialized with + * av_vda_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_vda_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VDA_H */ +/* + * VDA HW acceleration + * + * copyright (c) 2011 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDA_H +#define AVCODEC_VDA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vda + * Public libavcodec VDA header. + */ + +#include "libavcodec/avcodec.h" + +#include + +// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes +// http://openradar.appspot.com/8026390 +#undef __GNUC_STDC_INLINE__ + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/version.h" + +// extra flags not defined in VDADecoder.h +enum { + kVDADecodeInfo_Asynchronous = 1UL << 0, + kVDADecodeInfo_FrameDropped = 1UL << 1 +}; + +/** + * @defgroup lavc_codec_hwaccel_vda VDA + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +/** + * This structure is used to provide the necessary configurations and data + * to the VDA FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct vda_context { + /** + * VDA decoder object. + * + * - encoding: unused + * - decoding: Set/Unset by libavcodec. + */ + VDADecoder decoder; + + /** + * The Core Video pixel buffer that contains the current image data. + * + * encoding: unused + * decoding: Set by libavcodec. Unset by user. + */ + CVPixelBufferRef cv_buffer; + + /** + * Use the hardware decoder in synchronous mode. + * + * encoding: unused + * decoding: Set by user. + */ + int use_sync_decoding; + + /** + * The frame width. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int width; + + /** + * The frame height. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int height; + + /** + * The frame format. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int format; + + /** + * The pixel format for output image buffers. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + OSType cv_pix_fmt_type; + + /** + * unused + */ + uint8_t *priv_bitstream; + + /** + * unused + */ + int priv_bitstream_size; + + /** + * unused + */ + int priv_allocated_size; + + /** + * Use av_buffer to manage buffer. + * When the flag is set, the CVPixelBuffers returned by the decoder will + * be released automatically, so you have to retain them if necessary. + * Not setting this flag may cause memory leak. + * + * encoding: unused + * decoding: Set by user. + */ + int use_ref_buffer; +}; + +/** Create the video decoder. */ +int ff_vda_create_decoder(struct vda_context *vda_ctx, + uint8_t *extradata, + int extradata_size); + +/** Destroy the video decoder. */ +int ff_vda_destroy_decoder(struct vda_context *vda_ctx); + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing VDA decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_vda_alloc_context() and freed with av_free(). + */ +typedef struct AVVDAContext { + /** + * VDA decoder object. Created and freed by the caller. + */ + VDADecoder decoder; + + /** + * The output callback that must be passed to VDADecoderCreate. + * Set by av_vda_alloc_context(). + */ + VDADecoderOutputCallback output_callback; +} AVVDAContext; + +/** + * Allocate and initialize a VDA context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder + * object (using the output callback provided by libavcodec) that will be used + * for VDA-accelerated decoding. + * + * When decoding with VDA is finished, the caller must destroy the decoder + * object and free the VDA context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVDAContext *av_vda_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the VDA context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_vda_default_init(AVCodecContext *avctx); + +/** + * This function must be called to free the VDA context initialized with + * av_vda_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_vda_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VDA_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/vdpau.h b/extra_lib/include/ffmpeg_android/libavcodec/vdpau.h new file mode 100644 index 0000000..4d48529 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/vdpau.h @@ -0,0 +1,430 @@ +/* + * The Video Decode and Presentation API for UNIX (VDPAU) is used for + * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. + * + * Copyright (C) 2008 NVIDIA + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDPAU_H +#define AVCODEC_VDPAU_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vdpau + * Public libavcodec VDPAU header. + */ + + +/** + * @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer + * @ingroup lavc_codec_hwaccel + * + * VDPAU hardware acceleration has two modules + * - VDPAU decoding + * - VDPAU presentation + * + * The VDPAU decoding module parses all headers using FFmpeg + * parsing mechanisms and uses VDPAU for the actual decoding. + * + * As per the current implementation, the actual decoding + * and rendering (API calls) are done as part of the VDPAU + * presentation (vo_vdpau.c) module. + * + * @{ + */ + +#include +#include +#include "libavutil/avconfig.h" +#include "libavutil/attributes.h" + +#include "avcodec.h" +#include "version.h" + +#if FF_API_BUFS_VDPAU +union AVVDPAUPictureInfo { + VdpPictureInfoH264 h264; + VdpPictureInfoMPEG1Or2 mpeg; + VdpPictureInfoVC1 vc1; + VdpPictureInfoMPEG4Part2 mpeg4; +}; +#endif + +struct AVCodecContext; +struct AVFrame; + +typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *, + const VdpPictureInfo *, uint32_t, + const VdpBitstreamBuffer *); + +/** + * This structure is used to share data between the libavcodec library and + * the client video application. + * The user shall allocate the structure via the av_alloc_vdpau_hwaccel + * function and make it available as + * AVCodecContext.hwaccel_context. Members can be set by the user once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * The size of this structure is not a part of the public ABI and must not + * be used outside of libavcodec. Use av_vdpau_alloc_context() to allocate an + * AVVDPAUContext. + */ +typedef struct AVVDPAUContext { + /** + * VDPAU decoder handle + * + * Set by user. + */ + VdpDecoder decoder; + + /** + * VDPAU decoder render callback + * + * Set by the user. + */ + VdpDecoderRender *render; + +#if FF_API_BUFS_VDPAU + /** + * VDPAU picture information + * + * Set by libavcodec. + */ + attribute_deprecated + union AVVDPAUPictureInfo info; + + /** + * Allocated size of the bitstream_buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_allocated; + + /** + * Useful bitstream buffers in the bitstream buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_used; + + /** + * Table of bitstream buffers. + * The user is responsible for freeing this buffer using av_freep(). + * + * Set by libavcodec. + */ + attribute_deprecated + VdpBitstreamBuffer *bitstream_buffers; +#endif + AVVDPAU_Render2 render2; +} AVVDPAUContext; + +/** + * @brief allocation function for AVVDPAUContext + * + * Allows extending the struct without breaking API/ABI + */ +AVVDPAUContext *av_alloc_vdpaucontext(void); + +AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); +void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); + +/** + * Allocate an AVVDPAUContext. + * + * @return Newly-allocated AVVDPAUContext or NULL on failure. + */ +AVVDPAUContext *av_vdpau_alloc_context(void); + +/** + * Get a decoder profile that should be used for initializing a VDPAU decoder. + * Should be called from the AVCodecContext.get_format() callback. + * + * @param avctx the codec context being used for decoding the stream + * @param profile a pointer into which the result will be written on success. + * The contents of profile are undefined if this function returns + * an error. + * + * @return 0 on success (non-negative), a negative AVERROR on failure. + */ +int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); + +#if FF_API_CAP_VDPAU +/** @brief The videoSurface is used for rendering. */ +#define FF_VDPAU_STATE_USED_FOR_RENDER 1 + +/** + * @brief The videoSurface is needed for reference/prediction. + * The codec manipulates this. + */ +#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 + +/** + * @brief This structure is used as a callback between the FFmpeg + * decoder (vd_) and presentation (vo_) module. + * This is used for defining a video frame containing surface, + * picture parameter, bitstream information etc which are passed + * between the FFmpeg decoder and its clients. + */ +struct vdpau_render_state { + VdpVideoSurface surface; ///< Used as rendered surface, never changed. + + int state; ///< Holds FF_VDPAU_STATE_* values. + +#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI + /** picture parameter information for all supported codecs */ + union AVVDPAUPictureInfo info; +#endif + + /** Describe size/location of the compressed video data. + Set to 0 when freeing bitstream_buffers. */ + int bitstream_buffers_allocated; + int bitstream_buffers_used; + /** The user is responsible for freeing this buffer using av_freep(). */ + VdpBitstreamBuffer *bitstream_buffers; + +#if !AV_HAVE_INCOMPATIBLE_LIBAV_ABI + /** picture parameter information for all supported codecs */ + union AVVDPAUPictureInfo info; +#endif +}; +#endif + +/* @}*/ + +#endif /* AVCODEC_VDPAU_H */ +/* + * The Video Decode and Presentation API for UNIX (VDPAU) is used for + * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. + * + * Copyright (C) 2008 NVIDIA + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDPAU_H +#define AVCODEC_VDPAU_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vdpau + * Public libavcodec VDPAU header. + */ + + +/** + * @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer + * @ingroup lavc_codec_hwaccel + * + * VDPAU hardware acceleration has two modules + * - VDPAU decoding + * - VDPAU presentation + * + * The VDPAU decoding module parses all headers using FFmpeg + * parsing mechanisms and uses VDPAU for the actual decoding. + * + * As per the current implementation, the actual decoding + * and rendering (API calls) are done as part of the VDPAU + * presentation (vo_vdpau.c) module. + * + * @{ + */ + +#include +#include +#include "libavutil/avconfig.h" +#include "libavutil/attributes.h" + +#include "avcodec.h" +#include "version.h" + +#if FF_API_BUFS_VDPAU +union AVVDPAUPictureInfo { + VdpPictureInfoH264 h264; + VdpPictureInfoMPEG1Or2 mpeg; + VdpPictureInfoVC1 vc1; + VdpPictureInfoMPEG4Part2 mpeg4; +}; +#endif + +struct AVCodecContext; +struct AVFrame; + +typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *, + const VdpPictureInfo *, uint32_t, + const VdpBitstreamBuffer *); + +/** + * This structure is used to share data between the libavcodec library and + * the client video application. + * The user shall allocate the structure via the av_alloc_vdpau_hwaccel + * function and make it available as + * AVCodecContext.hwaccel_context. Members can be set by the user once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * The size of this structure is not a part of the public ABI and must not + * be used outside of libavcodec. Use av_vdpau_alloc_context() to allocate an + * AVVDPAUContext. + */ +typedef struct AVVDPAUContext { + /** + * VDPAU decoder handle + * + * Set by user. + */ + VdpDecoder decoder; + + /** + * VDPAU decoder render callback + * + * Set by the user. + */ + VdpDecoderRender *render; + +#if FF_API_BUFS_VDPAU + /** + * VDPAU picture information + * + * Set by libavcodec. + */ + attribute_deprecated + union AVVDPAUPictureInfo info; + + /** + * Allocated size of the bitstream_buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_allocated; + + /** + * Useful bitstream buffers in the bitstream buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_used; + + /** + * Table of bitstream buffers. + * The user is responsible for freeing this buffer using av_freep(). + * + * Set by libavcodec. + */ + attribute_deprecated + VdpBitstreamBuffer *bitstream_buffers; +#endif + AVVDPAU_Render2 render2; +} AVVDPAUContext; + +/** + * @brief allocation function for AVVDPAUContext + * + * Allows extending the struct without breaking API/ABI + */ +AVVDPAUContext *av_alloc_vdpaucontext(void); + +AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); +void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); + +/** + * Allocate an AVVDPAUContext. + * + * @return Newly-allocated AVVDPAUContext or NULL on failure. + */ +AVVDPAUContext *av_vdpau_alloc_context(void); + +/** + * Get a decoder profile that should be used for initializing a VDPAU decoder. + * Should be called from the AVCodecContext.get_format() callback. + * + * @param avctx the codec context being used for decoding the stream + * @param profile a pointer into which the result will be written on success. + * The contents of profile are undefined if this function returns + * an error. + * + * @return 0 on success (non-negative), a negative AVERROR on failure. + */ +int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); + +#if FF_API_CAP_VDPAU +/** @brief The videoSurface is used for rendering. */ +#define FF_VDPAU_STATE_USED_FOR_RENDER 1 + +/** + * @brief The videoSurface is needed for reference/prediction. + * The codec manipulates this. + */ +#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 + +/** + * @brief This structure is used as a callback between the FFmpeg + * decoder (vd_) and presentation (vo_) module. + * This is used for defining a video frame containing surface, + * picture parameter, bitstream information etc which are passed + * between the FFmpeg decoder and its clients. + */ +struct vdpau_render_state { + VdpVideoSurface surface; ///< Used as rendered surface, never changed. + + int state; ///< Holds FF_VDPAU_STATE_* values. + +#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI + /** picture parameter information for all supported codecs */ + union AVVDPAUPictureInfo info; +#endif + + /** Describe size/location of the compressed video data. + Set to 0 when freeing bitstream_buffers. */ + int bitstream_buffers_allocated; + int bitstream_buffers_used; + /** The user is responsible for freeing this buffer using av_freep(). */ + VdpBitstreamBuffer *bitstream_buffers; + +#if !AV_HAVE_INCOMPATIBLE_LIBAV_ABI + /** picture parameter information for all supported codecs */ + union AVVDPAUPictureInfo info; +#endif +}; +#endif + +/* @}*/ + +#endif /* AVCODEC_VDPAU_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/version.h b/extra_lib/include/ffmpeg_android/libavcodec/version.h new file mode 100644 index 0000000..ced479b --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/version.h @@ -0,0 +1,364 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#define LIBAVCODEC_VERSION_MAJOR 56 +#define LIBAVCODEC_VERSION_MINOR 1 +#define LIBAVCODEC_VERSION_MICRO 100 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_REQUEST_CHANNELS +#define FF_API_REQUEST_CHANNELS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_DECODE_AUDIO +#define FF_API_OLD_DECODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_ENCODE_AUDIO +#define FF_API_OLD_ENCODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_ENCODE_VIDEO +#define FF_API_OLD_ENCODE_VIDEO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_ID +#define FF_API_CODEC_ID (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AUDIO_CONVERT +#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AVCODEC_RESAMPLE +#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT +#endif +#ifndef FF_API_DEINTERLACE +#define FF_API_DEINTERLACE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DESTRUCT_PACKET +#define FF_API_DESTRUCT_PACKET (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_GET_BUFFER +#define FF_API_GET_BUFFER (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MISSING_SAMPLE +#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LOWRES +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CAP_VDPAU +#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_BUFS_VDPAU +#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_VOXWARE +#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_SET_DIMENSIONS +#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DEBUG_MV +#define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AC_VLC +#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_MSMPEG4 +#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ASPECT_EXTENDED +#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_THREAD_OPAQUE +#define FF_API_THREAD_OPAQUE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_PKT +#define FF_API_CODEC_PKT (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_ALPHA +#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ERROR_RATE +#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_QSCALE_TYPE +#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MB_TYPE +#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MAX_BFRAMES +#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_FAST_MALLOC +#define FF_API_FAST_MALLOC (LIBAVCODEC_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_NEG_LINESIZES +#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_EMU_EDGE +#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DSPUTIL +#define FF_API_DSPUTIL (LIBAVCODEC_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_ARCH_SH4 +#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_SPARC +#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_UNUSED_MEMBERS +#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_IDCT_XVIDMMX +#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_INPUT_PRESERVED +#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_NORMALIZE_AQP +#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_GMC +#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MV0 +#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_NAME +#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AFD +#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_VISMV +/* XXX: don't forget to drop the -vismv documentation */ +#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif + +#endif /* AVCODEC_VERSION_H */ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#define LIBAVCODEC_VERSION_MAJOR 56 +#define LIBAVCODEC_VERSION_MINOR 1 +#define LIBAVCODEC_VERSION_MICRO 100 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_REQUEST_CHANNELS +#define FF_API_REQUEST_CHANNELS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_DECODE_AUDIO +#define FF_API_OLD_DECODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_ENCODE_AUDIO +#define FF_API_OLD_ENCODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_ENCODE_VIDEO +#define FF_API_OLD_ENCODE_VIDEO (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_ID +#define FF_API_CODEC_ID (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AUDIO_CONVERT +#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AVCODEC_RESAMPLE +#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT +#endif +#ifndef FF_API_DEINTERLACE +#define FF_API_DEINTERLACE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DESTRUCT_PACKET +#define FF_API_DESTRUCT_PACKET (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_GET_BUFFER +#define FF_API_GET_BUFFER (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MISSING_SAMPLE +#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LOWRES +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CAP_VDPAU +#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_BUFS_VDPAU +#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_VOXWARE +#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_SET_DIMENSIONS +#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DEBUG_MV +#define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AC_VLC +#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_OLD_MSMPEG4 +#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ASPECT_EXTENDED +#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_THREAD_OPAQUE +#define FF_API_THREAD_OPAQUE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_PKT +#define FF_API_CODEC_PKT (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_ALPHA +#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ERROR_RATE +#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_QSCALE_TYPE +#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MB_TYPE +#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MAX_BFRAMES +#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_FAST_MALLOC +#define FF_API_FAST_MALLOC (LIBAVCODEC_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_NEG_LINESIZES +#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_EMU_EDGE +#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_DSPUTIL +#define FF_API_DSPUTIL (LIBAVCODEC_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_ARCH_SH4 +#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ARCH_SPARC +#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_UNUSED_MEMBERS +#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_IDCT_XVIDMMX +#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_INPUT_PRESERVED +#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_NORMALIZE_AQP +#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_GMC +#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_MV0 +#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CODEC_NAME +#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_AFD +#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_VISMV +/* XXX: don't forget to drop the -vismv documentation */ +#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 57) +#endif + +#endif /* AVCODEC_VERSION_H */ diff --git a/extra_lib/include/ffmpeg_android/libavcodec/xvmc.h b/extra_lib/include/ffmpeg_android/libavcodec/xvmc.h new file mode 100644 index 0000000..4ce5c6e --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavcodec/xvmc.h @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2003 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XVMC_H +#define AVCODEC_XVMC_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_xvmc + * Public libavcodec XvMC header. + */ + +#include + +#include "libavutil/attributes.h" +#include "version.h" +#include "avcodec.h" + +/** + * @defgroup lavc_codec_hwaccel_xvmc XvMC + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define AV_XVMC_ID 0x1DC711C0 /**< special value to ensure that regular pixel routines haven't corrupted the struct + the number is 1337 speak for the letters IDCT MCo (motion compensation) */ + +attribute_deprecated struct xvmc_pix_fmt { + /** The field contains the special constant value AV_XVMC_ID. + It is used as a test that the application correctly uses the API, + and that there is no corruption caused by pixel routines. + - application - set during initialization + - libavcodec - unchanged + */ + int xvmc_id; + + /** Pointer to the block array allocated by XvMCCreateBlocks(). + The array has to be freed by XvMCDestroyBlocks(). + Each group of 64 values represents one data block of differential + pixel information (in MoCo mode) or coefficients for IDCT. + - application - set the pointer during initialization + - libavcodec - fills coefficients/pixel data into the array + */ + short* data_blocks; + + /** Pointer to the macroblock description array allocated by + XvMCCreateMacroBlocks() and freed by XvMCDestroyMacroBlocks(). + - application - set the pointer during initialization + - libavcodec - fills description data into the array + */ + XvMCMacroBlock* mv_blocks; + + /** Number of macroblock descriptions that can be stored in the mv_blocks + array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_mv_blocks; + + /** Number of blocks that can be stored at once in the data_blocks array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_data_blocks; + + /** Indicate that the hardware would interpret data_blocks as IDCT + coefficients and perform IDCT on them. + - application - set during initialization + - libavcodec - unchanged + */ + int idct; + + /** In MoCo mode it indicates that intra macroblocks are assumed to be in + unsigned format; same as the XVMC_INTRA_UNSIGNED flag. + - application - set during initialization + - libavcodec - unchanged + */ + int unsigned_intra; + + /** Pointer to the surface allocated by XvMCCreateSurface(). + It has to be freed by XvMCDestroySurface() on application exit. + It identifies the frame and its state on the video hardware. + - application - set during initialization + - libavcodec - unchanged + */ + XvMCSurface* p_surface; + +/** Set by the decoder before calling ff_draw_horiz_band(), + needed by the XvMCRenderSurface function. */ +//@{ + /** Pointer to the surface used as past reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_past_surface; + + /** Pointer to the surface used as future reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_future_surface; + + /** top/bottom field or frame + - application - unchanged + - libavcodec - set + */ + unsigned int picture_structure; + + /** XVMC_SECOND_FIELD - 1st or 2nd field in the sequence + - application - unchanged + - libavcodec - set + */ + unsigned int flags; +//}@ + + /** Number of macroblock descriptions in the mv_blocks array + that have already been passed to the hardware. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may increment it + with filled_mb_block_num or zero both. + - libavcodec - unchanged + */ + int start_mv_blocks_num; + + /** Number of new macroblock descriptions in the mv_blocks array (after + start_mv_blocks_num) that are filled by libavcodec and have to be + passed to the hardware. + - application - zeroes it on get_buffer() or after successful + ff_draw_horiz_band(). + - libavcodec - increment with one of each stored MB + */ + int filled_mv_blocks_num; + + /** Number of the next free data block; one data block consists of + 64 short values in the data_blocks array. + All blocks before this one have already been claimed by placing their + position into the corresponding block description structure field, + that are part of the mv_blocks array. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may zero it together + with start_mb_blocks_num. + - libavcodec - each decoded macroblock increases it by the number + of coded blocks it contains. + */ + int next_free_data_block_num; +}; + +/** + * @} + */ + +#endif /* AVCODEC_XVMC_H */ +/* + * Copyright (C) 2003 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XVMC_H +#define AVCODEC_XVMC_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_xvmc + * Public libavcodec XvMC header. + */ + +#include + +#include "libavutil/attributes.h" +#include "version.h" +#include "avcodec.h" + +/** + * @defgroup lavc_codec_hwaccel_xvmc XvMC + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define AV_XVMC_ID 0x1DC711C0 /**< special value to ensure that regular pixel routines haven't corrupted the struct + the number is 1337 speak for the letters IDCT MCo (motion compensation) */ + +attribute_deprecated struct xvmc_pix_fmt { + /** The field contains the special constant value AV_XVMC_ID. + It is used as a test that the application correctly uses the API, + and that there is no corruption caused by pixel routines. + - application - set during initialization + - libavcodec - unchanged + */ + int xvmc_id; + + /** Pointer to the block array allocated by XvMCCreateBlocks(). + The array has to be freed by XvMCDestroyBlocks(). + Each group of 64 values represents one data block of differential + pixel information (in MoCo mode) or coefficients for IDCT. + - application - set the pointer during initialization + - libavcodec - fills coefficients/pixel data into the array + */ + short* data_blocks; + + /** Pointer to the macroblock description array allocated by + XvMCCreateMacroBlocks() and freed by XvMCDestroyMacroBlocks(). + - application - set the pointer during initialization + - libavcodec - fills description data into the array + */ + XvMCMacroBlock* mv_blocks; + + /** Number of macroblock descriptions that can be stored in the mv_blocks + array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_mv_blocks; + + /** Number of blocks that can be stored at once in the data_blocks array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_data_blocks; + + /** Indicate that the hardware would interpret data_blocks as IDCT + coefficients and perform IDCT on them. + - application - set during initialization + - libavcodec - unchanged + */ + int idct; + + /** In MoCo mode it indicates that intra macroblocks are assumed to be in + unsigned format; same as the XVMC_INTRA_UNSIGNED flag. + - application - set during initialization + - libavcodec - unchanged + */ + int unsigned_intra; + + /** Pointer to the surface allocated by XvMCCreateSurface(). + It has to be freed by XvMCDestroySurface() on application exit. + It identifies the frame and its state on the video hardware. + - application - set during initialization + - libavcodec - unchanged + */ + XvMCSurface* p_surface; + +/** Set by the decoder before calling ff_draw_horiz_band(), + needed by the XvMCRenderSurface function. */ +//@{ + /** Pointer to the surface used as past reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_past_surface; + + /** Pointer to the surface used as future reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_future_surface; + + /** top/bottom field or frame + - application - unchanged + - libavcodec - set + */ + unsigned int picture_structure; + + /** XVMC_SECOND_FIELD - 1st or 2nd field in the sequence + - application - unchanged + - libavcodec - set + */ + unsigned int flags; +//}@ + + /** Number of macroblock descriptions in the mv_blocks array + that have already been passed to the hardware. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may increment it + with filled_mb_block_num or zero both. + - libavcodec - unchanged + */ + int start_mv_blocks_num; + + /** Number of new macroblock descriptions in the mv_blocks array (after + start_mv_blocks_num) that are filled by libavcodec and have to be + passed to the hardware. + - application - zeroes it on get_buffer() or after successful + ff_draw_horiz_band(). + - libavcodec - increment with one of each stored MB + */ + int filled_mv_blocks_num; + + /** Number of the next free data block; one data block consists of + 64 short values in the data_blocks array. + All blocks before this one have already been claimed by placing their + position into the corresponding block description structure field, + that are part of the mv_blocks array. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may zero it together + with start_mb_blocks_num. + - libavcodec - each decoded macroblock increases it by the number + of coded blocks it contains. + */ + int next_free_data_block_num; +}; + +/** + * @} + */ + +#endif /* AVCODEC_XVMC_H */ diff --git a/extra_lib/include/ffmpeg_android/libavformat/avformat.h b/extra_lib/include/ffmpeg_android/libavformat/avformat.h index 5ff08c0..b915148 100644 --- a/extra_lib/include/ffmpeg_android/libavformat/avformat.h +++ b/extra_lib/include/ffmpeg_android/libavformat/avformat.h @@ -21,172 +21,359 @@ #ifndef AVFORMAT_AVFORMAT_H #define AVFORMAT_AVFORMAT_H -#define LIBAVFORMAT_VERSION_MAJOR 52 -#define LIBAVFORMAT_VERSION_MINOR 61 -#define LIBAVFORMAT_VERSION_MICRO 0 - -#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ - LIBAVFORMAT_VERSION_MINOR, \ - LIBAVFORMAT_VERSION_MICRO) -#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ - LIBAVFORMAT_VERSION_MINOR, \ - LIBAVFORMAT_VERSION_MICRO) -#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT - -#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) - -/** - * I return the LIBAVFORMAT_VERSION_INT constant. You got - * a fucking problem with that, douchebag? - */ -unsigned avformat_version(void); - /** - * Returns the libavformat build-time configuration. + * @file + * @ingroup libavf + * Main libavformat public API header */ -const char *avformat_configuration(void); /** - * Returns the libavformat license. + * @defgroup libavf I/O and Muxing/Demuxing Library + * @{ + * + * Libavformat (lavf) is a library for dealing with various media container + * formats. Its main two purposes are demuxing - i.e. splitting a media file + * into component streams, and the reverse process of muxing - writing supplied + * data in a specified container format. It also has an @ref lavf_io + * "I/O module" which supports a number of protocols for accessing the data (e.g. + * file, tcp, http and others). Before using lavf, you need to call + * av_register_all() to register all compiled muxers, demuxers and protocols. + * Unless you are absolutely sure you won't use libavformat's network + * capabilities, you should also call avformat_network_init(). + * + * A supported input format is described by an AVInputFormat struct, conversely + * an output format is described by AVOutputFormat. You can iterate over all + * registered input/output formats using the av_iformat_next() / + * av_oformat_next() functions. The protocols layer is not part of the public + * API, so you can only get the names of supported protocols with the + * avio_enum_protocols() function. + * + * Main lavf structure used for both muxing and demuxing is AVFormatContext, + * which exports all information about the file being read or written. As with + * most Libavformat structures, its size is not part of public ABI, so it cannot be + * allocated on stack or directly with av_malloc(). To create an + * AVFormatContext, use avformat_alloc_context() (some functions, like + * avformat_open_input() might do that for you). + * + * Most importantly an AVFormatContext contains: + * @li the @ref AVFormatContext.iformat "input" or @ref AVFormatContext.oformat + * "output" format. It is either autodetected or set by user for input; + * always set by user for output. + * @li an @ref AVFormatContext.streams "array" of AVStreams, which describe all + * elementary streams stored in the file. AVStreams are typically referred to + * using their index in this array. + * @li an @ref AVFormatContext.pb "I/O context". It is either opened by lavf or + * set by user for input, always set by user for output (unless you are dealing + * with an AVFMT_NOFILE format). + * + * @section lavf_options Passing options to (de)muxers + * Lavf allows to configure muxers and demuxers using the @ref avoptions + * mechanism. Generic (format-independent) libavformat options are provided by + * AVFormatContext, they can be examined from a user program by calling + * av_opt_next() / av_opt_find() on an allocated AVFormatContext (or its AVClass + * from avformat_get_class()). Private (format-specific) options are provided by + * AVFormatContext.priv_data if and only if AVInputFormat.priv_class / + * AVOutputFormat.priv_class of the corresponding format struct is non-NULL. + * Further options may be provided by the @ref AVFormatContext.pb "I/O context", + * if its AVClass is non-NULL, and the protocols layer. See the discussion on + * nesting in @ref avoptions documentation to learn how to access those. + * + * @defgroup lavf_decoding Demuxing + * @{ + * Demuxers read a media file and split it into chunks of data (@em packets). A + * @ref AVPacket "packet" contains one or more encoded frames which belongs to a + * single elementary stream. In the lavf API this process is represented by the + * avformat_open_input() function for opening a file, av_read_frame() for + * reading a single packet and finally avformat_close_input(), which does the + * cleanup. + * + * @section lavf_decoding_open Opening a media file + * The minimum information required to open a file is its URL or filename, which + * is passed to avformat_open_input(), as in the following code: + * @code + * const char *url = "in.mp3"; + * AVFormatContext *s = NULL; + * int ret = avformat_open_input(&s, url, NULL, NULL); + * if (ret < 0) + * abort(); + * @endcode + * The above code attempts to allocate an AVFormatContext, open the + * specified file (autodetecting the format) and read the header, exporting the + * information stored there into s. Some formats do not have a header or do not + * store enough information there, so it is recommended that you call the + * avformat_find_stream_info() function which tries to read and decode a few + * frames to find missing information. + * + * In some cases you might want to preallocate an AVFormatContext yourself with + * avformat_alloc_context() and do some tweaking on it before passing it to + * avformat_open_input(). One such case is when you want to use custom functions + * for reading input data instead of lavf internal I/O layer. + * To do that, create your own AVIOContext with avio_alloc_context(), passing + * your reading callbacks to it. Then set the @em pb field of your + * AVFormatContext to newly created AVIOContext. + * + * Since the format of the opened file is in general not known until after + * avformat_open_input() has returned, it is not possible to set demuxer private + * options on a preallocated context. Instead, the options should be passed to + * avformat_open_input() wrapped in an AVDictionary: + * @code + * AVDictionary *options = NULL; + * av_dict_set(&options, "video_size", "640x480", 0); + * av_dict_set(&options, "pixel_format", "rgb24", 0); + * + * if (avformat_open_input(&s, url, NULL, &options) < 0) + * abort(); + * av_dict_free(&options); + * @endcode + * This code passes the private options 'video_size' and 'pixel_format' to the + * demuxer. They would be necessary for e.g. the rawvideo demuxer, since it + * cannot know how to interpret raw video data otherwise. If the format turns + * out to be something different than raw video, those options will not be + * recognized by the demuxer and therefore will not be applied. Such unrecognized + * options are then returned in the options dictionary (recognized options are + * consumed). The calling program can handle such unrecognized options as it + * wishes, e.g. + * @code + * AVDictionaryEntry *e; + * if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + * fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key); + * abort(); + * } + * @endcode + * + * After you have finished reading the file, you must close it with + * avformat_close_input(). It will free everything associated with the file. + * + * @section lavf_decoding_read Reading from an opened file + * Reading data from an opened AVFormatContext is done by repeatedly calling + * av_read_frame() on it. Each call, if successful, will return an AVPacket + * containing encoded data for one AVStream, identified by + * AVPacket.stream_index. This packet may be passed straight into the libavcodec + * decoding functions avcodec_decode_video2(), avcodec_decode_audio4() or + * avcodec_decode_subtitle2() if the caller wishes to decode the data. + * + * AVPacket.pts, AVPacket.dts and AVPacket.duration timing information will be + * set if known. They may also be unset (i.e. AV_NOPTS_VALUE for + * pts/dts, 0 for duration) if the stream does not provide them. The timing + * information will be in AVStream.time_base units, i.e. it has to be + * multiplied by the timebase to convert them to seconds. + * + * If AVPacket.buf is set on the returned packet, then the packet is + * allocated dynamically and the user may keep it indefinitely. + * Otherwise, if AVPacket.buf is NULL, the packet data is backed by a + * static storage somewhere inside the demuxer and the packet is only valid + * until the next av_read_frame() call or closing the file. If the caller + * requires a longer lifetime, av_dup_packet() will make an av_malloc()ed copy + * of it. + * In both cases, the packet must be freed with av_free_packet() when it is no + * longer needed. + * + * @section lavf_decoding_seek Seeking + * @} + * + * @defgroup lavf_encoding Muxing + * @{ + * Muxers take encoded data in the form of @ref AVPacket "AVPackets" and write + * it into files or other output bytestreams in the specified container format. + * + * The main API functions for muxing are avformat_write_header() for writing the + * file header, av_write_frame() / av_interleaved_write_frame() for writing the + * packets and av_write_trailer() for finalizing the file. + * + * At the beginning of the muxing process, the caller must first call + * avformat_alloc_context() to create a muxing context. The caller then sets up + * the muxer by filling the various fields in this context: + * + * - The @ref AVFormatContext.oformat "oformat" field must be set to select the + * muxer that will be used. + * - Unless the format is of the AVFMT_NOFILE type, the @ref AVFormatContext.pb + * "pb" field must be set to an opened IO context, either returned from + * avio_open2() or a custom one. + * - Unless the format is of the AVFMT_NOSTREAMS type, at least one stream must + * be created with the avformat_new_stream() function. The caller should fill + * the @ref AVStream.codec "stream codec context" information, such as the + * codec @ref AVCodecContext.codec_type "type", @ref AVCodecContext.codec_id + * "id" and other parameters (e.g. width / height, the pixel or sample format, + * etc.) as known. The @ref AVStream.time_base "stream timebase" should + * be set to the timebase that the caller desires to use for this stream (note + * that the timebase actually used by the muxer can be different, as will be + * described later). + * - The caller may fill in additional information, such as @ref + * AVFormatContext.metadata "global" or @ref AVStream.metadata "per-stream" + * metadata, @ref AVFormatContext.chapters "chapters", @ref + * AVFormatContext.programs "programs", etc. as described in the + * AVFormatContext documentation. Whether such information will actually be + * stored in the output depends on what the container format and the muxer + * support. + * + * When the muxing context is fully set up, the caller must call + * avformat_write_header() to initialize the muxer internals and write the file + * header. Whether anything actually is written to the IO context at this step + * depends on the muxer, but this function must always be called. Any muxer + * private options must be passed in the options parameter to this function. + * + * The data is then sent to the muxer by repeatedly calling av_write_frame() or + * av_interleaved_write_frame() (consult those functions' documentation for + * discussion on the difference between them; only one of them may be used with + * a single muxing context, they should not be mixed). Do note that the timing + * information on the packets sent to the muxer must be in the corresponding + * AVStream's timebase. That timebase is set by the muxer (in the + * avformat_write_header() step) and may be different from the timebase + * requested by the caller. + * + * Once all the data has been written, the caller must call av_write_trailer() + * to flush any buffered packets and finalize the output file, then close the IO + * context (if any) and finally free the muxing context with + * avformat_free_context(). + * @} + * + * @defgroup lavf_io I/O Read/Write + * @{ + * @} + * + * @defgroup lavf_codec Demuxers + * @{ + * @defgroup lavf_codec_native Native Demuxers + * @{ + * @} + * @defgroup lavf_codec_wrappers External library wrappers + * @{ + * @} + * @} + * @defgroup lavf_protos I/O Protocols + * @{ + * @} + * @defgroup lavf_internal Internal + * @{ + * @} + * @} + * */ -const char *avformat_license(void); #include #include /* FILE */ #include "libavcodec/avcodec.h" +#include "libavutil/dict.h" +#include "libavutil/log.h" #include "avio.h" +#include "libavformat/version.h" struct AVFormatContext; +struct AVDeviceInfoList; +struct AVDeviceCapabilitiesQuery; -/* - * Public Metadata API. +/** + * @defgroup metadata_api Public Metadata API + * @{ + * @ingroup libavf * The metadata API allows libavformat to export metadata tags to a client - * application using a sequence of key/value pairs. Like all strings in FFmpeg, - * metadata must be stored as UTF-8 encoded Unicode. Note that metadata + * application when demuxing. Conversely it allows a client application to + * set metadata when muxing. + * + * Metadata is exported or set as pairs of key/value strings in the 'metadata' + * fields of the AVFormatContext, AVStream, AVChapter and AVProgram structs + * using the @ref lavu_dict "AVDictionary" API. Like all strings in FFmpeg, + * metadata is assumed to be UTF-8 encoded Unicode. Note that metadata * exported by demuxers isn't checked to be valid UTF-8 in most cases. + * * Important concepts to keep in mind: - * 1. Keys are unique; there can never be 2 tags with the same key. This is + * - Keys are unique; there can never be 2 tags with the same key. This is * also meant semantically, i.e., a demuxer should not knowingly produce * several keys that are literally different but semantically identical. * E.g., key=Author5, key=Author6. In this example, all authors must be * placed in the same tag. - * 2. Metadata is flat, not hierarchical; there are no subtags. If you + * - Metadata is flat, not hierarchical; there are no subtags. If you * want to store, e.g., the email address of the child of producer Alice * and actor Bob, that could have key=alice_and_bobs_childs_email_address. - * 3. Several modifiers can be applied to the tag name. This is done by + * - Several modifiers can be applied to the tag name. This is done by * appending a dash character ('-') and the modifier name in the order * they appear in the list below -- e.g. foo-eng-sort, not foo-sort-eng. - * a) language -- a tag whose value is localized for a particular language + * - language -- a tag whose value is localized for a particular language * is appended with the ISO 639-2/B 3-letter language code. * For example: Author-ger=Michael, Author-eng=Mike * The original/default language is in the unqualified "Author" tag. * A demuxer should set a default if it sets any translated tag. - * b) sorting -- a modified version of a tag that should be used for + * - sorting -- a modified version of a tag that should be used for * sorting will have '-sort' appended. E.g. artist="The Beatles", * artist-sort="Beatles, The". + * - Some protocols and demuxers support metadata updates. After a successful + * call to av_read_packet(), AVFormatContext.event_flags or AVStream.event_flags + * will be updated to indicate if metadata changed. In order to detect metadata + * changes on a stream, you need to loop through all streams in the AVFormatContext + * and check their individual event_flags. * - * 4. Tag names are normally exported exactly as stored in the container to - * allow lossless remuxing to the same format. For container-independent - * handling of metadata, av_metadata_conv() can convert it to ffmpeg generic - * format. Follows a list of generic tag names: - * - * album -- name of the set this work belongs to - * album_artist -- main creator of the set/album, if different from artist. - * e.g. "Various Artists" for compilation albums. - * artist -- main creator of the work - * comment -- any additional description of the file. - * composer -- who composed the work, if different from artist. - * copyright -- name of copyright holder. - * date -- date when the work was created, preferably in ISO 8601. - * disc -- number of a subset, e.g. disc in a multi-disc collection. - * encoder -- name/settings of the software/hardware that produced the file. - * encoded_by -- person/group who created the file. - * filename -- original name of the file. - * genre -- . - * language -- main language in which the work is performed, preferably - * in ISO 639-2 format. - * performer -- artist who performed the work, if different from artist. - * E.g for "Also sprach Zarathustra", artist would be "Richard - * Strauss" and performer "London Philharmonic Orchestra". - * publisher -- name of the label/publisher. - * title -- name of the work. - * track -- number of this work in the set, can be in form current/total. - */ - -#define AV_METADATA_MATCH_CASE 1 -#define AV_METADATA_IGNORE_SUFFIX 2 -#define AV_METADATA_DONT_STRDUP_KEY 4 -#define AV_METADATA_DONT_STRDUP_VAL 8 -#define AV_METADATA_DONT_OVERWRITE 16 ///< Don't overwrite existing tags. - -typedef struct { - char *key; - char *value; -}AVMetadataTag; - -typedef struct AVMetadata AVMetadata; -typedef struct AVMetadataConv AVMetadataConv; - -/** - * Gets a metadata element with matching key. - * @param prev Set to the previous matching element to find the next. - * If set to NULL the first matching element is returned. - * @param flags Allows case as well as suffix-insensitive comparisons. - * @return Found tag or NULL, changing key or value leads to undefined behavior. - */ -AVMetadataTag * -av_metadata_get(AVMetadata *m, const char *key, const AVMetadataTag *prev, int flags); - -#if LIBAVFORMAT_VERSION_MAJOR == 52 -/** - * Sets the given tag in m, overwriting an existing tag. - * @param key tag key to add to m (will be av_strduped) - * @param value tag value to add to m (will be av_strduped) - * @return >= 0 on success otherwise an error code <0 - */ -int av_metadata_set(AVMetadata **pm, const char *key, const char *value); -#endif - -/** - * Sets the given tag in m, overwriting an existing tag. - * @param key tag key to add to m (will be av_strduped depending on flags) - * @param value tag value to add to m (will be av_strduped depending on flags) - * @return >= 0 on success otherwise an error code <0 - */ -int av_metadata_set2(AVMetadata **pm, const char *key, const char *value, int flags); - -/** - * Converts all the metadata sets from ctx according to the source and - * destination conversion tables. If one of the tables is NULL, then - * tags are converted to/from ffmpeg generic tag names. - * @param d_conv destination tags format conversion table - * @param s_conv source tags format conversion table - */ -void av_metadata_conv(struct AVFormatContext *ctx,const AVMetadataConv *d_conv, - const AVMetadataConv *s_conv); - -/** - * Frees all the memory allocated for an AVMetadata struct. + * - Demuxers attempt to export metadata in a generic format, however tags + * with no generic equivalents are left as they are stored in the container. + * Follows a list of generic tag names: + * + @verbatim + album -- name of the set this work belongs to + album_artist -- main creator of the set/album, if different from artist. + e.g. "Various Artists" for compilation albums. + artist -- main creator of the work + comment -- any additional description of the file. + composer -- who composed the work, if different from artist. + copyright -- name of copyright holder. + creation_time-- date when the file was created, preferably in ISO 8601. + date -- date when the work was created, preferably in ISO 8601. + disc -- number of a subset, e.g. disc in a multi-disc collection. + encoder -- name/settings of the software/hardware that produced the file. + encoded_by -- person/group who created the file. + filename -- original name of the file. + genre -- . + language -- main language in which the work is performed, preferably + in ISO 639-2 format. Multiple languages can be specified by + separating them with commas. + performer -- artist who performed the work, if different from artist. + E.g for "Also sprach Zarathustra", artist would be "Richard + Strauss" and performer "London Philharmonic Orchestra". + publisher -- name of the label/publisher. + service_name -- name of the service in broadcasting (channel name). + service_provider -- name of the service provider in broadcasting. + title -- name of the work. + track -- number of this work in the set, can be in form current/total. + variant_bitrate -- the total bitrate of the bitrate variant that the current stream is part of + @endverbatim + * + * Look in the examples section for an application example how to use the Metadata API. + * + * @} */ -void av_metadata_free(AVMetadata **m); - /* packet functions */ /** - * Allocates and reads the payload of a packet and initializes its + * Allocate and read the payload of a packet and initialize its * fields with default values. * + * @param s associated IO context * @param pkt packet * @param size desired payload size * @return >0 (read size) if OK, AVERROR_xxx otherwise */ -int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size); +int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); + +/** + * Read data and append it to the current content of the AVPacket. + * If pkt->size is 0 this is identical to av_get_packet. + * Note that this uses av_grow_packet and thus involves a realloc + * which is inefficient. Thus this function should only be used + * when there is no reasonable way to know (an upper bound of) + * the final size. + * + * @param s associated IO context + * @param pkt packet + * @param size amount of data to read + * @return >0 (read size) if OK, AVERROR_xxx otherwise, previous data + * will not be lost even if an error occurs. + */ +int av_append_packet(AVIOContext *s, AVPacket *pkt, int size); +#if FF_API_LAVF_FRAC /*************************************************/ /* fractional numbers for exact pts handling */ @@ -197,45 +384,33 @@ int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size); typedef struct AVFrac { int64_t val, num, den; } AVFrac; +#endif /*************************************************/ /* input/output formats */ struct AVCodecTag; -/** This structure contains the data a format has to probe a file. */ +/** + * This structure contains the data a format has to probe a file. + */ typedef struct AVProbeData { const char *filename; unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */ int buf_size; /**< Size of buf except extra allocated bytes */ + uint8_t *mime_type; /**< mime_type, when known. */ } AVProbeData; -#define AVPROBE_SCORE_MAX 100 ///< maximum score, half of that is used for file-extension-based detection -#define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer +#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4) +#define AVPROBE_SCORE_STREAM_RETRY (AVPROBE_SCORE_MAX/4-1) -typedef struct AVFormatParameters { - AVRational time_base; - int sample_rate; - int channels; - int width; - int height; - enum PixelFormat pix_fmt; - int channel; /**< Used to select DV channel. */ - const char *standard; /**< TV standard, NTSC, PAL, SECAM */ - unsigned int mpeg2ts_raw:1; /**< Force raw MPEG-2 transport stream output, if possible. */ - unsigned int mpeg2ts_compute_pcr:1; /**< Compute exact PCR for each transport - stream packet (only meaningful if - mpeg2ts_raw is TRUE). */ - unsigned int initial_pause:1; /**< Do not begin to play the stream - immediately (RTSP only). */ - unsigned int prealloced_context:1; -#if LIBAVFORMAT_VERSION_INT < (53<<16) - enum CodecID video_codec_id; - enum CodecID audio_codec_id; -#endif -} AVFormatParameters; +#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension +#define AVPROBE_SCORE_MIME 75 ///< score for file mime type +#define AVPROBE_SCORE_MAX 100 ///< maximum score -//! Demuxer will use url_fopen, no opened file should be provided by the caller. +#define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer + +/// Demuxer will use avio_open, no opened file should be provided by the caller. #define AVFMT_NOFILE 0x0001 #define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */ #define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */ @@ -244,10 +419,37 @@ typedef struct AVFormatParameters { #define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ #define AVFMT_NOTIMESTAMPS 0x0080 /**< Format does not need / have any timestamps. */ #define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */ -#define AVFMT_TS_DISCONT 0x0200 /**< Format allows timestamp discontinuities. */ +#define AVFMT_TS_DISCONT 0x0200 /**< Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps */ #define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */ #define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */ +#define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */ +#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fall back on binary search via read_timestamp */ +#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */ +#define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */ +#define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */ +#if LIBAVFORMAT_VERSION_MAJOR <= 54 +#define AVFMT_TS_NONSTRICT 0x8020000 //we try to be compatible to the ABIs of ffmpeg and major forks +#else +#define AVFMT_TS_NONSTRICT 0x20000 +#endif + /**< Format does not require strictly + increasing timestamps, but they must + still be monotonic */ +#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative + timestamps. If not set the timestamp + will be shifted in av_write_frame and + av_interleaved_write_frame so they + start from 0. + The user or muxer can override this through + AVFormatContext.avoid_negative_ts + */ + +#define AVFMT_SEEK_TO_PTS 0x4000000 /**< Seeking is based on PTS */ +/** + * @addtogroup lavf_encoding + * @{ + */ typedef struct AVOutputFormat { const char *name; /** @@ -258,69 +460,195 @@ typedef struct AVOutputFormat { const char *long_name; const char *mime_type; const char *extensions; /**< comma-separated filename extensions */ - /** size of private data so that it can be allocated in the wrapper */ - int priv_data_size; /* output support */ - enum CodecID audio_codec; /**< default audio codec */ - enum CodecID video_codec; /**< default video codec */ - int (*write_header)(struct AVFormatContext *); - int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); - int (*write_trailer)(struct AVFormatContext *); - /** can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER */ + enum AVCodecID audio_codec; /**< default audio codec */ + enum AVCodecID video_codec; /**< default video codec */ + enum AVCodecID subtitle_codec; /**< default subtitle codec */ + /** + * can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_RAWPICTURE, + * AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, + * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, + * AVFMT_TS_NONSTRICT + */ int flags; - /** Currently only used to set pixel format if not YUV420P. */ - int (*set_parameters)(struct AVFormatContext *, AVFormatParameters *); - int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, - AVPacket *in, int flush); /** * List of supported codec_id-codec_tag pairs, ordered by "better - * choice first". The arrays are all terminated by CODEC_ID_NONE. + * choice first". The arrays are all terminated by AV_CODEC_ID_NONE. */ const struct AVCodecTag * const *codec_tag; - enum CodecID subtitle_codec; /**< default subtitle codec */ - const AVMetadataConv *metadata_conv; + const AVClass *priv_class; ///< AVClass for the private context - /* private fields */ + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ struct AVOutputFormat *next; + /** + * size of private data so that it can be allocated in the wrapper + */ + int priv_data_size; + + int (*write_header)(struct AVFormatContext *); + /** + * Write a packet. If AVFMT_ALLOW_FLUSH is set in flags, + * pkt can be NULL in order to flush data buffered in the muxer. + * When flushing, return 0 if there still is more data to flush, + * or 1 if everything was flushed and there is no more buffered + * data. + */ + int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); + int (*write_trailer)(struct AVFormatContext *); + /** + * Currently only used to set pixel format if not YUV420P. + */ + int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, + AVPacket *in, int flush); + /** + * Test if the given codec can be stored in this container. + * + * @return 1 if the codec is supported, 0 if it is not. + * A negative number if unknown. + * MKTAG('A', 'P', 'I', 'C') if the codec is only supported as AV_DISPOSITION_ATTACHED_PIC + */ + int (*query_codec)(enum AVCodecID id, int std_compliance); + + void (*get_output_timestamp)(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + /** + * Allows sending messages from application to device. + */ + int (*control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + + /** + * Write an uncoded AVFrame. + * + * See av_write_uncoded_frame() for details. + * + * The library will free *frame afterwards, but the muxer can prevent it + * by setting the pointer to NULL. + */ + int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index, + AVFrame **frame, unsigned flags); + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVOutputFormat; +/** + * @} + */ +/** + * @addtogroup lavf_decoding + * @{ + */ typedef struct AVInputFormat { + /** + * A comma separated list of short names for the format. New names + * may be appended with a minor bump. + */ const char *name; + /** * Descriptive name for the format, meant to be more human-readable * than name. You should use the NULL_IF_CONFIG_SMALL() macro * to define it. */ const char *long_name; - /** Size of private data so that it can be allocated in the wrapper. */ + + /** + * Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS, + * AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH, + * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS. + */ + int flags; + + /** + * If extensions are defined, then no probe is done. You should + * usually not use extension format guessing because it is not + * reliable enough + */ + const char *extensions; + + const struct AVCodecTag * const *codec_tag; + + const AVClass *priv_class; ///< AVClass for the private context + + /** + * Comma-separated list of mime types. + * It is used check for matching mime types while probing. + * @see av_probe_input_format2 + */ + const char *mime_type; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVInputFormat *next; + + /** + * Raw demuxers store their codec ID here. + */ + int raw_codec_id; + + /** + * Size of private data so that it can be allocated in the wrapper. + */ int priv_data_size; + /** * Tell if a given file has a chance of being parsed as this format. * The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes * big so you do not have to check for that unless you need more. */ int (*read_probe)(AVProbeData *); - /** Read the format header and initialize the AVFormatContext - structure. Return 0 if OK. 'ap' if non-NULL contains - additional parameters. Only used in raw format right - now. 'av_new_stream' should be called to create new streams. */ - int (*read_header)(struct AVFormatContext *, - AVFormatParameters *ap); - /** Read one packet and put it in 'pkt'. pts and flags are also - set. 'av_new_stream' can be called only if the flag - AVFMTCTX_NOHEADER is used. - @return 0 on success, < 0 on error. - When returning an error, pkt must not have been allocated - or must be freed before returning */ + + /** + * Read the format header and initialize the AVFormatContext + * structure. Return 0 if OK. Only used in raw format right + * now. 'avformat_new_stream' should be called to create new streams. + */ + int (*read_header)(struct AVFormatContext *); + + /** + * Read one packet and put it in 'pkt'. pts and flags are also + * set. 'avformat_new_stream' can be called only if the flag + * AVFMTCTX_NOHEADER is used and only in the calling thread (not in a + * background thread). + * @return 0 on success, < 0 on error. + * When returning an error, pkt must not have been allocated + * or must be freed before returning + */ int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); - /** Close the stream. The AVFormatContext and AVStreams are not - freed by this function */ + + /** + * Close the stream. The AVFormatContext and AVStreams are not + * freed by this function + */ int (*read_close)(struct AVFormatContext *); -#if LIBAVFORMAT_VERSION_MAJOR < 53 /** * Seek to a given timestamp relative to the frames in * stream component stream_index. @@ -331,56 +659,75 @@ typedef struct AVInputFormat { */ int (*read_seek)(struct AVFormatContext *, int stream_index, int64_t timestamp, int flags); -#endif + /** - * Gets the next timestamp in stream[stream_index].time_base units. + * Get the next timestamp in stream[stream_index].time_base units. * @return the timestamp or AV_NOPTS_VALUE if an error occurred */ int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, int64_t *pos, int64_t pos_limit); - /** Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER. */ - int flags; - /** If extensions are defined, then no probe is done. You should - usually not use extension format guessing because it is not - reliable enough */ - const char *extensions; - /** General purpose read-only value that the format can use. */ - int value; - /** Starts/resumes playing - only meaningful if using a network-based format - (RTSP). */ + /** + * Start/resume playing - only meaningful if using a network-based format + * (RTSP). + */ int (*read_play)(struct AVFormatContext *); - /** Pauses playing - only meaningful if using a network-based format - (RTSP). */ + /** + * Pause playing - only meaningful if using a network-based format + * (RTSP). + */ int (*read_pause)(struct AVFormatContext *); - const struct AVCodecTag * const *codec_tag; - /** - * Seeks to timestamp ts. + * Seek to timestamp ts. * Seeking will be done so that the point from which all active streams * can be presented successfully will be closest to ts and within min/max_ts. * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. */ int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); - const AVMetadataConv *metadata_conv; + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); - /* private fields */ - struct AVInputFormat *next; + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVInputFormat; +/** + * @} + */ enum AVStreamParseType { AVSTREAM_PARSE_NONE, AVSTREAM_PARSE_FULL, /**< full parsing and repack */ AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */ AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */ + AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */ + AVSTREAM_PARSE_FULL_RAW=MKTAG(0,'R','A','W'), /**< full parsing and repack with timestamp and position generation by parser for raw + this assumes that each packet in the file contains no demuxer level headers and + just codec level data, otherwise position generation would fail */ }; typedef struct AVIndexEntry { int64_t pos; - int64_t timestamp; + int64_t timestamp; /**< + * Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are available + * when seeking to this entry. That means preferable PTS on keyframe based formats. + * But demuxers can choose to store a different timestamp, if it is more convenient for the implementation or nothing better + * is known + */ #define AVINDEX_KEYFRAME 0x0001 int flags:2; int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs. 32 bytes due to possible 8-byte alignment). @@ -394,6 +741,37 @@ typedef struct AVIndexEntry { #define AV_DISPOSITION_LYRICS 0x0010 #define AV_DISPOSITION_KARAOKE 0x0020 +/** + * Track should be used during playback by default. + * Useful for subtitle track that should be displayed + * even when user did not explicitly ask for subtitles. + */ +#define AV_DISPOSITION_FORCED 0x0040 +#define AV_DISPOSITION_HEARING_IMPAIRED 0x0080 /**< stream for hearing impaired audiences */ +#define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */ +#define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */ +/** + * The stream is stored in the file as an attached picture/"cover art" (e.g. + * APIC frame in ID3v2). The single packet associated with it will be returned + * among the first few packets read from the file unless seeking takes place. + * It can also be accessed at any time in AVStream.attached_pic. + */ +#define AV_DISPOSITION_ATTACHED_PIC 0x0400 + +/** + * To specify text track kind (different from subtitles default). + */ +#define AV_DISPOSITION_CAPTIONS 0x10000 +#define AV_DISPOSITION_DESCRIPTIONS 0x20000 +#define AV_DISPOSITION_METADATA 0x40000 + +/** + * Options for behavior on timestamp wrap detection. + */ +#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap +#define AV_PTS_WRAP_ADD_OFFSET 1 ///< add the format specific offset on wrap detection +#define AV_PTS_WRAP_SUB_OFFSET -1 ///< subtract the format specific offset on wrap detection + /** * Stream structure. * New fields can be added to the end with minor version bumps. @@ -403,40 +781,50 @@ typedef struct AVIndexEntry { */ typedef struct AVStream { int index; /**< stream index in AVFormatContext */ - int id; /**< format-specific stream ID */ - AVCodecContext *codec; /**< codec context */ /** - * Real base framerate of the stream. - * This is the lowest framerate with which all timestamps can be - * represented accurately (it is the least common multiple of all - * framerates in the stream). Note, this value is just a guess! - * For example, if the time base is 1/90000 and all frames have either - * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + * Format-specific stream ID. + * decoding: set by libavformat + * encoding: set by the user, replaced by libavformat if left unset */ - AVRational r_frame_rate; + int id; + /** + * Codec context associated with this stream. Allocated and freed by + * libavformat. + * + * - decoding: The demuxer exports codec information stored in the headers + * here. + * - encoding: The user sets codec information, the muxer writes it to the + * output. Mandatory fields as specified in AVCodecContext + * documentation must be set even if this AVCodecContext is + * not actually used for encoding. + */ + AVCodecContext *codec; void *priv_data; - /* internal data used in av_find_stream_info() */ - int64_t first_dts; - /** encoding: pts generation when outputting stream */ +#if FF_API_LAVF_FRAC + /** + * @deprecated this field is unused + */ + attribute_deprecated struct AVFrac pts; +#endif /** * This is the fundamental unit of time (in seconds) in terms - * of which frame timestamps are represented. For fixed-fps content, - * time base should be 1/framerate and timestamp increments should be 1. + * of which frame timestamps are represented. + * + * decoding: set by libavformat + * encoding: May be set by the caller before avformat_write_header() to + * provide a hint to the muxer about the desired timebase. In + * avformat_write_header(), the muxer will overwrite this field + * with the timebase that will actually be used for the timestamps + * written into the file (which may or may not be related to the + * user-provided one, depending on the format). */ AVRational time_base; - int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ - /* ffmpeg.c private use */ - int stream_copy; /**< If set, just copy stream. */ - enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed. - //FIXME move stuff to a flags field? - /** Quality, as it has been removed from AVCodecContext and put in AVVideoFrame. - * MN: dunno if that is the right place for it */ - float quality; + /** - * Decoding: pts of the first frame of the stream, in stream time base. + * Decoding: pts of the first frame of the stream in presentation order, in stream time base. * Only set this if you are absolutely 100% sure that the value you set * it to really is the pts of the first frame. * This may be undefined (AV_NOPTS_VALUE). @@ -444,6 +832,7 @@ typedef struct AVStream { * demuxer must NOT set this. */ int64_t start_time; + /** * Decoding: duration of the stream, in stream time base. * If a source file does not specify a duration, but does specify @@ -451,36 +840,11 @@ typedef struct AVStream { */ int64_t duration; -#if LIBAVFORMAT_VERSION_INT < (53<<16) - char language[4]; /** ISO 639-2/B 3-letter language code (empty string if undefined) */ -#endif - - /* av_read_frame() support */ - enum AVStreamParseType need_parsing; - struct AVCodecParserContext *parser; - - int64_t cur_dts; - int last_IP_duration; - int64_t last_IP_pts; - /* av_seek_frame() support */ - AVIndexEntry *index_entries; /**< Only used if the format does not - support seeking natively. */ - int nb_index_entries; - unsigned int index_entries_allocated_size; - int64_t nb_frames; ///< number of frames in this stream if known or 0 -#if LIBAVFORMAT_VERSION_INT < (53<<16) - int64_t unused[4+1]; - - char *filename; /**< source filename of the stream */ -#endif - int disposition; /**< AV_DISPOSITION_* bit field */ - AVProbeData probe_data; -#define MAX_REORDER_DELAY 16 - int64_t pts_buffer[MAX_REORDER_DELAY+1]; + enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed. /** * sample aspect ratio (0 if unknown) @@ -489,48 +853,249 @@ typedef struct AVStream { */ AVRational sample_aspect_ratio; - AVMetadata *metadata; - - /* av_read_frame() support */ - const uint8_t *cur_ptr; - int cur_len; - AVPacket cur_pkt; + AVDictionary *metadata; - // Timestamp generation support: /** - * Timestamp corresponding to the last dts sync point. + * Average framerate * - * Initialized when AVCodecParserContext.dts_sync_point >= 0 and - * a DTS is received from the underlying container. Otherwise set to - * AV_NOPTS_VALUE by default. + * - demuxing: May be set by libavformat when creating the stream or in + * avformat_find_stream_info(). + * - muxing: May be set by the caller before avformat_write_header(). */ - int64_t reference_dts; + AVRational avg_frame_rate; /** - * Number of packets to buffer for codec probing - * NOT PART OF PUBLIC API + * For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet + * will contain the attached picture. + * + * decoding: set by libavformat, must not be modified by the caller. + * encoding: unused */ -#define MAX_PROBE_PACKETS 2500 - int probe_packets; + AVPacket attached_pic; /** - * last packet in packet_buffer for this stream when muxing. - * used internally, NOT PART OF PUBLIC API, dont read or write from outside of libav* + * An array of side data that applies to the whole stream (i.e. the + * container does not allow it to change between packets). + * + * There may be no overlap between the side data in this array and side data + * in the packets. I.e. a given side data is either exported by the muxer + * (demuxing) / set by the caller (muxing) in this array, then it never + * appears in the packets, or the side data is exported / sent through + * the packets (always in the first packet where the value becomes known or + * changes), then it does not appear in this array. + * + * - demuxing: Set by libavformat when the stream is created. + * - muxing: May be set by the caller before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + * + * @see av_format_inject_global_side_data() */ - struct AVPacketList *last_in_packet_buffer; + AVPacketSideData *side_data; + /** + * The number of elements in the AVStream.side_data array. + */ + int nb_side_data; /** - * Average framerate + * Flags for the user to detect events happening on the stream. Flags must + * be cleared by the user once the event has been handled. + * A combination of AVSTREAM_EVENT_FLAG_*. + */ + int event_flags; +#define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** */ - AVRational avg_frame_rate; /** - * Number of frames that have been demuxed during av_find_stream_info() + * Stream information used internally by av_find_stream_info() */ - int codec_info_nb_frames; -} AVStream; +#define MAX_STD_TIMEBASES (60*12+6) + struct { + int64_t last_dts; + int64_t duration_gcd; + int duration_count; + int64_t rfps_duration_sum; + double (*duration_error)[2][MAX_STD_TIMEBASES]; + int64_t codec_info_duration; + int64_t codec_info_duration_fields; + + /** + * 0 -> decoder has not been searched for yet. + * >0 -> decoder found + * <0 -> decoder with codec_id == -found_decoder has not been found + */ + int found_decoder; + + int64_t last_duration; + + /** + * Those are used for average framerate estimation. + */ + int64_t fps_first_dts; + int fps_first_dts_idx; + int64_t fps_last_dts; + int fps_last_dts_idx; + + } *info; -#define AV_PROGRAM_RUNNING 1 + int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ + + // Timestamp generation support: + /** + * Timestamp corresponding to the last dts sync point. + * + * Initialized when AVCodecParserContext.dts_sync_point >= 0 and + * a DTS is received from the underlying container. Otherwise set to + * AV_NOPTS_VALUE by default. + */ + int64_t first_dts; + int64_t cur_dts; + int64_t last_IP_pts; + int last_IP_duration; + + /** + * Number of packets to buffer for codec probing + */ +#define MAX_PROBE_PACKETS 2500 + int probe_packets; + + /** + * Number of frames that have been demuxed during av_find_stream_info() + */ + int codec_info_nb_frames; + + /* av_read_frame() support */ + enum AVStreamParseType need_parsing; + struct AVCodecParserContext *parser; + + /** + * last packet in packet_buffer for this stream when muxing. + */ + struct AVPacketList *last_in_packet_buffer; + AVProbeData probe_data; +#define MAX_REORDER_DELAY 16 + int64_t pts_buffer[MAX_REORDER_DELAY+1]; + + AVIndexEntry *index_entries; /**< Only used if the format does not + support seeking natively. */ + int nb_index_entries; + unsigned int index_entries_allocated_size; + + /** + * Real base framerate of the stream. + * This is the lowest framerate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * framerates in the stream). Note, this value is just a guess! + * For example, if the time base is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + * + * Code outside avformat should access this field using: + * av_stream_get/set_r_frame_rate(stream) + */ + AVRational r_frame_rate; + + /** + * Stream Identifier + * This is the MPEG-TS stream identifier +1 + * 0 means unknown + */ + int stream_identifier; + + int64_t interleaver_chunk_size; + int64_t interleaver_chunk_duration; + + /** + * stream probing state + * -1 -> probing finished + * 0 -> no probing requested + * rest -> perform probing with request_probe being the minimum score to accept. + * NOT PART OF PUBLIC API + */ + int request_probe; + /** + * Indicates that everything up to the next keyframe + * should be discarded. + */ + int skip_to_keyframe; + + /** + * Number of samples to skip at the start of the frame decoded from the next packet. + */ + int skip_samples; + + /** + * Number of internally decoded frames, used internally in libavformat, do not access + * its lifetime differs from info which is why it is not in that structure. + */ + int nb_decoded_frames; + + /** + * Timestamp offset added to timestamps before muxing + * NOT PART OF PUBLIC API + */ + int64_t mux_ts_offset; + + /** + * Internal data to check for wrapping of the time stamp + */ + int64_t pts_wrap_reference; + + /** + * Options for behavior, when a wrap is detected. + * + * Defined by AV_PTS_WRAP_ values. + * + * If correction is enabled, there are two possibilities: + * If the first time stamp is near the wrap point, the wrap offset + * will be subtracted, which will create negative time stamps. + * Otherwise the offset will be added. + */ + int pts_wrap_behavior; + + /** + * Internal data to prevent doing update_initial_durations() twice + */ + int update_initial_durations_done; + + /** + * Internal data to generate dts from pts + */ + int64_t pts_reorder_error[MAX_REORDER_DELAY+1]; + uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; + + /** + * Internal data to analyze DTS and detect faulty mpeg streams + */ + int64_t last_dts_for_order_check; + uint8_t dts_ordered; + uint8_t dts_misordered; + + /** + * Internal data to inject global side data + */ + int inject_global_side_data; + +} AVStream; + +AVRational av_stream_get_r_frame_rate(const AVStream *s); +void av_stream_set_r_frame_rate(AVStream *s, AVRational r); +struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); + +/** + * Returns the pts of the last muxed packet + its duration + * + * the retuned value is undefined when used with a demuxer. + */ +int64_t av_stream_get_end_pts(const AVStream *st); + +#define AV_PROGRAM_RUNNING 1 /** * New fields can be added to the end with minor version bumps. @@ -540,15 +1105,28 @@ typedef struct AVStream { */ typedef struct AVProgram { int id; -#if LIBAVFORMAT_VERSION_INT < (53<<16) - char *provider_name; ///< network name for DVB streams - char *name; ///< service name for DVB streams -#endif int flags; enum AVDiscard discard; ///< selects which program to discard and which to feed to the caller unsigned int *stream_index; unsigned int nb_stream_indexes; - AVMetadata *metadata; + AVDictionary *metadata; + + int program_num; + int pmt_pid; + int pcr_pid; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int64_t start_time; + int64_t end_time; + + int64_t pts_wrap_reference; ///< reference dts for wrap detection + int pts_wrap_behavior; ///< behavior on wrap detection } AVProgram; #define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present @@ -558,93 +1136,148 @@ typedef struct AVChapter { int id; ///< unique ID to identify the chapter AVRational time_base; ///< time base in which the start/end timestamps are specified int64_t start, end; ///< chapter start/end time in time_base units -#if LIBAVFORMAT_VERSION_INT < (53<<16) - char *title; ///< chapter title -#endif - AVMetadata *metadata; + AVDictionary *metadata; } AVChapter; -#if LIBAVFORMAT_VERSION_MAJOR < 53 -#define MAX_STREAMS 20 -#else -#define MAX_STREAMS 100 -#endif + +/** + * Callback used by devices to communicate with application. + */ +typedef int (*av_format_control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + + +/** + * The duration of a video can be estimated through various ways, and this enum can be used + * to know how the duration was estimated. + */ +enum AVDurationEstimationMethod { + AVFMT_DURATION_FROM_PTS, ///< Duration accurately estimated from PTSes + AVFMT_DURATION_FROM_STREAM, ///< Duration estimated from a stream with a known duration + AVFMT_DURATION_FROM_BITRATE ///< Duration estimated from bitrate (less accurate) +}; + +typedef struct AVFormatInternal AVFormatInternal; /** * Format I/O context. * New fields can be added to the end with minor version bumps. * Removal, reordering and changes to existing fields require a major * version bump. - * sizeof(AVFormatContext) must not be used outside libav*. + * sizeof(AVFormatContext) must not be used outside libav*, use + * avformat_alloc_context() to create an AVFormatContext. */ typedef struct AVFormatContext { - const AVClass *av_class; /**< Set by avformat_alloc_context. */ - /* Can only be iformat or oformat, not both at the same time. */ + /** + * A class for logging and @ref avoptions. Set by avformat_alloc_context(). + * Exports (de)muxer private options if they exist. + */ + const AVClass *av_class; + + /** + * The input container format. + * + * Demuxing only, set by avformat_open_input(). + */ struct AVInputFormat *iformat; + + /** + * The output container format. + * + * Muxing only, must be set by the caller before avformat_write_header(). + */ struct AVOutputFormat *oformat; + + /** + * Format private data. This is an AVOptions-enabled struct + * if and only if iformat/oformat.priv_class is not NULL. + * + * - muxing: set by avformat_write_header() + * - demuxing: set by avformat_open_input() + */ void *priv_data; - ByteIOContext *pb; - unsigned int nb_streams; - AVStream *streams[MAX_STREAMS]; - char filename[1024]; /**< input or output filename */ + + /** + * I/O context. + * + * - demuxing: either set by the user before avformat_open_input() (then + * the user must close it manually) or set by avformat_open_input(). + * - muxing: set by the user before avformat_write_header(). The caller must + * take care of closing / freeing the IO context. + * + * Do NOT set this field if AVFMT_NOFILE flag is set in + * iformat/oformat.flags. In such a case, the (de)muxer will handle + * I/O in some other way and this field will be NULL. + */ + AVIOContext *pb; + /* stream info */ - int64_t timestamp; -#if LIBAVFORMAT_VERSION_INT < (53<<16) - char title[512]; - char author[512]; - char copyright[512]; - char comment[512]; - char album[512]; - int year; /**< ID3 year, 0 if none */ - int track; /**< track number, 0 if none */ - char genre[32]; /**< ID3 genre */ -#endif + /** + * Flags signalling stream properties. A combination of AVFMTCTX_*. + * Set by libavformat. + */ + int ctx_flags; - int ctx_flags; /**< Format-specific flags, see AVFMTCTX_xx */ - /* private data for pts handling (do not modify directly). */ - /** This buffer is only needed when packets were already buffered but - not decoded, for example to get the codec parameters in MPEG - streams. */ - struct AVPacketList *packet_buffer; + /** + * Number of elements in AVFormatContext.streams. + * + * Set by avformat_new_stream(), must not be modified by any other code. + */ + unsigned int nb_streams; + /** + * A list of all streams in the file. New streams are created with + * avformat_new_stream(). + * + * - demuxing: streams are created by libavformat in avformat_open_input(). + * If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also + * appear in av_read_frame(). + * - muxing: streams are created by the user before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + */ + AVStream **streams; - /** Decoding: position of the first frame of the component, in - AV_TIME_BASE fractional seconds. NEVER set this value directly: - It is deduced from the AVStream values. */ + /** + * input or output filename + * + * - demuxing: set by avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + */ + char filename[1024]; + + /** + * Position of the first frame of the component, in + * AV_TIME_BASE fractional seconds. NEVER set this value directly: + * It is deduced from the AVStream values. + * + * Demuxing only, set by libavformat. + */ int64_t start_time; - /** Decoding: duration of the stream, in AV_TIME_BASE fractional - seconds. Only set this value if you know none of the individual stream - durations and also dont set any of them. This is deduced from the - AVStream values if not set. */ - int64_t duration; - /** decoding: total file size, 0 if unknown */ - int64_t file_size; - /** Decoding: total stream bitrate in bit/s, 0 if not - available. Never set it directly if the file_size and the - duration are known as FFmpeg can compute it automatically. */ - int bit_rate; - /* av_read_frame() support */ - AVStream *cur_st; -#if LIBAVFORMAT_VERSION_INT < (53<<16) - const uint8_t *cur_ptr_deprecated; - int cur_len_deprecated; - AVPacket cur_pkt_deprecated; -#endif + /** + * Duration of the stream, in AV_TIME_BASE fractional + * seconds. Only set this value if you know none of the individual stream + * durations and also do not set any of them. This is deduced from the + * AVStream values if not set. + * + * Demuxing only, set by libavformat. + */ + int64_t duration; - /* av_seek_frame() support */ - int64_t data_offset; /** offset of the first packet */ - int index_built; + /** + * Total stream bitrate in bit/s, 0 if not + * available. Never set it directly if the file_size and the + * duration are known as FFmpeg can compute it automatically. + */ + int bit_rate; - int mux_rate; unsigned int packet_size; - int preload; int max_delay; -#define AVFMT_NOOUTPUTLOOP -1 -#define AVFMT_INFINITEOUTPUTLOOP 0 - /** number of times to loop output in formats that support it */ - int loop_output; - + /** + * Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*. + * Set by the user before avformat_open_input() / avformat_write_header(). + */ int flags; #define AVFMT_FLAG_GENPTS 0x0001 ///< Generate missing pts even if it requires parsing future frames. #define AVFMT_FLAG_IGNIDX 0x0002 ///< Ignore index. @@ -652,15 +1285,31 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_IGNDTS 0x0008 ///< Ignore DTS on frames that contain both DTS & PTS #define AVFMT_FLAG_NOFILLIN 0x0010 ///< Do not infer any values from other values, just return what is stored in the container #define AVFMT_FLAG_NOPARSE 0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled +#define AVFMT_FLAG_NOBUFFER 0x0040 ///< Do not buffer frames when possible +#define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. +#define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted +#define AVFMT_FLAG_FLUSH_PACKETS 0x0200 ///< Flush the AVIOContext every packet. +/** + * When muxing, try to avoid writing any random/volatile data to the output. + * This includes any random IDs, real-time timestamps/dates, muxer version, etc. + * + * This flag is mainly intended for testing. + */ +#define AVFMT_FLAG_BITEXACT 0x0400 +#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload +#define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) +#define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) +#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. - int loop_input; - /** decoding: size of data to probe; encoding: unused. */ + /** + * @deprecated deprecated in favor of probesize2 + */ unsigned int probesize; /** - * Maximum time (in AV_TIME_BASE units) during which the input should - * be analyzed in av_find_stream_info(). + * @deprecated deprecated in favor of max_analyze_duration2 */ + attribute_deprecated int max_analyze_duration; const uint8_t *key; @@ -673,17 +1322,19 @@ typedef struct AVFormatContext { * Forced video codec_id. * Demuxing: Set by user. */ - enum CodecID video_codec_id; + enum AVCodecID video_codec_id; + /** * Forced audio codec_id. * Demuxing: Set by user. */ - enum CodecID audio_codec_id; + enum AVCodecID audio_codec_id; + /** * Forced subtitle codec_id. * Demuxing: Set by user. */ - enum CodecID subtitle_codec_id; + enum AVCodecID subtitle_codec_id; /** * Maximum amount of memory in bytes to use for the index of each stream. @@ -692,8 +1343,8 @@ typedef struct AVFormatContext { * accurate seeking (depends on demuxer). * Demuxers for which a full in-memory index is mandatory will ignore * this. - * muxing : unused - * demuxing: set by user + * - muxing: unused + * - demuxing: set by user */ unsigned int max_index_size; @@ -703,15 +1354,240 @@ typedef struct AVFormatContext { */ unsigned int max_picture_buffer; + /** + * Number of chapters in AVChapter array. + * When muxing, chapters are normally written in the file header, + * so nb_chapters should normally be initialized before write_header + * is called. Some muxers (e.g. mov and mkv) can also write chapters + * in the trailer. To write chapters in the trailer, nb_chapters + * must be zero when write_header is called and non-zero when + * write_trailer is called. + * - muxing: set by user + * - demuxing: set by libavformat + */ unsigned int nb_chapters; AVChapter **chapters; + /** + * Metadata that applies to the whole file. + * + * - demuxing: set by libavformat in avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + * + * Freed by libavformat in avformat_free_context(). + */ + AVDictionary *metadata; + + /** + * Start time of the stream in real world time, in microseconds + * since the Unix epoch (00:00 1st January 1970). That is, pts=0 in the + * stream was captured at this real world time. + * - muxing: Set by the caller before avformat_write_header(). If set to + * either 0 or AV_NOPTS_VALUE, then the current wall-time will + * be used. + * - demuxing: Set by libavformat. AV_NOPTS_VALUE if unknown. Note that + * the value may become known after some number of frames + * have been received. + */ + int64_t start_time_realtime; + + /** + * The number of frames used for determining the framerate in + * avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + */ + int fps_probe_size; + + /** + * Error recognition; higher values will detect more errors but may + * misdetect some more or less valid parts as errors. + * Demuxing only, set by the caller before avformat_open_input(). + */ + int error_recognition; + + /** + * Custom interrupt callbacks for the I/O layer. + * + * demuxing: set by the user before avformat_open_input(). + * muxing: set by the user before avformat_write_header() + * (mainly useful for AVFMT_NOFILE formats). The callback + * should also be passed to avio_open2() if it's used to + * open the file. + */ + AVIOInterruptCB interrupt_callback; + /** * Flags to enable debugging. */ int debug; #define FF_FDEBUG_TS 0x0001 + /** + * Maximum buffering duration for interleaving. + * + * To ensure all the streams are interleaved correctly, + * av_interleaved_write_frame() will wait until it has at least one packet + * for each stream before actually writing any packets to the output file. + * When some streams are "sparse" (i.e. there are large gaps between + * successive packets), this can result in excessive buffering. + * + * This field specifies the maximum difference between the timestamps of the + * first and the last packet in the muxing queue, above which libavformat + * will output a packet regardless of whether it has queued a packet for all + * the streams. + * + * Muxing only, set by the caller before avformat_write_header(). + */ + int64_t max_interleave_delta; + + /** + * Allow non-standard and experimental extension + * @see AVCodecContext.strict_std_compliance + */ + int strict_std_compliance; + + /** + * Flags for the user to detect events happening on the file. Flags must + * be cleared by the user once the event has been handled. + * A combination of AVFMT_EVENT_FLAG_*. + */ + int event_flags; +#define AVFMT_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + + /** + * Maximum number of packets to read while waiting for the first timestamp. + * Decoding only. + */ + int max_ts_probe; + + + /** + * Transport stream id. + * This will be moved into demuxer private options. Thus no API/ABI compatibility + */ + int ts_id; + + /** + * Audio preload in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int audio_preload; + + /** + * Max chunk time in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int max_chunk_duration; + + /** + * Max chunk size in bytes + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int max_chunk_size; + + /** + * forces the use of wallclock timestamps as pts/dts of packets + * This has undefined results in the presence of B frames. + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int use_wallclock_as_timestamps; + + /** + * Avoid negative timestamps during muxing. + * 0 -> allow negative timestamps + * 1 -> avoid negative timestamps + * -1 -> choose automatically (default) + * Note, this only works when interleave_packet_per_dts is in use. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int avoid_negative_ts; + + /** + * avio flags, used to force AVIO_FLAG_DIRECT. + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int avio_flags; + + /** + * The duration field can be estimated through various ways, and this field can be used + * to know how the duration was estimated. + * - encoding: unused + * - decoding: Read by user via AVOptions (NO direct access) + */ + enum AVDurationEstimationMethod duration_estimation_method; + + /** + * Skip initial bytes when opening stream + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int64_t skip_initial_bytes; + + /** + * Correct single timestamp overflows + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + unsigned int correct_ts_overflow; + + /** + * Force seeking to any (also non key) frames. + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int seek2any; + + /** + * Flush the I/O context after each packet. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int flush_packets; + + /** + * format probing score. + * The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes + * the format. + * - encoding: unused + * - decoding: set by avformat, read by user via av_format_get_probe_score() (NO direct access) + */ + int probe_score; + + /** + * number of bytes to read maximally to identify format. + * - encoding: unused + * - decoding: set by user through AVOPtions (NO direct access) + */ + int format_probesize; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + /** + * This buffer is only needed when packets were already buffered but + * not decoded, for example to get the codec parameters in MPEG + * streams. + */ + struct AVPacketList *packet_buffer; + struct AVPacketList *packet_buffer_end; + + /* av_seek_frame() support */ + int64_t data_offset; /**< offset of the first packet */ + /** * Raw packets from the demuxer, prior to parsing and decoding. * This buffer is used for buffering packets until the codec can @@ -720,213 +1596,394 @@ typedef struct AVFormatContext { */ struct AVPacketList *raw_packet_buffer; struct AVPacketList *raw_packet_buffer_end; - - struct AVPacketList *packet_buffer_end; - - AVMetadata *metadata; - + /** + * Packets split by the parser get queued here. + */ + struct AVPacketList *parse_queue; + struct AVPacketList *parse_queue_end; /** * Remaining size available for raw_packet_buffer, in bytes. - * NOT PART OF PUBLIC API */ #define RAW_PACKET_BUFFER_SIZE 2500000 int raw_packet_buffer_remaining_size; /** - * Start time of the stream in real world time, in microseconds - * since the unix epoch (00:00 1st January 1970). That is, pts=0 - * in the stream was captured at this real world time. - * - encoding: Set by user. - * - decoding: Unused. + * Offset to remap timestamps to be non-negative. + * Expressed in timebase units. + * @see AVStream.mux_ts_offset */ - int64_t start_time_realtime; + int64_t offset; + + /** + * Timebase for the timestamp offset. + */ + AVRational offset_timebase; + + /** + * An opaque field for libavformat internal usage. + * Must not be accessed in any way by callers. + */ + AVFormatInternal *internal; + + /** + * IO repositioned flag. + * This is set by avformat when the underlaying IO context read pointer + * is repositioned, for example when doing byte based seeking. + * Demuxers can use the flag to detect such changes. + */ + int io_repositioned; + + /** + * Forced video codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_video_codec (NO direct access). + */ + AVCodec *video_codec; + + /** + * Forced audio codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_audio_codec (NO direct access). + */ + AVCodec *audio_codec; + + /** + * Forced subtitle codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_subtitle_codec (NO direct access). + */ + AVCodec *subtitle_codec; + + /** + * Number of bytes to be written as padding in a metadata header. + * Demuxing: Unused. + * Muxing: Set by user via av_format_set_metadata_header_padding. + */ + int metadata_header_padding; + + /** + * User data. + * This is a place for some private data of the user. + * Mostly usable with control_message_cb or any future callbacks in device's context. + */ + void *opaque; + + /** + * Callback used by devices to communicate with application. + */ + av_format_control_message control_message_cb; + + /** + * Output timestamp offset, in microseconds. + * Muxing: set by user via AVOptions (NO direct access) + */ + int64_t output_ts_offset; + + /** + * Maximum duration (in AV_TIME_BASE units) of the data read + * from input in avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info() + * via AVOptions (NO direct access). + * Can be set to 0 to let avformat choose using a heuristic. + */ + int64_t max_analyze_duration2; + + /** + * Maximum size of the data read from input for determining + * the input container format. + * Demuxing only, set by the caller before avformat_open_input() + * via AVOptions (NO direct access). + */ + int64_t probesize2; } AVFormatContext; +int av_format_get_probe_score(const AVFormatContext *s); +AVCodec * av_format_get_video_codec(const AVFormatContext *s); +void av_format_set_video_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_audio_codec(const AVFormatContext *s); +void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); +void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +int av_format_get_metadata_header_padding(const AVFormatContext *s); +void av_format_set_metadata_header_padding(AVFormatContext *s, int c); +void * av_format_get_opaque(const AVFormatContext *s); +void av_format_set_opaque(AVFormatContext *s, void *opaque); +av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s); +void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback); + +/** + * This function will cause global side data to be injected in the next packet + * of each stream as well as after any subsequent seek. + */ +void av_format_inject_global_side_data(AVFormatContext *s); + +/** + * Returns the method used to set ctx->duration. + * + * @return AVFMT_DURATION_FROM_PTS, AVFMT_DURATION_FROM_STREAM, or AVFMT_DURATION_FROM_BITRATE. + */ +enum AVDurationEstimationMethod av_fmt_ctx_get_duration_estimation_method(const AVFormatContext* ctx); + typedef struct AVPacketList { AVPacket pkt; struct AVPacketList *next; } AVPacketList; -#if LIBAVFORMAT_VERSION_INT < (53<<16) -extern AVInputFormat *first_iformat; -extern AVOutputFormat *first_oformat; -#endif + +/** + * @defgroup lavf_core Core functions + * @ingroup libavf + * + * Functions for querying libavformat capabilities, allocating core structures, + * etc. + * @{ + */ + +/** + * Return the LIBAVFORMAT_VERSION_INT constant. + */ +unsigned avformat_version(void); + +/** + * Return the libavformat build-time configuration. + */ +const char *avformat_configuration(void); + +/** + * Return the libavformat license. + */ +const char *avformat_license(void); + +/** + * Initialize libavformat and register all the muxers, demuxers and + * protocols. If you do not call this function, then you can select + * exactly which formats you want to support. + * + * @see av_register_input_format() + * @see av_register_output_format() + */ +void av_register_all(void); + +void av_register_input_format(AVInputFormat *format); +void av_register_output_format(AVOutputFormat *format); + +/** + * Do global initialization of network components. This is optional, + * but recommended, since it avoids the overhead of implicitly + * doing the setup for each session. + * + * Calling this function will become mandatory if using network + * protocols at some major version bump. + */ +int avformat_network_init(void); + +/** + * Undo the initialization done by avformat_network_init. + */ +int avformat_network_deinit(void); /** * If f is NULL, returns the first registered input format, * if f is non-NULL, returns the next registered input format after f * or NULL if f is the last one. */ -AVInputFormat *av_iformat_next(AVInputFormat *f); +AVInputFormat *av_iformat_next(const AVInputFormat *f); /** * If f is NULL, returns the first registered output format, * if f is non-NULL, returns the next registered output format after f * or NULL if f is the last one. */ -AVOutputFormat *av_oformat_next(AVOutputFormat *f); - -enum CodecID av_guess_image2_codec(const char *filename); - -/* XXX: Use automatic init with either ELF sections or C file parser */ -/* modules. */ - -/* utils.c */ -void av_register_input_format(AVInputFormat *format); -void av_register_output_format(AVOutputFormat *format); -#if LIBAVFORMAT_VERSION_MAJOR < 53 -attribute_deprecated AVOutputFormat *guess_stream_format(const char *short_name, - const char *filename, - const char *mime_type); +AVOutputFormat *av_oformat_next(const AVOutputFormat *f); /** - * @deprecated Use av_guess_format() instead. + * Allocate an AVFormatContext. + * avformat_free_context() can be used to free the context and everything + * allocated by the framework within it. */ -attribute_deprecated AVOutputFormat *guess_format(const char *short_name, - const char *filename, - const char *mime_type); -#endif +AVFormatContext *avformat_alloc_context(void); /** - * Returns the output format in the list of registered output formats - * which best matches the provided parameters, or returns NULL if - * there is no match. - * - * @param short_name if non-NULL checks if short_name matches with the - * names of the registered formats - * @param filename if non-NULL checks if filename terminates with the - * extensions of the registered formats - * @param mime_type if non-NULL checks if mime_type matches with the - * MIME type of the registered formats + * Free an AVFormatContext and all its streams. + * @param s context to free */ -AVOutputFormat *av_guess_format(const char *short_name, - const char *filename, - const char *mime_type); +void avformat_free_context(AVFormatContext *s); /** - * Guesses the codec ID based upon muxer and filename. + * Get the AVClass for AVFormatContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). */ -enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, - const char *filename, const char *mime_type, - enum AVMediaType type); +const AVClass *avformat_get_class(void); /** - * Sends a nice hexadecimal dump of a buffer to the specified file stream. + * Add a new stream to a media file. * - * @param f The file stream pointer where the dump should be sent to. - * @param buf buffer - * @param size buffer size + * When demuxing, it is called by the demuxer in read_header(). If the + * flag AVFMTCTX_NOHEADER is set in s.ctx_flags, then it may also + * be called in read_packet(). + * + * When muxing, should be called by the user before avformat_write_header(). + * + * User is required to call avcodec_close() and avformat_free_context() to + * clean up the allocation by avformat_new_stream(). * - * @see av_hex_dump_log, av_pkt_dump, av_pkt_dump_log + * @param s media file handle + * @param c If non-NULL, the AVCodecContext corresponding to the new stream + * will be initialized to use this codec. This is needed for e.g. codec-specific + * defaults to be set, so codec should be provided if it is known. + * + * @return newly created stream or NULL on error. */ -void av_hex_dump(FILE *f, uint8_t *buf, int size); +AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c); /** - * Sends a nice hexadecimal dump of a buffer to the log. - * - * @param avcl A pointer to an arbitrary struct of which the first field is a - * pointer to an AVClass struct. - * @param level The importance level of the message, lower values signifying - * higher importance. - * @param buf buffer - * @param size buffer size + * Get side information from stream. * - * @see av_hex_dump, av_pkt_dump, av_pkt_dump_log + * @param stream stream + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise */ -void av_hex_dump_log(void *avcl, int level, uint8_t *buf, int size); +uint8_t *av_stream_get_side_data(AVStream *stream, + enum AVPacketSideDataType type, int *size); + +AVProgram *av_new_program(AVFormatContext *s, int id); /** - * Sends a nice dump of a packet to the specified file stream. - * - * @param f The file stream pointer where the dump should be sent to. - * @param pkt packet to dump - * @param dump_payload True if the payload must be displayed, too. + * @} */ -void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload); + +#if FF_API_ALLOC_OUTPUT_CONTEXT /** - * Sends a nice dump of a packet to the log. - * - * @param avcl A pointer to an arbitrary struct of which the first field is a - * pointer to an AVClass struct. - * @param level The importance level of the message, lower values signifying - * higher importance. - * @param pkt packet to dump - * @param dump_payload True if the payload must be displayed, too. + * @deprecated deprecated in favor of avformat_alloc_output_context2() */ -void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload); +attribute_deprecated +AVFormatContext *avformat_alloc_output_context(const char *format, + AVOutputFormat *oformat, + const char *filename); +#endif /** - * Initializes libavformat and registers all the muxers, demuxers and - * protocols. If you do not call this function, then you can select - * exactly which formats you want to support. + * Allocate an AVFormatContext for an output format. + * avformat_free_context() can be used to free the context and + * everything allocated by the framework within it. * - * @see av_register_input_format() - * @see av_register_output_format() - * @see av_register_protocol() + * @param *ctx is set to the created format context, or to NULL in + * case of failure + * @param oformat format to use for allocating the context, if NULL + * format_name and filename are used instead + * @param format_name the name of output format to use for allocating the + * context, if NULL filename is used instead + * @param filename the name of the filename to use for allocating the + * context, may be NULL + * @return >= 0 in case of success, a negative AVERROR code in case of + * failure */ -void av_register_all(void); +int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, + const char *format_name, const char *filename); -/** codec tag <-> codec id */ -enum CodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned int tag); -unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum CodecID id); - -/* media file input */ +/** + * @addtogroup lavf_decoding + * @{ + */ /** - * Finds AVInputFormat based on the short name of the input format. + * Find AVInputFormat based on the short name of the input format. */ AVInputFormat *av_find_input_format(const char *short_name); /** - * Guesses the file format. + * Guess the file format. * + * @param pd data to be probed * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. */ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); /** - * Allocates all the structures needed to read an input stream. - * This does not open the needed codecs for decoding the stream[s]. + * Guess the file format. + * + * @param pd data to be probed + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_max A probe score larger that this is required to accept a + * detection, the variable is set to the actual detection + * score afterwards. + * If the score is <= AVPROBE_SCORE_MAX / 4 it is recommended + * to retry with a larger probe buffer. */ -int av_open_input_stream(AVFormatContext **ic_ptr, - ByteIOContext *pb, const char *filename, - AVInputFormat *fmt, AVFormatParameters *ap); +AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max); /** - * Opens a media file as input. The codecs are not opened. Only the file - * header (if present) is read. + * Guess the file format. * - * @param ic_ptr The opened media file handle is put here. - * @param filename filename to open - * @param fmt If non-NULL, force the file format to use. - * @param buf_size optional buffer size (zero if default is OK) - * @param ap Additional parameters needed when opening the file - * (NULL if default). - * @return 0 if OK, AVERROR_xxx otherwise + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_ret The score of the best detection. */ -int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, - AVInputFormat *fmt, - int buf_size, - AVFormatParameters *ap); +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret); -#if LIBAVFORMAT_VERSION_MAJOR < 53 /** - * @deprecated Use avformat_alloc_context() instead. + * Probe a bytestream to determine the input format. Each time a probe returns + * with a score that is too low, the probe buffer size is increased and another + * attempt is made. When the maximum probe size is reached, the input format + * with the highest score is returned. + * + * @param pb the bytestream to probe + * @param fmt the input format is put here + * @param filename the filename of the stream + * @param logctx the log context + * @param offset the offset within the bytestream to probe from + * @param max_probe_size the maximum probe buffer size (zero for default) + * @return the score in case of success, a negative value corresponding to an + * the maximal score is AVPROBE_SCORE_MAX + * AVERROR code otherwise */ -attribute_deprecated AVFormatContext *av_alloc_format_context(void); -#endif +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size); /** - * Allocates an AVFormatContext. - * Can be freed with av_free() but do not forget to free everything you - * explicitly allocated as well! + * Like av_probe_input_buffer2() but returns 0 on success */ -AVFormatContext *avformat_alloc_context(void); +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size); + +/** + * Open an input stream and read the header. The codecs are not opened. + * The stream must be closed with avformat_close_input(). + * + * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). + * May be a pointer to NULL, in which case an AVFormatContext is allocated by this + * function and written into ps. + * Note that a user-supplied AVFormatContext will be freed on failure. + * @param filename Name of the stream to open. + * @param fmt If non-NULL, this parameter forces a specific input format. + * Otherwise the format is autodetected. + * @param options A dictionary filled with AVFormatContext and demuxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, a negative AVERROR on failure. + * + * @note If you want to use custom IO, preallocate the format context and set its pb field. + */ +int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); + +attribute_deprecated +int av_demuxer_open(AVFormatContext *ic); +#if FF_API_FORMAT_PARAMETERS /** - * Reads packets of a media file to get stream information. This + * Read packets of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This * function also computes the real framerate in case of MPEG-2 repeat * frame mode. @@ -937,11 +1994,85 @@ AVFormatContext *avformat_alloc_context(void); * @return >=0 if OK, AVERROR_xxx on error * @todo Let the user decide somehow what information is needed so that * we do not waste time getting stuff the user does not need. + * + * @deprecated use avformat_find_stream_info. */ +attribute_deprecated int av_find_stream_info(AVFormatContext *ic); +#endif + +/** + * Read packets of a media file to get stream information. This + * is useful for file formats with no headers such as MPEG. This + * function also computes the real framerate in case of MPEG-2 repeat + * frame mode. + * The logical file position is not changed by this function; + * examined packets may be buffered for later processing. + * + * @param ic media file handle + * @param options If non-NULL, an ic.nb_streams long array of pointers to + * dictionaries, where i-th member contains options for + * codec corresponding to i-th stream. + * On return each dictionary will be filled with options that were not found. + * @return >=0 if OK, AVERROR_xxx on error + * + * @note this function isn't guaranteed to open all the codecs, so + * options being non-empty at return is a perfectly normal behavior. + * + * @todo Let the user decide somehow what information is needed so that + * we do not waste time getting stuff the user does not need. + */ +int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); + +/** + * Find the programs which belong to a given stream. + * + * @param ic media file handle + * @param last the last found program, the search will start after this + * program, or from the beginning if it is NULL + * @param s stream index + * @return the next program which belongs to s, NULL if no program is found or + * the last program is not among the programs of ic. + */ +AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s); /** - * Reads a transport packet from a media file. + * Find the "best" stream in the file. + * The best stream is determined according to various heuristics as the most + * likely to be what the user expects. + * If the decoder parameter is non-NULL, av_find_best_stream will find the + * default decoder for the stream's codec; streams for which no decoder can + * be found are ignored. + * + * @param ic media file handle + * @param type stream type: video, audio, subtitles, etc. + * @param wanted_stream_nb user-requested stream number, + * or -1 for automatic selection + * @param related_stream try to find a stream related (eg. in the same + * program) to this one, or -1 if none + * @param decoder_ret if non-NULL, returns the decoder for the + * selected stream + * @param flags flags; none are currently defined + * @return the non-negative stream number in case of success, + * AVERROR_STREAM_NOT_FOUND if no stream with the requested type + * could be found, + * AVERROR_DECODER_NOT_FOUND if streams were found but no decoder + * @note If av_find_best_stream returns successfully and decoder_ret is not + * NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec. + */ +int av_find_best_stream(AVFormatContext *ic, + enum AVMediaType type, + int wanted_stream_nb, + int related_stream, + AVCodec **decoder_ret, + int flags); + +#if FF_API_READ_PACKET +/** + * @deprecated use AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE to read raw + * unprocessed packets + * + * Read a transport packet from a media file. * * This function is obsolete and should never be used. * Use av_read_frame() instead. @@ -950,18 +2081,25 @@ int av_find_stream_info(AVFormatContext *ic); * @param pkt is filled * @return 0 if OK, AVERROR_xxx on error */ +attribute_deprecated int av_read_packet(AVFormatContext *s, AVPacket *pkt); +#endif /** - * Returns the next frame of a stream. + * Return the next frame of a stream. + * This function returns what is stored in the file, and does not validate + * that what is there are valid frames for the decoder. It will split what is + * stored in the file into frames and return one for each call. It will not + * omit invalid data between valid frames so as to give the decoder the maximum + * information possible for decoding. * - * The returned packet is valid - * until the next av_read_frame() or until av_close_input_file() and - * must be freed with av_free_packet. For video, the packet contains - * exactly one frame. For audio, it contains an integer number of - * frames if each frame has a known fixed size (e.g. PCM or ADPCM - * data). If the audio frames have a variable size (e.g. MPEG audio), - * then it contains one frame. + * If pkt->buf is NULL, then the packet is valid until the next + * av_read_frame() or until avformat_close_input(). Otherwise the packet + * is valid indefinitely. In both cases the packet must be freed with + * av_free_packet when it is no longer needed. For video, the packet contains + * exactly one frame. For audio, it contains an integer number of frames if each + * frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames + * have a variable size (e.g. MPEG audio), then it contains one frame. * * pkt->pts, pkt->dts and pkt->duration are always set to correct * values in AVStream.time_base units (and guessed if the format cannot @@ -974,8 +2112,10 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt); int av_read_frame(AVFormatContext *s, AVPacket *pkt); /** - * Seeks to the keyframe at timestamp. + * Seek to the keyframe at timestamp. * 'timestamp' in 'stream_index'. + * + * @param s media file handle * @param stream_index If stream_index is (-1), a default * stream is selected, and timestamp is automatically converted * from AV_TIME_BASE units to the stream specific time_base. @@ -988,7 +2128,7 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags); /** - * Seeks to timestamp ts. + * Seek to timestamp ts. * Seeking will be done so that the point from which all active streams * can be presented successfully will be closest to ts and within min/max_ts. * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. @@ -1001,7 +2141,9 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, * or if stream_index is -1, in AV_TIME_BASE units. * If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as * keyframes (this may not be supported by all demuxers). + * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored. * + * @param s media file handle * @param stream_index index of the stream which is used as time base reference * @param min_ts smallest acceptable timestamp * @param ts target timestamp @@ -1009,40 +2151,48 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, * @param flags flags * @return >=0 on success, error code otherwise * - * @NOTE This is part of the new seek API which is still under construction. + * @note This is part of the new seek API which is still under construction. * Thus do not use this yet. It may change at any time, do not expect * ABI compatibility yet! */ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); /** - * Starts playing a network-based stream (e.g. RTSP stream) at the + * Start playing a network-based stream (e.g. RTSP stream) at the * current position. */ int av_read_play(AVFormatContext *s); /** - * Pauses a network-based stream (e.g. RTSP stream). + * Pause a network-based stream (e.g. RTSP stream). * * Use av_read_play() to resume it. */ int av_read_pause(AVFormatContext *s); +#if FF_API_CLOSE_INPUT_FILE /** - * Frees a AVFormatContext allocated by av_open_input_stream. - * @param s context to free - */ -void av_close_input_stream(AVFormatContext *s); - -/** - * Closes a media file (but not its codecs). + * @deprecated use avformat_close_input() + * Close a media file (but not its codecs). * * @param s media file handle */ +attribute_deprecated void av_close_input_file(AVFormatContext *s); +#endif /** - * Adds a new stream to a media file. + * Close an opened input AVFormatContext. Free it and all its contents + * and set *s to NULL. + */ +void avformat_close_input(AVFormatContext **s); +/** + * @} + */ + +#if FF_API_NEW_STREAM +/** + * Add a new stream to a media file. * * Can only be called in the read_header() function. If the flag * AVFMTCTX_NOHEADER is in the format context, then new streams @@ -1051,247 +2201,368 @@ void av_close_input_file(AVFormatContext *s); * @param s media file handle * @param id file-format-dependent stream ID */ +attribute_deprecated AVStream *av_new_stream(AVFormatContext *s, int id); -AVProgram *av_new_program(AVFormatContext *s, int id); - -/** - * Adds a new chapter. - * This function is NOT part of the public API - * and should ONLY be used by demuxers. - * - * @param s media file handle - * @param id unique ID for this chapter - * @param start chapter start time in time_base units - * @param end chapter end time in time_base units - * @param title chapter title - * - * @return AVChapter or NULL on error - */ -AVChapter *ff_new_chapter(AVFormatContext *s, int id, AVRational time_base, - int64_t start, int64_t end, const char *title); +#endif +#if FF_API_SET_PTS_INFO /** - * Sets the pts for a given stream. - * - * @param s stream - * @param pts_wrap_bits number of bits effectively used by the pts - * (used for wrap control, 33 is the value for MPEG) - * @param pts_num numerator to convert to seconds (MPEG: 1) - * @param pts_den denominator to convert to seconds (MPEG: 90000) + * @deprecated this function is not supposed to be called outside of lavf */ +attribute_deprecated void av_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den); +#endif #define AVSEEK_FLAG_BACKWARD 1 ///< seek backward #define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes #define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes #define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number -int av_find_default_stream_index(AVFormatContext *s); - /** - * Gets the index for a specific timestamp. - * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond - * to the timestamp which is <= the requested one, if backward - * is 0, then it will be >= - * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise - * @return < 0 if no such timestamp could be found + * @addtogroup lavf_encoding + * @{ */ -int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); - /** - * Ensures the index uses less memory than the maximum specified in - * AVFormatContext.max_index_size by discarding entries if it grows - * too large. - * This function is not part of the public API and should only be called - * by demuxers. + * Allocate the stream private data and write the stream header to + * an output media file. + * + * @param s Media file handle, must be allocated with avformat_alloc_context(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already opened AVIOContext. + * @param options An AVDictionary filled with AVFormatContext and muxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next. */ -void ff_reduce_index(AVFormatContext *s, int stream_index); +int avformat_write_header(AVFormatContext *s, AVDictionary **options); /** - * Adds an index entry into a sorted list. Updates the entry if the list - * already contains it. + * Write a packet to an output media file. * - * @param timestamp timestamp in the time base of the given stream + * This function passes the packet directly to the muxer, without any buffering + * or reordering. The caller is responsible for correctly interleaving the + * packets if the format requires it. Callers that want libavformat to handle + * the interleaving should call av_interleaved_write_frame() instead of this + * function. + * + * @param s media file handle + * @param pkt The packet containing the data to be written. Note that unlike + * av_interleaved_write_frame(), this function does not take + * ownership of the packet passed to it (though some muxers may make + * an internal reference to the input packet). + *
+ * This parameter can be NULL (at any time, not just at the end), in + * order to immediately flush data buffered within the muxer, for + * muxers that buffer up data internally before writing it to the + * output. + *
+ * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". It is very strongly + * recommended that timing information (@ref AVPacket.pts "pts", @ref + * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to + * correct values. + * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush + * + * @see av_interleaved_write_frame() */ -int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, - int size, int distance, int flags); +int av_write_frame(AVFormatContext *s, AVPacket *pkt); /** - * Does a binary search using av_index_search_timestamp() and - * AVCodec.read_timestamp(). - * This is not supposed to be called directly by a user application, - * but by demuxers. - * @param target_ts target timestamp in the time base of the given stream - * @param stream_index stream number + * Write a packet to an output media file ensuring correct interleaving. + * + * This function will buffer the packets internally as needed to make sure the + * packets in the output file are properly interleaved in the order of + * increasing dts. Callers doing their own interleaving should call + * av_write_frame() instead of this function. + * + * @param s media file handle + * @param pkt The packet containing the data to be written. + *
+ * If the packet is reference-counted, this function will take + * ownership of this reference and unreference it later when it sees + * fit. + * The caller must not access the data through this reference after + * this function returns. If the packet is not reference-counted, + * libavformat will make a copy. + *
+ * This parameter can be NULL (at any time, not just at the end), to + * flush the interleaving queues. + *
+ * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". It is very strongly + * recommended that timing information (@ref AVPacket.pts "pts", @ref + * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to + * correct values. + * + * @return 0 on success, a negative AVERROR on error. Libavformat will always + * take care of freeing the packet, even if this function fails. + * + * @see av_write_frame(), AVFormatContext.max_interleave_delta */ -int av_seek_frame_binary(AVFormatContext *s, int stream_index, - int64_t target_ts, int flags); +int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); /** - * Updates cur_dts of all streams based on the given timestamp and AVStream. + * Write a uncoded frame to an output media file. + * + * The frame must be correctly interleaved according to the container + * specification; if not, then av_interleaved_write_frame() must be used. * - * Stream ref_st unchanged, others set cur_dts in their native time base. - * Only needed for timestamp wrapping or if (dts not set and pts!=dts). - * @param timestamp new dts expressed in time_base of param ref_st - * @param ref_st reference stream giving time_base of param timestamp + * See av_interleaved_write_frame() for details. */ -void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp); +int av_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); /** - * Does a binary search using read_timestamp(). - * This is not supposed to be called directly by a user application, - * but by demuxers. - * @param target_ts target timestamp in the time base of the given stream - * @param stream_index stream number + * Write a uncoded frame to an output media file. + * + * If the muxer supports it, this function allows to write an AVFrame + * structure directly, without encoding it into a packet. + * It is mostly useful for devices and similar special muxers that use raw + * video or PCM data and will not serialize it into a byte stream. + * + * To test whether it is possible to use it with a given muxer and stream, + * use av_write_uncoded_frame_query(). + * + * The caller gives up ownership of the frame and must not access it + * afterwards. + * + * @return >=0 for success, a negative code on error */ -int64_t av_gen_search(AVFormatContext *s, int stream_index, - int64_t target_ts, int64_t pos_min, - int64_t pos_max, int64_t pos_limit, - int64_t ts_min, int64_t ts_max, - int flags, int64_t *ts_ret, - int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )); +int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); -/** media file output */ -int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); +/** + * Test whether a muxer supports uncoded frame. + * + * @return >=0 if an uncoded frame can be written to that muxer and stream, + * <0 if not + */ +int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index); /** - * Allocates the stream private data and writes the stream header to an - * output media file. + * Write the stream trailer to an output media file and free the + * file private data. + * + * May only be called after a successful call to avformat_write_header. * * @param s media file handle * @return 0 if OK, AVERROR_xxx on error */ -int av_write_header(AVFormatContext *s); +int av_write_trailer(AVFormatContext *s); /** - * Writes a packet to an output media file. + * Return the output format in the list of registered output formats + * which best matches the provided parameters, or return NULL if + * there is no match. * - * The packet shall contain one audio or video frame. - * The packet must be correctly interleaved according to the container - * specification, if not then av_interleaved_write_frame must be used. + * @param short_name if non-NULL checks if short_name matches with the + * names of the registered formats + * @param filename if non-NULL checks if filename terminates with the + * extensions of the registered formats + * @param mime_type if non-NULL checks if mime_type matches with the + * MIME type of the registered formats + */ +AVOutputFormat *av_guess_format(const char *short_name, + const char *filename, + const char *mime_type); + +/** + * Guess the codec ID based upon muxer and filename. + */ +enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, + const char *filename, const char *mime_type, + enum AVMediaType type); + +/** + * Get timing information for the data currently output. + * The exact meaning of "currently output" depends on the format. + * It is mostly relevant for devices that have an internal buffer and/or + * work in real time. + * @param s media file handle + * @param stream stream in the media file + * @param[out] dts DTS of the last packet output for the stream, in stream + * time_base units + * @param[out] wall absolute time when that packet whas output, + * in microsecond + * @return 0 if OK, AVERROR(ENOSYS) if the format does not support it + * Note: some formats or devices may not allow to measure dts and wall + * atomically. + */ +int av_get_output_timestamp(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + + +/** + * @} + */ + + +/** + * @defgroup lavf_misc Utility functions + * @ingroup libavf + * @{ * - * @param s media file handle - * @param pkt The packet, which contains the stream_index, buf/buf_size, - dts/pts, ... - * @return < 0 on error, = 0 if OK, 1 if end of stream wanted + * Miscellaneous utility functions related to both muxing and demuxing + * (or neither). */ -int av_write_frame(AVFormatContext *s, AVPacket *pkt); /** - * Writes a packet to an output media file ensuring correct interleaving. + * Send a nice hexadecimal dump of a buffer to the specified file stream. * - * The packet must contain one audio or video frame. - * If the packets are already correctly interleaved, the application should - * call av_write_frame() instead as it is slightly faster. It is also important - * to keep in mind that completely non-interleaved input will need huge amounts - * of memory to interleave with this, so it is preferable to interleave at the - * demuxer level. + * @param f The file stream pointer where the dump should be sent to. + * @param buf buffer + * @param size buffer size * - * @param s media file handle - * @param pkt The packet, which contains the stream_index, buf/buf_size, - dts/pts, ... - * @return < 0 on error, = 0 if OK, 1 if end of stream wanted + * @see av_hex_dump_log, av_pkt_dump2, av_pkt_dump_log2 */ -int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); +void av_hex_dump(FILE *f, const uint8_t *buf, int size); /** - * Interleaves a packet per dts in an output media file. + * Send a nice hexadecimal dump of a buffer to the log. * - * Packets with pkt->destruct == av_destruct_packet will be freed inside this - * function, so they cannot be used after it. Note that calling av_free_packet() - * on them is still safe. + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param buf buffer + * @param size buffer size * - * @param s media file handle - * @param out the interleaved packet will be output here - * @param in the input packet - * @param flush 1 if no further packets are available as input and all - * remaining packets should be output - * @return 1 if a packet was output, 0 if no packet could be output, - * < 0 if an error occurred + * @see av_hex_dump, av_pkt_dump2, av_pkt_dump_log2 */ -int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, - AVPacket *pkt, int flush); +void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size); /** - * Writes the stream trailer to an output media file and frees the - * file private data. + * Send a nice dump of a packet to the specified file stream. * - * May only be called after a successful call to av_write_header. + * @param f The file stream pointer where the dump should be sent to. + * @param pkt packet to dump + * @param dump_payload True if the payload must be displayed, too. + * @param st AVStream that the packet belongs to + */ +void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st); + + +/** + * Send a nice dump of a packet to the log. * - * @param s media file handle - * @return 0 if OK, AVERROR_xxx on error + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param pkt packet to dump + * @param dump_payload True if the payload must be displayed, too. + * @param st AVStream that the packet belongs to */ -int av_write_trailer(AVFormatContext *s); +void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload, + const AVStream *st); -void dump_format(AVFormatContext *ic, - int index, - const char *url, - int is_output); +/** + * Get the AVCodecID for the given codec tag tag. + * If no codec id is found returns AV_CODEC_ID_NONE. + * + * @param tags list of supported codec_id-codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param tag codec tag to match to a codec ID + */ +enum AVCodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned int tag); -#if LIBAVFORMAT_VERSION_MAJOR < 53 /** - * Parses width and height out of string str. - * @deprecated Use av_parse_video_frame_size instead. + * Get the codec tag for the given codec id id. + * If no codec tag is found returns 0. + * + * @param tags list of supported codec_id-codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec ID to match to a codec tag */ -attribute_deprecated int parse_image_size(int *width_ptr, int *height_ptr, - const char *str); +unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum AVCodecID id); /** - * Converts framerate from a string to a fraction. - * @deprecated Use av_parse_video_frame_rate instead. + * Get the codec tag for the given codec id. + * + * @param tags list of supported codec_id - codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec id that should be searched for in the list + * @param tag A pointer to the found tag + * @return 0 if id was not found in tags, > 0 if it was found */ -attribute_deprecated int parse_frame_rate(int *frame_rate, int *frame_rate_base, - const char *arg); -#endif +int av_codec_get_tag2(const struct AVCodecTag * const *tags, enum AVCodecID id, + unsigned int *tag); + +int av_find_default_stream_index(AVFormatContext *s); /** - * Parses datestr and returns a corresponding number of microseconds. - * @param datestr String representing a date or a duration. - * - If a date the syntax is: - * @code - * [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]} - * @endcode - * Time is local time unless Z is appended, in which case it is - * interpreted as UTC. - * If the year-month-day part is not specified it takes the current - * year-month-day. - * Returns the number of microseconds since 1st of January, 1970 up to - * the time of the parsed date or INT64_MIN if datestr cannot be - * successfully parsed. - * - If a duration the syntax is: - * @code - * [-]HH[:MM[:SS[.m...]]] - * [-]S+[.m...] - * @endcode - * Returns the number of microseconds contained in a time interval - * with the specified duration or INT64_MIN if datestr cannot be - * successfully parsed. - * @param duration Flag which tells how to interpret datestr, if - * not zero datestr is interpreted as a duration, otherwise as a - * date. + * Get the index for a specific timestamp. + * + * @param st stream that the timestamp belongs to + * @param timestamp timestamp to retrieve the index for + * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond + * to the timestamp which is <= the requested one, if backward + * is 0, then it will be >= + * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise + * @return < 0 if no such timestamp could be found + */ +int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); + +/** + * Add an index entry into a sorted list. Update the entry if the list + * already contains it. + * + * @param timestamp timestamp in the time base of the given stream */ -int64_t parse_date(const char *datestr, int duration); +int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, + int size, int distance, int flags); -/** Gets the current time in microseconds. */ -int64_t av_gettime(void); -/* ffm-specific for ffserver */ -#define FFM_PACKET_SIZE 4096 -int64_t ffm_read_write_index(int fd); -int ffm_write_write_index(int fd, int64_t pos); -void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size); +/** + * Split a URL string into components. + * + * The pointers to buffers for storing individual components may be null, + * in order to ignore that component. Buffers for components not found are + * set to empty strings. If the port is not found, it is set to a negative + * value. + * + * @param proto the buffer for the protocol + * @param proto_size the size of the proto buffer + * @param authorization the buffer for the authorization + * @param authorization_size the size of the authorization buffer + * @param hostname the buffer for the host name + * @param hostname_size the size of the hostname buffer + * @param port_ptr a pointer to store the port number in + * @param path the buffer for the path + * @param path_size the size of the path buffer + * @param url the URL to split + */ +void av_url_split(char *proto, int proto_size, + char *authorization, int authorization_size, + char *hostname, int hostname_size, + int *port_ptr, + char *path, int path_size, + const char *url); + /** - * Attempts to find a specific tag in a URL. + * Print detailed information about the input or output format, such as + * duration, bitrate, streams, container, programs, metadata, side data, + * codec and time base. * - * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. - * Return 1 if found. + * @param ic the context to analyze + * @param index index of the stream to dump information about + * @param url the URL to print, such as source or destination file + * @param is_output Select whether the specified context is an input(0) or output(1) */ -int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); +void av_dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output); /** - * Returns in 'buf' the path with '%d' replaced by a number. + * Return in 'buf' the path with '%d' replaced by a number. * * Also handles the '%0nd' format where 'n' is the total number * of digits and '%%'. @@ -1306,7 +2577,7 @@ int av_get_frame_filename(char *buf, int buf_size, const char *path, int number); /** - * Checks whether filename actually is a numbered sequence generator. + * Check whether filename actually is a numbered sequence generator. * * @param filename possible numbered sequence string * @return 1 if a valid numbered sequence string, 0 otherwise @@ -1314,7 +2585,10 @@ int av_get_frame_filename(char *buf, int buf_size, int av_filename_number_test(const char *filename); /** - * Generates an SDP for an RTP session. + * Generate an SDP for an RTP session. + * + * Note, this overwrites the id values of AVStreams in the muxer contexts + * for getting unique dynamic payload types. * * @param ac array of AVFormatContexts describing the RTP streams. If the * array is composed by only one context, such context can contain @@ -1322,19 +2596,118 @@ int av_filename_number_test(const char *filename); * all the contexts in the array (an AVCodecContext per RTP stream) * must contain only one AVStream. * @param n_files number of AVCodecContexts contained in ac - * @param buff buffer where the SDP will be stored (must be allocated by - * the caller) + * @param buf buffer where the SDP will be stored (must be allocated by + * the caller) * @param size the size of the buffer * @return 0 if OK, AVERROR_xxx on error */ -int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size); +int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size); /** - * Returns a positive value if the given filename has one of the given + * Return a positive value if the given filename has one of the given * extensions, 0 otherwise. * + * @param filename file name to check against the given extensions * @param extensions a comma-separated list of filename extensions */ int av_match_ext(const char *filename, const char *extensions); +/** + * Test if the given container can store a codec. + * + * @param ofmt container to check for compatibility + * @param codec_id codec to potentially store in container + * @param std_compliance standards compliance level, one of FF_COMPLIANCE_* + * + * @return 1 if codec with ID codec_id can be stored in ofmt, 0 if it cannot. + * A negative number if this information is not available. + */ +int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id, + int std_compliance); + +/** + * @defgroup riff_fourcc RIFF FourCCs + * @{ + * Get the tables mapping RIFF FourCCs to libavcodec AVCodecIDs. The tables are + * meant to be passed to av_codec_get_id()/av_codec_get_tag() as in the + * following code: + * @code + * uint32_t tag = MKTAG('H', '2', '6', '4'); + * const struct AVCodecTag *table[] = { avformat_get_riff_video_tags(), 0 }; + * enum AVCodecID id = av_codec_get_id(table, tag); + * @endcode + */ +/** + * @return the table mapping RIFF FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_riff_video_tags(void); +/** + * @return the table mapping RIFF FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_riff_audio_tags(void); +/** + * @return the table mapping MOV FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_video_tags(void); +/** + * @return the table mapping MOV FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_audio_tags(void); + +/** + * @} + */ + +/** + * Guess the sample aspect ratio of a frame, based on both the stream and the + * frame aspect ratio. + * + * Since the frame aspect ratio is set by the codec but the stream aspect ratio + * is set by the demuxer, these two may not be equal. This function tries to + * return the value that you should use if you would like to display the frame. + * + * Basic logic is to use the stream aspect ratio if it is set to something sane + * otherwise use the frame aspect ratio. This way a container setting, which is + * usually easy to modify can override the coded value in the frames. + * + * @param format the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame with the aspect ratio to be determined + * @return the guessed (valid) sample_aspect_ratio, 0/1 if no idea + */ +AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame); + +/** + * Guess the frame rate, based on both the container and codec information. + * + * @param ctx the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame for which the frame rate should be determined, may be NULL + * @return the guessed (valid) frame rate, 0/1 if no idea + */ +AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame); + +/** + * Check if the stream st contained in s is matched by the stream specifier + * spec. + * + * See the "stream specifiers" chapter in the documentation for the syntax + * of spec. + * + * @return >0 if st is matched by spec; + * 0 if st is not matched by spec; + * AVERROR code if spec is invalid + * + * @note A stream specifier can match several streams in the format. + */ +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec); + +int avformat_queue_attached_pictures(AVFormatContext *s); + + +/** + * @} + */ + #endif /* AVFORMAT_AVFORMAT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavformat/avio.h b/extra_lib/include/ffmpeg_android/libavformat/avio.h index d186876..2210c01 100644 --- a/extra_lib/include/ffmpeg_android/libavformat/avio.h +++ b/extra_lib/include/ffmpeg_android/libavformat/avio.h @@ -21,189 +21,214 @@ #define AVFORMAT_AVIO_H /** - * @file libavformat/avio.h - * unbuffered I/O operations - * - * @warning This file has to be considered an internal but installed - * header, so it should not be directly included in your projects. + * @file + * @ingroup lavf_io + * Buffered I/O operations */ #include #include "libavutil/common.h" +#include "libavutil/dict.h" +#include "libavutil/log.h" -/* unbuffered I/O */ +#include "libavformat/version.h" -/** - * URL Context. - * New fields can be added to the end with minor version bumps. - * Removal, reordering and changes to existing fields require a major - * version bump. - * sizeof(URLContext) must not be used outside libav*. - */ -typedef struct URLContext { -#if LIBAVFORMAT_VERSION_MAJOR >= 53 - const AVClass *av_class; ///< information for av_log(). Set by url_open(). -#endif - struct URLProtocol *prot; - int flags; - int is_streamed; /**< true if streamed (no seek possible), default = false */ - int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */ - void *priv_data; - char *filename; /**< specified URL */ -} URLContext; - -typedef struct URLPollEntry { - URLContext *handle; - int events; - int revents; -} URLPollEntry; - -#define URL_RDONLY 0 -#define URL_WRONLY 1 -#define URL_RDWR 2 -typedef int URLInterruptCB(void); - -/** - * Creates an URLContext for accessing to the resource indicated by - * url, and opens it using the URLProtocol up. - * - * @param puc pointer to the location where, in case of success, the - * function puts the pointer to the created URLContext - * @param flags flags which control how the resource indicated by url - * is to be opened - * @return 0 in case of success, a negative value corresponding to an - * AVERROR code in case of failure - */ -int url_open_protocol (URLContext **puc, struct URLProtocol *up, - const char *url, int flags); +#define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */ /** - * Creates an URLContext for accessing to the resource indicated by - * url, and opens it. + * Callback for checking whether to abort blocking functions. + * AVERROR_EXIT is returned in this case by the interrupted + * function. During blocking operations, callback is called with + * opaque as parameter. If the callback returns 1, the + * blocking operation will be aborted. * - * @param puc pointer to the location where, in case of success, the - * function puts the pointer to the created URLContext - * @param flags flags which control how the resource indicated by url - * is to be opened - * @return 0 in case of success, a negative value corresponding to an - * AVERROR code in case of failure + * No members can be added to this struct without a major bump, if + * new elements have been added after this struct in AVFormatContext + * or AVIOContext. */ -int url_open(URLContext **h, const char *url, int flags); +typedef struct AVIOInterruptCB { + int (*callback)(void*); + void *opaque; +} AVIOInterruptCB; /** - * Reads up to size bytes from the resource accessed by h, and stores - * the read bytes in buf. + * Bytestream IO Context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVIOContext) must not be used outside libav*. * - * @return The number of bytes actually read, or a negative value - * corresponding to an AVERROR code in case of error. A value of zero - * indicates that it is not possible to read more from the accessed - * resource (except if the value of the size argument is also zero). - */ -int url_read(URLContext *h, unsigned char *buf, int size); + * @note None of the function pointers in AVIOContext should be called + * directly, they should only be set by the client application + * when implementing custom I/O. Normally these are set to the + * function pointers specified in avio_alloc_context() + */ +typedef struct AVIOContext { + /** + * A class for private options. + * + * If this AVIOContext is created by avio_open2(), av_class is set and + * passes the options down to protocols. + * + * If this AVIOContext is manually allocated, then av_class may be set by + * the caller. + * + * warning -- this field can be NULL, be sure to not pass this AVIOContext + * to any av_opt_* functions in that case. + */ + const AVClass *av_class; + unsigned char *buffer; /**< Start of the buffer. */ + int buffer_size; /**< Maximum buffer size */ + unsigned char *buf_ptr; /**< Current position in the buffer */ + unsigned char *buf_end; /**< End of the data, may be less than + buffer+buffer_size if the read function returned + less data than requested, e.g. for streams where + no more data has been received yet. */ + void *opaque; /**< A private pointer, passed to the read/write/seek/... + functions. */ + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); + int64_t (*seek)(void *opaque, int64_t offset, int whence); + int64_t pos; /**< position in the file of the current buffer */ + int must_flush; /**< true if the next seek should flush */ + int eof_reached; /**< true if eof reached */ + int write_flag; /**< true if open for writing */ + int max_packet_size; + unsigned long checksum; + unsigned char *checksum_ptr; + unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); + int error; /**< contains the error code or 0 if no error happened */ + /** + * Pause or resume playback for network streaming protocols - e.g. MMS. + */ + int (*read_pause)(void *opaque, int pause); + /** + * Seek to a given timestamp in stream with the specified stream_index. + * Needed for some network streaming protocols which don't support seeking + * to byte position. + */ + int64_t (*read_seek)(void *opaque, int stream_index, + int64_t timestamp, int flags); + /** + * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable. + */ + int seekable; + + /** + * max filesize, used to limit allocations + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t maxsize; + + /** + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ + int direct; + + /** + * Bytes read statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t bytes_read; + + /** + * seek statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int seek_count; + + /** + * writeout statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int writeout_count; + + /** + * Original buffer size + * used internally after probing and ensure seekback to reset the buffer size + * This field is internal to libavformat and access from outside is not allowed. + */ + int orig_buffer_size; +} AVIOContext; -/** - * Read as many bytes as possible (up to size), calling the - * read function multiple times if necessary. - * Will also retry if the read function returns AVERROR(EAGAIN). - * This makes special short-read handling in applications - * unnecessary, if the return value is < size then it is - * certain there was either an error or the end of file was reached. - */ -int url_read_complete(URLContext *h, unsigned char *buf, int size); -int url_write(URLContext *h, unsigned char *buf, int size); +/* unbuffered I/O */ /** - * Changes the position that will be used by the next read/write - * operation on the resource accessed by h. + * Return the name of the protocol that will handle the passed URL. * - * @param pos specifies the new position to set - * @param whence specifies how pos should be interpreted, it must be - * one of SEEK_SET (seek from the beginning), SEEK_CUR (seek from the - * current position), SEEK_END (seek from the end), or AVSEEK_SIZE - * (return the filesize of the requested resource, pos is ignored). - * @return a negative value corresponding to an AVERROR code in case - * of failure, or the resulting file position, measured in bytes from - * the beginning of the file. You can use this feature together with - * SEEK_CUR to read the current file position. - */ -int64_t url_seek(URLContext *h, int64_t pos, int whence); - -/** - * Closes the resource accessed by the URLContext h, and frees the - * memory used by it. + * NULL is returned if no protocol could be found for the given URL. * - * @return a negative value if an error condition occurred, 0 - * otherwise - */ -int url_close(URLContext *h); - -/** - * Returns a non-zero value if the resource indicated by url - * exists, 0 otherwise. + * @return Name of the protocol or NULL. */ -int url_exist(const char *url); - -int64_t url_filesize(URLContext *h); +const char *avio_find_protocol_name(const char *url); /** - * Return the file descriptor associated with this URL. For RTP, this - * will return only the RTP file descriptor, not the RTCP file descriptor. - * To get both, use rtp_get_file_handles(). + * Return AVIO_FLAG_* access flags corresponding to the access permissions + * of the resource in url, or a negative value corresponding to an + * AVERROR code in case of failure. The returned access flags are + * masked by the value in flags. * - * @return the file descriptor associated with this URL, or <0 on error. + * @note This function is intrinsically unsafe, in the sense that the + * checked resource may change its existence or permission status from + * one call to another. Thus you should not trust the returned value, + * unless you are sure that no other processes are accessing the + * checked resource. */ -int url_get_file_handle(URLContext *h); +int avio_check(const char *url, int flags); /** - * Return the maximum packet size associated to packetized file - * handle. If the file is not packetized (stream like HTTP or file on - * disk), then 0 is returned. + * Allocate and initialize an AVIOContext for buffered I/O. It must be later + * freed with av_free(). * - * @param h file handle - * @return maximum packet size in bytes - */ -int url_get_max_packet_size(URLContext *h); -void url_get_filename(URLContext *h, char *buf, int buf_size); - -/** - * The callback is called in blocking functions to test regulary if - * asynchronous interruption is needed. AVERROR(EINTR) is returned - * in this case by the interrupted function. 'NULL' means no interrupt - * callback is given. + * @param buffer Memory block for input/output operations via AVIOContext. + * The buffer must be allocated with av_malloc() and friends. + * @param buffer_size The buffer size is very important for performance. + * For protocols with fixed blocksize it should be set to this blocksize. + * For others a typical size is a cache page, e.g. 4kb. + * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise. + * @param opaque An opaque pointer to user-specific data. + * @param read_packet A function for refilling the buffer, may be NULL. + * @param write_packet A function for writing the buffer contents, may be NULL. + * The function may not change the input buffers content. + * @param seek A function for seeking to specified byte position, may be NULL. + * + * @return Allocated AVIOContext or NULL on failure. */ -void url_set_interrupt_cb(URLInterruptCB *interrupt_cb); +AVIOContext *avio_alloc_context( + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + int64_t (*seek)(void *opaque, int64_t offset, int whence)); -/* not implemented */ -int url_poll(URLPollEntry *poll_table, int n, int timeout); +void avio_w8(AVIOContext *s, int b); +void avio_write(AVIOContext *s, const unsigned char *buf, int size); +void avio_wl64(AVIOContext *s, uint64_t val); +void avio_wb64(AVIOContext *s, uint64_t val); +void avio_wl32(AVIOContext *s, unsigned int val); +void avio_wb32(AVIOContext *s, unsigned int val); +void avio_wl24(AVIOContext *s, unsigned int val); +void avio_wb24(AVIOContext *s, unsigned int val); +void avio_wl16(AVIOContext *s, unsigned int val); +void avio_wb16(AVIOContext *s, unsigned int val); /** - * Pause and resume playing - only meaningful if using a network streaming - * protocol (e.g. MMS). - * @param pause 1 for pause, 0 for resume + * Write a NULL-terminated string. + * @return number of bytes written. */ -int av_url_read_pause(URLContext *h, int pause); +int avio_put_str(AVIOContext *s, const char *str); /** - * Seek to a given timestamp relative to some component stream. - * Only meaningful if using a network streaming protocol (e.g. MMS.). - * @param stream_index The stream index that the timestamp is relative to. - * If stream_index is (-1) the timestamp should be in AV_TIME_BASE - * units from the beginning of the presentation. - * If a stream_index >= 0 is used and the protocol does not support - * seeking based on component streams, the call will fail with ENOTSUP. - * @param timestamp timestamp in AVStream.time_base units - * or if there is no stream specified then in AV_TIME_BASE units. - * @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE - * and AVSEEK_FLAG_ANY. The protocol may silently ignore - * AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will - * fail with ENOTSUP if used and not supported. - * @return >= 0 on success - * @see AVInputFormat::read_seek + * Convert an UTF-8 string to UTF-16LE and write it. + * @return number of bytes written. */ -int64_t av_url_read_seek(URLContext *h, int stream_index, - int64_t timestamp, int flags); +int avio_put_str16le(AVIOContext *s, const char *str); /** * Passing this as the "whence" parameter to a seek function causes it to @@ -214,312 +239,283 @@ int64_t av_url_read_seek(URLContext *h, int stream_index, /** * Oring this flag as into the "whence" parameter to a seek function causes it to - * seek by any means (like reopening and linear reading) or other normally unreasonble - * means that can be extreemly slow. + * seek by any means (like reopening and linear reading) or other normally unreasonable + * means that can be extremely slow. * This may be ignored by the seek code. */ #define AVSEEK_FORCE 0x20000 -typedef struct URLProtocol { - const char *name; - int (*url_open)(URLContext *h, const char *url, int flags); - int (*url_read)(URLContext *h, unsigned char *buf, int size); - int (*url_write)(URLContext *h, unsigned char *buf, int size); - int64_t (*url_seek)(URLContext *h, int64_t pos, int whence); - int (*url_close)(URLContext *h); - struct URLProtocol *next; - int (*url_read_pause)(URLContext *h, int pause); - int64_t (*url_read_seek)(URLContext *h, int stream_index, - int64_t timestamp, int flags); - int (*url_get_file_handle)(URLContext *h); -} URLProtocol; - -#if LIBAVFORMAT_VERSION_MAJOR < 53 -extern URLProtocol *first_protocol; -#endif - -extern URLInterruptCB *url_interrupt_cb; - /** - * If protocol is NULL, returns the first registered protocol, - * if protocol is non-NULL, returns the next registered protocol after protocol, - * or NULL if protocol is the last one. + * fseek() equivalent for AVIOContext. + * @return new position or AVERROR. */ -URLProtocol *av_protocol_next(URLProtocol *p); +int64_t avio_seek(AVIOContext *s, int64_t offset, int whence); -#if LIBAVFORMAT_VERSION_MAJOR < 53 /** - * @deprecated Use av_register_protocol() instead. + * Skip given number of bytes forward + * @return new position or AVERROR. */ -attribute_deprecated int register_protocol(URLProtocol *protocol); -#endif +int64_t avio_skip(AVIOContext *s, int64_t offset); /** - * Registers the URLProtocol protocol. + * ftell() equivalent for AVIOContext. + * @return position or AVERROR. */ -int av_register_protocol(URLProtocol *protocol); +static av_always_inline int64_t avio_tell(AVIOContext *s) +{ + return avio_seek(s, 0, SEEK_CUR); +} /** - * Bytestream IO Context. - * New fields can be added to the end with minor version bumps. - * Removal, reordering and changes to existing fields require a major - * version bump. - * sizeof(ByteIOContext) must not be used outside libav*. + * Get the filesize. + * @return filesize or AVERROR */ -typedef struct { - unsigned char *buffer; - int buffer_size; - unsigned char *buf_ptr, *buf_end; - void *opaque; - int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); - int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); - int64_t (*seek)(void *opaque, int64_t offset, int whence); - int64_t pos; /**< position in the file of the current buffer */ - int must_flush; /**< true if the next seek should flush */ - int eof_reached; /**< true if eof reached */ - int write_flag; /**< true if open for writing */ - int is_streamed; - int max_packet_size; - unsigned long checksum; - unsigned char *checksum_ptr; - unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); - int error; ///< contains the error code or 0 if no error happened - int (*read_pause)(void *opaque, int pause); - int64_t (*read_seek)(void *opaque, int stream_index, - int64_t timestamp, int flags); -} ByteIOContext; +int64_t avio_size(AVIOContext *s); -int init_put_byte(ByteIOContext *s, - unsigned char *buffer, - int buffer_size, - int write_flag, - void *opaque, - int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), - int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), - int64_t (*seek)(void *opaque, int64_t offset, int whence)); -ByteIOContext *av_alloc_put_byte( - unsigned char *buffer, - int buffer_size, - int write_flag, - void *opaque, - int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), - int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), - int64_t (*seek)(void *opaque, int64_t offset, int whence)); - -void put_byte(ByteIOContext *s, int b); -void put_buffer(ByteIOContext *s, const unsigned char *buf, int size); -void put_le64(ByteIOContext *s, uint64_t val); -void put_be64(ByteIOContext *s, uint64_t val); -void put_le32(ByteIOContext *s, unsigned int val); -void put_be32(ByteIOContext *s, unsigned int val); -void put_le24(ByteIOContext *s, unsigned int val); -void put_be24(ByteIOContext *s, unsigned int val); -void put_le16(ByteIOContext *s, unsigned int val); -void put_be16(ByteIOContext *s, unsigned int val); -void put_tag(ByteIOContext *s, const char *tag); +/** + * feof() equivalent for AVIOContext. + * @return non zero if and only if end of file + */ +int avio_feof(AVIOContext *s); +#if FF_API_URL_FEOF +/** + * @deprecated use avio_feof() + */ +attribute_deprecated +int url_feof(AVIOContext *s); +#endif -void put_strz(ByteIOContext *s, const char *buf); +/** @warning currently size is limited */ +int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); /** - * fseek() equivalent for ByteIOContext. - * @return new position or AVERROR. + * Force flushing of buffered data to the output s. + * + * Force the buffered data to be immediately written to the output, + * without to wait to fill the internal buffer. */ -int64_t url_fseek(ByteIOContext *s, int64_t offset, int whence); +void avio_flush(AVIOContext *s); /** - * Skip given number of bytes forward. - * @param offset number of bytes + * Read size bytes from AVIOContext into buf. + * @return number of bytes read or AVERROR */ -void url_fskip(ByteIOContext *s, int64_t offset); +int avio_read(AVIOContext *s, unsigned char *buf, int size); /** - * ftell() equivalent for ByteIOContext. - * @return position or AVERROR. + * @name Functions for reading from AVIOContext + * @{ + * + * @note return 0 if EOF, so you cannot use it if EOF handling is + * necessary */ -int64_t url_ftell(ByteIOContext *s); - +int avio_r8 (AVIOContext *s); +unsigned int avio_rl16(AVIOContext *s); +unsigned int avio_rl24(AVIOContext *s); +unsigned int avio_rl32(AVIOContext *s); +uint64_t avio_rl64(AVIOContext *s); +unsigned int avio_rb16(AVIOContext *s); +unsigned int avio_rb24(AVIOContext *s); +unsigned int avio_rb32(AVIOContext *s); +uint64_t avio_rb64(AVIOContext *s); /** - * Gets the filesize. - * @return filesize or AVERROR + * @} */ -int64_t url_fsize(ByteIOContext *s); /** - * feof() equivalent for ByteIOContext. - * @return non zero if and only if end of file + * Read a string from pb into buf. The reading will terminate when either + * a NULL character was encountered, maxlen bytes have been read, or nothing + * more can be read from pb. The result is guaranteed to be NULL-terminated, it + * will be truncated if buf is too small. + * Note that the string is not interpreted or validated in any way, it + * might get truncated in the middle of a sequence for multi-byte encodings. + * + * @return number of bytes read (is always <= maxlen). + * If reading ends on EOF or error, the return value will be one more than + * bytes actually read. */ -int url_feof(ByteIOContext *s); - -int url_ferror(ByteIOContext *s); - -int av_url_read_fpause(ByteIOContext *h, int pause); -int64_t av_url_read_fseek(ByteIOContext *h, int stream_index, - int64_t timestamp, int flags); +int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen); -#define URL_EOF (-1) -/** @note return URL_EOF (-1) if EOF */ -int url_fgetc(ByteIOContext *s); - -/** @warning currently size is limited */ -#ifdef __GNUC__ -int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); -#else -int url_fprintf(ByteIOContext *s, const char *fmt, ...); -#endif - -/** @note unlike fgets, the EOL character is not returned and a whole - line is parsed. return NULL if first char read was EOF */ -char *url_fgets(ByteIOContext *s, char *buf, int buf_size); - -void put_flush_packet(ByteIOContext *s); +/** + * Read a UTF-16 string from pb and convert it to UTF-8. + * The reading will terminate when either a null or invalid character was + * encountered or maxlen bytes have been read. + * @return number of bytes read (is always <= maxlen) + */ +int avio_get_str16le(AVIOContext *pb, int maxlen, char *buf, int buflen); +int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen); /** - * Reads size bytes from ByteIOContext into buf. - * @return number of bytes read or AVERROR + * @name URL open modes + * The flags argument to avio_open must be one of the following + * constants, optionally ORed with other flags. + * @{ */ -int get_buffer(ByteIOContext *s, unsigned char *buf, int size); - +#define AVIO_FLAG_READ 1 /**< read-only */ +#define AVIO_FLAG_WRITE 2 /**< write-only */ +#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */ /** - * Reads size bytes from ByteIOContext into buf. - * This reads at most 1 packet. If that is not enough fewer bytes will be - * returned. - * @return number of bytes read or AVERROR + * @} */ -int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size); - -/** @note return 0 if EOF, so you cannot use it if EOF handling is - necessary */ -int get_byte(ByteIOContext *s); -unsigned int get_le24(ByteIOContext *s); -unsigned int get_le32(ByteIOContext *s); -uint64_t get_le64(ByteIOContext *s); -unsigned int get_le16(ByteIOContext *s); - -char *get_strz(ByteIOContext *s, char *buf, int maxlen); -unsigned int get_be16(ByteIOContext *s); -unsigned int get_be24(ByteIOContext *s); -unsigned int get_be32(ByteIOContext *s); -uint64_t get_be64(ByteIOContext *s); - -uint64_t ff_get_v(ByteIOContext *bc); - -static inline int url_is_streamed(ByteIOContext *s) -{ - return s->is_streamed; -} /** - * Creates and initializes a ByteIOContext for accessing the - * resource referenced by the URLContext h. - * @note When the URLContext h has been opened in read+write mode, the - * ByteIOContext can be used only for writing. - * - * @param s Used to return the pointer to the created ByteIOContext. - * In case of failure the pointed to value is set to NULL. - * @return 0 in case of success, a negative value corresponding to an - * AVERROR code in case of failure + * Use non-blocking mode. + * If this flag is set, operations on the context will return + * AVERROR(EAGAIN) if they can not be performed immediately. + * If this flag is not set, operations on the context will never return + * AVERROR(EAGAIN). + * Note that this flag does not affect the opening/connecting of the + * context. Connecting a protocol will always block if necessary (e.g. on + * network protocols) but never hang (e.g. on busy devices). + * Warning: non-blocking protocols is work-in-progress; this flag may be + * silently ignored. */ -int url_fdopen(ByteIOContext **s, URLContext *h); +#define AVIO_FLAG_NONBLOCK 8 -/** @warning must be called before any I/O */ -int url_setbufsize(ByteIOContext *s, int buf_size); -#if LIBAVFORMAT_VERSION_MAJOR < 53 -/** Reset the buffer for reading or writing. - * @note Will drop any data currently in the buffer without transmitting it. - * @param flags URL_RDONLY to set up the buffer for reading, or URL_WRONLY - * to set up the buffer for writing. */ -int url_resetbuf(ByteIOContext *s, int flags); -#endif +/** + * Use direct mode. + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ +#define AVIO_FLAG_DIRECT 0x8000 /** - * Rewinds the ByteIOContext using the specified buffer containing the first buf_size bytes of the file. - * Used after probing to avoid seeking. - * Joins buf and s->buffer, taking any overlap into consideration. - * @note s->buffer must overlap with buf or they can't be joined and the function fails - * @note This function is NOT part of the public API + * Create and initialize a AVIOContext for accessing the + * resource indicated by url. + * @note When the resource indicated by url has been opened in + * read+write mode, the AVIOContext can be used only for writing. * - * @param s The read-only ByteIOContext to rewind - * @param buf The probe buffer containing the first buf_size bytes of the file - * @param buf_size The size of buf - * @return 0 in case of success, a negative value corresponding to an + * @param s Used to return the pointer to the created AVIOContext. + * In case of failure the pointed to value is set to NULL. + * @param url resource to access + * @param flags flags which control how the resource indicated by url + * is to be opened + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ -int ff_rewind_with_probe_data(ByteIOContext *s, unsigned char *buf, int buf_size); +int avio_open(AVIOContext **s, const char *url, int flags); /** - * Creates and initializes a ByteIOContext for accessing the + * Create and initialize a AVIOContext for accessing the * resource indicated by url. * @note When the resource indicated by url has been opened in - * read+write mode, the ByteIOContext can be used only for writing. + * read+write mode, the AVIOContext can be used only for writing. * - * @param s Used to return the pointer to the created ByteIOContext. + * @param s Used to return the pointer to the created AVIOContext. * In case of failure the pointed to value is set to NULL. + * @param url resource to access * @param flags flags which control how the resource indicated by url * is to be opened - * @return 0 in case of success, a negative value corresponding to an + * @param int_cb an interrupt callback to be used at the protocols level + * @param options A dictionary filled with protocol-private options. On return + * this parameter will be destroyed and replaced with a dict containing options + * that were not found. May be NULL. + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ -int url_fopen(ByteIOContext **s, const char *url, int flags); - -int url_fclose(ByteIOContext *s); -URLContext *url_fileno(ByteIOContext *s); +int avio_open2(AVIOContext **s, const char *url, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options); /** - * Return the maximum packet size associated to packetized buffered file - * handle. If the file is not packetized (stream like http or file on - * disk), then 0 is returned. + * Close the resource accessed by the AVIOContext s and free it. + * This function can only be used if s was opened by avio_open(). * - * @param s buffered file handle - * @return maximum packet size in bytes + * The internal buffer is automatically flushed before closing the + * resource. + * + * @return 0 on success, an AVERROR < 0 on error. + * @see avio_closep */ -int url_fget_max_packet_size(ByteIOContext *s); - -int url_open_buf(ByteIOContext **s, uint8_t *buf, int buf_size, int flags); - -/** return the written or read size */ -int url_close_buf(ByteIOContext *s); +int avio_close(AVIOContext *s); /** - * Open a write only memory stream. + * Close the resource accessed by the AVIOContext *s, free it + * and set the pointer pointing to it to NULL. + * This function can only be used if s was opened by avio_open(). * - * @param s new IO context - * @return zero if no error. + * The internal buffer is automatically flushed before closing the + * resource. + * + * @return 0 on success, an AVERROR < 0 on error. + * @see avio_close */ -int url_open_dyn_buf(ByteIOContext **s); +int avio_closep(AVIOContext **s); + /** - * Open a write only packetized memory stream with a maximum packet - * size of 'max_packet_size'. The stream is stored in a memory buffer - * with a big endian 4 byte header giving the packet size in bytes. + * Open a write only memory stream. * * @param s new IO context - * @param max_packet_size maximum packet size (must be > 0) * @return zero if no error. */ -int url_open_dyn_packet_buf(ByteIOContext **s, int max_packet_size); +int avio_open_dyn_buf(AVIOContext **s); /** * Return the written size and a pointer to the buffer. The buffer - * must be freed with av_free(). + * must be freed with av_free(). + * Padding of FF_INPUT_BUFFER_PADDING_SIZE is added to the buffer. + * * @param s IO context * @param pbuffer pointer to a byte buffer * @return the length of the byte buffer */ -int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer); +int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer); -unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, - unsigned int len); -unsigned long get_checksum(ByteIOContext *s); -void init_checksum(ByteIOContext *s, - unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), - unsigned long checksum); +/** + * Iterate through names of available protocols. + * + * @param opaque A private pointer representing current protocol. + * It must be a pointer to NULL on first iteration and will + * be updated by successive calls to avio_enum_protocols. + * @param output If set to 1, iterate over output protocols, + * otherwise over input protocols. + * + * @return A static string containing the name of current protocol or NULL + */ +const char *avio_enum_protocols(void **opaque, int output); -/* udp.c */ -int udp_set_remote_url(URLContext *h, const char *uri); -int udp_get_local_port(URLContext *h); -#if (LIBAVFORMAT_VERSION_MAJOR <= 52) -int udp_get_file_handle(URLContext *h); -#endif +/** + * Pause and resume playing - only meaningful if using a network streaming + * protocol (e.g. MMS). + * + * @param h IO context from which to call the read_pause function pointer + * @param pause 1 for pause, 0 for resume + */ +int avio_pause(AVIOContext *h, int pause); + +/** + * Seek to a given timestamp relative to some component stream. + * Only meaningful if using a network streaming protocol (e.g. MMS.). + * + * @param h IO context from which to call the seek function pointers + * @param stream_index The stream index that the timestamp is relative to. + * If stream_index is (-1) the timestamp should be in AV_TIME_BASE + * units from the beginning of the presentation. + * If a stream_index >= 0 is used and the protocol does not support + * seeking based on component streams, the call will fail. + * @param timestamp timestamp in AVStream.time_base units + * or if there is no stream specified then in AV_TIME_BASE units. + * @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE + * and AVSEEK_FLAG_ANY. The protocol may silently ignore + * AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will + * fail if used and not supported. + * @return >= 0 on success + * @see AVInputFormat::read_seek + */ +int64_t avio_seek_time(AVIOContext *h, int stream_index, + int64_t timestamp, int flags); + +/* Avoid a warning. The header can not be included because it breaks c++. */ +struct AVBPrint; + +/** + * Read contents of h into print buffer, up to max_size bytes, or up to EOF. + * + * @return 0 for success (max_size bytes read or EOF reached), negative error + * code otherwise + */ +int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size); #endif /* AVFORMAT_AVIO_H */ diff --git a/extra_lib/include/ffmpeg_android/libavformat/version.h b/extra_lib/include/ffmpeg_android/libavformat/version.h new file mode 100644 index 0000000..90e43af --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavformat/version.h @@ -0,0 +1,170 @@ +/* + * Version macros. + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_VERSION_H +#define AVFORMAT_VERSION_H + +/** + * @file + * @ingroup libavf + * Libavformat version macros + */ + +#include "libavutil/version.h" + +#define LIBAVFORMAT_VERSION_MAJOR 56 +#define LIBAVFORMAT_VERSION_MINOR 4 +#define LIBAVFORMAT_VERSION_MICRO 101 + +#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT + +#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ +#ifndef FF_API_LAVF_BITEXACT +#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LAVF_FRAC +#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LAVF_CODEC_TB +#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_URL_FEOF +#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif + +#ifndef FF_API_ALLOC_OUTPUT_CONTEXT +#define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_FORMAT_PARAMETERS +#define FF_API_FORMAT_PARAMETERS (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_NEW_STREAM +#define FF_API_NEW_STREAM (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_SET_PTS_INFO +#define FF_API_SET_PTS_INFO (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_CLOSE_INPUT_FILE +#define FF_API_CLOSE_INPUT_FILE (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_READ_PACKET +#define FF_API_READ_PACKET (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_R_FRAME_RATE +#define FF_API_R_FRAME_RATE 1 +#endif +#endif /* AVFORMAT_VERSION_H */ +/* + * Version macros. + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_VERSION_H +#define AVFORMAT_VERSION_H + +/** + * @file + * @ingroup libavf + * Libavformat version macros + */ + +#include "libavutil/version.h" + +#define LIBAVFORMAT_VERSION_MAJOR 56 +#define LIBAVFORMAT_VERSION_MINOR 4 +#define LIBAVFORMAT_VERSION_MICRO 101 + +#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT + +#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ +#ifndef FF_API_LAVF_BITEXACT +#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LAVF_FRAC +#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_LAVF_CODEC_TB +#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_URL_FEOF +#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif + +#ifndef FF_API_ALLOC_OUTPUT_CONTEXT +#define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_FORMAT_PARAMETERS +#define FF_API_FORMAT_PARAMETERS (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_NEW_STREAM +#define FF_API_NEW_STREAM (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_SET_PTS_INFO +#define FF_API_SET_PTS_INFO (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_CLOSE_INPUT_FILE +#define FF_API_CLOSE_INPUT_FILE (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_READ_PACKET +#define FF_API_READ_PACKET (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_R_FRAME_RATE +#define FF_API_R_FRAME_RATE 1 +#endif +#endif /* AVFORMAT_VERSION_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/adler32.h b/extra_lib/include/ffmpeg_android/libavutil/adler32.h new file mode 100644 index 0000000..ac95692 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/adler32.h @@ -0,0 +1,110 @@ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include +#include "attributes.h" + +/** + * @file + * Public header for libavutil Adler32 hasher + * + * @defgroup lavu_adler32 Adler32 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, + unsigned int len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include +#include "attributes.h" + +/** + * @file + * Public header for libavutil Adler32 hasher + * + * @defgroup lavu_adler32 Adler32 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, + unsigned int len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/aes.h b/extra_lib/include/ffmpeg_android/libavutil/aes.h new file mode 100644 index 0000000..3e75b92 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/aes.h @@ -0,0 +1,130 @@ +/* + * copyright (c) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * @param count number of 16 byte blocks + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ +/* + * copyright (c) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * @param count number of 16 byte blocks + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/attributes.h b/extra_lib/include/ffmpeg_android/libavutil/attributes.h index 1208bc0..7d3f4a9 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/attributes.h +++ b/extra_lib/include/ffmpeg_android/libavutil/attributes.h @@ -19,7 +19,7 @@ */ /** - * @file libavutil/attributes.h + * @file * Macro definitions for various function/variable attributes */ @@ -35,79 +35,126 @@ #ifndef av_always_inline #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define av_always_inline __forceinline #else # define av_always_inline inline #endif #endif -#ifndef av_noinline +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +# define av_extern_inline extern inline +#else +# define av_extern_inline inline +#endif +#endif + #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define av_noinline __declspec(noinline) #else # define av_noinline #endif -#endif -#ifndef av_pure #if AV_GCC_VERSION_AT_LEAST(3,1) # define av_pure __attribute__((pure)) #else # define av_pure #endif -#endif -#ifndef av_const #if AV_GCC_VERSION_AT_LEAST(2,6) # define av_const __attribute__((const)) #else # define av_const #endif -#endif -#ifndef av_cold -#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(4,3) +#if AV_GCC_VERSION_AT_LEAST(4,3) # define av_cold __attribute__((cold)) #else # define av_cold #endif -#endif -#ifndef av_flatten -#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(4,1) +#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__) # define av_flatten __attribute__((flatten)) #else # define av_flatten #endif -#endif -#ifndef attribute_deprecated #if AV_GCC_VERSION_AT_LEAST(3,1) # define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define attribute_deprecated __declspec(deprecated) #else # define attribute_deprecated #endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4,6) +# define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +# define AV_NOWARN_DEPRECATED(code) code +#endif #endif -#ifndef av_unused + #if defined(__GNUC__) # define av_unused __attribute__((unused)) #else # define av_unused #endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_used __attribute__((used)) +#else +# define av_used #endif -#ifndef av_uninit -#if defined(__GNUC__) && !defined(__ICC) +#if AV_GCC_VERSION_AT_LEAST(3,3) +# define av_alias __attribute__((may_alias)) +#else +# define av_alias +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) # define av_uninit(x) x=x #else # define av_uninit(x) x #endif -#endif #ifdef __GNUC__ # define av_builtin_constant_p __builtin_constant_p +# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) #else # define av_builtin_constant_p(x) 0 +# define av_printf_format(fmtpos, attrpos) +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,5) +# define av_noreturn __attribute__((noreturn)) +#else +# define av_noreturn #endif #endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/audio_fifo.h b/extra_lib/include/ffmpeg_android/libavutil/audio_fifo.h new file mode 100644 index 0000000..08c9075 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/audio_fifo.h @@ -0,0 +1,306 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/audioconvert.h b/extra_lib/include/ffmpeg_android/libavutil/audioconvert.h new file mode 100644 index 0000000..a86a4b0 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/audioconvert.h @@ -0,0 +1,12 @@ + +#include "version.h" + +#if FF_API_AUDIOCONVERT +#include "channel_layout.h" +#endif + +#include "version.h" + +#if FF_API_AUDIOCONVERT +#include "channel_layout.h" +#endif diff --git a/extra_lib/include/ffmpeg_android/libavutil/avassert.h b/extra_lib/include/ffmpeg_android/libavutil/avassert.h new file mode 100644 index 0000000..30f9790 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/avassert.h @@ -0,0 +1,132 @@ +/* + * copyright (c) 2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#include "avutil.h" +#include "log.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speedloss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#else +#define av_assert2(cond) ((void)0) +#endif + +#endif /* AVUTIL_AVASSERT_H */ +/* + * copyright (c) 2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#include "avutil.h" +#include "log.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speedloss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#else +#define av_assert2(cond) ((void)0) +#endif + +#endif /* AVUTIL_AVASSERT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/avconfig.h b/extra_lib/include/ffmpeg_android/libavutil/avconfig.h index b028bb4..36a8cd1 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/avconfig.h +++ b/extra_lib/include/ffmpeg_android/libavutil/avconfig.h @@ -2,4 +2,6 @@ #ifndef AVUTIL_AVCONFIG_H #define AVUTIL_AVCONFIG_H #define AV_HAVE_BIGENDIAN 0 +#define AV_HAVE_FAST_UNALIGNED 1 +#define AV_HAVE_INCOMPATIBLE_LIBAV_ABI 0 #endif /* AVUTIL_AVCONFIG_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/avstring.h b/extra_lib/include/ffmpeg_android/libavutil/avstring.h new file mode 100644 index 0000000..af4956a --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/avstring.h @@ -0,0 +1,728 @@ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Convert a number to a av_malloced string. + */ +char *av_d2str(double d); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +int av_isdigit(int c); + +/** + * Locale-independent conversion of ASCII isgraph. + */ +int av_isgraph(int c); + +/** + * Locale-independent conversion of ASCII isspace. + */ +int av_isspace(int c); + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +int av_isxdigit(int c); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + + +/** + * Thread safe basename. + * @param path the path, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the path, on DOS both \ and / are considered separators. + * @return the path with the separator replaced by the string terminator or ".". + * @note the function may change the input string. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE 0x01 + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT 0x02 + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Convert a number to a av_malloced string. + */ +char *av_d2str(double d); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +int av_isdigit(int c); + +/** + * Locale-independent conversion of ASCII isgraph. + */ +int av_isgraph(int c); + +/** + * Locale-independent conversion of ASCII isspace. + */ +int av_isspace(int c); + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +int av_isxdigit(int c); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + + +/** + * Thread safe basename. + * @param path the path, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the path, on DOS both \ and / are considered separators. + * @return the path with the separator replaced by the string terminator or ".". + * @note the function may change the input string. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE 0x01 + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT 0x02 + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/avutil.h b/extra_lib/include/ffmpeg_android/libavutil/avutil.h index 1523de6..e6ebb6c 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/avutil.h +++ b/extra_lib/include/ffmpeg_android/libavutil/avutil.h @@ -22,68 +22,323 @@ #define AVUTIL_AVUTIL_H /** - * @file libavutil/avutil.h + * @file * external API header */ +/** + * @mainpage + * + * @section ffmpeg_intro Introduction + * + * This document describes the usage of the different libraries + * provided by FFmpeg. + * + * @li @ref libavc "libavcodec" encoding/decoding library + * @li @ref lavfi "libavfilter" graph-based frame editing library + * @li @ref libavf "libavformat" I/O and muxing/demuxing library + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing + * @li @ref lpp "libpostproc" post processing library + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility + * + * Each of the FFmpeg libraries contains a version.h header, which defines a + * major, minor and micro version number with the + * LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO} macros. The major version + * number is incremented with backward incompatible changes - e.g. removing + * parts of the public API, reordering public struct members, etc. The minor + * version number is incremented for backward compatible API changes or major + * new features - e.g. adding a new public function or a new decoder. The micro + * version number is incremented for smaller changes that a calling program + * might still want to check for - e.g. changing behavior in a previously + * unspecified situation. + * + * FFmpeg guarantees backward API and ABI compatibility for each library as long + * as its major version number is unchanged. This means that no public symbols + * will be removed or renamed. Types and names of the public struct members and + * values of public macros and enums will remain the same (unless they were + * explicitly declared as not part of the public API). Documented behavior will + * not change. + * + * In other words, any correct program that works with a given FFmpeg snapshot + * should work just as well without any changes with any later snapshot with the + * same major versions. This applies to both rebuilding the program against new + * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program + * links against. + * + * However, new public symbols may be added and new members may be appended to + * public structs whose size is not part of public ABI (most public structs in + * FFmpeg). New macros and enum values may be added. Behavior in undocumented + * situations may change slightly (and be documented). All those are accompanied + * by an entry in doc/APIchanges and incrementing either the minor or micro + * version number. + */ -#define AV_STRINGIFY(s) AV_TOSTRING(s) -#define AV_TOSTRING(s) #s - -#define AV_GLUE(a, b) a ## b -#define AV_JOIN(a, b) AV_GLUE(a, b) - -#define AV_PRAGMA(s) _Pragma(#s) - -#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c) -#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c -#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) - -#define LIBAVUTIL_VERSION_MAJOR 50 -#define LIBAVUTIL_VERSION_MINOR 14 -#define LIBAVUTIL_VERSION_MICRO 0 +/** + * @defgroup lavu Common utility functions + * + * @brief + * libavutil contains the code shared across all the other FFmpeg + * libraries + * + * @note In order to use the functions provided by avutil you must include + * the specific header. + * + * @{ + * + * @defgroup lavu_crypto Crypto and Hashing + * + * @{ + * @} + * + * @defgroup lavu_math Maths + * @{ + * + * @} + * + * @defgroup lavu_string String Manipulation + * + * @{ + * + * @} + * + * @defgroup lavu_mem Memory Management + * + * @{ + * + * @} + * + * @defgroup lavu_data Data Structures + * @{ + * + * @} + * + * @defgroup lavu_audio Audio related + * + * @{ + * + * @} + * + * @defgroup lavu_error Error Codes + * + * @{ + * + * @} + * + * @defgroup lavu_log Logging Facility + * + * @{ + * + * @} + * + * @defgroup lavu_misc Other + * + * @{ + * + * @defgroup lavu_internal Internal + * + * Not exported functions, for internal usage only + * + * @{ + * + * @} + * + * @defgroup preproc_misc Preprocessor String Macros + * + * @{ + * + * @} + * + * @defgroup version_utils Library Version Macros + * + * @{ + * + * @} + */ -#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ - LIBAVUTIL_VERSION_MINOR, \ - LIBAVUTIL_VERSION_MICRO) -#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ - LIBAVUTIL_VERSION_MINOR, \ - LIBAVUTIL_VERSION_MICRO) -#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT -#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) +/** + * @addtogroup lavu_ver + * @{ + */ /** - * Returns the LIBAVUTIL_VERSION_INT constant. + * Return the LIBAVUTIL_VERSION_INT constant. */ unsigned avutil_version(void); /** - * Returns the libavutil build-time configuration. + * Return the libavutil build-time configuration. */ const char *avutil_configuration(void); /** - * Returns the libavutil license. + * Return the libavutil license. */ const char *avutil_license(void); +/** + * @} + */ + +/** + * @addtogroup lavu_media Media Type + * @brief Media Type + */ + enum AVMediaType { - AVMEDIA_TYPE_UNKNOWN = -1, + AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, - AVMEDIA_TYPE_DATA, + AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous AVMEDIA_TYPE_SUBTITLE, - AVMEDIA_TYPE_ATTACHMENT, + AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse AVMEDIA_TYPE_NB }; +/** + * Return a string describing the media_type enum, NULL if media_type + * is unknown. + */ +const char *av_get_media_type_string(enum AVMediaType media_type); + +/** + * @defgroup lavu_const Constants + * @{ + * + * @defgroup lavu_enc Encoding specific + * + * @note those definition should move to avcodec + * @{ + */ + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1< + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BASE64_H +#define AVUTIL_BASE64_H + +#include + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/blowfish.h b/extra_lib/include/ffmpeg_android/libavutil/blowfish.h new file mode 100644 index 0000000..ba4d8f5 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/blowfish.h @@ -0,0 +1,154 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/bprint.h b/extra_lib/include/ffmpeg_android/libavutil/bprint.h new file mode 100644 index 0000000..3ddfe99 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/bprint.h @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include + +#include "attributes.h" +#include "avstring.h" + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ +#define FF_PAD_STRUCTURE(size, ...) \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct { __VA_ARGS__ })]; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local "char buf[512]". + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, buf->len can be greater than buf->size and records the + * total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The size_max field determines several possible behaviours: + * + * size_max = -1 (= UINT_MAX) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * + * size_max = 0 prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using size_init = size_max = len + 1). + * + * size_max = 1 is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ +typedef struct AVBPrint { + FF_PAD_STRUCTURE(1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; + ) +} AVBPrint; + +/** + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +#define AV_BPRINT_SIZE_AUTOMATIC 1 +#define AV_BPRINT_SIZE_COUNT_ONLY 0 + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * 0 means do not write anything, just count the length; + * 1 is replaced by the maximum value for automatic storage; + * any large value means that the internal buffer will be + * reallocated as needed up to that limit; -1 is converted to + * UINT_MAX, the largest limit possible. + * Check also AV_BPRINT_SIZE_* macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * param buf bprint buffer to use + * param data pointer to data + * param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * param buf bprint buffer to use + * param fmt date and time format string, see strftime() + * param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#endif /* AVUTIL_BPRINT_H */ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include + +#include "attributes.h" +#include "avstring.h" + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ +#define FF_PAD_STRUCTURE(size, ...) \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct { __VA_ARGS__ })]; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local "char buf[512]". + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, buf->len can be greater than buf->size and records the + * total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The size_max field determines several possible behaviours: + * + * size_max = -1 (= UINT_MAX) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * + * size_max = 0 prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using size_init = size_max = len + 1). + * + * size_max = 1 is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ +typedef struct AVBPrint { + FF_PAD_STRUCTURE(1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; + ) +} AVBPrint; + +/** + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +#define AV_BPRINT_SIZE_AUTOMATIC 1 +#define AV_BPRINT_SIZE_COUNT_ONLY 0 + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * 0 means do not write anything, just count the length; + * 1 is replaced by the maximum value for automatic storage; + * any large value means that the internal buffer will be + * reallocated as needed up to that limit; -1 is converted to + * UINT_MAX, the largest limit possible. + * Check also AV_BPRINT_SIZE_* macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * param buf bprint buffer to use + * param data pointer to data + * param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * param buf bprint buffer to use + * param fmt date and time format string, see strftime() + * param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#endif /* AVUTIL_BPRINT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/bswap.h b/extra_lib/include/ffmpeg_android/libavutil/bswap.h new file mode 100644 index 0000000..01b76bc --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/bswap.h @@ -0,0 +1,218 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/bswap.h" +#elif ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_AVR32 +# include "avr32/bswap.h" +#elif ARCH_SH4 +# include "sh4/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/bswap.h" +#elif ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_AVR32 +# include "avr32/bswap.h" +#elif ARCH_SH4 +# include "sh4/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/buffer.h b/extra_lib/include/ffmpeg_android/libavutil/buffer.h new file mode 100644 index 0000000..dfbe52c --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/buffer.h @@ -0,0 +1,548 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + int size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(int size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(int size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, int size); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + * @see av_buffer_pool_can_uninit() + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + int size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(int size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(int size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, int size); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + * @see av_buffer_pool_can_uninit() + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/channel_layout.h b/extra_lib/include/ffmpeg_android/libavutil/channel_layout.h new file mode 100644 index 0000000..9810d5e --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/channel_layout.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include + +/** + * @file + * audio channel layout utility functions + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_FRONT_CENTER 0x00000004 +#define AV_CH_LOW_FREQUENCY 0x00000008 +#define AV_CH_BACK_LEFT 0x00000010 +#define AV_CH_BACK_RIGHT 0x00000020 +#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 +#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 +#define AV_CH_BACK_CENTER 0x00000100 +#define AV_CH_SIDE_LEFT 0x00000200 +#define AV_CH_SIDE_RIGHT 0x00000400 +#define AV_CH_TOP_CENTER 0x00000800 +#define AV_CH_TOP_FRONT_LEFT 0x00001000 +#define AV_CH_TOP_FRONT_CENTER 0x00002000 +#define AV_CH_TOP_FRONT_RIGHT 0x00004000 +#define AV_CH_TOP_BACK_LEFT 0x00008000 +#define AV_CH_TOP_BACK_CENTER 0x00010000 +#define AV_CH_TOP_BACK_RIGHT 0x00020000 +#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. +#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. +#define AV_CH_WIDE_LEFT 0x0000000080000000ULL +#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL +#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL +#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL +#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * Return a channel layout id that matches name, or 0 if no match is found. + * + * name can be one or several of the following notations, + * separated by '+' or '|': + * - the name of an usual channel layout (mono, stereo, 4.0, quad, 5.0, + * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); + * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, + * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); + * - a number of channels, in decimal, optionally followed by 'c', yielding + * the default channel layout for that number of channels (@see + * av_get_default_channel_layout); + * - a channel layout mask, in hexadecimal starting with "0x" (see the + * AV_CH_* macros). + * + * @warning Starting from the next major bump the trailing character + * 'c' to specify a number of channels will be required, while a + * channel layout mask could also be specified as a decimal number + * (if and only if not followed by "c"). + * + * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" + */ +uint64_t av_get_channel_layout(const char *name); + +/** + * Return a description of a channel layout. + * If nb_channels is <= 0, it is guessed from the channel_layout. + * + * @param buf put here the string containing the channel layout + * @param buf_size size in bytes of the buffer + */ +void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout); + +struct AVBPrint; +/** + * Append a description of a channel layout to a bprint buffer. + */ +void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout); + +/** + * Return the number of channels in the channel layout. + */ +int av_get_channel_layout_nb_channels(uint64_t channel_layout); + +/** + * Return default channel layout for a given number of channels. + */ +int64_t av_get_default_channel_layout(int nb_channels); + +/** + * Get the index of a channel in channel_layout. + * + * @param channel a channel layout describing exactly one channel which must be + * present in channel_layout. + * + * @return index of channel in channel_layout on success, a negative AVERROR + * on error. + */ +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel); + +/** + * Get the channel with the given index in channel_layout. + */ +uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); + +/** + * Get the name of a given channel. + * + * @return channel name on success, NULL on error. + */ +const char *av_get_channel_name(uint64_t channel); + +/** + * Get the description of a given channel. + * + * @param channel a channel layout with a single channel + * @return channel description on success, NULL on error + */ +const char *av_get_channel_description(uint64_t channel); + +/** + * Get the value and name of a standard channel layout. + * + * @param[in] index index in an internal list, starting at 0 + * @param[out] layout channel layout mask + * @param[out] name name of the layout + * @return 0 if the layout exists, + * <0 if index is beyond the limits + */ +int av_get_standard_channel_layout(unsigned index, uint64_t *layout, + const char **name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ +/* + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include + +/** + * @file + * audio channel layout utility functions + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_FRONT_CENTER 0x00000004 +#define AV_CH_LOW_FREQUENCY 0x00000008 +#define AV_CH_BACK_LEFT 0x00000010 +#define AV_CH_BACK_RIGHT 0x00000020 +#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 +#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 +#define AV_CH_BACK_CENTER 0x00000100 +#define AV_CH_SIDE_LEFT 0x00000200 +#define AV_CH_SIDE_RIGHT 0x00000400 +#define AV_CH_TOP_CENTER 0x00000800 +#define AV_CH_TOP_FRONT_LEFT 0x00001000 +#define AV_CH_TOP_FRONT_CENTER 0x00002000 +#define AV_CH_TOP_FRONT_RIGHT 0x00004000 +#define AV_CH_TOP_BACK_LEFT 0x00008000 +#define AV_CH_TOP_BACK_CENTER 0x00010000 +#define AV_CH_TOP_BACK_RIGHT 0x00020000 +#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. +#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. +#define AV_CH_WIDE_LEFT 0x0000000080000000ULL +#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL +#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL +#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL +#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * Return a channel layout id that matches name, or 0 if no match is found. + * + * name can be one or several of the following notations, + * separated by '+' or '|': + * - the name of an usual channel layout (mono, stereo, 4.0, quad, 5.0, + * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); + * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, + * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); + * - a number of channels, in decimal, optionally followed by 'c', yielding + * the default channel layout for that number of channels (@see + * av_get_default_channel_layout); + * - a channel layout mask, in hexadecimal starting with "0x" (see the + * AV_CH_* macros). + * + * @warning Starting from the next major bump the trailing character + * 'c' to specify a number of channels will be required, while a + * channel layout mask could also be specified as a decimal number + * (if and only if not followed by "c"). + * + * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" + */ +uint64_t av_get_channel_layout(const char *name); + +/** + * Return a description of a channel layout. + * If nb_channels is <= 0, it is guessed from the channel_layout. + * + * @param buf put here the string containing the channel layout + * @param buf_size size in bytes of the buffer + */ +void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout); + +struct AVBPrint; +/** + * Append a description of a channel layout to a bprint buffer. + */ +void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout); + +/** + * Return the number of channels in the channel layout. + */ +int av_get_channel_layout_nb_channels(uint64_t channel_layout); + +/** + * Return default channel layout for a given number of channels. + */ +int64_t av_get_default_channel_layout(int nb_channels); + +/** + * Get the index of a channel in channel_layout. + * + * @param channel a channel layout describing exactly one channel which must be + * present in channel_layout. + * + * @return index of channel in channel_layout on success, a negative AVERROR + * on error. + */ +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel); + +/** + * Get the channel with the given index in channel_layout. + */ +uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); + +/** + * Get the name of a given channel. + * + * @return channel name on success, NULL on error. + */ +const char *av_get_channel_name(uint64_t channel); + +/** + * Get the description of a given channel. + * + * @param channel a channel layout with a single channel + * @return channel description on success, NULL on error + */ +const char *av_get_channel_description(uint64_t channel); + +/** + * Get the value and name of a standard channel layout. + * + * @param[in] index index in an internal list, starting at 0 + * @param[out] layout channel layout mask + * @param[out] name name of the layout + * @return 0 if the layout exists, + * <0 if index is beyond the limits + */ +int av_get_standard_channel_layout(unsigned index, uint64_t *layout, + const char **name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/common.h b/extra_lib/include/ffmpeg_android/libavutil/common.h index fae0b5b..c82a3a6 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/common.h +++ b/extra_lib/include/ffmpeg_android/libavutil/common.h @@ -19,27 +19,45 @@ */ /** - * @file libavutil/common.h + * @file * common internal and external API header */ #ifndef AVUTIL_COMMON_H #define AVUTIL_COMMON_H -#include +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C) +#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS +#endif + #include #include #include #include +#include #include #include #include + #include "attributes.h" +#include "version.h" +#include "libavutil/avconfig.h" + +#if AV_HAVE_BIGENDIAN +# define AV_NE(be, le) (be) +#else +# define AV_NE(be, le) (le) +#endif //rounded division & shift #define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) /* assume b>0 */ #define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +/* assume a>0 and b>0 */ +#define FF_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ + : ((a) + (1<<(b)) - 1) >> (b)) +#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) +#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) #define FFABS(a) ((a) >= 0 ? (a) : (-(a))) #define FFSIGN(a) ((a) > 0 ? 1 : -1) @@ -53,162 +71,265 @@ #define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) /* misc math functions */ -extern const uint8_t ff_log2_tab[256]; - -extern const uint8_t av_reverse[256]; - -static inline av_const int av_log2_c(unsigned int v) -{ - int n = 0; - if (v & 0xffff0000) { - v >>= 16; - n += 16; - } - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - -static inline av_const int av_log2_16bit_c(unsigned int v) -{ - int n = 0; - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - return n; -} +/** + * Reverse the order of the bits of an 8-bits unsigned integer. + */ +#if FF_API_AV_REVERSE +extern attribute_deprecated const uint8_t av_reverse[256]; +#endif #ifdef HAVE_AV_CONFIG_H # include "config.h" # include "intmath.h" #endif +/* Pull in unguarded fallback defines at the end of this file. */ +#include "common.h" + #ifndef av_log2 -# define av_log2 av_log2_c +av_const int av_log2(unsigned v); #endif + #ifndef av_log2_16bit -# define av_log2_16bit av_log2_16bit_c +av_const int av_log2_16bit(unsigned v); #endif /** - * Clips a signed integer value into the amin-amax range. + * Clip a signed integer value into the amin-amax range. * @param a value to clip * @param amin minimum value of the clip range * @param amax maximum value of the clip range * @return clipped value */ -static inline av_const int av_clip(int a, int amin, int amax) +static av_always_inline av_const int av_clip_c(int a, int amin, int amax) { +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif if (a < amin) return amin; else if (a > amax) return amax; else return a; } /** - * Clips a signed integer value into the 0-255 range. + * Clip a signed 64bit integer value into the amin-amax range. * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range * @return clipped value */ -static inline av_const uint8_t av_clip_uint8(int a) +static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) { - if (a&(~255)) return (-a)>>31; - else return a; +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; } /** - * Clips a signed integer value into the 0-65535 range. + * Clip a signed integer value into the 0-255 range. * @param a value to clip * @return clipped value */ -static inline av_const uint16_t av_clip_uint16(int a) +static av_always_inline av_const uint8_t av_clip_uint8_c(int a) +{ + if (a&(~0xFF)) return (-a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -128,127 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int8_t av_clip_int8_c(int a) +{ + if ((a+0x80) & ~0xFF) return (a>>31) ^ 0x7F; + else return a; +} + +/** + * Clip a signed integer value into the 0-65535 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint16_t av_clip_uint16_c(int a) +{ + if (a&(~0xFFFF)) return (-a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +/** + * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) +{ + if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; +} + +/** + * Clip a signed integer to an unsigned power of two range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) +{ + if (a & ~((1<> 31 & ((1<>31; - else return a; + return av_sat_add32(a, av_sat_add32(b, b)); } /** - * Clips a signed integer value into the -32768,32767 range. + * Clip a float value into the amin-amax range. * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range * @return clipped value */ -static inline av_const int16_t av_clip_int16(int a) +static av_always_inline av_const float av_clipf_c(float a, float amin, float amax) { - if ((a+32768) & ~65535) return (a>>31) ^ 32767; - else return a; +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; } /** - * Clips a float value into the amin-amax range. + * Clip a double value into the amin-amax range. * @param a value to clip * @param amin minimum value of the clip range * @param amax maximum value of the clip range * @return clipped value */ -static inline av_const float av_clipf(float a, float amin, float amax) +static av_always_inline av_const double av_clipd_c(double a, double amin, double amax) { +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif if (a < amin) return amin; else if (a > amax) return amax; else return a; } -/** Computes ceil(log2(x)). +/** Compute ceil(log2(x)). * @param x value used to compute ceil(log2(x)) * @return computed ceiling of log2(x) */ -static inline av_const int av_ceil_log2(int x) +static av_always_inline av_const int av_ceil_log2_c(int x) { return av_log2((x - 1) << 1); } -#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) -#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24)) - -/*! - * \def GET_UTF8(val, GET_BYTE, ERROR) - * Converts a UTF-8 character (up to 4 bytes long) to its 32-bit UCS-4 encoded form - * \param val is the output and should be of type uint32_t. It holds the converted - * UCS-4 character and should be a left value. - * \param GET_BYTE gets UTF-8 encoded bytes from any proper source. It can be - * a function or a statement whose return value or evaluated value is of type - * uint8_t. It will be executed up to 4 times for values in the valid UTF-8 range, - * and up to 7 times in the general case. - * \param ERROR action that should be taken when an invalid UTF-8 byte is returned - * from GET_BYTE. It should be a statement that jumps out of the macro, - * like exit(), goto, return, break, or continue. +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount_c(uint32_t x) +{ + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount64_c(uint64_t x) +{ + return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); +} + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) +#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) + +/** + * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_BYTE Expression reading one byte from the input. + * Evaluated up to 7 times (4 for the currently + * assigned Unicode range). With a memory buffer + * input, this could be *ptr++. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + * + * @warning ERROR should not contain a loop control statement which + * could interact with the internal while loop, and should force an + * exit from the macro code (e.g. through a goto or a return) in order + * to prevent undefined results. */ #define GET_UTF8(val, GET_BYTE, ERROR)\ val= GET_BYTE;\ {\ - int ones= 7 - av_log2(val ^ 255);\ - if(ones==1)\ + uint32_t top = (val & 128) >> 1;\ + if ((val & 0xc0) == 0x80 || val >= 0xFE)\ ERROR\ - val&= 127>>ones;\ - while(--ones > 0){\ + while (val & top) {\ int tmp= GET_BYTE - 128;\ if(tmp>>6)\ ERROR\ val= (val<<6) + tmp;\ + top <<= 5;\ }\ + val &= (top << 1) - 1;\ } -/*! - * \def GET_UTF16(val, GET_16BIT, ERROR) - * Converts a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form - * \param val is the output and should be of type uint32_t. It holds the converted - * UCS-4 character and should be a left value. - * \param GET_16BIT gets two bytes of UTF-16 encoded data converted to native endianness. - * It can be a function or a statement whose return value or evaluated value is of type - * uint16_t. It will be executed up to 2 times. - * \param ERROR action that should be taken when an invalid UTF-16 surrogate is - * returned from GET_BYTE. It should be a statement that jumps out of the macro, - * like exit(), goto, return, break, or continue. +/** + * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_16BIT Expression returning two bytes of UTF-16 data converted + * to native byte order. Evaluated one or two times. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. */ #define GET_UTF16(val, GET_16BIT, ERROR)\ val = GET_16BIT;\ @@ -222,16 +343,16 @@ static inline av_const int av_ceil_log2(int x) }\ }\ -/*! - * \def PUT_UTF8(val, tmp, PUT_BYTE) - * Converts a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). - * \param val is an input-only argument and should be of type uint32_t. It holds +/** + * @def PUT_UTF8(val, tmp, PUT_BYTE) + * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). + * @param val is an input-only argument and should be of type uint32_t. It holds * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If * val is given as a function it is executed only once. - * \param tmp is a temporary variable and should be of type uint8_t. It + * @param tmp is a temporary variable and should be of type uint8_t. It * represents an intermediate value during conversion that is to be * output by PUT_BYTE. - * \param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. + * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. * It could be a function or a statement, and uses tmp as the input byte. * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be * executed up to 4 times for values in the valid UTF-8 range and up to @@ -258,16 +379,16 @@ static inline av_const int av_ceil_log2(int x) }\ } -/*! - * \def PUT_UTF16(val, tmp, PUT_16BIT) - * Converts a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). - * \param val is an input-only argument and should be of type uint32_t. It holds +/** + * @def PUT_UTF16(val, tmp, PUT_16BIT) + * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). + * @param val is an input-only argument and should be of type uint32_t. It holds * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If * val is given as a function it is executed only once. - * \param tmp is a temporary variable and should be of type uint16_t. It + * @param tmp is a temporary variable and should be of type uint16_t. It * represents an intermediate value during conversion that is to be * output by PUT_16BIT. - * \param PUT_16BIT writes the converted UTF-16 data to any proper destination + * @param PUT_16BIT writes the converted UTF-16 data to any proper destination * in desired endianness. It could be a function or a statement, and uses tmp * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" * PUT_BYTE will be executed 1 or 2 times depending on input character. @@ -295,3 +416,54 @@ static inline av_const int av_ceil_log2(int x) #endif /* HAVE_AV_CONFIG_H */ #endif /* AVUTIL_COMMON_H */ + +/* + * The following definitions are outside the multiple inclusion guard + * to ensure they are immediately available in intmath.h. + */ + +#ifndef av_ceil_log2 +# define av_ceil_log2 av_ceil_log2_c +#endif +#ifndef av_clip +# define av_clip av_clip_c +#endif +#ifndef av_clip64 +# define av_clip64 av_clip64_c +#endif +#ifndef av_clip_uint8 +# define av_clip_uint8 av_clip_uint8_c +#endif +#ifndef av_clip_int8 +# define av_clip_int8 av_clip_int8_c +#endif +#ifndef av_clip_uint16 +# define av_clip_uint16 av_clip_uint16_c +#endif +#ifndef av_clip_int16 +# define av_clip_int16 av_clip_int16_c +#endif +#ifndef av_clipl_int32 +# define av_clipl_int32 av_clipl_int32_c +#endif +#ifndef av_clip_uintp2 +# define av_clip_uintp2 av_clip_uintp2_c +#endif +#ifndef av_sat_add32 +# define av_sat_add32 av_sat_add32_c +#endif +#ifndef av_sat_dadd32 +# define av_sat_dadd32 av_sat_dadd32_c +#endif +#ifndef av_clipf +# define av_clipf av_clipf_c +#endif +#ifndef av_clipd +# define av_clipd av_clipd_c +#endif +#ifndef av_popcount +# define av_popcount av_popcount_c +#endif +#ifndef av_popcount64 +# define av_popcount64 av_popcount64_c +#endif diff --git a/extra_lib/include/ffmpeg_android/libavutil/cpu.h b/extra_lib/include/ffmpeg_android/libavutil/cpu.h new file mode 100644 index 0000000..8060cec --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/cpu.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include "attributes.h" + +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +// #if LIBAVUTIL_VERSION_MAJOR <52 +#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction +// #else +// #define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +// #endif +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_SETEND (1 <<16) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in a application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Set a mask on flags returned by av_get_cpu_flags(). + * This function is mainly useful for testing. + * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible + * + * @warning this function is not thread safe. + */ +attribute_deprecated void av_set_cpu_flags_mask(int mask); + +/** + * Parse CPU flags from a string. + * + * The returned flags contain the specified flags as well as related unspecified flags. + * + * This function exists only for compatibility with libav. + * Please use av_parse_cpu_caps() when possible. + * @return a combination of AV_CPU_* flags, negative on error. + */ +attribute_deprecated +int av_parse_cpu_flags(const char *s); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +#endif /* AVUTIL_CPU_H */ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include "attributes.h" + +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +// #if LIBAVUTIL_VERSION_MAJOR <52 +#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction +// #else +// #define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +// #endif +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_SETEND (1 <<16) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in a application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Set a mask on flags returned by av_get_cpu_flags(). + * This function is mainly useful for testing. + * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible + * + * @warning this function is not thread safe. + */ +attribute_deprecated void av_set_cpu_flags_mask(int mask); + +/** + * Parse CPU flags from a string. + * + * The returned flags contain the specified flags as well as related unspecified flags. + * + * This function exists only for compatibility with libav. + * Please use av_parse_cpu_caps() when possible. + * @return a combination of AV_CPU_* flags, negative on error. + */ +attribute_deprecated +int av_parse_cpu_flags(const char *s); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +#endif /* AVUTIL_CPU_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/crc.h b/extra_lib/include/ffmpeg_android/libavutil/crc.h new file mode 100644 index 0000000..43abe1f --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/crc.h @@ -0,0 +1,172 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#include "attributes.h" + +/** + * @defgroup lavu_crc32 CRC32 + * @ingroup lavu_crypto + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ + AV_CRC_24_IEEE = 12, + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param crc CRC of previous blocks if any or initial value for CRC + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#include "attributes.h" + +/** + * @defgroup lavu_crc32 CRC32 + * @ingroup lavu_crypto + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ + AV_CRC_24_IEEE = 12, + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param crc CRC of previous blocks if any or initial value for CRC + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/dict.h b/extra_lib/include/ffmpeg_android/libavutil/dict.h new file mode 100644 index 0000000..3f2f488 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/dict.h @@ -0,0 +1,356 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include + +#include "version.h" + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key:value pairs. To create + * an AVDictionary, simply pass an address of a NULL pointer to + * av_dict_set(). NULL can be used as an empty dictionary wherever + * a pointer to an AVDictionary is required. + * Use av_dict_get() to retrieve an entry or iterate over all + * entries and finally av_dict_free() to free the dictionary + * and all its contents. + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + * + */ + +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * To iterate through all the dictionary entries, you can set the matching key + * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key matching key + * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved + * @return found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(FF_CONST_AVUTIL53 AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key entry key to add to *pm (will be av_strduped depending on flags) + * @param value entry value to add to *pm (will be av_strduped depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set that converts the value to a string + * and stores it. + * + * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @param flags flags to use when adding to dictionary. + * AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src pointer to source AVDictionary struct + * @param flags flags to use when setting entries in *dst + * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag + */ +void av_dict_copy(AVDictionary **dst, FF_CONST_AVUTIL53 AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include + +#include "version.h" + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key:value pairs. To create + * an AVDictionary, simply pass an address of a NULL pointer to + * av_dict_set(). NULL can be used as an empty dictionary wherever + * a pointer to an AVDictionary is required. + * Use av_dict_get() to retrieve an entry or iterate over all + * entries and finally av_dict_free() to free the dictionary + * and all its contents. + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + * + */ + +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * To iterate through all the dictionary entries, you can set the matching key + * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key matching key + * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved + * @return found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(FF_CONST_AVUTIL53 AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key entry key to add to *pm (will be av_strduped depending on flags) + * @param value entry value to add to *pm (will be av_strduped depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set that converts the value to a string + * and stores it. + * + * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @param flags flags to use when adding to dictionary. + * AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src pointer to source AVDictionary struct + * @param flags flags to use when setting entries in *dst + * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag + */ +void av_dict_copy(AVDictionary **dst, FF_CONST_AVUTIL53 AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/display.h b/extra_lib/include/ffmpeg_android/libavutil/display.h new file mode 100644 index 0000000..639b873 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/display.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include + +/** + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * + * The transformation can also be more explicitly written in components as + * follows: + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame. + * The angle will be in range [-180.0, 180.0], or NaN if the matrix is + * singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure rotation by the + * specified angle (in degrees). + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param matrix an allocated transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +#endif /* AVUTIL_DISPLAY_H */ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include + +/** + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * + * The transformation can also be more explicitly written in components as + * follows: + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame. + * The angle will be in range [-180.0, 180.0], or NaN if the matrix is + * singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure rotation by the + * specified angle (in degrees). + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param matrix an allocated transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +#endif /* AVUTIL_DISPLAY_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/downmix_info.h b/extra_lib/include/ffmpeg_android/libavutil/downmix_info.h new file mode 100644 index 0000000..6d00e04 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/downmix_info.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/error.h b/extra_lib/include/ffmpeg_android/libavutil/error.h index c757981..621279a 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/error.h +++ b/extra_lib/include/ffmpeg_android/libavutil/error.h @@ -17,7 +17,7 @@ */ /** - * @file libavutil/error.h + * @file * error code definitions */ @@ -25,7 +25,14 @@ #define AVUTIL_ERROR_H #include -#include "avutil.h" +#include + +/** + * @addtogroup lavu_error + * + * @{ + */ + /* error handling */ #if EDOM > 0 @@ -37,34 +44,76 @@ #define AVUNERROR(e) (e) #endif -#if LIBAVUTIL_VERSION_MAJOR < 51 -#define AVERROR_INVALIDDATA AVERROR(EINVAL) ///< Invalid data found when processing input -#define AVERROR_IO AVERROR(EIO) ///< I/O error -#define AVERROR_NOENT AVERROR(ENOENT) ///< No such file or directory -#define AVERROR_NOFMT AVERROR(EILSEQ) ///< Unknown format -#define AVERROR_NOMEM AVERROR(ENOMEM) ///< Not enough memory -#define AVERROR_NUMEXPECTED AVERROR(EDOM) ///< Number syntax expected in filename -#define AVERROR_UNKNOWN AVERROR(EINVAL) ///< Unknown error -#endif +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) -#define AVERROR_EOF AVERROR(EPIPE) ///< End of file -#define AVERROR_NOTSUPP AVERROR(ENOSYS) ///< Operation not supported +#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found +#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 +#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small +#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found +#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found +#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found +#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file +#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted +#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library +#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found +#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found -#define AVERROR_PATCHWELCOME (-MKTAG('P','A','W','E')) ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found +/** + * This is semantically identical to AVERROR_BUG + * it has been introduced in Libav after our AVERROR_BUG and with a modified value. + */ +#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') +#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library +#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) -#if LIBAVUTIL_VERSION_MAJOR > 50 -#define AVERROR_INVALIDDATA (-MKTAG('I','N','D','A')) ///< Invalid data found when processing input -#define AVERROR_NUMEXPECTED (-MKTAG('N','U','E','X')) ///< Number syntax expected in filename -#endif +#define AV_ERROR_MAX_STRING_SIZE 64 /** - * Puts a description of the AVERROR code errnum in errbuf. + * Put a description of the AVERROR code errnum in errbuf. * In case of failure the global variable errno is set to indicate the - * error. + * error. Even in case of failure av_strerror() will print a generic + * error message indicating the errnum provided to errbuf. * + * @param errnum error code to describe + * @param errbuf buffer to which description is written * @param errbuf_size the size in bytes of errbuf - * @return 0 on success, a negative value otherwise + * @return 0 on success, a negative value if a description for errnum + * cannot be found */ int av_strerror(int errnum, char *errbuf, size_t errbuf_size); +/** + * Fill the provided buffer with a string containing an error string + * corresponding to the AVERROR code errnum. + * + * @param errbuf a buffer + * @param errbuf_size size in bytes of errbuf + * @param errnum error code to describe + * @return the buffer in input, filled with the error description + * @see av_strerror() + */ +static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) +{ + av_strerror(errnum, errbuf, errbuf_size); + return errbuf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_err2str(errnum) \ + av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) + +/** + * @} + */ + #endif /* AVUTIL_ERROR_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/eval.h b/extra_lib/include/ffmpeg_android/libavutil/eval.h new file mode 100644 index 0000000..9f06523 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/eval.h @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +#include "avutil.h" + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value for + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ +/* + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +#include "avutil.h" + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value for + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/ffversion.h b/extra_lib/include/ffmpeg_android/libavutil/ffversion.h new file mode 100644 index 0000000..6d57c2e --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/ffversion.h @@ -0,0 +1,8 @@ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "2.4.3" +#endif /* AVUTIL_FFVERSION_H */ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "2.4.3" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/fifo.h b/extra_lib/include/ffmpeg_android/libavutil/fifo.h new file mode 100644 index 0000000..09cf593 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/fifo.h @@ -0,0 +1,316 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a very simple circular buffer FIFO implementation + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef struct AVFifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; + uint32_t rndx, wndx; +} AVFifoBuffer; + +/** + * Initialize an AVFifoBuffer. + * @param size of FIFO + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc(unsigned int size); + +/** + * Initialize an AVFifoBuffer. + * @param nmemb number of elements + * @param size size of the single element + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size); + +/** + * Free an AVFifoBuffer. + * @param f AVFifoBuffer to free + */ +void av_fifo_free(AVFifoBuffer *f); + +/** + * Free an AVFifoBuffer and reset pointer to NULL. + * @param f AVFifoBuffer to free + */ +void av_fifo_freep(AVFifoBuffer **f); + +/** + * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. + * @param f AVFifoBuffer to reset + */ +void av_fifo_reset(AVFifoBuffer *f); + +/** + * Return the amount of data in bytes in the AVFifoBuffer, that is the + * amount of data you can read from it. + * @param f AVFifoBuffer to read from + * @return size + */ +int av_fifo_size(FF_CONST_AVUTIL53 AVFifoBuffer *f); + +/** + * Return the amount of space in bytes in the AVFifoBuffer, that is the + * amount of data you can write into it. + * @param f AVFifoBuffer to write into + * @return size + */ +int av_fifo_space(FF_CONST_AVUTIL53 AVFifoBuffer *f); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from a user-supplied callback to an AVFifoBuffer. + * @param f AVFifoBuffer to write to + * @param src data source; non-const since it may be used as a + * modifiable context by the function defined in func + * @param size number of bytes to write + * @param func generic write function; the first parameter is src, + * the second is dest_buf, the third is dest_buf_size. + * func must return the number of bytes written to dest_buf, or <= 0 to + * indicate no more data available to write. + * If func is NULL, src is interpreted as a simple byte array for source data. + * @return the number of bytes written to the FIFO + */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); + +/** + * Resize an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * + * @param f AVFifoBuffer to resize + * @param size new AVFifoBuffer size in bytes + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); + +/** + * Enlarge an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * The new fifo size may be larger than the requested size. + * + * @param f AVFifoBuffer to resize + * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size() + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space); + +/** + * Read and discard the specified amount of data from an AVFifoBuffer. + * @param f AVFifoBuffer to read from + * @param size amount of data to read in bytes + */ +void av_fifo_drain(AVFifoBuffer *f, int size); + +/** + * Return a pointer to the data stored in a FIFO buffer at a certain offset. + * The FIFO buffer is not modified. + * + * @param f AVFifoBuffer to peek at, f must be non-NULL + * @param offs an offset in bytes, its absolute value must be less + * than the used buffer size or the returned pointer will + * point outside to the buffer data. + * The used buffer size can be checked with av_fifo_size(). + */ +static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) +{ + uint8_t *ptr = f->rptr + offs; + if (ptr >= f->end) + ptr = f->buffer + (ptr - f->end); + else if (ptr < f->buffer) + ptr = f->end - (f->buffer - ptr); + return ptr; +} + +#endif /* AVUTIL_FIFO_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a very simple circular buffer FIFO implementation + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef struct AVFifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; + uint32_t rndx, wndx; +} AVFifoBuffer; + +/** + * Initialize an AVFifoBuffer. + * @param size of FIFO + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc(unsigned int size); + +/** + * Initialize an AVFifoBuffer. + * @param nmemb number of elements + * @param size size of the single element + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size); + +/** + * Free an AVFifoBuffer. + * @param f AVFifoBuffer to free + */ +void av_fifo_free(AVFifoBuffer *f); + +/** + * Free an AVFifoBuffer and reset pointer to NULL. + * @param f AVFifoBuffer to free + */ +void av_fifo_freep(AVFifoBuffer **f); + +/** + * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. + * @param f AVFifoBuffer to reset + */ +void av_fifo_reset(AVFifoBuffer *f); + +/** + * Return the amount of data in bytes in the AVFifoBuffer, that is the + * amount of data you can read from it. + * @param f AVFifoBuffer to read from + * @return size + */ +int av_fifo_size(FF_CONST_AVUTIL53 AVFifoBuffer *f); + +/** + * Return the amount of space in bytes in the AVFifoBuffer, that is the + * amount of data you can write into it. + * @param f AVFifoBuffer to write into + * @return size + */ +int av_fifo_space(FF_CONST_AVUTIL53 AVFifoBuffer *f); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from a user-supplied callback to an AVFifoBuffer. + * @param f AVFifoBuffer to write to + * @param src data source; non-const since it may be used as a + * modifiable context by the function defined in func + * @param size number of bytes to write + * @param func generic write function; the first parameter is src, + * the second is dest_buf, the third is dest_buf_size. + * func must return the number of bytes written to dest_buf, or <= 0 to + * indicate no more data available to write. + * If func is NULL, src is interpreted as a simple byte array for source data. + * @return the number of bytes written to the FIFO + */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); + +/** + * Resize an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * + * @param f AVFifoBuffer to resize + * @param size new AVFifoBuffer size in bytes + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); + +/** + * Enlarge an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * The new fifo size may be larger than the requested size. + * + * @param f AVFifoBuffer to resize + * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size() + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space); + +/** + * Read and discard the specified amount of data from an AVFifoBuffer. + * @param f AVFifoBuffer to read from + * @param size amount of data to read in bytes + */ +void av_fifo_drain(AVFifoBuffer *f, int size); + +/** + * Return a pointer to the data stored in a FIFO buffer at a certain offset. + * The FIFO buffer is not modified. + * + * @param f AVFifoBuffer to peek at, f must be non-NULL + * @param offs an offset in bytes, its absolute value must be less + * than the used buffer size or the returned pointer will + * point outside to the buffer data. + * The used buffer size can be checked with av_fifo_size(). + */ +static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) +{ + uint8_t *ptr = f->rptr + offs; + if (ptr >= f->end) + ptr = f->buffer + (ptr - f->end); + else if (ptr < f->buffer) + ptr = f->end - (f->buffer - ptr); + return ptr; +} + +#endif /* AVUTIL_FIFO_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/file.h b/extra_lib/include/ffmpeg_android/libavutil/file.h new file mode 100644 index 0000000..b2e36e6 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/file.h @@ -0,0 +1,132 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include + +#include "avutil.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * The returned buffer must be released with av_file_unmap(). + * + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or -1 on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + */ +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include + +#include "avutil.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * The returned buffer must be released with av_file_unmap(). + * + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or -1 on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + */ +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/frame.h b/extra_lib/include/ffmpeg_android/libavutil/frame.h new file mode 100644 index 0000000..b9c0974 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/frame.h @@ -0,0 +1,1518 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include + +#include "avutil.h" +#include "buffer.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + int size; + AVDictionary *metadata; +} AVFrameSideData; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * Similarly fields that are marked as to be only accessed by + * av_opt_ptr() can be reordered. This allows 2 forks to add fields + * without breaking compatibility with each other. + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, size in bytes of each picture line. + * For audio, size in bytes of each plane. + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + */ + int linesize[AV_NUM_DATA_POINTERS]; + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; + + /** + * width and height of the video frame + */ + int width, height; + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * 1 -> keyframe, 0-> not + */ + int key_frame; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + uint8_t *base[AV_NUM_DATA_POINTERS]; +#endif + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + + /** + * PTS copied from the AVPacket that was decoded to produce this frame. + */ + int64_t pkt_pts; + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * picture number in bitstream order + */ + int coded_picture_number; + /** + * picture number in display order + */ + int display_picture_number; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int reference; + + /** + * QP table + */ + attribute_deprecated + int8_t *qscale_table; + /** + * QP store stride + */ + attribute_deprecated + int qstride; + + attribute_deprecated + int qscale_type; + + /** + * mbskip_table[mb]>=1 if MB didn't change + * stride= mb_width = (width+15)>>4 + */ + attribute_deprecated + uint8_t *mbskip_table; + + /** + * motion vector table + * @code + * example: + * int mv_sample_log2= 4 - motion_subsample_log2; + * int mb_width= (width+15)>>4; + * int mv_stride= (mb_width << mv_sample_log2) + 1; + * motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y]; + * @endcode + */ + int16_t (*motion_val[2])[2]; + + /** + * macroblock type table + * mb_type_base + mb_width + 2 + */ + attribute_deprecated + uint32_t *mb_type; + + /** + * DCT coefficients + */ + attribute_deprecated + short *dct_coeff; + + /** + * motion reference frame index + * the order in which these are stored can depend on the codec. + */ + attribute_deprecated + int8_t *ref_index[2]; +#endif + + /** + * for some private data of the user + */ + void *opaque; + + /** + * error + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int type; +#endif + + /** + * When decoding, this signals how much the picture must be delayed. + * extra_delay = repeat_pict / (2*fps) + */ + int repeat_pict; + + /** + * The content of the picture is interlaced. + */ + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + */ + int top_field_first; + + /** + * Tell user application that palette has changed from previous frame. + */ + int palette_has_changed; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int buffer_hints; + + /** + * Pan scan. + */ + attribute_deprecated + struct AVPanScan *pan_scan; +#endif + + /** + * reordered opaque 64bit (generally an integer or a double precision float + * PTS but can be anything). + * The user sets AVCodecContext.reordered_opaque to represent the input at + * that time, + * the decoder reorders values as needed and sets AVFrame.reordered_opaque + * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque + * @deprecated in favor of pkt_pts + */ + int64_t reordered_opaque; + +#if FF_API_AVFRAME_LAVC + /** + * @deprecated this field is unused + */ + attribute_deprecated void *hwaccel_picture_private; + + attribute_deprecated + struct AVCodecContext *owner; + attribute_deprecated + void *thread_opaque; + + /** + * log2 of the size of the block which a single vector in motion_val represents: + * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2) + */ + uint8_t motion_subsample_log2; +#endif + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * Channel layout of the audio data. + */ + uint64_t channel_layout; + + /** + * AVBuffer references backing the data for this frame. If all elements of + * this array are NULL, then this frame is not reference counted. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * It must be accessed using av_frame_get_color_range() and + * av_frame_set_color_range(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * It must be accessed using av_frame_get_colorspace() and + * av_frame_set_colorspace(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * Code outside libavcodec should access this field using: + * av_frame_get_best_effort_timestamp(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * reordered pos from the last AVPacket that has been input into the decoder + * Code outside libavcodec should access this field using: + * av_frame_get_pkt_pos(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_pos; + + /** + * duration of the corresponding packet, expressed in + * AVStream->time_base units, 0 if unknown. + * Code outside libavcodec should access this field using: + * av_frame_get_pkt_duration(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_duration; + + /** + * metadata. + * Code outside libavcodec should access this field using: + * av_frame_get_metadata(frame) + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVDictionary *metadata; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * Code outside libavcodec should access this field using: + * av_frame_get_decode_error_flags(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 + + /** + * number of audio channels, only used for audio. + * Code outside libavcodec should access this field using: + * av_frame_get_channels(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int channels; + + /** + * size of the corresponding packet containing the compressed + * frame. It must be accessed using av_frame_get_pkt_size() and + * av_frame_set_pkt_size(). + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int pkt_size; + + /** + * Not to be accessed directly from outside libavutil + */ + AVBufferRef *qp_table_buf; +} AVFrame; + +/** + * Accessors for some AVFrame fields. + * The position of these field in the structure is not part of the ABI, + * they should not be accessed directly outside libavcodec. + */ +int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_duration (const AVFrame *frame); +void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_pos (const AVFrame *frame); +void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +int64_t av_frame_get_channel_layout (const AVFrame *frame); +void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +int av_frame_get_channels (const AVFrame *frame); +void av_frame_set_channels (AVFrame *frame, int val); +int av_frame_get_sample_rate (const AVFrame *frame); +void av_frame_set_sample_rate (AVFrame *frame, int val); +AVDictionary *av_frame_get_metadata (const AVFrame *frame); +void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +int av_frame_get_decode_error_flags (const AVFrame *frame); +void av_frame_set_decode_error_flags (AVFrame *frame, int val); +int av_frame_get_pkt_size(const AVFrame *frame); +void av_frame_set_pkt_size(AVFrame *frame, int val); +AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); +enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); + +/** + * Get the name of a colorspace. + * @return a static string identifying the colorspace; can be NULL. + */ +const char *av_get_colorspace_name(enum AVColorSpace val); + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everythnig contained in src to dst and reset src. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and channel_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @param frame frame in which to store the new buffers. + * @param align required buffer size alignment + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * If side data of the supplied type exists in the frame, free it and remove it + * from the frame. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include + +#include "avutil.h" +#include "buffer.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + int size; + AVDictionary *metadata; +} AVFrameSideData; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * Similarly fields that are marked as to be only accessed by + * av_opt_ptr() can be reordered. This allows 2 forks to add fields + * without breaking compatibility with each other. + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, size in bytes of each picture line. + * For audio, size in bytes of each plane. + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + */ + int linesize[AV_NUM_DATA_POINTERS]; + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; + + /** + * width and height of the video frame + */ + int width, height; + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * 1 -> keyframe, 0-> not + */ + int key_frame; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + uint8_t *base[AV_NUM_DATA_POINTERS]; +#endif + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + + /** + * PTS copied from the AVPacket that was decoded to produce this frame. + */ + int64_t pkt_pts; + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * picture number in bitstream order + */ + int coded_picture_number; + /** + * picture number in display order + */ + int display_picture_number; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int reference; + + /** + * QP table + */ + attribute_deprecated + int8_t *qscale_table; + /** + * QP store stride + */ + attribute_deprecated + int qstride; + + attribute_deprecated + int qscale_type; + + /** + * mbskip_table[mb]>=1 if MB didn't change + * stride= mb_width = (width+15)>>4 + */ + attribute_deprecated + uint8_t *mbskip_table; + + /** + * motion vector table + * @code + * example: + * int mv_sample_log2= 4 - motion_subsample_log2; + * int mb_width= (width+15)>>4; + * int mv_stride= (mb_width << mv_sample_log2) + 1; + * motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y]; + * @endcode + */ + int16_t (*motion_val[2])[2]; + + /** + * macroblock type table + * mb_type_base + mb_width + 2 + */ + attribute_deprecated + uint32_t *mb_type; + + /** + * DCT coefficients + */ + attribute_deprecated + short *dct_coeff; + + /** + * motion reference frame index + * the order in which these are stored can depend on the codec. + */ + attribute_deprecated + int8_t *ref_index[2]; +#endif + + /** + * for some private data of the user + */ + void *opaque; + + /** + * error + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int type; +#endif + + /** + * When decoding, this signals how much the picture must be delayed. + * extra_delay = repeat_pict / (2*fps) + */ + int repeat_pict; + + /** + * The content of the picture is interlaced. + */ + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + */ + int top_field_first; + + /** + * Tell user application that palette has changed from previous frame. + */ + int palette_has_changed; + +#if FF_API_AVFRAME_LAVC + attribute_deprecated + int buffer_hints; + + /** + * Pan scan. + */ + attribute_deprecated + struct AVPanScan *pan_scan; +#endif + + /** + * reordered opaque 64bit (generally an integer or a double precision float + * PTS but can be anything). + * The user sets AVCodecContext.reordered_opaque to represent the input at + * that time, + * the decoder reorders values as needed and sets AVFrame.reordered_opaque + * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque + * @deprecated in favor of pkt_pts + */ + int64_t reordered_opaque; + +#if FF_API_AVFRAME_LAVC + /** + * @deprecated this field is unused + */ + attribute_deprecated void *hwaccel_picture_private; + + attribute_deprecated + struct AVCodecContext *owner; + attribute_deprecated + void *thread_opaque; + + /** + * log2 of the size of the block which a single vector in motion_val represents: + * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2) + */ + uint8_t motion_subsample_log2; +#endif + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * Channel layout of the audio data. + */ + uint64_t channel_layout; + + /** + * AVBuffer references backing the data for this frame. If all elements of + * this array are NULL, then this frame is not reference counted. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * It must be accessed using av_frame_get_color_range() and + * av_frame_set_color_range(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * It must be accessed using av_frame_get_colorspace() and + * av_frame_set_colorspace(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * Code outside libavcodec should access this field using: + * av_frame_get_best_effort_timestamp(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * reordered pos from the last AVPacket that has been input into the decoder + * Code outside libavcodec should access this field using: + * av_frame_get_pkt_pos(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_pos; + + /** + * duration of the corresponding packet, expressed in + * AVStream->time_base units, 0 if unknown. + * Code outside libavcodec should access this field using: + * av_frame_get_pkt_duration(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_duration; + + /** + * metadata. + * Code outside libavcodec should access this field using: + * av_frame_get_metadata(frame) + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVDictionary *metadata; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * Code outside libavcodec should access this field using: + * av_frame_get_decode_error_flags(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 + + /** + * number of audio channels, only used for audio. + * Code outside libavcodec should access this field using: + * av_frame_get_channels(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int channels; + + /** + * size of the corresponding packet containing the compressed + * frame. It must be accessed using av_frame_get_pkt_size() and + * av_frame_set_pkt_size(). + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int pkt_size; + + /** + * Not to be accessed directly from outside libavutil + */ + AVBufferRef *qp_table_buf; +} AVFrame; + +/** + * Accessors for some AVFrame fields. + * The position of these field in the structure is not part of the ABI, + * they should not be accessed directly outside libavcodec. + */ +int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_duration (const AVFrame *frame); +void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_pos (const AVFrame *frame); +void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +int64_t av_frame_get_channel_layout (const AVFrame *frame); +void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +int av_frame_get_channels (const AVFrame *frame); +void av_frame_set_channels (AVFrame *frame, int val); +int av_frame_get_sample_rate (const AVFrame *frame); +void av_frame_set_sample_rate (AVFrame *frame, int val); +AVDictionary *av_frame_get_metadata (const AVFrame *frame); +void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +int av_frame_get_decode_error_flags (const AVFrame *frame); +void av_frame_set_decode_error_flags (AVFrame *frame, int val); +int av_frame_get_pkt_size(const AVFrame *frame); +void av_frame_set_pkt_size(AVFrame *frame, int val); +AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); +enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); + +/** + * Get the name of a colorspace. + * @return a static string identifying the colorspace; can be NULL. + */ +const char *av_get_colorspace_name(enum AVColorSpace val); + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everythnig contained in src to dst and reset src. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and channel_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @param frame frame in which to store the new buffers. + * @param align required buffer size alignment + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * If side data of the supplied type exists in the frame, free it and remove it + * from the frame. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/hash.h b/extra_lib/include/ffmpeg_android/libavutil/hash.h new file mode 100644 index 0000000..a28ede8 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/hash.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * @note The context is not initialized, you must call av_hash_init(). + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param i index of the hash algorithm, starting from 0 + * @return a pointer to a static string or NULL if i is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size will currently return. + * + * You can use this if you absolutely want or need to use static allocation + * and are fine with not supporting hashes newly added to libavutil without + * recompilation. + * Note that you still need to check against av_hash_get_size, adding new hashes + * with larger sizes will not be considered an ABI change and should not cause + * your code to overflow a buffer. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The pointer passed to av_hash_final have space for at least this many bytes. + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + */ +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); + +/** + * Finalize a hash context and compute the actual hash value. + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and compute the actual hash value. + * If size is smaller than the hash size, the hash is truncated; + * if size is larger, the buffer is padded with 0. + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a hex string. + * The string is always 0-terminated. + * If size is smaller than 2 * hash_size + 1, the hex string is truncated. + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a base64 string. + * The string is always 0-terminated. + * If size is smaller than AV_BASE64_SIZE(hash_size), the base64 string is + * truncated. + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context. + */ +void av_hash_freep(struct AVHashContext **ctx); + +#endif /* AVUTIL_HASH_H */ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * @note The context is not initialized, you must call av_hash_init(). + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param i index of the hash algorithm, starting from 0 + * @return a pointer to a static string or NULL if i is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size will currently return. + * + * You can use this if you absolutely want or need to use static allocation + * and are fine with not supporting hashes newly added to libavutil without + * recompilation. + * Note that you still need to check against av_hash_get_size, adding new hashes + * with larger sizes will not be considered an ABI change and should not cause + * your code to overflow a buffer. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The pointer passed to av_hash_final have space for at least this many bytes. + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + */ +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); + +/** + * Finalize a hash context and compute the actual hash value. + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and compute the actual hash value. + * If size is smaller than the hash size, the hash is truncated; + * if size is larger, the buffer is padded with 0. + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a hex string. + * The string is always 0-terminated. + * If size is smaller than 2 * hash_size + 1, the hex string is truncated. + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a base64 string. + * The string is always 0-terminated. + * If size is smaller than AV_BASE64_SIZE(hash_size), the base64 string is + * truncated. + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context. + */ +void av_hash_freep(struct AVHashContext **ctx); + +#endif /* AVUTIL_HASH_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/hmac.h b/extra_lib/include/ffmpeg_android/libavutil/hmac.h new file mode 100644 index 0000000..3da333d --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/hmac.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include + +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224 = 10, + AV_HMAC_SHA256, + AV_HMAC_SHA384, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include + +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224 = 10, + AV_HMAC_SHA256, + AV_HMAC_SHA384, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/imgutils.h b/extra_lib/include/ffmpeg_android/libavutil/imgutils.h new file mode 100644 index 0000000..bc8b585 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/imgutils.h @@ -0,0 +1,426 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include "avutil.h" +#include "pixdesc.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst_linesize linesize for the image plane in dst + * @param src_linesize linesize for the image plane in src + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_linesizes linesizes for the image in dst_data + * @param src_linesizes linesizes for the image in src_data + */ +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with !src to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesizes linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param[in] align the assumed linesize alignment + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesizes linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include "avutil.h" +#include "pixdesc.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst_linesize linesize for the image plane in dst + * @param src_linesize linesize for the image plane in src + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_linesizes linesizes for the image in dst_data + * @param src_linesizes linesizes for the image in src_data + */ +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with !src to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesizes linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param[in] align the assumed linesize alignment + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesizes linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/intfloat.h b/extra_lib/include/ffmpeg_android/libavutil/intfloat.h new file mode 100644 index 0000000..7bbd04d --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/intfloat.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/intfloat_readwrite.h b/extra_lib/include/ffmpeg_android/libavutil/intfloat_readwrite.h index 1b80fc6..1d79e3e 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/intfloat_readwrite.h +++ b/extra_lib/include/ffmpeg_android/libavutil/intfloat_readwrite.h @@ -22,19 +22,23 @@ #define AVUTIL_INTFLOAT_READWRITE_H #include + #include "attributes.h" +#include "version.h" +#if FF_API_INTFLOAT /* IEEE 80 bits extended float */ typedef struct AVExtFloat { uint8_t exponent[2]; uint8_t mantissa[8]; } AVExtFloat; -double av_int2dbl(int64_t v) av_const; -float av_int2flt(int32_t v) av_const; -double av_ext2dbl(const AVExtFloat ext) av_const; -int64_t av_dbl2int(double d) av_const; -int32_t av_flt2int(float d) av_const; -AVExtFloat av_dbl2ext(double d) av_const; +attribute_deprecated double av_int2dbl(int64_t v) av_const; +attribute_deprecated float av_int2flt(int32_t v) av_const; +attribute_deprecated double av_ext2dbl(const AVExtFloat ext) av_const; +attribute_deprecated int64_t av_dbl2int(double d) av_const; +attribute_deprecated int32_t av_flt2int(float d) av_const; +attribute_deprecated AVExtFloat av_dbl2ext(double d) av_const; +#endif /* FF_API_INTFLOAT */ #endif /* AVUTIL_INTFLOAT_READWRITE_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/intreadwrite.h b/extra_lib/include/ffmpeg_android/libavutil/intreadwrite.h new file mode 100644 index 0000000..b0886c9 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/intreadwrite.h @@ -0,0 +1,1258 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/intreadwrite.h" +#elif ARCH_AVR32 +# include "avr32/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_TOMI +# include "tomi/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(__DECC) + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. They may be implemented using MMX, + * so emms_c() must be called before using any float code + * afterwards. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/intreadwrite.h" +#elif ARCH_AVR32 +# include "avr32/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_TOMI +# include "tomi/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(__DECC) + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. They may be implemented using MMX, + * so emms_c() must be called before using any float code + * afterwards. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/lfg.h b/extra_lib/include/ffmpeg_android/libavutil/lfg.h new file mode 100644 index 0000000..305f274 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/lfg.h @@ -0,0 +1,124 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + return c->state[c->index++ & 63]; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + return c->state[c->index++ & 63] = 2*a*b+a+b; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + return c->state[c->index++ & 63]; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + return c->state[c->index++ & 63] = 2*a*b+a+b; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/log.h b/extra_lib/include/ffmpeg_android/libavutil/log.h index b0a1493..e1ff09b 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/log.h +++ b/extra_lib/include/ffmpeg_android/libavutil/log.h @@ -23,13 +23,47 @@ #include #include "avutil.h" +#include "attributes.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB, ///< not part of ABI/API +}AVClassCategory; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; /** - * Describes the class of an AVClass context structure. That is an + * Describe the class of an AVClass context structure. That is an * arbitrary struct of which the first field is a pointer to an * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). */ -typedef struct { +typedef struct AVClass { /** * The name of the class; usually it is the same name as the * context structure type to which the AVClass is associated. @@ -48,10 +82,78 @@ typedef struct { * @see av_set_default_options() */ const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added without requiring major + * version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where log_level_offset is stored. + * 0 means there is no such variable + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an av_log() implementation + * could then leverage to display the parent context. + * The offset can be NULL. + */ + int parent_log_context_offset; + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Return an AVClass corresponding to the next potential + * AVOptions-enabled child. + * + * The difference between child_next and this is that + * child_next iterates over _already existing_ objects, while + * child_class_next iterates over _all possible_ children. + */ + const struct AVClass* (*child_class_next)(const struct AVClass *prev); + + /** + * Category used for visualization (like color) + * This is only set if the category is equal for all objects using this class. + * available since version (51 << 16 | 56 << 8 | 100) + */ + AVClassCategory category; + + /** + * Callback to return the category. + * available since version (51 << 16 | 59 << 8 | 100) + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + * available since version (52.12) + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); } AVClass; -/* av_log API */ +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ +/** + * Print no output. + */ #define AV_LOG_QUIET -8 /** @@ -78,7 +180,14 @@ typedef struct { */ #define AV_LOG_WARNING 24 +/** + * Standard information. + */ #define AV_LOG_INFO 32 + +/** + * Detailed information. + */ #define AV_LOG_VERBOSE 40 /** @@ -86,30 +195,156 @@ typedef struct { */ #define AV_LOG_DEBUG 48 +#define AV_LOG_MAX_OFFSET (AV_LOG_DEBUG - AV_LOG_QUIET) + /** - * Sends the specified message to the log if the level is less than or equal + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) (x << 8) + +/** + * Send the specified message to the log if the level is less than or equal * to the current av_log_level. By default, all logging messages are sent to - * stderr. This behavior can be altered by setting a different av_vlog callback + * stderr. This behavior can be altered by setting a different logging callback * function. + * @see av_log_set_callback * * @param avcl A pointer to an arbitrary struct of which the first field is a - * pointer to an AVClass struct. - * @param level The importance level of the message, lower values signifying - * higher importance. + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". * @param fmt The format string (printf-compatible) that specifies how - * subsequent arguments are converted to output. - * @see av_vlog + * subsequent arguments are converted to output. */ -#ifdef __GNUC__ -void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); + + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formated line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * av_dlog macros + * Useful to print debug messages that shouldn't get compiled in normally. + */ + +#ifdef DEBUG +# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) #else -void av_log(void*, int level, const char *fmt, ...); +# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) #endif -void av_vlog(void*, int level, const char *fmt, va_list); -int av_log_get_level(void); -void av_log_set_level(int); -void av_log_set_callback(void (*)(void*, int, const char*, va_list)); -void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl); +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ #endif /* AVUTIL_LOG_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/lzo.h b/extra_lib/include/ffmpeg_android/libavutil/lzo.h new file mode 100644 index 0000000..32fbaba --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/lzo.h @@ -0,0 +1,132 @@ +/* + * LZO 1x decompression + * copyright (c) 2006 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LZO_H +#define AVUTIL_LZO_H + +/** + * @defgroup lavu_lzo LZO + * @ingroup lavu_crypto + * + * @{ + */ + +#include + +/** @name Error flags returned by av_lzo1x_decode + * @{ */ +/// end of the input buffer reached before decoding finished +#define AV_LZO_INPUT_DEPLETED 1 +/// decoded data did not fit into output buffer +#define AV_LZO_OUTPUT_FULL 2 +/// a reference to previously decoded data was wrong +#define AV_LZO_INVALID_BACKPTR 4 +/// a non-specific error in the compressed bitstream +#define AV_LZO_ERROR 8 +/** @} */ + +#define AV_LZO_INPUT_PADDING 8 +#define AV_LZO_OUTPUT_PADDING 12 + +/** + * @brief Decodes LZO 1x compressed data. + * @param out output buffer + * @param outlen size of output buffer, number of bytes left are returned here + * @param in input buffer + * @param inlen size of input buffer, number of bytes left are returned here + * @return 0 on success, otherwise a combination of the error flags above + * + * Make sure all buffers are appropriately padded, in must provide + * AV_LZO_INPUT_PADDING, out must provide AV_LZO_OUTPUT_PADDING additional bytes. + */ +int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen); + +/** + * @} + */ + +#endif /* AVUTIL_LZO_H */ +/* + * LZO 1x decompression + * copyright (c) 2006 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LZO_H +#define AVUTIL_LZO_H + +/** + * @defgroup lavu_lzo LZO + * @ingroup lavu_crypto + * + * @{ + */ + +#include + +/** @name Error flags returned by av_lzo1x_decode + * @{ */ +/// end of the input buffer reached before decoding finished +#define AV_LZO_INPUT_DEPLETED 1 +/// decoded data did not fit into output buffer +#define AV_LZO_OUTPUT_FULL 2 +/// a reference to previously decoded data was wrong +#define AV_LZO_INVALID_BACKPTR 4 +/// a non-specific error in the compressed bitstream +#define AV_LZO_ERROR 8 +/** @} */ + +#define AV_LZO_INPUT_PADDING 8 +#define AV_LZO_OUTPUT_PADDING 12 + +/** + * @brief Decodes LZO 1x compressed data. + * @param out output buffer + * @param outlen size of output buffer, number of bytes left are returned here + * @param in input buffer + * @param inlen size of input buffer, number of bytes left are returned here + * @return 0 on success, otherwise a combination of the error flags above + * + * Make sure all buffers are appropriately padded, in must provide + * AV_LZO_INPUT_PADDING, out must provide AV_LZO_OUTPUT_PADDING additional bytes. + */ +int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen); + +/** + * @} + */ + +#endif /* AVUTIL_LZO_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/macros.h b/extra_lib/include/ffmpeg_android/libavutil/macros.h new file mode 100644 index 0000000..3df0218 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/macros.h @@ -0,0 +1,96 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#endif /* AVUTIL_MACROS_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#endif /* AVUTIL_MACROS_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/mathematics.h b/extra_lib/include/ffmpeg_android/libavutil/mathematics.h index e198aef..ac94488 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/mathematics.h +++ b/extra_lib/include/ffmpeg_android/libavutil/mathematics.h @@ -1,5 +1,5 @@ /* - * copyright (c) 2005 Michael Niedermayer + * copyright (c) 2005-2012 Michael Niedermayer * * This file is part of FFmpeg. * @@ -25,6 +25,7 @@ #include #include "attributes.h" #include "rational.h" +#include "intfloat.h" #ifndef M_E #define M_E 2.7182818284590452354 /* e */ @@ -38,9 +39,15 @@ #ifndef M_LOG2_10 #define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ #endif +#ifndef M_PHI +#define M_PHI 1.61803398874989484820 /* phi / golden ratio */ +#endif #ifndef M_PI #define M_PI 3.14159265358979323846 /* pi */ #endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif #ifndef M_SQRT1_2 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ #endif @@ -48,51 +55,110 @@ #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ #endif #ifndef NAN -#define NAN (0.0/0.0) +#define NAN av_int2float(0x7fc00000) #endif #ifndef INFINITY -#define INFINITY (1.0/0.0) +#define INFINITY av_int2float(0x7f800000) #endif +/** + * @addtogroup lavu_math + * @{ + */ + + enum AVRounding { AV_ROUND_ZERO = 0, ///< Round toward zero. AV_ROUND_INF = 1, ///< Round away from zero. AV_ROUND_DOWN = 2, ///< Round toward -infinity. AV_ROUND_UP = 3, ///< Round toward +infinity. AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. + AV_ROUND_PASS_MINMAX = 8192, ///< Flag to pass INT64_MIN/MAX through instead of rescaling, this avoids special cases for AV_NOPTS_VALUE }; /** - * Returns the greatest common divisor of a and b. + * Return the greatest common divisor of a and b. * If both a and b are 0 or either or both are <0 then behavior is * undefined. */ int64_t av_const av_gcd(int64_t a, int64_t b); /** - * Rescales a 64-bit integer with rounding to nearest. + * Rescale a 64-bit integer with rounding to nearest. * A simple a*b/c isn't possible as it can overflow. */ int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; /** - * Rescales a 64-bit integer with specified rounding. + * Rescale a 64-bit integer with specified rounding. * A simple a*b/c isn't possible as it can overflow. + * + * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is + * INT64_MIN or INT64_MAX then a is passed through unchanged. */ int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const; /** - * Rescales a 64-bit integer by 2 rational numbers. + * Rescale a 64-bit integer by 2 rational numbers. */ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; /** - * Compares 2 timestamps each in its own timebases. + * Rescale a 64-bit integer by 2 rational numbers with specified rounding. + * + * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is + * INT64_MIN or INT64_MAX then a is passed through unchanged. + */ +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding) av_const; + +/** + * Compare 2 timestamps each in its own timebases. * The result of the function is undefined if one of the timestamps * is outside the int64_t range when represented in the others timebase. * @return -1 if ts_a is before ts_b, 1 if ts_a is after ts_b or 0 if they represent the same position */ int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); +/** + * Compare 2 integers modulo mod. + * That is we compare integers a and b for which only the least + * significant log2(mod) bits are known. + * + * @param mod must be a power of 2 + * @return a negative value if a is smaller than b + * a positive value if a is greater than b + * 0 if a equals b + */ +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * Rescale a timestamp while preserving known durations. + * + * @param in_ts Input timestamp + * @param in_tb Input timebase + * @param fs_tb Duration and *last timebase + * @param duration duration till the next call + * @param out_tb Output timebase + */ +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb); + +/** + * Add a value to a timestamp. + * + * This function guarantees that when the same value is repeatly added that + * no accumulation of rounding errors occurs. + * + * @param ts Input timestamp + * @param ts_tb Input timestamp timebase + * @param inc value to add to ts + * @param inc_tb inc timebase + */ +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc); + + + /** + * @} + */ #endif /* AVUTIL_MATHEMATICS_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/md5.h b/extra_lib/include/ffmpeg_android/libavutil/md5.h new file mode 100644 index 0000000..2096294 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/md5.h @@ -0,0 +1,162 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len); + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len); + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/mem.h b/extra_lib/include/ffmpeg_android/libavutil/mem.h index fffbb87..2a1e36d 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/mem.h +++ b/extra_lib/include/ffmpeg_android/libavutil/mem.h @@ -19,16 +19,27 @@ */ /** - * @file libavutil/mem.h + * @file * memory handling functions */ #ifndef AVUTIL_MEM_H #define AVUTIL_MEM_H +#include +#include + #include "attributes.h" +#include "error.h" +#include "avutil.h" + +/** + * @addtogroup lavu_mem + * @{ + */ + -#if defined(__ICC) || defined(__SUNPRO_C) +#if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v #elif defined(__TI_COMPILER_VERSION__) @@ -40,7 +51,7 @@ static const t __attribute__((aligned(n))) v #elif defined(__GNUC__) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v - #define DECLARE_ASM_CONST(n,t,v) static const t attribute_used __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v #elif defined(_MSC_VER) #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v @@ -55,38 +66,126 @@ #define av_malloc_attrib #endif -#if (!defined(__ICC) || __ICC > 1110) && AV_GCC_VERSION_AT_LEAST(4,3) - #define av_alloc_size(n) __attribute__((alloc_size(n))) +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) #else - #define av_alloc_size(n) + #define av_alloc_size(...) #endif /** - * Allocates a block of size bytes with alignment suitable for all + * Allocate a block of size bytes with alignment suitable for all * memory accesses (including vectors if available on the CPU). * @param size Size in bytes for the memory block to be allocated. * @return Pointer to the allocated block, NULL if the block cannot * be allocated. * @see av_mallocz() */ -void *av_malloc(unsigned int size) av_malloc_attrib av_alloc_size(1); +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); /** - * Allocates or reallocates a block of memory. - * If ptr is NULL and size > 0, allocates a new block. If - * size is zero, frees the memory block pointed to by ptr. - * @param size Size in bytes for the memory block to be allocated or - * reallocated. + * Allocate a block of size * nmemb bytes with av_malloc(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_malloc() + */ +av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +/** + * Allocate or reallocate a block of memory. + * If ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. * @param ptr Pointer to a memory block already allocated with - * av_malloc(z)() or av_realloc() or NULL. - * @return Pointer to a newly reallocated block or NULL if the block + * av_realloc() or NULL. + * @param size Size in bytes of the memory block to be allocated or + * reallocated. + * @return Pointer to a newly-reallocated block or NULL if the block * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. * @see av_fast_realloc() */ -void *av_realloc(void *ptr, unsigned int size) av_alloc_size(2); +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate or reallocate a block of memory. + * This function does the same thing as av_realloc, except: + * - It takes two arguments and checks the result of the multiplication for + * integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic "buf = realloc(buf); if (!buf) return -1;". + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); /** - * Frees a memory block which has been allocated with av_malloc(z)() or + * Allocate or reallocate a block of memory. + * If *ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or pointer to a pointer to NULL. + * The pointer is updated on success, or freed on failure. + * @param size Size in bytes for the memory block to be allocated or + * reallocated + * @return Zero on success, an AVERROR error code on failure. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_reallocp(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate or reallocate an array. + * If ptr is NULL and nmemb > 0, allocate a new block. If + * nmemb is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or NULL. + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate or reallocate an array through a pointer to a pointer. + * If *ptr is NULL and nmemb > 0, allocate a new block. If + * nmemb is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or pointer to a pointer to NULL. + * The pointer is updated on success, or freed on failure. + * @param nmemb Number of elements + * @param size Size of the single element + * @return Zero on success, an AVERROR error code on failure. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_alloc_size(2, 3) int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or * av_realloc(). * @param ptr Pointer to the memory block which should be freed. * @note ptr = NULL is explicitly allowed. @@ -96,30 +195,195 @@ void *av_realloc(void *ptr, unsigned int size) av_alloc_size(2); void av_free(void *ptr); /** - * Allocates a block of size bytes with alignment suitable for all + * Allocate a block of size bytes with alignment suitable for all * memory accesses (including vectors if available on the CPU) and - * zeroes all the bytes of the block. + * zero all the bytes of the block. * @param size Size in bytes for the memory block to be allocated. * @return Pointer to the allocated block, NULL if it cannot be allocated. * @see av_malloc() */ -void *av_mallocz(unsigned int size) av_malloc_attrib av_alloc_size(1); +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); /** - * Duplicates the string s. + * Allocate a block of nmemb * size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU) and + * zero all the bytes of the block. + * The allocation will fail if nmemb * size is greater than or equal + * to INT_MAX. + * @param nmemb + * @param size + * @return Pointer to the allocated block, NULL if it cannot be allocated. + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib; + +/** + * Allocate a block of size * nmemb bytes with av_mallocz(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + * @see av_malloc_array() + */ +av_alloc_size(1, 2) static inline void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +/** + * Duplicate the string s. * @param s string to be duplicated - * @return Pointer to a newly allocated string containing a + * @return Pointer to a newly-allocated string containing a * copy of s or NULL if the string cannot be allocated. */ char *av_strdup(const char *s) av_malloc_attrib; /** - * Frees a memory block which has been allocated with av_malloc(z)() or + * Duplicate a substring of the string s. + * @param s string to be duplicated + * @param len the maximum length of the resulting string (not counting the + * terminating byte). + * @return Pointer to a newly-allocated string containing a + * copy of s or NULL if the string cannot be allocated. + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate the buffer p. + * @param p buffer to be duplicated + * @return Pointer to a newly allocated buffer containing a + * copy of p or NULL if the buffer cannot be allocated. + */ +void *av_memdup(const void *p, size_t size); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or * av_realloc() and set the pointer pointing to it to NULL. * @param ptr Pointer to the pointer to the memory block which should * be freed. + * @note passing a pointer to a NULL pointer is safe and leads to no action. * @see av_free() */ void av_freep(void *ptr); +/** + * Add an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by nb_ptr + * is incremented. + * In case of failure, the array is freed, *tab_ptr is set to NULL and + * *nb_ptr is set to 0. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem element to add + * @return >=0 on success, negative otherwise. + * @see av_dynarray_add(), av_dynarray2_add() + */ +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size elem_size to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by nb_ptr + * is incremented. + * In case of failure, the array is freed, *tab_ptr is set to NULL and + * *nb_ptr is set to 0. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem_size size in bytes of the elements in the array + * @param elem_data pointer to the data of the element to add. If NULL, the space of + * the new added element is not filled. + * @return pointer to the data of the element to copy in the new allocated space. + * If NULL, the new allocated space is left uninitialized." + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * Multiply two size_t values checking for overflow. + * @return 0 if success, AVERROR(EINVAL) if overflow. + */ +static inline int av_size_mult(size_t a, size_t b, size_t *r) +{ + size_t t = a * b; + /* Hack inspired from glibc: only try the division if nelem and elsize + * are both greater than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); + *r = t; + return 0; +} + +/** + * Set the maximum size that may me allocated in one block. + */ +void av_max_alloc(size_t max); + +/** + * deliberately overlapping memcpy implementation + * @param dst destination buffer + * @param back how many bytes back we start (the initial size of the overlapping window), must be > 0 + * @param cnt number of bytes to copy, must be >= 0 + * + * cnt > back is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of back. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * Reallocate the given block if it is not large enough, otherwise do nothing. + * + * @see av_realloc + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special + * handling to avoid memleaks is necessary. + * + * @param ptr pointer to pointer to already allocated buffer, overwritten with pointer to new buffer + * @param size size of the buffer *ptr points to + * @param min_size minimum size of *ptr buffer after returning, *ptr will be NULL and + * *size 0 if an error occurred. + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * @} + */ + #endif /* AVUTIL_MEM_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/motion_vector.h b/extra_lib/include/ffmpeg_android/libavutil/motion_vector.h new file mode 100644 index 0000000..acd01f8 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/motion_vector.h @@ -0,0 +1,100 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/murmur3.h b/extra_lib/include/ffmpeg_android/libavutil/murmur3.h new file mode 100644 index 0000000..42ea7ee --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/murmur3.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include + +struct AVMurMur3 *av_murmur3_alloc(void); +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); +void av_murmur3_init(struct AVMurMur3 *c); +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +#endif /* AVUTIL_MURMUR3_H */ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include + +struct AVMurMur3 *av_murmur3_alloc(void); +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); +void av_murmur3_init(struct AVMurMur3 *c); +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +#endif /* AVUTIL_MURMUR3_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/old_pix_fmts.h b/extra_lib/include/ffmpeg_android/libavutil/old_pix_fmts.h new file mode 100644 index 0000000..30dfab1 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/old_pix_fmts.h @@ -0,0 +1,354 @@ +/* + * copyright (c) 2006-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OLD_PIX_FMTS_H +#define AVUTIL_OLD_PIX_FMTS_H + +/* + * This header exists to prevent new pixel formats from being accidentally added + * to the deprecated list. + * Do not include it directly. It will be removed on next major bump + * + * Do not add new items to this list. Use the AVPixelFormat enum instead. + */ + PIX_FMT_NONE = AV_PIX_FMT_NONE, + PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + PIX_FMT_GRAY8, ///< Y , 8bpp + PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette + PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range + PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range + PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range +#if FF_API_XVMC + PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing + PIX_FMT_XVMC_MPEG2_IDCT, +#endif /* FF_API_XVMC */ + PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of PIX_FMT_YUV440P and setting color_range + PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) +#if FF_API_VDPAU + PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 + PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 + + PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1 + PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1 + + PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + + PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian +#if FF_API_VDPAU + PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 + PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 + PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1 + PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1 + PIX_FMT_GRAY8A, ///< 8bit gray, 8bit alpha + PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + //the following 10 formats have the disadvantage of needing 1 format for each bit depth, thus + //If you want to support multiple bit depths, then using PIX_FMT_YUV420P16* with the bpp stored separately + //is better + PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_VDA_VLD, ///< hardware decoding through VDA + +#ifdef AV_PIX_FMT_ABI_GIT_MASTER + PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big endian + PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little endian + PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big endian + PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little endian + PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big endian + PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little endian + +#ifndef AV_PIX_FMT_ABI_GIT_MASTER + PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + PIX_FMT_0RGB=0x123+4, ///< packed RGB 8:8:8, 32bpp, 0RGB0RGB... + PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGB0RGB0... + PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, 0BGR0BGR... + PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGR0BGR0... + PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + + PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big endian + PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little endian + PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big endian + PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little endian + + PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +#endif /* AVUTIL_OLD_PIX_FMTS_H */ +/* + * copyright (c) 2006-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OLD_PIX_FMTS_H +#define AVUTIL_OLD_PIX_FMTS_H + +/* + * This header exists to prevent new pixel formats from being accidentally added + * to the deprecated list. + * Do not include it directly. It will be removed on next major bump + * + * Do not add new items to this list. Use the AVPixelFormat enum instead. + */ + PIX_FMT_NONE = AV_PIX_FMT_NONE, + PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + PIX_FMT_GRAY8, ///< Y , 8bpp + PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette + PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range + PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range + PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range +#if FF_API_XVMC + PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing + PIX_FMT_XVMC_MPEG2_IDCT, +#endif /* FF_API_XVMC */ + PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of PIX_FMT_YUV440P and setting color_range + PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) +#if FF_API_VDPAU + PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0 + PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0 + + PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1 + PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1 + + PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + + PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian +#if FF_API_VDPAU + PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0 + PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0 + PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1 + PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1 + PIX_FMT_GRAY8A, ///< 8bit gray, 8bit alpha + PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + //the following 10 formats have the disadvantage of needing 1 format for each bit depth, thus + //If you want to support multiple bit depths, then using PIX_FMT_YUV420P16* with the bpp stored separately + //is better + PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_VDA_VLD, ///< hardware decoding through VDA + +#ifdef AV_PIX_FMT_ABI_GIT_MASTER + PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big endian + PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little endian + PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big endian + PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little endian + PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big endian + PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little endian + +#ifndef AV_PIX_FMT_ABI_GIT_MASTER + PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian +#endif + PIX_FMT_0RGB=0x123+4, ///< packed RGB 8:8:8, 32bpp, 0RGB0RGB... + PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGB0RGB0... + PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, 0BGR0BGR... + PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGR0BGR0... + PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + + PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big endian + PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little endian + PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big endian + PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little endian + + PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +#endif /* AVUTIL_OLD_PIX_FMTS_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/opt.h b/extra_lib/include/ffmpeg_android/libavutil/opt.h new file mode 100644 index 0000000..fb1a105 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/opt.h @@ -0,0 +1,1718 @@ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_malloc(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_next() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_next(const AVClass *prev) + * { + * return prev ? NULL : &child_class; + * } + * @endcode + * Putting child_next() and child_class_next() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_next() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_next() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_next() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_next() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This allows to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +enum AVOptionType{ + AV_OPT_TYPE_FLAGS, + AV_OPT_TYPE_INT, + AV_OPT_TYPE_INT64, + AV_OPT_TYPE_DOUBLE, + AV_OPT_TYPE_FLOAT, + AV_OPT_TYPE_STRING, + AV_OPT_TYPE_RATIONAL, + AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + AV_OPT_TYPE_DICT, + AV_OPT_TYPE_CONST = 128, + AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), + AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'), + AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational + AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), + AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), + AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'), +#if FF_API_OLD_AVOPTIONS + FF_OPT_TYPE_FLAGS = 0, + FF_OPT_TYPE_INT, + FF_OPT_TYPE_INT64, + FF_OPT_TYPE_DOUBLE, + FF_OPT_TYPE_FLOAT, + FF_OPT_TYPE_STRING, + FF_OPT_TYPE_RATIONAL, + FF_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + FF_OPT_TYPE_CONST=128, +#endif +}; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + int flags; +#define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding +#define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding +#if FF_API_OPT_TYPE_METADATA +#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... +#endif +#define AV_OPT_FLAG_AUDIO_PARAM 8 +#define AV_OPT_FLAG_VIDEO_PARAM 16 +#define AV_OPT_FLAG_SUBTITLE_PARAM 32 +/** + * The option is inteded for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT 64 +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +//FIXME think about enc-audio, ... style flags + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of componentes. + */ + int nb_components; +} AVOptionRanges; + + +#if FF_API_FIND_OPT +/** + * Look for an option in obj. Look only for the options which + * have the flags set as specified in mask and flags (that is, + * for which it is the case that (opt->flags & mask) == flags). + * + * @param[in] obj a pointer to a struct whose first element is a + * pointer to an AVClass + * @param[in] name the name of the option to look for + * @param[in] unit the unit of the option to look for, or any if NULL + * @return a pointer to the option found, or NULL if no option + * has been found + * + * @deprecated use av_opt_find. + */ +attribute_deprecated +const AVOption *av_find_opt(void *obj, const char *name, const char *unit, int mask, int flags); +#endif + +#if FF_API_OLD_AVOPTIONS +/** + * Set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an + * AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. If the field is not of a string + * type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param[out] o_out if non-NULL put here a pointer to the AVOption + * found + * @param alloc this parameter is currently ignored + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + * @deprecated use av_opt_set() + */ +attribute_deprecated +int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out); + +attribute_deprecated const AVOption *av_set_double(void *obj, const char *name, double n); +attribute_deprecated const AVOption *av_set_q(void *obj, const char *name, AVRational n); +attribute_deprecated const AVOption *av_set_int(void *obj, const char *name, int64_t n); + +double av_get_double(void *obj, const char *name, const AVOption **o_out); +AVRational av_get_q(void *obj, const char *name, const AVOption **o_out); +int64_t av_get_int(void *obj, const char *name, const AVOption **o_out); +attribute_deprecated const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len); +attribute_deprecated const AVOption *av_next_option(void *obj, const AVOption *last); +#endif + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +#if FF_API_OLD_AVOPTIONS +attribute_deprecated +void av_opt_set_defaults2(void *s, int mask, int flags); +#endif + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#define AV_OPT_SEARCH_CHILDREN 0x0001 /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ 0x0002 + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE 0x1000 + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_set_string3(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param prev result of a previous call to this function or NULL + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) + +/** + * @} + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); +/** + * @} + */ +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +int av_opt_copy(void *dest, void *src); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_malloc(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_next() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_next(const AVClass *prev) + * { + * return prev ? NULL : &child_class; + * } + * @endcode + * Putting child_next() and child_class_next() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_next() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_next() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_next() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_next() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This allows to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +enum AVOptionType{ + AV_OPT_TYPE_FLAGS, + AV_OPT_TYPE_INT, + AV_OPT_TYPE_INT64, + AV_OPT_TYPE_DOUBLE, + AV_OPT_TYPE_FLOAT, + AV_OPT_TYPE_STRING, + AV_OPT_TYPE_RATIONAL, + AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + AV_OPT_TYPE_DICT, + AV_OPT_TYPE_CONST = 128, + AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), + AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'), + AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational + AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), + AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), + AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'), +#if FF_API_OLD_AVOPTIONS + FF_OPT_TYPE_FLAGS = 0, + FF_OPT_TYPE_INT, + FF_OPT_TYPE_INT64, + FF_OPT_TYPE_DOUBLE, + FF_OPT_TYPE_FLOAT, + FF_OPT_TYPE_STRING, + FF_OPT_TYPE_RATIONAL, + FF_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + FF_OPT_TYPE_CONST=128, +#endif +}; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + int flags; +#define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding +#define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding +#if FF_API_OPT_TYPE_METADATA +#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... +#endif +#define AV_OPT_FLAG_AUDIO_PARAM 8 +#define AV_OPT_FLAG_VIDEO_PARAM 16 +#define AV_OPT_FLAG_SUBTITLE_PARAM 32 +/** + * The option is inteded for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT 64 +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +//FIXME think about enc-audio, ... style flags + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of componentes. + */ + int nb_components; +} AVOptionRanges; + + +#if FF_API_FIND_OPT +/** + * Look for an option in obj. Look only for the options which + * have the flags set as specified in mask and flags (that is, + * for which it is the case that (opt->flags & mask) == flags). + * + * @param[in] obj a pointer to a struct whose first element is a + * pointer to an AVClass + * @param[in] name the name of the option to look for + * @param[in] unit the unit of the option to look for, or any if NULL + * @return a pointer to the option found, or NULL if no option + * has been found + * + * @deprecated use av_opt_find. + */ +attribute_deprecated +const AVOption *av_find_opt(void *obj, const char *name, const char *unit, int mask, int flags); +#endif + +#if FF_API_OLD_AVOPTIONS +/** + * Set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an + * AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. If the field is not of a string + * type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param[out] o_out if non-NULL put here a pointer to the AVOption + * found + * @param alloc this parameter is currently ignored + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + * @deprecated use av_opt_set() + */ +attribute_deprecated +int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out); + +attribute_deprecated const AVOption *av_set_double(void *obj, const char *name, double n); +attribute_deprecated const AVOption *av_set_q(void *obj, const char *name, AVRational n); +attribute_deprecated const AVOption *av_set_int(void *obj, const char *name, int64_t n); + +double av_get_double(void *obj, const char *name, const AVOption **o_out); +AVRational av_get_q(void *obj, const char *name, const AVOption **o_out); +int64_t av_get_int(void *obj, const char *name, const AVOption **o_out); +attribute_deprecated const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len); +attribute_deprecated const AVOption *av_next_option(void *obj, const AVOption *last); +#endif + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +#if FF_API_OLD_AVOPTIONS +attribute_deprecated +void av_opt_set_defaults2(void *s, int mask, int flags); +#endif + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#define AV_OPT_SEARCH_CHILDREN 0x0001 /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ 0x0002 + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE 0x1000 + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_set_string3(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param prev result of a previous call to this function or NULL + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) + +/** + * @} + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); +/** + * @} + */ +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +int av_opt_copy(void *dest, void *src); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/parseutils.h b/extra_lib/include/ffmpeg_android/libavutil/parseutils.h new file mode 100644 index 0000000..1da1db0 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/parseutils.h @@ -0,0 +1,374 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * In particular it actually supports the parameters: + * - %H: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - %J: hours as a decimal number, in the range '0' through INT_MAX + * - %M: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %S: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %Y: the year as a decimal number, using the Gregorian calendar + * - %m: the month as a decimal number, in the range '1' through '12' + * - %d: the day of the month as a decimal number, in the range '1' + * through '31' + * - %%: a literal '%' + * + * @return a pointer to the first character not processed in this + * function call, or NULL in case the function fails to match all of + * the fmt string and therefore an error occurred + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * In particular it actually supports the parameters: + * - %H: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - %J: hours as a decimal number, in the range '0' through INT_MAX + * - %M: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %S: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %Y: the year as a decimal number, using the Gregorian calendar + * - %m: the month as a decimal number, in the range '1' through '12' + * - %d: the day of the month as a decimal number, in the range '1' + * through '31' + * - %%: a literal '%' + * + * @return a pointer to the first character not processed in this + * function call, or NULL in case the function fails to match all of + * the fmt string and therefore an error occurred + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/pixdesc.h b/extra_lib/include/ffmpeg_android/libavutil/pixdesc.h new file mode 100644 index 0000000..cc3bf20 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/pixdesc.h @@ -0,0 +1,718 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + uint16_t plane : 2; + + /** + * Number of elements between 2 horizontally consecutive pixels minus 1. + * Elements are bits for bitstream formats, bytes otherwise. + */ + uint16_t step_minus1 : 3; + + /** + * Number of elements before the component of the first pixel plus 1. + * Elements are bits for bitstream formats, bytes otherwise. + */ + uint16_t offset_plus1 : 3; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + uint16_t shift : 3; + + /** + * Number of bits in the component minus 1. + */ + uint16_t depth_minus1 : 4; +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = -((-luma_width) >> log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; ///< chroma_width = -((-luma_width )>>log2_chroma_w) + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= -((-luma_height) >> log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + uint8_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 2 or 4 components, then alpha is last. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components, + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) +/** + * The pixel format is "pseudo-paletted". This means that FFmpeg treats it as + * paletted internally, but the palette is generated by the decoder and is not + * stored in the file. + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) +/** + * The pixel format has an alpha channel. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +#if FF_API_PIX_FMT +/** + * @deprecated use the AV_PIX_FMT_FLAG_* flags + */ +#define PIX_FMT_BE AV_PIX_FMT_FLAG_BE +#define PIX_FMT_PAL AV_PIX_FMT_FLAG_PAL +#define PIX_FMT_BITSTREAM AV_PIX_FMT_FLAG_BITSTREAM +#define PIX_FMT_HWACCEL AV_PIX_FMT_FLAG_HWACCEL +#define PIX_FMT_PLANAR AV_PIX_FMT_FLAG_PLANAR +#define PIX_FMT_RGB AV_PIX_FMT_FLAG_RGB +#define PIX_FMT_PSEUDOPAL AV_PIX_FMT_FLAG_PSEUDOPAL +#define PIX_FMT_ALPHA AV_PIX_FMT_FLAG_ALPHA +#endif + +#if FF_API_PIX_FMT_DESC +/** + * The array of all the pixel format descriptors. + */ +extern attribute_deprecated const AVPixFmtDescriptor av_pix_fmt_descriptors[]; +#endif + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + */ +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + */ +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * See av_get_chroma_sub_sample() for a function that asserts a + * valid pixel format instead of returning an error code. + * Its recommended that you use avcodec_get_chroma_sub_sample unless + * you do check the return code! + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +void ff_check_pixfmt_descriptors(void); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); +#endif /* AVUTIL_PIXDESC_H */ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + uint16_t plane : 2; + + /** + * Number of elements between 2 horizontally consecutive pixels minus 1. + * Elements are bits for bitstream formats, bytes otherwise. + */ + uint16_t step_minus1 : 3; + + /** + * Number of elements before the component of the first pixel plus 1. + * Elements are bits for bitstream formats, bytes otherwise. + */ + uint16_t offset_plus1 : 3; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + uint16_t shift : 3; + + /** + * Number of bits in the component minus 1. + */ + uint16_t depth_minus1 : 4; +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = -((-luma_width) >> log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; ///< chroma_width = -((-luma_width )>>log2_chroma_w) + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= -((-luma_height) >> log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + uint8_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 2 or 4 components, then alpha is last. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components, + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) +/** + * The pixel format is "pseudo-paletted". This means that FFmpeg treats it as + * paletted internally, but the palette is generated by the decoder and is not + * stored in the file. + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) +/** + * The pixel format has an alpha channel. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +#if FF_API_PIX_FMT +/** + * @deprecated use the AV_PIX_FMT_FLAG_* flags + */ +#define PIX_FMT_BE AV_PIX_FMT_FLAG_BE +#define PIX_FMT_PAL AV_PIX_FMT_FLAG_PAL +#define PIX_FMT_BITSTREAM AV_PIX_FMT_FLAG_BITSTREAM +#define PIX_FMT_HWACCEL AV_PIX_FMT_FLAG_HWACCEL +#define PIX_FMT_PLANAR AV_PIX_FMT_FLAG_PLANAR +#define PIX_FMT_RGB AV_PIX_FMT_FLAG_RGB +#define PIX_FMT_PSEUDOPAL AV_PIX_FMT_FLAG_PSEUDOPAL +#define PIX_FMT_ALPHA AV_PIX_FMT_FLAG_ALPHA +#endif + +#if FF_API_PIX_FMT_DESC +/** + * The array of all the pixel format descriptors. + */ +extern attribute_deprecated const AVPixFmtDescriptor av_pix_fmt_descriptors[]; +#endif + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + */ +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + */ +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * See av_get_chroma_sub_sample() for a function that asserts a + * valid pixel format instead of returning an error code. + * Its recommended that you use avcodec_get_chroma_sub_sample unless + * you do check the return code! + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +void ff_check_pixfmt_descriptors(void); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); +#endif /* AVUTIL_PIXDESC_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/pixelutils.h b/extra_lib/include/ffmpeg_android/libavutil/pixelutils.h new file mode 100644 index 0000000..672582b --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/pixelutils.h @@ -0,0 +1,104 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXELUTILS_H +#define AVUTIL_PIXELUTILS_H + +#include +#include +#include "common.h" + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1< +#include +#include "common.h" + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1< + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ +/* + * Copyright (c) 2009 Baptiste Coudurier + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/rational.h b/extra_lib/include/ffmpeg_android/libavutil/rational.h index c5ecf2c..7439701 100644 --- a/extra_lib/include/ffmpeg_android/libavutil/rational.h +++ b/extra_lib/include/ffmpeg_android/libavutil/rational.h @@ -20,7 +20,7 @@ */ /** - * @file libavutil/rational.h + * @file * rational numbers * @author Michael Niedermayer */ @@ -29,8 +29,14 @@ #define AVUTIL_RATIONAL_H #include +#include #include "attributes.h" +/** + * @addtogroup lavu_math + * @{ + */ + /** * rational number numerator/denominator */ @@ -40,20 +46,34 @@ typedef struct AVRational{ } AVRational; /** - * Compares two rationals. + * Create a rational. + * Useful for compilers that do not support compound literals. + * @note The return value is not reduced. + */ +static inline AVRational av_make_q(int num, int den) +{ + AVRational r = { num, den }; + return r; +} + +/** + * Compare two rationals. * @param a first rational * @param b second rational - * @return 0 if a==b, 1 if a>b and -1 if ab, -1 if a>63)|1; - else return 0; + if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1; + else if(b.den && a.den) return 0; + else if(a.num && b.num) return (a.num>>31) - (b.num>>31); + else return INT_MIN; } /** - * Converts rational to double. + * Convert rational to double. * @param a rational to convert * @return (double) a */ @@ -62,7 +82,7 @@ static inline double av_q2d(AVRational a){ } /** - * Reduces a fraction. + * Reduce a fraction. * This is useful for framerate calculations. * @param dst_num destination numerator * @param dst_den destination denominator @@ -74,7 +94,7 @@ static inline double av_q2d(AVRational a){ int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); /** - * Multiplies two rationals. + * Multiply two rationals. * @param b first rational * @param c second rational * @return b*c @@ -82,7 +102,7 @@ int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max) AVRational av_mul_q(AVRational b, AVRational c) av_const; /** - * Divides one rational by another. + * Divide one rational by another. * @param b first rational * @param c second rational * @return b/c @@ -90,7 +110,7 @@ AVRational av_mul_q(AVRational b, AVRational c) av_const; AVRational av_div_q(AVRational b, AVRational c) av_const; /** - * Adds two rationals. + * Add two rationals. * @param b first rational * @param c second rational * @return b+c @@ -98,7 +118,7 @@ AVRational av_div_q(AVRational b, AVRational c) av_const; AVRational av_add_q(AVRational b, AVRational c) av_const; /** - * Subtracts one rational from another. + * Subtract one rational from another. * @param b first rational * @param c second rational * @return b-c @@ -106,7 +126,20 @@ AVRational av_add_q(AVRational b, AVRational c) av_const; AVRational av_sub_q(AVRational b, AVRational c) av_const; /** - * Converts a double precision floating point number to a rational. + * Invert a rational. + * @param q value + * @return 1 / q + */ +static av_always_inline AVRational av_inv_q(AVRational q) +{ + AVRational r = { q.den, q.num }; + return r; +} + +/** + * Convert a double precision floating point number to a rational. + * inf is expressed as {1,0} or {-1,0} depending on the sign. + * * @param d double to convert * @param max the maximum allowed numerator and denominator * @return (AVRational) d @@ -120,10 +153,14 @@ AVRational av_d2q(double d, int max) av_const; int av_nearer_q(AVRational q, AVRational q1, AVRational q2); /** - * Finds the nearest value in q_list to q. + * Find the nearest value in q_list to q. * @param q_list an array of rationals terminated by {0, 0} * @return the index of the nearest value found in the array */ int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); +/** + * @} + */ + #endif /* AVUTIL_RATIONAL_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/replaygain.h b/extra_lib/include/ffmpeg_android/libavutil/replaygain.h new file mode 100644 index 0000000..1f0bf34 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/replaygain.h @@ -0,0 +1,102 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/ripemd.h b/extra_lib/include/ffmpeg_android/libavutil/ripemd.h new file mode 100644 index 0000000..bfe2565 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/ripemd.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/samplefmt.h b/extra_lib/include/ffmpeg_android/libavutil/samplefmt.h new file mode 100644 index 0000000..2c5a9e5 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/samplefmt.h @@ -0,0 +1,558 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include + +#include "avutil.h" +#include "attributes.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + * + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +#if FF_API_GET_BITS_PER_SAMPLE_FMT +/** + * @deprecated Use av_get_bytes_per_sample() instead. + */ +attribute_deprecated +int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt); +#endif + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return minimum size in bytes required for the buffer in case + * of success at the next bump + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include + +#include "avutil.h" +#include "attributes.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + * + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +#if FF_API_GET_BITS_PER_SAMPLE_FMT +/** + * @deprecated Use av_get_bytes_per_sample() instead. + */ +attribute_deprecated +int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt); +#endif + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return minimum size in bytes required for the buffer in case + * of success at the next bump + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/sha.h b/extra_lib/include/ffmpeg_android/libavutil/sha.h new file mode 100644 index 0000000..22eeecd --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/sha.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha_update(struct AVSHA* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ +/* + * Copyright (C) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha_update(struct AVSHA* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/sha512.h b/extra_lib/include/ffmpeg_android/libavutil/sha512.h new file mode 100644 index 0000000..446f020 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/sha512.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha512 SHA512 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha512 SHA512 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/stereo3d.h b/extra_lib/include/ffmpeg_android/libavutil/stereo3d.h new file mode 100644 index 0000000..4465fe6 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/stereo3d.h @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include + +#include "frame.h" + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + */ + AV_STEREO3D_COLUMNS, +}; + + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_STEREO3D_H */ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include + +#include "frame.h" + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + */ + AV_STEREO3D_COLUMNS, +}; + + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_STEREO3D_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/threadmessage.h b/extra_lib/include/ffmpeg_android/libavutil/threadmessage.h new file mode 100644 index 0000000..3132ea8 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/threadmessage.h @@ -0,0 +1,182 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +#endif /* AVUTIL_THREADMESSAGE_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +#endif /* AVUTIL_THREADMESSAGE_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/time.h b/extra_lib/include/ffmpeg_android/libavutil/time.h new file mode 100644 index 0000000..380b14a --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/time.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * If a monotonic clock is not available on the targeted platform, the + * implementation fallsback on using av_gettime(). + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * If a monotonic clock is not available on the targeted platform, the + * implementation fallsback on using av_gettime(). + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/timecode.h b/extra_lib/include/ffmpeg_android/libavutil/timecode.h new file mode 100644 index 0000000..b9c6050 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/timecode.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 16 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, 30 or 60 + * @return adjusted frame number + * @warning adjustment is only valid in NTSC 29.97 and 59.94 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity + * correction (PC) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Load timecode string in buf. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 16 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, 30 or 60 + * @return adjusted frame number + * @warning adjustment is only valid in NTSC 29.97 and 59.94 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity + * correction (PC) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Load timecode string in buf. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/timestamp.h b/extra_lib/include/ffmpeg_android/libavutil/timestamp.h new file mode 100644 index 0000000..5206555 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/timestamp.h @@ -0,0 +1,156 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "common.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%"PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "common.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%"PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ diff --git a/extra_lib/include/ffmpeg_android/libavutil/version.h b/extra_lib/include/ffmpeg_android/libavutil/version.h new file mode 100644 index 0000000..c64570e --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/version.h @@ -0,0 +1,310 @@ +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * @} + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compiletime and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 54 +#define LIBAVUTIL_VERSION_MINOR 7 +#define LIBAVUTIL_VERSION_MICRO 100 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @} + * + * @defgroup depr_guards Deprecation guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @{ + */ + +#ifndef FF_API_GET_BITS_PER_SAMPLE_FMT +#define FF_API_GET_BITS_PER_SAMPLE_FMT (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_FIND_OPT +#define FF_API_FIND_OPT (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_OLD_AVOPTIONS +#define FF_API_OLD_AVOPTIONS (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_PIX_FMT +#define FF_API_PIX_FMT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_CONTEXT_SIZE +#define FF_API_CONTEXT_SIZE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_PIX_FMT_DESC +#define FF_API_PIX_FMT_DESC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AV_REVERSE +#define FF_API_AV_REVERSE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AUDIOCONVERT +#define FF_API_AUDIOCONVERT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_CPU_FLAG_MMX2 +#define FF_API_CPU_FLAG_MMX2 (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_SAMPLES_UTILS_RETURN_ZERO +#define FF_API_SAMPLES_UTILS_RETURN_ZERO (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_LLS_PRIVATE +#define FF_API_LLS_PRIVATE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_LLS1 +#define FF_API_LLS1 (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_AVFRAME_LAVC +#define FF_API_AVFRAME_LAVC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_VDPAU +#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_GET_CHANNEL_LAYOUT_COMPAT +#define FF_API_GET_CHANNEL_LAYOUT_COMPAT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_OLD_OPENCL +#define FF_API_OLD_OPENCL (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_INTFLOAT +#define FF_API_INTFLOAT (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_OPT_TYPE_METADATA +#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 55) +#endif + + +#ifndef FF_CONST_AVUTIL53 +#if LIBAVUTIL_VERSION_MAJOR >= 53 +#define FF_CONST_AVUTIL53 const +#else +#define FF_CONST_AVUTIL53 +#endif +#endif + +/** + * @} + */ + +#endif /* AVUTIL_VERSION_H */ + +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * @} + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compiletime and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 54 +#define LIBAVUTIL_VERSION_MINOR 7 +#define LIBAVUTIL_VERSION_MICRO 100 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @} + * + * @defgroup depr_guards Deprecation guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @{ + */ + +#ifndef FF_API_GET_BITS_PER_SAMPLE_FMT +#define FF_API_GET_BITS_PER_SAMPLE_FMT (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_FIND_OPT +#define FF_API_FIND_OPT (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_OLD_AVOPTIONS +#define FF_API_OLD_AVOPTIONS (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_PIX_FMT +#define FF_API_PIX_FMT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_CONTEXT_SIZE +#define FF_API_CONTEXT_SIZE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_PIX_FMT_DESC +#define FF_API_PIX_FMT_DESC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AV_REVERSE +#define FF_API_AV_REVERSE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_AUDIOCONVERT +#define FF_API_AUDIOCONVERT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_CPU_FLAG_MMX2 +#define FF_API_CPU_FLAG_MMX2 (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_SAMPLES_UTILS_RETURN_ZERO +#define FF_API_SAMPLES_UTILS_RETURN_ZERO (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_LLS_PRIVATE +#define FF_API_LLS_PRIVATE (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_LLS1 +#define FF_API_LLS1 (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_AVFRAME_LAVC +#define FF_API_AVFRAME_LAVC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_VDPAU +#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_GET_CHANNEL_LAYOUT_COMPAT +#define FF_API_GET_CHANNEL_LAYOUT_COMPAT (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_OLD_OPENCL +#define FF_API_OLD_OPENCL (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_INTFLOAT +#define FF_API_INTFLOAT (LIBAVUTIL_VERSION_MAJOR < 54) +#endif +#ifndef FF_API_OPT_TYPE_METADATA +#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 55) +#endif + + +#ifndef FF_CONST_AVUTIL53 +#if LIBAVUTIL_VERSION_MAJOR >= 53 +#define FF_CONST_AVUTIL53 const +#else +#define FF_CONST_AVUTIL53 +#endif +#endif + +/** + * @} + */ + +#endif /* AVUTIL_VERSION_H */ + diff --git a/extra_lib/include/ffmpeg_android/libavutil/xtea.h b/extra_lib/include/ffmpeg_android/libavutil/xtea.h new file mode 100644 index 0000000..a778c81 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libavutil/xtea.h @@ -0,0 +1,128 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ diff --git a/extra_lib/include/ffmpeg_android/libswscale/swscale.h b/extra_lib/include/ffmpeg_android/libswscale/swscale.h index 1e7af3a..903e120 100644 --- a/extra_lib/include/ffmpeg_android/libswscale/swscale.h +++ b/extra_lib/include/ffmpeg_android/libswscale/swscale.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2003 Michael Niedermayer + * Copyright (C) 2001-2011 Michael Niedermayer * * This file is part of FFmpeg. * @@ -23,38 +23,32 @@ /** * @file - * @brief - * external api for the swscale stuff + * @ingroup libsws + * external API header */ -#include "libavutil/avutil.h" - -#define LIBSWSCALE_VERSION_MAJOR 0 -#define LIBSWSCALE_VERSION_MINOR 11 -#define LIBSWSCALE_VERSION_MICRO 0 - -#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ - LIBSWSCALE_VERSION_MINOR, \ - LIBSWSCALE_VERSION_MICRO) -#define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ - LIBSWSCALE_VERSION_MINOR, \ - LIBSWSCALE_VERSION_MICRO) -#define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT +#include -#define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) +#include "libavutil/avutil.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "version.h" /** - * Returns the LIBSWSCALE_VERSION_INT constant. + * @defgroup libsws Color conversion and scaling + * @{ + * + * Return the LIBSWSCALE_VERSION_INT constant. */ unsigned swscale_version(void); /** - * Returns the libswscale build-time configuration. + * Return the libswscale build-time configuration. */ const char *swscale_configuration(void); /** - * Returns the libswscale license. + * Return the libswscale license. */ const char *swscale_license(void); @@ -86,12 +80,23 @@ const char *swscale_license(void); #define SWS_DIRECT_BGR 0x8000 #define SWS_ACCURATE_RND 0x40000 #define SWS_BITEXACT 0x80000 +#define SWS_ERROR_DIFFUSION 0x800000 +#if FF_API_SWS_CPU_CAPS +/** + * CPU caps are autodetected now, those flags + * are only provided for API compatibility. + */ #define SWS_CPU_CAPS_MMX 0x80000000 +#define SWS_CPU_CAPS_MMXEXT 0x20000000 #define SWS_CPU_CAPS_MMX2 0x20000000 #define SWS_CPU_CAPS_3DNOW 0x40000000 #define SWS_CPU_CAPS_ALTIVEC 0x10000000 +#if FF_API_ARCH_BFIN #define SWS_CPU_CAPS_BFIN 0x01000000 +#endif +#define SWS_CPU_CAPS_SSE2 0x02000000 +#endif #define SWS_MAX_REDUCE_CUTOFF 0.002 @@ -104,7 +109,7 @@ const char *swscale_license(void); #define SWS_CS_DEFAULT 5 /** - * Returns a pointer to yuv<->rgb coefficients for the given colorspace + * Return a pointer to yuv<->rgb coefficients for the given colorspace * suitable for sws_setColorspaceDetails(). * * @param colorspace One of the SWS_CS_* macros. If invalid, @@ -112,16 +117,15 @@ const char *swscale_license(void); */ const int *sws_getCoefficients(int colorspace); - // when used for filters they must have an odd number of elements // coeffs cannot be shared between vectors -typedef struct { +typedef struct SwsVector { double *coeff; ///< pointer to the list of coefficients int length; ///< number of coefficients in the vector } SwsVector; // vectors can be shared -typedef struct { +typedef struct SwsFilter { SwsVector *lumH; SwsVector *lumV; SwsVector *chrH; @@ -131,25 +135,47 @@ typedef struct { struct SwsContext; /** - * Returns a positive value if pix_fmt is a supported input format, 0 + * Return a positive value if pix_fmt is a supported input format, 0 * otherwise. */ -int sws_isSupportedInput(enum PixelFormat pix_fmt); +int sws_isSupportedInput(enum AVPixelFormat pix_fmt); /** - * Returns a positive value if pix_fmt is a supported output format, 0 + * Return a positive value if pix_fmt is a supported output format, 0 * otherwise. */ -int sws_isSupportedOutput(enum PixelFormat pix_fmt); +int sws_isSupportedOutput(enum AVPixelFormat pix_fmt); + +/** + * @param[in] pix_fmt the pixel format + * @return a positive value if an endianness conversion for pix_fmt is + * supported, 0 otherwise. + */ +int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt); /** - * Frees the swscaler context swsContext. + * Allocate an empty SwsContext. This must be filled and passed to + * sws_init_context(). For filling see AVOptions, options.c and + * sws_setColorspaceDetails(). + */ +struct SwsContext *sws_alloc_context(void); + +/** + * Initialize the swscaler context sws_context. + * + * @return zero or positive value on success, a negative value on + * error + */ +int sws_init_context(struct SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter); + +/** + * Free the swscaler context swsContext. * If swsContext is NULL, then does nothing. */ void sws_freeContext(struct SwsContext *swsContext); /** - * Allocates and returns a SwsContext. You need it to perform + * Allocate and return an SwsContext. You need it to perform * scaling/conversion operations using sws_scale(). * * @param srcW the width of the source image @@ -160,14 +186,16 @@ void sws_freeContext(struct SwsContext *swsContext); * @param dstFormat the destination image format * @param flags specify which algorithm and options to use for rescaling * @return a pointer to an allocated context, or NULL in case of error + * @note this function is to be removed after a saner alternative is + * written */ -struct SwsContext *sws_getContext(int srcW, int srcH, enum PixelFormat srcFormat, - int dstW, int dstH, enum PixelFormat dstFormat, +struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param); /** - * Scales the image slice in srcSlice and puts the resulting scaled + * Scale the image slice in srcSlice and put the resulting scaled * slice in the image in dst. A slice is a sequence of consecutive * rows in an image. * @@ -175,7 +203,7 @@ struct SwsContext *sws_getContext(int srcW, int srcH, enum PixelFormat srcFormat * top-bottom or bottom-top order. If slices are provided in * non-sequential order the behavior of the function is undefined. * - * @param context the scaling context previously created with + * @param c the scaling context previously created with * sws_getContext() * @param srcSlice the array containing the pointers to the planes of * the source slice @@ -192,20 +220,18 @@ struct SwsContext *sws_getContext(int srcW, int srcH, enum PixelFormat srcFormat * the destination image * @return the height of the output slice */ -int sws_scale(struct SwsContext *context, const uint8_t* const srcSlice[], const int srcStride[], - int srcSliceY, int srcSliceH, uint8_t* const dst[], const int dstStride[]); -#if LIBSWSCALE_VERSION_MAJOR < 1 -/** - * @deprecated Use sws_scale() instead. - */ -int sws_scale_ordered(struct SwsContext *context, const uint8_t* const src[], - int srcStride[], int srcSliceY, int srcSliceH, - uint8_t* dst[], int dstStride[]) attribute_deprecated; -#endif +int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]); /** - * @param inv_table the yuv2rgb coefficients, normally ff_yuv2rgb_coeffs[x] - * @param fullRange if 1 then the luma range is 0..255 if 0 it is 16..235 + * @param dstRange flag indicating the while-black range of the output (1=jpeg / 0=mpeg) + * @param srcRange flag indicating the while-black range of the input (1=jpeg / 0=mpeg) + * @param table the yuv2rgb coefficients describing the output yuv space, normally ff_yuv2rgb_coeffs[x] + * @param inv_table the yuv2rgb coefficients describing the input yuv space, normally ff_yuv2rgb_coeffs[x] + * @param brightness 16.16 fixed point brightness correction + * @param contrast 16.16 fixed point contrast correction + * @param saturation 16.16 fixed point saturation correction * @return -1 if not supported */ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], @@ -220,35 +246,35 @@ int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table, int *brightness, int *contrast, int *saturation); /** - * Allocates and returns an uninitialized vector with length coefficients. + * Allocate and return an uninitialized vector with length coefficients. */ SwsVector *sws_allocVec(int length); /** - * Returns a normalized Gaussian curve used to filter stuff - * quality=3 is high quality, lower is lower quality. + * Return a normalized Gaussian curve used to filter stuff + * quality = 3 is high quality, lower is lower quality. */ SwsVector *sws_getGaussianVec(double variance, double quality); /** - * Allocates and returns a vector with length coefficients, all + * Allocate and return a vector with length coefficients, all * with the same value c. */ SwsVector *sws_getConstVec(double c, int length); /** - * Allocates and returns a vector with just one coefficient, with + * Allocate and return a vector with just one coefficient, with * value 1.0. */ SwsVector *sws_getIdentityVec(void); /** - * Scales all the coefficients of a by the scalar value. + * Scale all the coefficients of a by the scalar value. */ void sws_scaleVec(SwsVector *a, double scalar); /** - * Scales all the coefficients of a so that their sum equals height. + * Scale all the coefficients of a so that their sum equals height. */ void sws_normalizeVec(SwsVector *a, double height); void sws_convVec(SwsVector *a, SwsVector *b); @@ -257,20 +283,13 @@ void sws_subVec(SwsVector *a, SwsVector *b); void sws_shiftVec(SwsVector *a, int shift); /** - * Allocates and returns a clone of the vector a, that is a vector + * Allocate and return a clone of the vector a, that is a vector * with the same coefficients as a. */ SwsVector *sws_cloneVec(SwsVector *a); -#if LIBSWSCALE_VERSION_MAJOR < 1 -/** - * @deprecated Use sws_printVec2() instead. - */ -attribute_deprecated void sws_printVec(SwsVector *a); -#endif - /** - * Prints with av_log() a textual representation of the vector a + * Print with av_log() a textual representation of the vector a * if log_level <= av_log_level. */ void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level); @@ -284,8 +303,7 @@ SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur, void sws_freeFilter(SwsFilter *filter); /** - * Checks if context can be reused, otherwise reallocates a new - * one. + * Check if context can be reused, otherwise reallocate a new one. * * If context is NULL, just calls sws_getContext() to get a new * context. Otherwise, checks if the parameters are the ones already @@ -297,13 +315,13 @@ void sws_freeFilter(SwsFilter *filter); * are assumed to remain the same. */ struct SwsContext *sws_getCachedContext(struct SwsContext *context, - int srcW, int srcH, enum PixelFormat srcFormat, - int dstW, int dstH, enum PixelFormat dstFormat, + int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param); /** - * Converts an 8bit paletted frame into a frame with a color depth of 32-bits. + * Convert an 8-bit paletted frame into a frame with a color depth of 32 bits. * * The output frame will have the same packed format as the palette. * @@ -312,10 +330,10 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, * @param num_pixels number of pixels to convert * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src */ -void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, long num_pixels, const uint8_t *palette); +void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); /** - * Converts an 8bit paletted frame into a frame with a color depth of 24 bits. + * Convert an 8-bit paletted frame into a frame with a color depth of 24 bits. * * With the palette format "ABCD", the destination frame ends up with the format "ABC". * @@ -324,7 +342,18 @@ void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, long num_pi * @param num_pixels number of pixels to convert * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src */ -void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, long num_pixels, const uint8_t *palette); +void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); + +/** + * Get the AVClass for swsContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *sws_get_class(void); +/** + * @} + */ #endif /* SWSCALE_SWSCALE_H */ diff --git a/extra_lib/include/ffmpeg_android/libswscale/version.h b/extra_lib/include/ffmpeg_android/libswscale/version.h new file mode 100644 index 0000000..d8777c8 --- /dev/null +++ b/extra_lib/include/ffmpeg_android/libswscale/version.h @@ -0,0 +1,118 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_VERSION_H +#define SWSCALE_VERSION_H + +/** + * @file + * swscale version macros + */ + +#include "libavutil/version.h" + +#define LIBSWSCALE_VERSION_MAJOR 3 +#define LIBSWSCALE_VERSION_MINOR 0 +#define LIBSWSCALE_VERSION_MICRO 100 + +#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT + +#define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_SWS_CPU_CAPS +#define FF_API_SWS_CPU_CAPS (LIBSWSCALE_VERSION_MAJOR < 4) +#endif +#ifndef FF_API_SWS_FORMAT_NAME +#define FF_API_SWS_FORMAT_NAME (LIBSWSCALE_VERSION_MAJOR < 3) +#endif +#ifndef FF_API_ARCH_BFIN +#define FF_API_ARCH_BFIN (LIBSWSCALE_VERSION_MAJOR < 4) +#endif + +#endif /* SWSCALE_VERSION_H */ +/* + * This file is part of FFmpeg. + * + * FFmpeg 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.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_VERSION_H +#define SWSCALE_VERSION_H + +/** + * @file + * swscale version macros + */ + +#include "libavutil/version.h" + +#define LIBSWSCALE_VERSION_MAJOR 3 +#define LIBSWSCALE_VERSION_MINOR 0 +#define LIBSWSCALE_VERSION_MICRO 100 + +#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT + +#define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_SWS_CPU_CAPS +#define FF_API_SWS_CPU_CAPS (LIBSWSCALE_VERSION_MAJOR < 4) +#endif +#ifndef FF_API_SWS_FORMAT_NAME +#define FF_API_SWS_FORMAT_NAME (LIBSWSCALE_VERSION_MAJOR < 3) +#endif +#ifndef FF_API_ARCH_BFIN +#define FF_API_ARCH_BFIN (LIBSWSCALE_VERSION_MAJOR < 4) +#endif + +#endif /* SWSCALE_VERSION_H */ diff --git a/extra_lib/include/js/jscpucfg.h b/extra_lib/include/js/jscpucfg.h index 316205d..8176abc 100644 --- a/extra_lib/include/js/jscpucfg.h +++ b/extra_lib/include/js/jscpucfg.h @@ -42,11 +42,12 @@ #include "jsosdep.h" -#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE) +#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE) || defined(IPHONE_OS) #if defined(_WIN64) #if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) + #define IS_LITTLE_ENDIAN 1 #undef IS_BIG_ENDIAN @@ -94,7 +95,7 @@ #error "CPU type is unknown" #endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ -#elif defined(_WIN32) || defined(XP_OS2) || defined(WINCE) +#elif defined(_WIN32) || defined(XP_OS2) || defined(WINCE) #ifdef __WATCOMC__ #define HAVE_VA_LIST_AS_ARRAY @@ -143,8 +144,111 @@ #define JS_BYTES_PER_WORD_LOG2 2L #define JS_BYTES_PER_DWORD_LOG2 3L #define PR_WORDS_PER_DWORD_LOG2 1L + #endif /* _WIN32 || XP_OS2 || WINCE*/ +#if defined(IPHONE_OS) + +//ios64 +#if defined(__LP64__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define JS_BYTES_PER_BYTE 1L +#define JS_BYTES_PER_SHORT 2L +#define JS_BYTES_PER_INT 4L +#define JS_BYTES_PER_INT64 8L +#define JS_BYTES_PER_LONG 4L +#define JS_BYTES_PER_FLOAT 4L +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 8L +#define JS_BYTES_PER_DWORD 8L + +#define JS_BITS_PER_BYTE 8L +#define JS_BITS_PER_SHORT 16L +#define JS_BITS_PER_INT 32L +#define JS_BITS_PER_INT64 64L +#define JS_BITS_PER_LONG 32L +#define JS_BITS_PER_FLOAT 32L +#define JS_BITS_PER_DOUBLE 64L +#define JS_BITS_PER_WORD 64L + +#define JS_BITS_PER_BYTE_LOG2 3L +#define JS_BITS_PER_SHORT_LOG2 4L +#define JS_BITS_PER_INT_LOG2 5L +#define JS_BITS_PER_INT64_LOG2 6L +#define JS_BITS_PER_LONG_LOG2 5L +#define JS_BITS_PER_FLOAT_LOG2 5L +#define JS_BITS_PER_DOUBLE_LOG2 6L +#define JS_BITS_PER_WORD_LOG2 6L + +#define JS_ALIGN_OF_SHORT 2L +#define JS_ALIGN_OF_INT 4L +#define JS_ALIGN_OF_LONG 4L +#define JS_ALIGN_OF_INT64 8L +#define JS_ALIGN_OF_FLOAT 4L +#define JS_ALIGN_OF_DOUBLE 8L +#define JS_ALIGN_OF_POINTER 8L +#define JS_ALIGN_OF_WORD 8L + +#define JS_BYTES_PER_WORD_LOG2 3L +#define JS_BYTES_PER_DWORD_LOG2 3L +#define PR_WORDS_PER_DWORD_LOG2 0L + +#else //ios64 + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define JS_BYTES_PER_BYTE 1L +#define JS_BYTES_PER_SHORT 2L +#define JS_BYTES_PER_INT 4L +#define JS_BYTES_PER_INT64 8L +#define JS_BYTES_PER_LONG 4L +#define JS_BYTES_PER_FLOAT 4L +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 4L +#define JS_BYTES_PER_DWORD 8L + +#define JS_BITS_PER_BYTE 8L +#define JS_BITS_PER_SHORT 16L +#define JS_BITS_PER_INT 32L +#define JS_BITS_PER_INT64 64L +#define JS_BITS_PER_LONG 32L +#define JS_BITS_PER_FLOAT 32L +#define JS_BITS_PER_DOUBLE 64L +#define JS_BITS_PER_WORD 32L + +#define JS_BITS_PER_BYTE_LOG2 3L +#define JS_BITS_PER_SHORT_LOG2 4L +#define JS_BITS_PER_INT_LOG2 5L +#define JS_BITS_PER_INT64_LOG2 6L +#define JS_BITS_PER_LONG_LOG2 5L +#define JS_BITS_PER_FLOAT_LOG2 5L +#define JS_BITS_PER_DOUBLE_LOG2 6L +#define JS_BITS_PER_WORD_LOG2 5L + +#define JS_ALIGN_OF_SHORT 2L +#define JS_ALIGN_OF_INT 4L +#define JS_ALIGN_OF_LONG 4L +#define JS_ALIGN_OF_INT64 4L +#define JS_ALIGN_OF_FLOAT 4L +#define JS_ALIGN_OF_DOUBLE 4L +#define JS_ALIGN_OF_POINTER 4L +#define JS_ALIGN_OF_WORD 4L + +#define JS_BYTES_PER_WORD_LOG2 2L +#define JS_BYTES_PER_DWORD_LOG2 3L +#define JS_WORDS_PER_DWORD_LOG2 1L + +#define JS_STACK_GROWTH_DIRECTION (-1) + +#endif //ios32 + + +#endif + + #if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */ #define IS_LITTLE_ENDIAN 1 diff --git a/extra_lib/include/js/jstypes.h b/extra_lib/include/js/jstypes.h index 8aca929..b48f24b 100644 --- a/extra_lib/include/js/jstypes.h +++ b/extra_lib/include/js/jstypes.h @@ -239,7 +239,7 @@ #define JS_MIN(x,y) ((x)<(y)?(x):(y)) #define JS_MAX(x,y) ((x)>(y)?(x):(y)) -#if (defined(XP_WIN) && !defined(CROSS_COMPILE)) || defined (WINCE) +#if (defined(XP_WIN) && !defined(CROSS_COMPILE)) || defined (WINCE) || defined (IPHONE_OS) # include "jscpucfg.h" /* Use standard Mac or Windows configuration */ #elif defined(XP_UNIX) || defined(XP_BEOS) || defined(XP_OS2) || defined(CROSS_COMPILE) # include "jsautocfg.h" /* Use auto-detected configuration */ diff --git a/extra_lib/include/openHevcWrapper.h b/extra_lib/include/openHevcWrapper.h index 349c0ee..a598dc2 100644 --- a/extra_lib/include/openHevcWrapper.h +++ b/extra_lib/include/openHevcWrapper.h @@ -1,4 +1,4 @@ -/* +/* * openhevc.h wrapper to openhevc or ffmpeg * Copyright (c) 2012-2013 Micka�l Raulet, Wassim Hamidouche, Gildas Cocherel, Pierre Edouard Lepere * @@ -37,6 +37,13 @@ typedef struct OpenHevc_Rational{ int den; ///< denominator } OpenHevc_Rational; + +enum ChromaFormat { + YUV420 = 0, + YUV422, + YUV444, +}; + typedef struct OpenHevc_FrameInfo { int nYPitch; @@ -45,6 +52,7 @@ typedef struct OpenHevc_FrameInfo int nBitDepth; int nWidth; int nHeight; + int chromat_format; OpenHevc_Rational sample_aspect_ratio; OpenHevc_Rational frameRate; int display_picture_number; diff --git a/fixEOL.sh b/fixEOL.sh deleted file mode 100644 index 2f94901..0000000 --- a/fixEOL.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -for i in `find . -name '*.sh'` ; do svn propset svn:eol-style LF $i ; done -for i in `find . -name '*.txt'` ; do svn propset svn:eol-style native $i ; done -for i in `find . -name '*.cpp'` ; do svn propset svn:eol-style native $i ; done -for i in `find . -name '*.c'` ; do svn propset svn:eol-style native $i ; done -for i in `find . -name '*.h'` ; do svn propset svn:eol-style native $i ; done -for i in `find . -name 'Makefile'` ; do svn propset svn:eol-style native $i ; done -for i in `find . -name '*.vcproj'` ; do svn propset svn:eol-style CRLF $i ; done -for i in `find . -name '*.sln'` ; do svn propset svn:eol-style CRLF $i ; done -for i in `find . -name '*.dsp'` ; do svn propset svn:eol-style CRLF $i ; done -for i in `find . -name '*.dsw'` ; do svn propset svn:eol-style CRLF $i ; done diff --git a/generate_installer.bat b/generate_installer.bat index ead9623..20577a6 100644 --- a/generate_installer.bat +++ b/generate_installer.bat @@ -1,94 +1,100 @@ -@echo off -set OLDDIR=%CD% -cd /d %~dp0 -REM ============================================ -echo *** Generating a Windows GPAC installer *** -REM ============================================ - - -:begin -IF "%1"=="win32" GOTO next -IF "%1"=="x64" GOTO next -echo You must specified target architecture : win32 or x64 -GOTO Abort - -:next -echo: -REM ============================================ -echo Check NSIS is in your PATH -REM ============================================ -if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( - SET "PRGROOT=%programfiles(x86)%" -) -if "%PROCESSOR_ARCHITECTURE%" == "x86" ( - SET PRGROOT=%programfiles% -) - -set NSIS_EXEC="%PRGROOT%\NSIS\makensis.exe" -if not exist "%PRGROOT%\NSIS\makensis.exe" echo NSIS couldn't be found at default location %NSIS_EXEC% -if not exist "%PRGROOT%\NSIS\makensis.exe" goto Abort -echo Found NSIS at default location %NSIS_EXEC% - - -echo: -REM ============================================ -echo Retrieving version/revision information -REM ============================================ -if not exist include/gpac/revision.h echo version couldn't be found - check include/gpac/revision.h exists -if not exist include/gpac/revision.h goto Abort - -REM execute svnversion and check if the result if found within revision.h -for /f "delims=" %%i in ('svnversion.exe') do Set VarRevisionSVN=%%i -REM 'M', 'S', 'P', ':' are special 'svnversion' results -for /f "delims=" %%i in ('echo %VarRevisionSVN% ^| findstr /i /r M^"') do goto RevisionAbort -for /f "delims=" %%i in ('echo %VarRevisionSVN% ^| findstr /i /r S^"') do goto RevisionAbort -for /f "delims=" %%i in ('echo %VarRevisionSVN% ^| findstr /i /r P^"') do goto RevisionAbort -for /f "delims=" %%i in ('echo %VarRevisionSVN% ^| findstr /i /r :^"') do goto RevisionAbort -for /f "delims=" %%i in ('type include\gpac\revision.h ^| findstr /i /r "%VarRevisionSVN%"') do Set VarRevisionBuild=%%i -echo VarRevisionBuild = %VarRevisionBuild% -echo VarRevisionSVN = %VarRevisionSVN% -if !"%VarRevisionBuild%"==!"%VarRevisionSVN%" echo local revision and last build revision are not congruent - please consider rebuilding before generating an installer -if !"%VarRevisionBuild%"==!"%VarRevisionSVN%" goto Abort -REM echo version found: %VarRevisionSVN% - -move packagers\win32_64\nsis\default.out packagers\win32_64\nsis\default.out_ -echo Name "GPAC Framework ${GPAC_VERSION} for %1 revision %VarRevisionSVN%" > packagers\win32_64\nsis\default.out -echo OutFile "GPAC.Framework.Setup-${GPAC_VERSION}-rev%VarRevisionSVN%-%1.exe" >> packagers\win32_64\nsis\default.out -IF "%1"=="x64" echo !define IS_WIN64 >> packagers\win32_64\nsis\default.out - -echo: -REM ============================================ -echo Executing NSIS -REM ============================================ -call %NSIS_EXEC% packagers\win32_64\nsis\gpac_installer.nsi - - -echo: -REM ============================================ -echo Removing temporary files -REM ============================================ -move packagers\win32_64\nsis\default.out_ packagers\win32_64\nsis\default.out - - -echo: -REM ============================================ -echo Windows GPAC installer generated - goodbye! -REM ============================================ -REM LeaveBatchSuccess -set VarRevisionSVN= -set VarRevisionBuild= -cd /d %OLDDIR% -exit/b 0 - -:RevisionAbort -echo SVN revision "%VarRevisionSVN%" is not a simple number, you may have local modification (please check 'svnrevision' flags meaning or execute the NSIS script manually) - -:Abort -echo: -echo *** ABORTING: CHECK ERROR MESSAGES ABOVE *** - -REM LeaveBatchError -set VarRevisionSVN= -set VarRevisionBuild= -cd /d %OLDDIR% -exit/b 1 +@echo off +set OLDDIR=%CD% +cd /d %~dp0 +REM ============================================ +echo *** Generating a Windows GPAC installer *** +REM ============================================ + + +:begin +IF "%1"=="win32" GOTO next +IF "%1"=="x64" GOTO next +echo You must specified target architecture : win32 or x64 +GOTO Abort + +:next +echo: +REM ============================================ +echo Check NSIS is in your PATH +REM ============================================ +if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( + SET "PRGROOT=%programfiles(x86)%" +) +if "%PROCESSOR_ARCHITECTURE%" == "x86" ( + SET PRGROOT=%programfiles% +) + +set NSIS_EXEC="%PRGROOT%\NSIS\makensis.exe" +if not exist "%PRGROOT%\NSIS\makensis.exe" echo NSIS couldn't be found at default location %NSIS_EXEC% +if not exist "%PRGROOT%\NSIS\makensis.exe" goto Abort +echo Found NSIS at default location %NSIS_EXEC% + + +echo: +REM ============================================ +echo Retrieving version/revision information +REM ============================================ +if not exist include/gpac/revision.h echo version couldn't be found - check include/gpac/revision.h exists +if not exist include/gpac/revision.h goto Abort + +REM check if found a local commit which has not been pushed +for /f "delims=" %%a in ('git diff master..origin/master') do @set diff=%%a +echo diff = %diff% +if "%diff"=="" goto RevisionAbort + +REM execute git and check if the result if found within revision.h +for /f "delims=" %%a in ('git describe --tags --long') do @set VERSION=%%a +for /f "delims=" %%a in ('git describe --tags --abbrev^=0') do @set TAG=%%a- +for /f "delims=" %%a in ('git rev-parse --abbrev-ref HEAD') do @set BRANCH=%%a +REM remove anotated tag from VERSION +setlocal enabledelayedexpansion +call set VERSION=%%VERSION:!TAG!=%% +setlocal disabledelayedexpansion +SET VarRevisionGIT=%VERSION%-%BRANCH% +for /f "delims=" %%i in ('type include\gpac\revision.h ^| findstr /i /r "%VarRevisionGIT%"') do Set VarRevisionBuild=%%i +echo VarRevisionBuild = %VarRevisionBuild% +echo VarRevisionGIT = %VarRevisionGIT% +if !"%VarRevisionBuild%"==!"%VarRevisionGIT%" echo local revision and last build revision are not congruent - please consider rebuilding before generating an installer +if !"%VarRevisionBuild%"==!"%VarRevisionGIT%" goto Abort + +move packagers\win32_64\nsis\default.out packagers\win32_64\nsis\default.out_ +echo Name "GPAC Framework ${GPAC_VERSION} for %1 revision %VarRevisionGIT%" > packagers\win32_64\nsis\default.out +echo OutFile "gpac-${GPAC_VERSION}-rev%VarRevisionGIT%-%1.exe" >> packagers\win32_64\nsis\default.out +IF "%1"=="x64" echo !define IS_WIN64 >> packagers\win32_64\nsis\default.out + +echo: +REM ============================================ +echo Executing NSIS +REM ============================================ +call %NSIS_EXEC% packagers\win32_64\nsis\gpac_installer.nsi + + +echo: +REM ============================================ +echo Removing temporary files +REM ============================================ +move packagers\win32_64\nsis\default.out_ packagers\win32_64\nsis\default.out + + +echo: +REM ============================================ +echo Windows GPAC installer generated - goodbye! +REM ============================================ +REM LeaveBatchSuccess +set VarRevisionGIT= +set VarRevisionBuild= +cd /d %OLDDIR% +exit/b 0 + +:RevisionAbort +echo Local revision and remote revision are not congruent; you may have local commit +echo Please consider pushing your commit before generating an installer + +:Abort +echo: +echo *** ABORTING: CHECK ERROR MESSAGES ABOVE *** + +REM LeaveBatchError +set VarRevisionBuild= +cd /d %OLDDIR% +exit/b 1 diff --git a/gui/extensions/H2B2VS/H2B2VS.png b/gui/extensions/H2B2VS/H2B2VS.png new file mode 100644 index 0000000000000000000000000000000000000000..9453f7b035fb3e639aef6d0576a420f61c8984a0 GIT binary patch literal 22850 zcmXtARZv{Z7CpGTyE_CYI0SbI?ry~IHyJ$5n*RuLKM=4`~7tgw$Rt%$3gNETl_uhn#8_%8ZlUUt-ZSBm+5 zFo6Xlc1R>EW8r&4kZGT!=V#UE?Dy1~*P9$FO$1q3I96c_O?HAT$%|}3v)Pvoj3-AV z;FU~8%kN>$ad8)fGs6k!niaHT$^sJxdxF&0eTrOzsJM83+2D{0+z2OEE4VQkI)Zg)G$ zY>5|<0bHO4QWP2JhZ02u3Rw+WZ#-I3sK@HgH!kj%V7R6tT6s(0@QfO=~T=2zj9mzx* zgp&gE5Ly25@j`>IKD~}EDQ770%q3L3A;LPCTkgWuSaQmHHSz_$)|IgRBzxoDEan0N zxx#k_h1$x{lh?`G(8k7w?|#i?iq-vesrE}>C`!QZhn=VrNhzs1#0cT>@t#>cYUZ_< zF`@ACHmkIo!ay&DBeVe-jDMc^CSL8mdqk+o8tH>JC8j81-2`C0Pdw( zNGngTl!Sz~<#;N)?LZ`sm6-=HfuhB@x;t#z(D0@+;{LiB&y$ zm%yvBhG*n^StjIj*Y5GSm!kYJO~LMCTw{ypEfTLuyH9~tuaD|B1iXUAC&2<&F;$Vf z=Ma?pg43ZplrgHTMrA!&$}XI#_+uvbhkx5J7hUgf<+ckIUJl^T{cU_Yi#ah$_lWnH z5|drq8YWOgk!hQL*lUqxv(3Nyv=e|aGNh0-dGPrHcbDxzGwANnVJzF09qaOBuvTxyG* zuAqtJ)D(6T>%9mpGs&QjhY%ll+<)Ua?ekJ0x=ou`6K24rNSi>z%E~It&(BZG$jHbb zBqYQqARyrPZ>#61FAQx;K}JTVPMcZNI6UjCoU$NFinfBJq~uX$^TyMbmXV(Z>^Irs zQwpenE1QaDL!*=9B&1G?IjAvEl8S+oEkAt532 zcPMr$4FsS<7$jT;CVF~&8=edn;FG+!guI{Yc0a#aj^lc(+g}_l{mYC5I%S@3h9(i% zcwZ+w@-GrXXujNfRW7FW-l>Va(uFrx^{Q%H!VbyDHrupT`VSpnDnidli6AmH(tS<~jDukh)uckR$$)!6fMhqd+fn01GbV3%nrFGp(A|8VO3`>URw z-hHuRhWqQeN0*PuT8mQ(q-d?PLhj^ltLIktxB6`Vrz5R(2M@ZoK5_bZ3qEVDa5Uiu zV=r}ebqHu&wFDCKVahMwBg&;T!g)VxjM7!tvOCQSQpn^`3tIeo2uCLRLNgA?2$N%^ zH^X-3V^Lyg!oD_#t~#`xdH8pcJ-_;&UO&$Do!k;Kvgdd63kW#r=q$&za#Wjg%{Y&35QJtJ(9>4SHpbUAL;X1jKM1abZhzB7SAJ_1^sQ za)iglhTqmGQ}s*HvRyGw%CGMH{Cqi5znkeUR}T*l@b_7%M(p^4SK$Q2CL4Js7_K5o zM~lAtI&Y0sKR;TIj3e9W4tU$S-Yf*W(qwM^aWoY9Atb!9&mugoS=hST@+lwu!kctG zrFjvf=~*?M&X(&Bw(=#Tl7lv;igXRsiWPqE|J&}9_LLhfm6u_vV?(#`Dh$d*#v_uS;-_~a+|(ZCDQh6r7;5$2`S>c zp_To>(2#P#MaR8nXhDrc^5QcH*h(N^2tz00E>9%#Zrh`uP9e$`8)9<>{R^d9u2qS^ zqV=Zjo!OT8Es~`j;f;$pHr5vlA)kVRX-q@=0B795)mJDBRiEsXYLX1^JL7 z0#|f)@g@!|2d}fn#Sh^zF_HrAr@V)kp5~IIU)$C>V8)(}n%KYpG?0=5g4* z%#}`Sme1EathaW^p&PI++e#SB_AgBPAD8$)p(PCW%0Yf7%Y)~BB~P5EscX^yfVc76 z<=~ra0<8f|=7${^JpHfo;Bukw6uf%$-NY%Q21U_%Hdip3Yxr{N-PZ0UAbwWmyb^tbbLT1L|_5Ybjq`PuAwxq}IWH!Ry- z;zrTf^oL`VLBXLaOpT7p#Y9F%(#gSdt`7g{S2NASjt0>(;Pu2PXWjdxQn|6Ap~c$H z!NKA9zr9yCG&FQj=|x7&g1qM^^3;}2rK8PNkXu%XI=Q0n8b zRAch{6s^5(k@;O2+^4_)!Sv#2tGKR7?U;wBuybB7BrS8I7(AT=y+sLDUkDhNQkQq#r6#AH7N&yd&ca%Z4E43#8Z zUhktIQnZHVZo06!PAG^JEB~Q%l|h@k#tgv-2;`0%?TSzP+Z@Rt&cv-qQ0e8X>~6oi2p?~sWL7iKfm$LPv7h3LO}t2UO5LHxQC_9geJ zb`S-o=f+KhIi6IT8P^5ekhlMc-9*MmM@x0}M8!f0Z41d98~O6zzn7iBd$4i6mtvGW zeHBa0$MIk9@a3bSp$SnMlKEy5omXF9Z{Hh?fP_ZEuZ}WkAl@slr4_@>43acfSqY(S ztn=&HZzviReR*V1O*wCz=7lxPAV4tio>bJ+W(s=E{JnnEKRY}7adqV^?c?JUHhXj< zTGMMf8@k;WRi2_BcJ?|Y%sUBynIwy zUT*ucpW%4d{;wD5g4wYB;T+uHWq1m2MdLq&JtlpjES?8h9-7{Qq}9_maNdZ}X>X#% z!me&^+fPqV3nK}1@4<@i$K}O?nDrtz2qz%cth>!5UPBF zE-L?Rn;!92Ol<`~*kV^V&&BQyA^h%$w$>xahIHZ2GGNlG(igFs%*>duyf*)%Cx!*& zE?L$e;eM=75V1LtFKj?174&50=61u)>Krgls{^;8x`k63hI)*{AFKvLm_WfTJsnMS zdS=5AybfSm8hui_&s2N>YdwddLRC1rrv2shXKfyvao`bn4{=!hC%5cb%^Ikngv>e$ z3ZNX9>nx^%V33ki6=>a|x=aE3Y<9CjHxQ8MJbjEp>Kgt-$QGx+?ok6A1oTX{!#^pm z2?+_6LfXz%lPy59(Kh&lL;&xmjUOKbI)ocrsF6nK6@EJ7sv{q7d+b2Zxj0n1lV76S z1I0|em%H#d&2&pD&iFBcrAy0EWpdoj%M_d}iUAdYE!vrq(e>-L6&Js{ufdOwTm z$wa-tM>d|Eg@xrd9+aiV$8%*=qhn*SbMy0jHjlr4{US_ZHR^QV>5u5+;N;|#5E+!i zBFWCq7N!RavJTX%S=18?3z~}&Sad&FLAKXKEjw(DLPb-~$HX-D_TNE60RDf7&u;j| z(^_G%4)GwU7&%l8Z_=bYB9xhA?$aLIXDHtOGTm;s{*Gun1K6j6|UQb>L0 z*X6aDDa^l~5_u;M+(OI7qvikaF{(SCjzgTBoM!IMR>#^6tCi!Bnj0J4y6!i8PD0Vh zvU#0%hkYH2>HY1NKp{Fr3^LT0t)B06qK^xx#Jnn;U=y1I8wQG%G^|%a2t38`$jFFc zm;Y<%@$oV3AJ+(lECeU3?#OYSCxR*F{eh2idamngcJ$doJ&{+I)Fq`%cjALrRgwn8 z1qZL%?8%EX>VDehJ_OmDB_&ZA5wW%hlUZRkqy|sH(jNT!s*P{fZaI;z0Z$RfD!<5L-W;7<$!uK3?ou-a0j>Kp zfhR+Xp4m1oq~1+VxmIv2R;b?BKU%w$NIbj#BK7R}#>^*Fa{NND-aqa@OFpqCcxWABur-b$Tt}NQZ>=yrl zWkYx7{_L77MR_ol6Chvu+IH9gvUV%5b0a`YA&<0I=@|0*w!ZEk968X6kP7`Jq3K*Z&(@w%rhFE1^%Rshdq_jta%3uYkb z^7+;C_IQ33?}NT}Cb*cfvyTW@?3%RemrwPY9o9){Sk!fNyuLi$96f?mEo~b+eA({D z;pwTJ9$2zU@V;IBGnBZRAogqDh&RLsz-upDD)|eAje9DGbgvaM*Dq&&^nLip@SpZ$ zsqT7vT6J@C8|tgo^;GgQCHTGW0QQE69N()Et+YL%0gy(uwlp?2(x|8RJG+3&rmU>Y zw$O9v*GlGS_NuZnKFj)LM1UL#deQ^S8dZE@u@C8BJ*p}W!qD|5`QoTM zUamjkHUMPO2qlK$GZ#aVwW8bBrhX=M%wx_jE-uobnKMt9<6CzGax|kR&^}-RwH5|w z>WoRjmkH5itE~=42>ZW0lBBTqqunF%0ov>i~C8Gy?)XIiJiu)Z>Qh2h{RAzyt!d{ zuuWPhe5{Xhl9N|ao4>O^xc*+SQv{b;IW5<>%n z^@jyL$JbTM`bS!&Ol@P^7&d<}dpRDC5+bzB7k;%C{ZC(?YCHPsWzYIj8Kzo)i{r(r-eYThu)yUdb;vIim5^sG9GkP zQ6!&YD0UeNR<6CU@59#+YYLu>$x^WU{U8$&MoKhHV;;MT#9`tIZnG8uiEc+t4I5mL z-*}+t`*a;`ibRO~CB}a061>{*YaRsfrLC3dMO*98&ih7aOfM$oOCz0TDx`(@#y1T0ex2w-O z>=Du!`;1*3a&(LwVp5o4JTl-AR^C=nuzG^kkDz6l4T*-MtQ1v0pggWH5)%_WoRKNS zM#4r7#xy~b-)~t^SgOtoR%1UBS2?=Ox7|=idIqgyVmQW8my?U|f4P4o&Jyk_q2q{p zh_{-yOyFCvLp{l&fbMLqIxqhEC?yx4h))owo{F9V1?ZSz?R*AQC?lfS9URZ^n&w^I z=6znA6}@bw-O3kN=k~P9aRgNQpDB=#0PPR0hxsG_xv28EQ6YNCsn>16pbhl{G#;2h z?v@!mG*cwc>iPC~5P-*sqLbWnao@)|C3rphdcXNjIO3wDq%;#pCH)qHjyNXM0xH0_ z2QVM$LI7I*He+aYp#2Wfq6wWhr$UQ`;R6Atb-Tic8Fu3$s2>2(R_t4Arv0k%ccy~SgEt;X?7xS$LGuv;d0sY-nwS#y1E{EKC3 zsjK)IR!oNS)w&m|CY|cH-e9ATEV2wL)&0&@Exs8U;F)QV-Sor3alSJ_v8`EiKA`bd`*lB3O$kn8l5$`|7->Fm1RzI| z4R16OGFg&zk+w99vyaU(=1JRuU<3A_rP&6-6Mp`;5{Z@L-}=5JV5GG`ayOQ`C<6fu zcaf$&FL@n}bRiS&^#Fk~1klz4mn-kjt8ss;gX7b#6;d}doH?u8C~g0YN%=yU0l~)A z1-Gwl9x3m0;f{8}%etBPMjS52Gx;wN?3{2Csr3K_lMp6MH^F=_04&Y#-)fLKT&%S& zPB(p#H@hCh`p}GZgA1>0k_OT33|fZ<&qE?_m%`bb@M@s`%fw-hre@-MOzieA*`5zi z(LYP?l}W$3H@HidOik%>x1$+}0l3IAmAmPXu#%TR5i`^!TRsi8F-Dy+auc+kxo`VK zd|Dhj=UI@d_&E^RG?C<%<5zRgb|AbSU}xo#>xS#sAT=7AX4lTL?O%w++ub2h!u%QS?>)b8wiUVWEk_jb=|blw)AI1quD&746*l9QQ|?8-`B zDXY#195RvuiPWoj42Wa&WUhX=I`NF|3Sw*dq8(V*Fz~*GMhhSPD0edO2{2r2ET7!) zQ00CLjhfH+bE2CW=*oDIBpR&(QG5YnroL~%{SQP{QzWNLXV$NWIZ1Seynj|y^Zs#& z=h_a(-|QwRcYZV*jNWmX67s-xG-WvZM{BZZ;ITdcUc>RayF2%ffQ-GpeHG|%RkeYU zSoQ9|KNw>0p`bOv35tiCy1F_-cvmEo*QZ+nsTjfm4ebhj(5@%5t<|QE9V$>8J&pS7 zZzrnZ8qH?h9T<0&RuJeG!am*fsgh}(4DP#ao~fD_1b1*y;@4w>usN>!f=Y&*9JQ90 zs+S%nEM^Qd2nw7ioRCk#Jke!T;jBSR@Gd>9SFj!T7cNo(92}F$2!o@1Dh`n>GQy&! zEb*feD!DJ{stUhCLVUs`>8s4GS2U)KKG#_c#JFsxvGMX{F{G$)oNTn|h<$x6d|A$T zbDVBIh$X(#tCy8SoCCL39RdP^;><;AuI-b0K_H+rh%DEBcw27i`#dM9=5GSEvzr%UxWbUoU`k|5XKR&7j| z#{dh`=JMxF)VtF{i%<%hY`~-?Px)x1vD*S6`LFoP$9N_zvAc+fOA#M;v7YAGn6Usa z?FtqgWM6&5>cx8Vk@z7n-pPbm@P1DijYA~k{c8LKvOBujNAK&2k0NwaF~xG^!QCLk znBqIgbaH(HTig=Om0s-;Ex7h}cMBO+8awNflFoijiwSoMyE(RT$jH(p7SaP8A zwSsc?EAKy5SdIa&B=6#iBKTP~SnP^y)dxjG{W(d&3U7Kc5x&EQ?+=uL71k&1%Ed7o zTmdRO+DfFZb=J702tcXu|7QWD>}-yVGI2|kwS&j8IMu53o%%A*qK5XAq+dM7M-?W2 z)p?)q#23XH@E#el$L$jX`GGb>?C6NcX__h$gheO0#)_DA2He6IwNnAY7iYWpvYd)eD@{TZ>HumX+@CbH)4rpg$7)P zL4y3Ab>4YdOotvqA&aT+cRPQbWQ+h9gDfKn6jJl)cBX0&6wqoVN?F}oW3O+bvB9@l z)6NipOuRV*BjYHHl=So{RQE%OZE)?%4AjDk%9BJ~Y0$syY3H(jZ25+@ zcD@>K*U(YYj413WmNaDh-7Q=}_3bY_qt;N%`8`bG)(-Y@NaYoX}5^U=BE$0fkH^u2WH6C__Bh{jHDEHO=`NsB!U;atMK1=IF=#^ z=B{DZG?j&rd*7fgWHgS|#fx=OV3)QT5RkH44^P7w-c&YLYG;}L68^%TZ)Yz;T4rzh z?PSU6$faYhf7lbowb^-yI`YT|2UE#=ZG9rYY;AG%*~X@*SjS@ zB%RA>Z}U0+6))fe;bpv}7_|t0(Vi>6z}wSe*P9yGY8GuUx`d?U@_(L(L|C;>{XS8F z4JMZ`A0M9u=z*DIi4d4Erz9nj;3}3GUwV0Y@r_pg3KL^so|IpB!Pb?AfykFq3E~gU zlbz!(T85p`c(Uc9Q~HPvhajJQ6V#gZ_wxgn$Epk1uwy) ztiW(WJZ5ofTw+k1q4K|n#A857At zK|u;n%bc_$5Fudncp84Qo?C{8^yzY15-rE* zg)=TQ_&lBc?v1ycCP@)3aPb;XtwlTd=S}zNrLvq%d6>~0_Xju$j~%EL7UMq@m86u= zv!73qe8_QAii?);7+I1>!=~{1NTpAlgNUqR$MjO!|4|U*YC4jYNgLG!8cdN?w4ZJ^ zqS)fZxkk$I?WU&_4z;?SbfQ|U|EvLROEK^BIWQ>U2c`b6=zm;bl892|um?sjfAfeh zcK@?adZ_7YX9THim7#Ws1&G1ZBFHZK(Fvs6q$H%~*abAqkEN$Xj< zo$I;4t*o-w9~z-6ZyEn@kOS|(oJyaEWFs-G0nFS%x5)>DF{rr5?r%_GU<%^mRadh< z@$%wpY69~8dC;53=R2`EVdCN8arl$_sR^7{_~k+x@%_gnd4|a=w~!Yq28*a7k)({; zmmWD4F2-T1QJolW!`(dw=RdfpdF@N3iPM+UNZ}+F;R9Pf@1B2Om5D3-I|mAKke_zq zbcbssH*Qx|)6gar>o;T6S&Dp}Wr%2~&ND`2o$xGHC@(79-I}K#RYX(@4eF`v0l*ej z^WA+uD=`QE<9aV$Bv=X07(AQHmBgAaK*a^KY!n6&#+R`}S_i>`nn46s+X8 zIs1a=^>y|~K6OVxCZL>*g${U%C7zpUf(|K5C>#tR<YeMi{F3espg}! zGE2>f5OswS0P~W?gN?PNIv*FavB@qHb`gJ2(iGvLDETpu+KqnJG~s<$e_PLNbc+!X zwL^y1(FWCp#~hfYpb~P?;{mR6VQaICpc76C4&})NfsX9ZktcI@F^F)~x>d=^xXp_v z_VwD#PJ%SjGG3NE858_Qw!8_jZV8ve!@2yp;Yqd<&mpcsQM6YCmqoQ-e(5qv8lA{M z0{DF0?oFDWrlKyHZm%pR@s=}xm-+W<|9ndeNYLoO>mD_ydtEj>$M-T${7hS=ZglTPSK zD;gSodiEc>$LU%_a|bjdcakfj5P|%D-?mRudVW`RM!0qrvR^tKU=c*u0NQUS+kYi= zrk#&QBk5eq7wNk03~u3?9au>`+WQ*8P0N9&FVBKxrqImbJivrOAkL%rh-U zW@c(EH9vryjL*3+`v+aCrWD~Bb^sah0M5&hxcX9wtQ<}k{0;o+Y|BK5am#a!SBao^7T1gAko0^({80mTaD@;}q?@)44>u;rZq2 z>Uc24rV}2k;Pd7Hk$DuctQl1PKY?$lUV~Q_=aN$(Jq-QvVUfz#eH|KKP!~^W+~ZH+ z;Wz~XJG)(a!OUqIyb3XWhzvFZwFTSu~7P+4=w=Zf18hZ8;0g z%}~*)Z~RDl^0l(+%()pN&`ylpVrVIHgp=wtZ{bI*NLd+Oa*~Nogn8AGv%tlgm+|F# z+t`pFMooo;_Es?1#2OkB1t1bjcuh@BM$yh6MewYb;>o^XViP>}FR`_X9{Dsre`>|R$L7Q~F}`9MN>%)dZQ%2ExAw#L+0G zYrL>8s9HSD_SBqv(GTDhEHpOOx?((_5?U`K@MA_3oEI-DZ+*Abza#P`gbU6>$_-FZg@021HL6?M)n zvvp4oagzlF)vfL@H5j5SP$jdf5N2uKEvCBGSJJ|Q+9hL(?!w-t9Pt~DpRzFU6HLC9 z#o#G5mF(>7kX3Nw$M$AeF4=o^!EpqA{mit%k6c_W;*Ztvvhfm30%@HP@Nf9R68uCG zMrDxUd+3eOl$@G0uQfv4(1__|!7BQ}BgBsEI`eVz5V!#GeAYP+Jgw>ptyv(UD0z8K zjYB`G+5%0j68@NaqulL6nNr!+9$Ouz>$ZRN-kC;;yEQ}PqnI&8Taui3Z4Ks5L~X%E z#g}&sWBN*4O+6cU{}TO8y^K|t%&dp}6MS1KP2`yM`L))9F;*>#3Y1-Nl$ql>BOS(H zGu|%`0Y>LsP~H$0Ab^muqFX&+y8D*IX^?&H+3!6jR#uO|Ky67->QhGzP(n0Hf)g|cejfUt zeYL-=bA^SosvCbPFJJjvxQ?RiLileByX70L7Re%G@~3~b;Zp*>`NS2(!ulsNOf;>T z!;Sl7$4rf`ZXajMA|4pogGRfVWz{#3-^@%N5m;<;n4#GCq~?-36}aun7Y{zz+CRIR zn)b4W--<_n0$Vp=fBM%B^Ix2&NgGWU99eTj)CvyRC`RX+zxNlC0V)hwjxj!-f4 z@6tHBP5%uC8lWrWd6P()2k!}K;VgoYGvi{l(R*iI5wb^v%I_3#F4_wla#RY%2+Z@I z@y#N#Zbo>wEp(Fova+&BM9-*e!I?}}_CZC#&cysg46!RPPDlN|AAnR=6C|^k2aGan zg%vewrco>yNre%)jg{VLPo`F`JBLkO*xo-0Ibm2z{U9&ECuY2zljf5g_l5G|7{vIJ4luNB*qG|Mcb&eWZl-NZ#g-D~L8^HPc za5c#Rbnh0n*g#cFYP*5C5*s6-tI1HM==e05+OmX2b~PcPX+C0Wu(mS)fyJz9mj} zmIM`-f;x$M)hbj^Q;H)jf~KDlFjz!StxPKG8`6K~UCcwxA!p%<9{BfACd@3h&451N zoabkn8q8pXaQiKs%aIpVS_8HYo3dsyQh_12H?{w`O%P`Vy%S%6Zo)rAG&}d1KEb?G zkn{0?(Wq`IH4(!4Xu;L(!eo~6uUiAANt+d9w1PiOE(Bi@R|>q6{oJ%Q^uACAT-c zX63593rTGtP@ZGfUuX#zXOt1AWAp1U{3=n=fSRU|s^DoFo@Kv)%yML_O+GTyx-f^a zQX?&XIqJFLL#-!S@t~TU;b#_tqonC;18hb|H$U-g0+WN{WycnBAt&bGxcAj-Sc4R6 zc09mRPmLTmLsx!rj*q9tGb;#gN1v8L#%~6XFv(Kc`{>H18UivxNwwcY3%(y{Wi;JFGvcu6K7dNczQu} z$mT_(+LGe3bh_22r{cZBZ|ZU3ljWG9s%uNZEk{xu5P|CPcB~M=r~J$`L=#pn1>Zlg zA^^Gh9UUlaRcIhduSr+biH(_f_m%rB<`4fH+2R}~`D~*Wv78mo7AFMp!iIQV%%OF) zhX}HWv;1>zJUKb%9$RlD&G)4ghh2b+aXj~7rC0d_nSrkDG06#Apn?>lq&61hYF~&B zlND+->&|e=Mot1|j)$7Vikf$4;)*6SlPEmDuk*mdU{hAl(V+kf#1OUWy|%nO`S(w0 zpBe_3*EuY9D=b8WF2?#(OKV+SD0f!3???@6o1M86ijjf3Xow~ffkxd60qVzv@+FG9 zr6Z=QjB6<+(@cjTGO9M;_smNVADY@_m)`HQk;iE-t9asc3^?)2eU{Th}h)*tz*r|Cx}7%+CA86%hR*iMrT zBER3IT^1OoCY!P>V0@gav-?qscMbT|O+$F9;PwVC>_QXKM5G$bSO>xU!M6CODr(KGJl=+NNjQEc*9In*N>c zzur_BR!E!PyAFG4Of7}S!nU9ul1^6?mj}UPr+`wL(tJGD|88{QDvXf7HQY?VI@iR) zW={YKss5r5h%f$ZW7FtNlFqR;%9=c$^8(rdtRl}EM^O`54tQDT_B1efhC&n4|{jfYZpn~l;WbTdk3Xo6=R#7k!TZ^B*td(!a|Jdl= zF5PwVmBjx33H98gi9~pQ-tWOYrETHplE2hw6k!KR_Z4wod<$jr&vrhSb_iY}Qty_1 zFdm^K_vU zBx_|_d!MKD!6{CYM$}p&=nT>HPdZ#?dIpb{U|aF%Y-Vv>bu^U1+mGS*#9{ydm#fd6 zu$t<%@*hLwd&xg!cmneN)2W$6pn>f2y#*w!*%H2XI`-F*csytC0B>YuaAg&*YHe4O z*X`j=zZbNka`&GX2Z%b!^!iASc&X+#A%|SXz08*$tn(b9H~U~n5yRfTpmeCfq~{+( zpA9#AC$Fb9PFacTbHwFP2yNm-WP%=I~zA{dBM03m>2)v$& z54XxIm^iVuzJB_V+}xA`vJs!V#s+(Vh3#L?kMm^07?0nNIKS?MmYZuM78xsj6sAYp zHVhXpP8fQL=8EuV?ZEI}~{eC;* zym~SA>jRVRSq1fjbv<`i3OITYyleh&*c-umjgDPBe_y)2=oXW zRPqxC<8%EXQra^%_hzRLt)CW2=2RQY$9@;(?G1FJ)g0CWqV`tM=s(6G9FZakjM)#6 znhUe|(E;Wqhv*0Kez>H`G6h$_$~<)}=$Kcz3mymXRQM6cN(=Z~u) z{PD+_(LJ_$Je*QrRStD8oebpH%l5WmM)UsBRK+=Pgb5kAwtwqGDx~69u9YkhU4#Gq zp!N!Dk+s@kP3qu$x;OKAQZBkpDZJ?2EO3vGkW621v-iVoo?P@seuz@Y2MTXN<>v-v zyt~5s>yxofZGrc0hCG;pawJzhMGd@q zFV`tbuhje;l(XJiAQMi$>x+%S6~6L_51Oyd{}w*zu_xYT%s0g8%Ci}bdIPRcnX(_ z0evr3pc(ZlY`_Yz$~v5~T$$iP(=Q?sD++VmYmTNv8*;`EvQ!-&WtEC0$|@td{7=Z5*0 zZ7>;?B|{g&ElrzZ#s!8+Z#qkOPTQRRPU~I~`B1bW6Df1EqMd3ff296~30W~;07kHH zsSgld%))eo$yh`tAGmtsYbIh^&&gwVy*)fuFXYi!?#$M3=MEX&;32GiHp6-r(WA&M zeNA6T0&)Z`7k@(~$mJf)Qiw6+e`Ob}kbww|r`c`8QxwEf{9NGu{aZwWt9am?OYTja zZeF6Tv3KM#XD+SB7j5VjXblO^a_x$~Nb`W3?#ug4L8(OCkOBNAo<`w!(WBY}sMQZJ zU$5b4CfjYSSBwC-%n8cQ+~K{O2lus_*FRGR{%H<-OLgkxPfj2GN|Xu{pMKnq)U^%l zITV?5#H(r1wfgyQS~ym8G_~@vy+~9IY zh%%&~(%$O7($#X>=_&bm{+zmJPrcbxoNNygTPeL>IR+1j)nggL9NsN49>)V@g-mIl z8Z0vi^JtO`LSiC54w$5Qu!o#?kyRP)UOq#umXwl(Ewqt;KgoLtjf&w);|Ne=vzusK zCP0z^m2&;3muyqXDP<HfdQhb}GSIbYbQ>FnrapB)(vod_-{9)&J=Pp{kq2Cb97Vu@xziIVWX-P^ z%Y+^fp#HTYsc6%N?W?p()KdysUTjsVTd;UCimJ0MtL7y87ZVA6)&uIYk(d@`F4M>>`y^$u^dk@JKielsK-w6S;8Iiy zV02pxQ2r!XgSP#N)(!ky@o+20vu7k~?)d%cCf)3D!s_nlVNbN@Ns3F9blJa@iN+G2 zSXdlU`?DH(>9K9*Z`2*1z){*{Z;H52ZvzKH(~m<{5mCGLP7^q~e(VmX+wp2kv?+3t zuOp+(r=}4MV};p;@dEc#zsw0FE!BH zeyN-1(8*$O4Af|f-yWf4F3&=>8mJVIE2$D*_AF5zY`l@sYP7`*s&4g$?j4{!F`#nU zAT_U#N4fTcr#F~C77q!fXUF+-P&khI9pH4p!pjpHRrrPT^RYFww#u{m`Ay7o zS7wpIe`o!=ah6OgovQ~AJeAe;8;BCh)I`gMtEFrv7A{#)h-%KXMAqP&mCTS}`$>qU z>2(O-C&0xDzt2|sNVU6E>_6#hE%FnX;iY}T(6xM>GqRtk!Y5)#<8YiBdqb(N=#5K5 zfTGPFj~EKAbzP~oGm4Y`ly-2AE2At4f0Jh}x&;;N2P}nQ+?jNb+i6x1qkD!X9pFC$ z3{y$xDd#6puiS33R!Y`qAU)FO5Mk$ej!7Ku7R28l+qv?4UMgGN5ZP$KeW0dS zs}!2!w{`VU{@tey8!e>GC(5^EyY~+QmY^mQrqyhcbXUhbIPvNsXvA?)T8BA$T*4vS zqCnWi)$O?*!h!}WP|)65cjMv!Cjfs*+UP)JC)&J)W&rTsUE*))cXECGy3ltaY z=o4@KWb5AZZr)Zp_=SpN=YL*v>cMZDoh!QixYQ@(4vevkNjpx-tTjiZ5f3f%#KicY z4Ypa6`XDp={qVxUAnc4{jea#p@X;gvfDuttszHPR06aJCIDA%Px3@Q2Y3S(r@wp#n zMq4Kk-YgmHTqrV&0jNTFZBqUd6YVhQC$U@baRiZ`=Y(S@zhZH?KZ-Wt7F760jaHU}du^dgGh`Zwwei+s*HPb;;M? z)m1a))+4^;`M#F652vQsZ=v%>J0r*>&7rZjDMMpy_ExXYH!L=0CYdy>AM4g*H#g|k z4u-M_Ldtxs)8#nU=~@i{>XNABNQ)&Y(vmSW)|ML^Va^*JA2(v4H8L;5X3aMtln#I; zP<*MRn{OmDMmX;L^nn+>a`gBsr$J_;b2xEMJJx7FEJI6$=zevigA{6@ddg+3owc=H zo(3K^1RveG%P)J#hrs*HwP%KD(HSS#(jP`=EuEAYbB9g?2l3JF%UWIUK3rD)0OqGj zlc*60u;8Rku1>UcxOUYvv2%Wm$g%50Nm^qM=5fnWlwdGLe&ZPADOigS7{IcxIq_MoRkhlmg=5`PpQA7NP9U|9va{3&hD?T+){pHYoIr2ln+rkYQ?8x!S+GLGKb>3?#Ribi{Jd> zyv}ZKHPQ-4$Tu$1l3$XOR@{TUsLw1W$^6n~=e(R{kDUepI=`RR)zu7E3<%!Zap~&MO$Ftkv{8aPyPzU*vl?C4=DTxb9QW6%CdrjitV_!?#>QnCS4iVqJ z$Q&;AP+Mp1%SVsDa@{w3$JchbSBH|BN}TZPk%Qj@1ZGucHEohd ztR7CUzvAW{hc0RN`Q4m!dHD?D%Np@|w-~p)bTWs__uCVV4R7x_bU*DW6Y@nE&L5FE zlaoHF7hK+vW)r+|^~{GS3`xE!5QXx>Va*v#x`7A)R+k_D^KU=j@mCPPqmX<>*v*ZO zWq~$_OtGQ7cH|yo7!emUZ`6Re1=>5-Kc}%<0$a%#^6iVvJ;641dpdr#``}`?&tGLE zGs$nHWJ<}fMJ4r;Z>aAw+-GM5E7EFU5Ux$~R2PkEE>*I#C&ds1>4^A{Fzv%s(q#WM zT^VFyv3%7+$cv52dbTL{6B8htnl7C_nMR?6VGIp7Z9lZ|V4KUqk(n-3UVc=*!3$@C z^Tf#mtGL4A`?swJJ_3xLY|1>oqtfgXLGYeM>EAwW^vyGe4Z4^3Q$S4@sQRGgr?Rni z#ggS;-|r2~tu?Yf4Ec(%TN+xnA`JEF@7vL)qF!B zsju36z5u$4P4fvd&1dEf8oPAb=yw1i3#|$@&sE@_G%B6l-pac_+Hy&Kdshb|Kd;de z@(l;OsiAo#xgmZt&B;mmKIsdD^})*ZrodJ*Ve##Y%ss`HI@@ZMsX;+9bMhPf&Gueq z*02$!$%}Vdu{<-8PDt<}YTgN~j;bN*Nl=&2$b#c47#)9NRgqc10S%`5;RXEEwBjPn z(m$t+_{)$O>nt7?Q}?7Iyi?WineP0YJ1x+xXCk zFX%^#>6Vu^$>FRa12bP=JY!{q*%YtYR-map`iuZv-CoDlZ>^iZt-68yta+$Li_14$ z?B>RnuQA{zI?t-IR+e~aa|MZIO`dD-o$3yrahZFHwVEU?E-fC6+ROY>7xCUP~Vqw#DQ1>~3xibPKVz#4F%u z)vRdBJ*_Rs*HjnmZE5{?Q@2OAW9pfbxu@7M@dI*^+5l4fad7er80am8ddl~EOFSQz zQ9l}JU5=Qr;AvFE10 zZ#%d#L>_n_Ot{4T*uH9LUJjrc7{rvRYGEYziglV|=Ud*I6$kYt1<;f-$3&U^M${WX!#@iXI`nLh;>k{FG=wL9#}eq&Kgb`CMi~?1iC} zDdFo~ZnG`usJg+}*rY zCgJcE$_i zAHS2vPD_a|cw%h!G7~~pBP=LWG&;O;)wSPLTynIdi~MSHI0{wt!h^!K1uD!451q-- zWXN}T@_?kbuRV8JQjE1w>p~mzEvs{E=g2Gp06a2p(l4jwrr#oViRdNYQPuGJtsi{# zs88l9UiMy8A9{^-dVRh?w~!gY(5BuqxmT{0+kGu<|85TaU`3B*o|Kr7`TH?>UqqUu zJOF@5lazYH(7`KTDlUBQoRq{uQ(*6{UgdX6QbN(aqjEnnNhpq$S<9FfaHPHS>(0Or zq4cJld3k1Wq4dTX!-iT*7<5gq!2%#oYfT{tx;C_BC9>ee3Ib`~GE96C%2;)a$9MRu zt>u>;r*>Z`7!aNMY|+q_W(g(Ho;DUsh7PlBP)~511mQdtCfp> z?o!|x=*m=(2A6MQwAGSrkIh(6kTvh>iFtR~Eapsl4Pk(zfG@_Lt;gy&^3wgytZ|oK zJ#p9*Y=@g(qe$N$I@PlFruR4A=94k`VOCxq!YS82VK<&?{;>cKZD!ZEk*TCXQh;l?Lh~(UhS!5P~u8Sbgxs^6A3{%?(%XP;~HAOL=K+^HC~@*XXG-lk2UG zEgSC`fgL75b|PnxeXBD_i1md#Ha9v}Q|X4q_pC&F&hH9`ePJ<4Ihucr<%=vsW25Kh z#6-{iX-V`I&xTtLViP)flv>uwdk z9bRAghWe%r;gl7XM>fAa<3Xqs1Yu_c8*1@$@V!zvnDYT@KQ^E~6J_3rr_7uI00Q%_ z6ve1;asRfo>WbBM4t0Cp1dG}H=H&d>(xW0vbkigmtoA!`f&bG}<8PTUFyWTqy#)d> zcvx+V56$8vSf|%t^~uTRp*s1gwoyasvC2eF`+%rOJMC#=rXd7j^k?M`iLe^q*SA+Z zt9 z{uAiy4_hySuAN@5XRo96t&n~ENfA*K#sYls3)Zm>EUg4sQ^D6Iz9H9$4@Vp`o<6dfc)~&+M7P8ZupwSGa-Pd z$K^g&7$1FUpwdvE6@}F%pc4B)v%C<^gH${LR^4S4aj=~HXv!pbu?%ft(V?1jrypC_ z+WGZAcOL#XEo)9*(&(Od^aiUCZ503n*AMRV4X2c!vsX+W zEj>*A*T!BjVAyb~iQZW>B;Rof1JWNDJ#39dLOELU+G>n&`08?c8nB1kJ3n4_y!IoJ z%z`|z`8Co75_3!_$ZqgLu|P0o#eEH?#NC8}$HzQrH|w0+aqvKIK32AA*Qwhrgv_Kq@UbGU%~Ve&nl z*p_b3;XfTX`g1Q?IOGgixYayCp&moaE6={5x z$Onfpz}BX=fBfIBBY&iyUz0WP!pk#Lp27f<))En)3uuy(pWsohky=Ca%S=dnj}5SN z83bc>dDfLs@I9?cu$)TgXi(JyKnm9a7{UpFWO?ZJhf=bOM~KLrt2FW?HZ|P zeWRqGGk&_UK^6g9sd*NI%rH3!5>g*!E+_1~a;F;(QO#E;#rwz;NKe9w;4uEPC z^?nCLRZPTUd1;H3BzdMi$AQ%Ax;*P{*na5NF6}3^;Iho*;s*<|-bM&pNCzm;Wz%C3 zC8sJg1}(lWZ=i+=vFbA(RxK}8`O-E81{{Q>)1&=F`gncA`eoVm(&hsCM;HcQQvbBZq<2_Hw|CoJyUS;kwYJj(6hfJQ=oHE!F6b(1 z+qBY^i|lg1On~gOY#0I5c6FC6-dcV|mtQ6$Dso|bbk1)_4f#-#P@Kk>K7;xbT{=0b zblG;F-7i~&RpX1XK`jKWTtIiN=Rv7mI9*srr@P|LkG7oq(3+k9^ali$5rB06obflz z8b0{mfU!xvJL*R_c(yZZU7raoMWGtjpnAH!$+_7p<0f5`q#MCTfH49;#?Ea`E$e7( zPx!iJS$^qA)$8}}sTg;pt@C4yv5b{f^hSJ1E=jXUlxz4{0j$x$et7+%U=Qj@c8B0U+(^HQB|i~T^}{r7HR+I zStC{sh%jda>bKtVAs+$|B|?dX$e!cm8&QNubX+xid@NfA9Bj~l2CMq$3QIbsI=e~T zZ>;xNkI!HK&aNZR{C|5_^V38S#ov~Sr4|ID#fS+gL}SEiFcL3%GzJbNaxpRCZ1mv4 zKY@gQfW(7dj4>g`VB{jkj|51n0x>kT3f8m`1EsWuPIpTyuqT!HsUViH zBWoUpHF2x+(e`%wD-vH{YOL=sh`NdVca(mk4hL!3CFz|_rWWr^`}=yEk6r6N;eOEO za^4UC>^!{%cGB#iwjW-d0q|Bx+IaaiyfomAC$(X{+5AsYTQRWzt>faosn43bGIl(D z<0TP=5c5WqOqzHr2DCn#tl;$BnPA_igc#P!HB{T}kGoC}*B!8X^8P{nbJdQDiBqW! z(KLX*(LE0(wlEM8m%;B+SRsGAdI1BLqQWJ8Aj%URIrj;PoLFLh%_8s=uWipFzKI+alKNq2F62v3h;!Hbk~l zGOy6r-mS!+cQzjGFI>46^zY2iu8SjtE}lHgdPkR|lcUSg@s9f1_U_~ETNfJYdYc>v zJpfQG2m;Y|^3GZ#9uH%zWMn1ajjxZ4MPkqVNL*yyZ#lLy!SeD@LfML8&GumxjDbVx z?8k{1vT{nVyt$)juQ*uo+PqZ@u5g+rC&F`7G4suhWLSlT?!m z0N7A=Gdlh=V)b<6k|~r({a%%_YXA`OEhXlIaTHvYvNBP`VEY<-72G_3@``sMYUQAU ze?kju;GPTNbt)y#QbfASoO`(jWi~w%0n3 zoN^uNY;!q1EiUKT<{C%qQAf2KFm40@7XUa^+!kOE0U!}bii;U}XMQdveeomd^S6{l z4*R%z%c(O5%Zko;JX%)8u>u3c62x*ktf5^oY$=#xGAfA$PI=yS-cw+=W6d5eR-T0W z*u8<}ITwSv5jT2BNdN!<07*qoM6N<$g8!|xXaE2J literal 0 HcmV?d00001 diff --git a/gui/extensions/H2B2VS/h2b2vs.js b/gui/extensions/H2B2VS/h2b2vs.js new file mode 100644 index 0000000..dbd8b75 --- /dev/null +++ b/gui/extensions/H2B2VS/h2b2vs.js @@ -0,0 +1,392 @@ +extension = { + setup: false, + dialog: null, + uhd_demo_enabled: false, + uhd_demo_on: false, + uhd_state_on: true, + active_addon: null, + icon_width: 0, + icon_height: 0, + movie_width: 0, + movie_height: 0, + + toggle_uhd_demo: function (val) { + this.uhd_demo_on = val; + var notif = null; + if (this.uhd_demo_on) { + notif = gw_new_message(null, 'UHD Demo Enbaled', 'Click to toggle quality'); + } else { + notif = gw_new_message(null, 'UHD Demo Disabled', 'Double-click to re-enable'); + this.logo.children[0].url[0] = ''; + } + this.do_layout(); + notif.set_size(20 * gwskin.default_text_font_size, gwskin.default_icon_height + 2 * gwskin.default_text_font_size); + notif.show(); + }, + + ext_filter_event: function (evt) { + switch (evt.type) { + case GF_EVENT_ADDON_DETECTED: + this.confirm_addon(evt); + return true; + case GF_EVENT_QUIT: + this.save_session(); + return false; + case GF_EVENT_DBLCLICK: + if (this.uhd_demo_enabled) { + this.toggle_uhd_demo(!this.uhd_demo_on); + } + return false; + case GF_EVENT_MOUSEUP: + if (this.uhd_demo_on) { + this.uhd_state_on = !this.uhd_state_on; + gpac.switch_quality(this.uhd_state_on); + return true; + } + return false; + + case GF_EVENT_MOUSEDOWN: + if (this.uhd_demo_on) { + return true; + } + return false; + + case GF_EVENT_SCENE_SIZE: + if (typeof evt.width != 'undefined') { + this.movie_width = evt.width; + this.movie_height = evt.height; + if (this.movie_height > 1080) this.uhd_state_on = true; + + if (this.uhd_demo_on) { + this.do_layout(); + } + } + return false; + default: + return false; + } + }, + + create_event_filter: function (__anobj) { + return function (evt) { + return __anobj.ext_filter_event(evt); + } + }, + + do_layout: function () { + if (this.uhd_demo_enabled && this.uhd_demo_on) { + var url = this.get_option('path'); + if (this.movie_height > 1080) { + url += 'logo_uhd.png'; + this.logo.scale.x = 1; + this.logo.scale.y = 1; + } else { + url += 'logo_hd.png'; + this.logo.scale.x = 2; + this.logo.scale.y = 2; + } + this.logo.children[0].url[0] = url; + } else { + this.logo.children[0].url[0] = ''; + } + }, + + start: function () { + //first launch - register event filter and exit + if (!this.setup) { + gwlib_add_event_filter(this.create_event_filter(this), true); + this.setup = true; + + /*create media nodes element for playback*/ + this.logo = gw_new_container(); + this.logo.children[0] = new SFNode('Inline'); + this.logo.children[0].extension = this; + this.logo.children[0].url[0] = ''; + this.logo.children[0].on_scene_size = function (evt) { + this.extension.icon_width = evt.width; + this.extension.icon_height = evt.height; + this.extension.do_layout(); + }; + + gw_add_child(null, this.logo); + + this.logo.children[0].addEventListener('gpac_scene_attached', this.logo.children[0].on_scene_size, 0); + + this.restore_session(); + + //check our args + var i, argc = gpac.argc; + for (i = 1; i < argc; i++) { + var arg = gpac.get_arg(i); + if (arg == '-demo-uhd') { + this.uhd_demo_enabled = true; + this.toggle_uhd_demo(true); + gwlog(l_war, 'UHD Demo enabled'); + break; + } + } + return; + } + + gw_hide_dock(); + var wnd = gw_new_window_full(null, true, 'H2B2VS Preferences'); + + this.dialog = wnd; + this.dialog.extension = this; + + wnd.area = gw_new_grid_container(wnd); + wnd.area.spread_h = true; + wnd.area.break_at_hidden = true; + + wnd.txt1 = gw_new_text(wnd.area, 'Overlay Position'); + gw_new_separator(wnd.area); + + + wnd.check_pos = function (value) { + this.chk_pos1.set_checked((value == 0) ? true : false); + this.chk_pos2.set_checked((value == 1) ? true : false); + this.chk_pos3.set_checked((value == 2) ? true : false); + this.chk_pos4.set_checked((value == 3) ? true : false); + + this.extension.set_option('OverlayPosition', '' + value); + this.extension.refresh_addon(); + } + wnd.chk_pos4 = gw_new_checkbox(wnd.area, 'Top-Left'); + wnd.chk_pos4.on_check = function (value) { + this.parent.parent.check_pos(3); + } + wnd.chk_pos2 = gw_new_checkbox(wnd.area, 'Top-Right'); + wnd.chk_pos2.on_check = function (value) { + this.parent.parent.check_pos(1); + } + wnd.chk_pos3 = gw_new_checkbox(wnd.area, 'Bottom-Left'); + wnd.chk_pos3.on_check = function (value) { + this.parent.parent.check_pos(2); + } + wnd.chk_pos1 = gw_new_checkbox(wnd.area, 'Bottom-Right'); + wnd.chk_pos1.on_check = function (value) { + this.parent.parent.check_pos(0); + } + + wnd.txt2 = gw_new_text(wnd.area, 'Overlay Size'); + gw_new_separator(wnd.area); + + + wnd.check_size = function (value) { + this.chk_size1.set_checked((value == 0) ? true : false); + this.chk_size2.set_checked((value == 1) ? true : false); + this.chk_size3.set_checked((value == 2) ? true : false); + this.extension.set_option('OverlaySize', '' + value); + this.extension.refresh_addon(); + } + wnd.chk_size1 = gw_new_checkbox(wnd.area, '1/2 Height'); + wnd.chk_size1.on_check = function (value) { + this.parent.parent.check_size(0); + } + wnd.chk_size2 = gw_new_checkbox(wnd.area, '1/3 Height'); + wnd.chk_size2.on_check = function (value) { + this.parent.parent.check_size(1); + } + wnd.chk_size3 = gw_new_checkbox(wnd.area, '1/4 Height'); + wnd.chk_size3.on_check = function (value) { + this.parent.parent.check_size(2); + } + + wnd.txt3 = gw_new_text(wnd.area, 'User Identifier'); + gw_new_separator(wnd.area); + wnd.edit = gw_new_text_edit(wnd.area, this.get_option('UserID', 'H2B2VSUser')); + gpac.set_focus(wnd.edit); + wnd.edit.on_text = function (val) { + if (val != '') { + this.parent.parent.extension.set_option('UserID', val); + } + } + + gw_new_separator(wnd.area); + wnd.chk_addon = gw_new_checkbox(wnd.area, 'Auto-select addon'); + wnd.chk_addon.on_check = function (value) { + this.parent.parent.extension.set_option('AutoSelect', value ? 'yes' : 'no'); + } + var do_sel = this.get_option('AutoSelect', 'no'); + wnd.chk_addon.set_checked((do_sel == 'yes') ? true : false); + + wnd.dbg_addon = gw_new_checkbox(wnd.area, 'Debug PVR addon'); + wnd.dbg_addon.on_check = function (value) { + gpac.set_option('Systems', 'DebugPVRScene', value ? 'yes' : 'no'); + } + do_sel = gpac.get_option('Systems', 'DebugPVRScene'); + wnd.dbg_addon.set_checked((do_sel == 'yes') ? true : false); + + gw_new_separator(wnd.area); + wnd.uhd_demo = gw_new_checkbox(wnd.area, 'UHD Demo'); + wnd.uhd_demo.on_check = function (value) { + this.parent.parent.extension.uhd_demo_enabled = value; + this.parent.parent.extension.set_option('UHDDemo', value ? 'yes' : 'no'); + } + do_sel = this.get_option('UHDDemo', 'no'); + this.uhd_demo_enabled = (do_sel == 'yes') ? true : false; + wnd.uhd_demo.set_checked(this.uhd_demo_enabled); + if (this.uhd_demo_enabled) this.uhd_demo_on = true; + + wnd.on_display_size = function (width, height) { + w = 0.9 * width; + if (w > 500) w = 500; + this.txt1.set_size(w / 3, gwskin.default_icon_height); + + this.chk_pos1.set_size(w / 2, gwskin.default_control_height); + this.chk_pos2.set_size(w / 2, gwskin.default_control_height); + this.chk_pos3.set_size(w / 2, gwskin.default_control_height); + this.chk_pos4.set_size(w / 2, gwskin.default_control_height); + + this.txt2.set_size(w / 3, gwskin.default_icon_height); + + this.chk_size1.set_size(w / 3, gwskin.default_control_height); + this.chk_size2.set_size(w / 3, gwskin.default_control_height); + this.chk_size3.set_size(w / 3, gwskin.default_control_height); + + this.txt3.set_size(w / 3, gwskin.default_icon_height); + this.edit.set_size(w / 2, gwskin.default_icon_height); + this.chk_addon.set_size(w / 2, gwskin.default_icon_height); + this.dbg_addon.set_size(w / 2, gwskin.default_icon_height); + this.uhd_demo.set_size(w / 2, gwskin.default_icon_height); + + this.set_size(w, 13 * gwskin.default_icon_height); + } + + wnd.check_pos(parseInt(this.get_option('OverlayPosition', '0'))); + wnd.check_size(parseInt(this.get_option('OverlaySize', '0'))); + + + wnd.on_display_size(gw_display_width, gw_display_height); + wnd.set_alpha(0.9); + wnd.show(); + + + wnd.on_close = function () { + gw_show_dock(); + wnd.extension.dialog = null; + }; + }, + + refresh_addon: function () { + if (this.active_url) { + var odm = gpac.get_object_manager(this.active_url); + if (odm) { + odm.addon_layout(parseInt(this.get_option('OverlayPosition', '0')), parseInt(this.get_option('OverlaySize', '0'))); + } + } + }, + + do_activate_addon: function (obj) { + var odm = gpac.get_object_manager(obj.scene_url); + if (odm) { + odm.enable_addon(obj.addon_url); + odm.addon_layout(parseInt(this.get_option('OverlayPosition', '0')), parseInt(this.get_option('OverlaySize', '0'))); + } + this.active_url = obj.scene_url; + }, + + confirm_addon: function (evt) { + + if (this.get_option('AutoSelect', 'no') == 'yes') { + this.do_activate_addon(evt); + return; + } + + var names = ext = evt.addon_url.split('/'); + if (names.length == 0) names = f.url.split('\\'); + + var dlg = gw_new_confirm_wnd(null, 'Addon detected (' + names.pop() + '), enable it ?'); + dlg.set_alpha(0.95); + dlg.show(); + dlg.extension = this; + dlg.scene_url = evt.scene_url; + dlg.addon_url = evt.addon_url; + + dlg.on_confirm = function (value) { + if (!value) return; + this.extension.do_activate_addon(this); + } + }, + + do_xhr: function (url, cmd) { + var xhr = new XMLHttpRequest(); + xhr.open('POST', url, false); + + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.setRequestHeader('Content-Length', cmd.length); + xhr.send(cmd); + + if ((xhr.status != 200) || (xhr.readyState != 4)) { + if (xhr.status) { + gwlog(l_err, '[H2B2VS] Failed to query server: ' + xhr.responseText); + } else { + gwlog(l_err, '[H2B2VS] Failed to send request'); + } + return null; + } + gwlog(l_deb, 'Command sent is ' + cmd + ' - response is ' + xhr.responseText); + + var obj = gwskin.parse(xhr.responseText); + if (typeof obj.result == 'undefined') { + gwlog(l_err, '[H2B2VS] Non conformant response object ' + xhr.responseText); + return null; + } + if (obj.result != 0) { + gwlog(l_inf, '[H2B2VS] No session found for user - ' + xhr.responseText); + return null; + } + return obj; + }, + + restore_session: function () { + + if (gwskin.media_url) { + gwlog(l_inf, 'URL was given when opening, skipping session restore'); + return; + } + var server = this.get_option('SessionServer', null); + var user = this.get_option('UserID', null); + if (!server || !user) return; + + var url = server + 'getData'; + var cmd = 'ID=' + user; + + var obj = this.do_xhr(url, cmd); + if (!obj) return; + + var dlg = gw_new_confirm_wnd(null, 'Restore last session ?'); + dlg.set_alpha(0.95); + dlg.show(); + dlg.sess = obj.data; + + dlg.on_confirm = function (value) { + if (!value) return; + gwskin.restore_session(this.sess.url, this.sess.media_time, this.sess.media_clock); + } + }, + + save_session: function () { + var server = this.get_option('SessionServer', null); + var user = this.get_option('UserID', null); + if (!server || !user) return; + + var obj = {}; + var url = gwskin.pvr_url; + if (url === '') url = gwskin.media_url; + + obj.url = url.replace(/\\/g, "/"); + obj.media_time = 0; + obj.media_clock = 0; + if (typeof gwskin.media_time != 'undefined') obj.media_time = gwskin.media_time; + if (typeof gwskin.media_clock != 'undefined') obj.media_clock = gwskin.media_clock; + + var str = gwskin.stringify(obj); + + var url = server + 'setData'; + var cmd = 'ID=' + user + '&Data=' + str; + this.do_xhr(url, cmd); + + } +}; + diff --git a/gui/extensions/H2B2VS/init.js b/gui/extensions/H2B2VS/init.js new file mode 100644 index 0000000..3f2d800 --- /dev/null +++ b/gui/extensions/H2B2VS/init.js @@ -0,0 +1,16 @@ + +my_ext = { + whoami: "GPAC-GUI-Extension", + name: "", + icon: "H2B2VS.png", + author: "JeanLF", + description: "H2B2VS Preferences", + url: "http://h2b2vs.epfl.ch/", + execjs: ["h2b2vs.js"], + autostart: true, + config_id: "H2B2VS", + requires_gl: false, + version_major: 1, + version_minor: 0 +}; + diff --git a/gui/extensions/H2B2VS/logo_hd.png b/gui/extensions/H2B2VS/logo_hd.png new file mode 100644 index 0000000000000000000000000000000000000000..ee32b4a91aa02daf438a3bff7b7c9257c180f361 GIT binary patch literal 16123 zcmeHtdt8!t|2NH*Tbb_ub+>etw(Z&N?rE9xR36u?+f{dVP(ehcMxrH1rih4O%??|6 zSnEj_q;y!BfS{71C{Vd@jgXaHqN13gk{1dpU7{%ZTpjFwocDUy-wfv z_w#)pKKRqV$cUB8KUt1IAXe`DZud&!et#weSk*5=>yw8LLM`S+h6K05U@`n#`p-umj|^2+JY73|7gdw$t<0L?jw z5B|{S^2x(l&dx}?e6)kJS7*t1+QyQ)&R=+S05~{MY;Jl6Nf zf zC(7U~sNxGYRTUL`YcUdv$EgI9L@KTn^TnLN+M>M7g7iFcGBlioHufEoqWBhMNFtq4 zrtsikI{e~m+J^6W%gX@w(xmBG*U9I9<;;6eP_W$kCx-mQT{I-r%yu42&9C98r)T9kk#nv{CxX++2LMnkN-x+XMA z!nIyXLQC(o#FipS*j5_R=l761MRk7KpTOO~442KFOTp}$ivjX52~AqskqY61{UKs$ zTS)*zY;{w8oGmb0y*Q+<$;nD^4JWU`Q?Y;k^K#eKci+r;#9r+e-ZkpzAKuSgeZ7>I z=a#bUqS{yWAtMU90VoZ6%sm5pnFv>aLgn4C%JH|YhkagzbUPrOeDgIP%zG1}s*J!m z+hZ4VU@ar7A!k1n4q%U-`K>s{iKhy^Q$$IEO33uR(K7PT^HygPf35{w+c6D8leSFi z&OBruG{llPQgKd~v#z4e;bf~bDtbN<`rI%Z*E;<@nUG-k!qCI7l8Vsjvu$ACm6}$s z5Cx@O6HxX8=)X`XqoMO8P;_mmE!x0XzCw5mjnhk03=bwA9R&(uHt8a3SnL|r?L)>dPSSKMoeq&HlHcmNis1Yx-USUJzwitJUhHW*gYAR za;7~-6eD}gdt|#W4lDJ=e4U4Z)&oh(XVXS+d05xcvgZ2sxfRNzFFcsrEHvglV{!+5 z>tBTa*)wEQqKI#aXmzH*x4cYt-RqmL3pb=TxvNb#g}IC!kkwmGYkTr!dMHw)(oS?i zG+ppV2)oy_9^=84e;!vbPq*nYocUW+e^VJS|AZG`g)XGsGBEqW8E#%Y{VH6zgfqWa zFfZ{)gk|jFn6M}tcYPbn_J^}B8qz7xY1RCUMm-^lRIa8)KokzeOL3eqvlLh0sW={oDp&LzBhBiZ8wVti26Svr2I ziEoI7W`KMH2IXrvxG})D1vt-KEecZyQ>K1*oXO0C&X+mnl8z#m1;}HW8-J4>)dbEB zqVM-r)%?pR*LDe?`XU?%i1CUq8GM|CX56p>_`CG_kXL({QE5e$@!PZ$f8w`Ddsi^; zjZGFzoCN7GeY})Cn|-&4@maO#pR6ZWs@IX~f0%2*Kb!tzYeC*^>YOpsn2I!{E#EBb z0yOd>)yG*gIpENxho&+sSph-kpYkC5vs;7&YJw@m)9_+^jw_J0 z4FMT2J!*jfO(K;y(i&VQLc4fk`c><;OWe( z?bO~B)1lEwM?NlX^x+EC_}oS1u4ftiKN3m?JDqh-9Exv?p1JxV$r;yNVddaErGqKZ zS$GeCdK%-MekWpD`egg*sX}nF2DAfOVa>F}SOUVIMKCXMP1(zCWpUb9%M^j4in^zf zXGIZQEZ2C1bm@^s|MEh`)NHYz-Ah5jJbgbT#(!iJ4^7|47?0K$4h64T;Gt$edBbgM z5r|=)90&ozcnq#M4_%^5Zq#39Y9E5*kjYMYuFG!p+RB&Cx_uRPx>fKdNI`y0>YdpR zDFC-J-IbC^wtX(&$kk#c*V-@rA-J8`?r=h+U8~G`%r>tGnScN8>taO&vlF@<+?@RL zl@wH1lc%C)rDa{EV~AZwP-1UWo8cQWk(@5fp+w*c@&QW>>FAkCnV)=W6c0^&uIvEp zxr)-HuBcyw#~&HiE_)6=IvEw)=R^=-T=OYYL=IklK}hwqVUv$?%zK zSusj9`e}CaH7^n>cbg~7F9qY5@y}>za+J>&Nk%CKwuf3CAvBSG99`lq&%WIiHys0f z0dVEc^LWum*#+rD2nSn+s_HzBbv7!#!(FXDFH%CP7_ZJOB@u|Q`Fa(+vvB$vA61tm zyZr&KV2!V42X@jyX^K+*RgXu^?!guGwvEuyWS!NbD|0MxBi18BA3I314VAg!H{!9d@M$MH5Ki% zkDdw*fw4aC(+`njpwd=nFFu2eE^%+u55S%}R6cbHgbZddijTsd=4nM zu=i-ZY!2CHdtU2lA*`KP1*lMYRpRR|U&?B8RNZOT3y|2O!y>DrmW&;s-?A!`(B(b; zvM5|Z6UUuJyeV3js1M{gv1@oLqzI{ICp~1x>Hk>z*;`xwtTAO|@H#~3vH0e2%{7zZPYS@-CFjSrapFw03EjF?VI6(eg0*@9hbH)OxaAakG5}rnbi+XTA)d zWW1>S*?JxSLGEGt5WJhXTCzOWz12BP#Meh~Qn@6;ndagEO}P5ehcLPR?yCIiIh!Av zUGh)HZ&n@oiXAOhbpuym@%N}KCd|CpE)02T$B?cmLO8!(;uE%k6lffrz<)7ZDU8qH zp?6qM!`i81ErTVj&08MC>Nf`Xd(fQ7fwRHrkmgVeiqpqS6f@?!@%wVr^^L*tbi#UF z#;EJR*hi6SS5kR9?WJc%ZlAO69{%P;K!D2FyZoj|zC{~svUK3bW@Z$%>w*-q#YNt8 z`+c6;jCk^RjB<09$K8;|HeC_^#Y`$--{Joxxrj33taDe}8gHUQav#_4Hf~ig!(t^B z;xrA-$zK!3p743Hk{ahd)$3A_FVY(GLTFi{8n3FfqsUHa zwab_*X_=UUdS$Hc)*Fg_TiWu0pI~o&Og@97&+n#XPXbCpTBU2xutSfxe20?LyO!BM zJgEF@@+bTWYa_@{Lc3~oj6^NrK`u;tpDQ;{*MM{QYPu>h4kOUdCU!eW4VfL;ndp)T z3Od8U7#(hUUipp`S05>;8L@0WUQqLtkR)+y)f|~E`ykINc!5*K?(kx|NR^3_{@Sw~ zY#63)v%c8pZR9#pVfYTR1A_eH%~DWA1WtePw!{$Sd<9eQVEUh7MPNCYjv*gfU;Q@E z+-=V!la*&wdyyhkE8+h*r8EXbn3_!?>uWt*kO{F1yZzZe*Wx?@1xt@G4Lk5H@i+@6x7*@O z&AK9iDoE_9Sf!uddR7&iY%te%P+@?gRL|AvJB3SM*7h@-IIXth|G`1^A)G#e^IR5J zz)y>trziRRD7o!|2-_bL-HV}rUod_FY=>(|vw2d%5ggHf)uBSU@i%d$eCrvI%UR=R z*R3=7gayc_bfBH0HrM!1zWEpM47pGQdpT}LGB&;tuEOugd1Q^V?gr2b7ffDhjZ+K> z-5SJd;yS&ui3RCsSU1Q%BaGW(vcy;jtWY;Lr<9o@BV$TYeOu+7%XKDBXsxGWr)Yd>>QZHbm#NAJw7uZB{5w%7~+t2^XpNoJWr z!BNOz&cU3A4^8F3if{v+-gKqq6R)Gop7g~@_^>5sLjZzViTR z-{CE~LO@2l5toex_@5ez9ZSy4L6$)6Lhf7 zTq??_Gmevs6NScySrJ@KX_8B7(}<#6zRrzQe`4spEeBV;;f>B>xw9Y*c|$rB>^M^h z$1E#ExzN#{d(FvotS?EK@w3-f zMRIWrMWEl@SAD2JGW9*V7&~?P(}l)Np9?NNo{lwp_7s--tETDK(f0zg8s~li3zOfk z^%_=a*0YanRrtXC{h0}Wq&{Cd?wOiPhj7YzCF=@dSv58e+d4VcQyK%SYp3f|SF}F; zU`sp&+%S6@BLC*{8TO^GRI3V5c@Dkz*Mfhyy||?GAqK4W)dGa7*-AX7U%>+I_tnnP z{dWtyE#LY0^2JgiN>VlV`2Vb zISImZWOoX3J{c-cLKme;w#u{j``osz7+v>o*P|;-TAk0reSox$g>F@IRA>dDe=XPz zw{u944p6Q&!ll1izNOkzQ3**zsJ@y*MebZIf36RN+b#rwKST9u6X$g~P$|dvkcky` z&r(?@$I>FJEIr7OhPFW`*0s?=V1~0dAiozC5N;{^!P?60BO*7GstlG_73j`5^uaQsVdX_J?~og@(snlsyn^W4|1Aa=H_g$5_IKcpi3^o z!itpjI$WUSz`5i6a6SN!7&xXQ$N}SkQ-_|ObygJ?Z;OPwv)X1IErZExuzkU9*%xtu zS40p2O~i%NHH~48yv_4_YeT?c>=Sr($se z2-(_jKt=i>Pt-xhRB(^0hQ9H6mR5z79x?Ork@o(LyMy?u&nF+;|!8=HP{^U$(Y7=RG0p&ZR)#K+}G_9_4P%8X_z%5Gkvg6c$p<+l4oeH-(5?X0@F|K9@}VIUus%gl@j-^3*gC z?eil=Yw~#)ju;uu=%r081#9#yHVSUD9TPr(S%m*`wgwaerT(Yxd8KAx27;K$+O*@> z;k0&`dvr3|=M=qn6HX#?`Q9}2+}~d8&RUWMBoRZS8o|BHQK1F=f=)d@?6aPm_Ucye zIGkb5HWz42DVAN&m>Yj|LaBKI!IAQsCbH{TQ>(L#hEFm$>kdNaR;rv0Hj8m$c6axc zrZSH7sl#DXCBOIBXbTWwiIwCgkyBdqd-=M$P&0F-+EozxWVoY~Ha_8hRv*Dt&1?-5 zE(Dkn55si5EP);ljS~6CdmmoIzn~H!2*AJ&PvWUKD@qVzFavO(P}H_Y`;3G4OIs_S z{#IBAr7};B!ySS8I&DfwyCtb9*m5Bf^DIlY^io(4 zvLRW_d=$jTZ^;>{bcEY%);7P7s>J-9@iR16qGfr<=YW!EY^LS;I7n)#X~syoSnfVq zUB1TGu5%BrH!-AxkWP;hzDISp@XS4256!yrVlbmDH2>G+A3y%<&4flU@OFr`O*rc) zEI=qA*6(NR@cFl-+2y|R=Ggc_=oW~LcJjk~NeXP4?9UR&>FE$Bf!`=`f!lyCSBwMM zWL2#veAAM(tR<6?MKNx0Gy9>p+)w${U>V_bT`{`_1$&4cYeVyD#Y8yBG9IWr7i`v{+;OYE4GhtNOI9DnjJgONH=>9lwBdziy0H^qKn5 z5ebtT9C0iC8njQ(Q18&5#goYpL~OIp{U*+^%~%tLvhRptVyh|jg3qaTDJLx#x`91y ze;*3|+d{hMVZt8>i2AWCU)AFf>X1F0-3iDx#<7C&Iv_xlv1NLn@Ch{Gk1}@fIwj3H z2hXZx(wvO7-#!O*K!v4YrG0n&63O63z~G-d7Yotgr3-{hZJXuRE`0RvkR~pWCF-{z6@O8ru|VS?eEc zz5t>Edl}QU{%7lMh`Cg}DKSAEjLNX(QFp`KOjB=|+F_uPQZhOwk3r{^$H)qa z(!WDJQY)Y5<*3E-i?FkWBz5Ti=HXmjA4e8MrOao*phvffMVaq)ylx1{q0*|0Jh#Pu+1Ulu>9!iy}@lLO* zI;8z1L~S}PyJ77G*>K_;b4d->^8S(#om4^b33bvjFu(XBuVJd zx)whXGEB`o7vctwVQsLio3`qNElTsbfYTk880?nTWUYD_9FR0rm6@Xb87URykR4A0piI=%d)r8=r_br( zP?6R0$=)JwMm_r8?B`{)FD6Q&4D0gf34O_J$CWn?aRF8RMzAI$cha2`#?wAFF0Hs> zjW;*r%a^<>r9xPu;o#8=UIZuss{4}blEJuE)}f*G$`cb5P8h5b1073gg!8!=$cbYT zNNZfSvt6zi4K+T%@!>Azyw~4@6o!RGf&%r! zmb|myy2dyBSsABrZ&gP2^L4Tt_HdQ}cp!bZ@Va$ha#+;#VKPlG;;{Dg75_)1^1D+x z80M#AD*-^cd2*j{;^lT&)_+5vq$NX_VeO}D^81Lo!~-@I;572`1*qoCOR1B_wOq9y z=3j0{&fF>%sG6#*(PT~H4}I%9s1L+)wXenxE98%lVE<7PoBi5?f>Rvav|RqH z*T5&DxLt1MLUZQ2h0ve7l)BUW@BXsj4nm!SYUjdAOF!cgOGvy;UB|j?06pux{;LJ~ z!v50{B}g%QS6ZTrJHIODE);$4&4%B^(zvXt*=TrW^t?ma$OWG~wQKx3C|=2Sp<1=@z$f${ERoVRAJ52JA-*C_v;lErNg9iZm+>s?K-wp*Yq*z3D`GWUH1n*ra z14Q{dh=aK$Ni`q7Ic@QE5rIVn77-Xy?_lb=2IhL-@G00-|Z+Y9>0jd lA_9vDEF$p#C<4y!u@qC6QSguc>HP!8U+?K`QJBs>*PnCI|BGY2a&9E0j3T@C^LMB3 z4TG&eT9w>>Ic(!RmGh{#TjBWa&mTC-C(F0|{l>}L+PGk|6Wv3L?HF$R&`@!eVA!{` ziEcW!5@kN%nJpIM^|N^*ai}D6s`7bbfOh{Uk@^)STy?|U0>3gTia3XL!Ukb4VheMe#$AD} zL{=I)2xe|B3RuawdTE~{X-)ubhATyT~b2hX5CSpA9_qo6j8{VW((L7h21rC4?fGVy? z?=ZM+qno-XcvHPof+Q!jLSLw`&ph~|@x&y|S8BBP__sk{qsJk3*hs9q)v}<^%td8? z+SUwO#gK(_0XyZI(L1HD&^A%Zu_WkN0d-n!N}wKk!D+o_f5~Sa|qlR93-OpV@xYXDL7Cl0R7KfdRe)(-QJ`}C6@o3!Fi_%Gw<`zC z^2ZvGB@q{~D6EgQT(cYqor zVNdW131zcEx>&LjET&#~7eoT5?FMR+^T0;%F>s$$sV?_A=}MT=z}8r5|C}G$zt$Vg zn_vZ@`1ZDiS#GW_nGNSgu0I?`u^wB&xt&dL8gCJBM~qe``HwY<;au9e*2t)s)~3gQ zGQl|TQS~F=QTm(bt+~Zp2r22St}X$~@I&NUh}Cg11wN^dFmJuu(sMFFqMrI^rCJsj#jJCn`BzY9^$l;NU%22W zSR3A8uFYTE5-oUe#*W>xP%@U+Q+i%C$35oeCVqd9uQpK!*KknsyUi#A(bPXayu)9= z(Y(Ztc(TB;rXa^^;X5)hAocx@!9!9=WaeAcJ2n9PG$DA-YvvT{73&vDdT+3~MFAxg zM}`aI9AhZ?4CfeyD5Pwo70th3nyJgZ)KB+FIsu-?`ta`iBP|8>gx@*eu{qov0r#Xz z);t!VA+G(x^zmnzjg3}SL6<;`)fYHmu0$0ugShhnVQpXec9(Rg2XeA)$}MLKOC;8E zf0a$_yp5m22{KpC{0#%R3E=#G8)KOfb%{#$^paIca~kpy zu?d(59s_7J4HI>6=FK_#HoaVc6Z=6);%!{2J7nj;B%k_#nUq~9>Ar0OSsrT5s|9HtewFtM zL5-mZOTbzG(JDUGfy$W6j3Lfn7@#sPZF<*1L}LQQr9^j3n5KGNj&`hQE1*K6+q;{2 zadg!vQ#!^&i+?=Cx7Ae(Ek_#TXW;;#Tb1c5P6AH0b&9(|4LB>Z1P=tIXH?o{_4M=# zh7T0iMYV*Z4R3T_$dU3S{rZW!B7<@_H)s1^yVYM3;m1qGdUDCkQRRWr-%58IMEmoS z)aw;6kb6*9YbjPusFf`3Ys1$^*>bk{m2iVm~Y8@Fp>Ub0}q9%BGV$H74-D+S@i3<^ip^pLYjrw{~GU z<87_Pz6_@FH%z+nF)G!xB&TnoR#XEr35qWTq2JM$J*?1E7{67Vi*uhrx;ZTB9Ph)n zNewa+F_u+El3K-MX3?F?#lcSA#UgPEY3<-k3mtpa#5%s&X;q0U?KZ%^Sh^c?dx6DaXpq)c)64H}`|22t z-tBT>o>}}Z%LVBZ7fwgqpj{aA<6CbC7v>)NT)jI!GT)ZJeQiMbJBy${m+`=@0`l~2 zwwfu0j0?6Z0A>$6ijVf)j6u5|@`}QzjGd)h-*op?fKzj3Z^rme{~;PUM7QxB*Q;Wg zdaYh3lr4w0P)X5E_1Hg`ncz*8V#}h}!M{Zkt?$+G6SobZUEc=M_6DuoSY$GK?(Eu` zC>4i9xjHmmR%hE5Chk5I?aRyapJ@QIz@FQX1K&I{D$0aw#MX@4B`CFKRlKObOVoix zoK4jCD=0)rp4SI;R-J6SmyJS3c2<#yN&z*6f2%=bv_fVVeAf1|b>OY~{s#p#Qo7FI zct2RA(m7&>^o$F?m2Mujqrqk)!{8CEh^E$cA^GU`q+Kj}&-KuPncX2A)N0D^{-BfN zW(rB*y+&{-LD7a~CmsvEdw!e)?(rleuXZly!LQTLO0xaYOJ}$m2GMT3)ZN*LHyUv5 zk6rs6XlWkIa6n~msvrfZQt6DZ8#Lx_fIS!`4qq(1>(2=~Y4tllmGIMiu+{g=ZQyl( zj;qxx9CrubiQDF-(%cw15hA?ptBx(ypr7XF0^T*w{ifUig+7Z~FF$wQ%R`IVKYFcp zd(p)>fCtZ+QW;3la(1l^#uqf@3I~iZ5yIyLTx70?=>AA!ND%Nh6^AV$QoPGSOEf}0 zv}Sw}pmjfa6r^`${F~Y5WQ@Y|?v}Ab?$<tm6aKtY~2v7l!cHV z<2I!q&Wm`hIE!!HAy892qiHNz29rI>_+Zh*y=yU6){_8DjC{Ulj<^|k?8&dCm>Q1P zbBZ{-LS}mnEPONKfoz+D7+YQ^oUB!tW%0rSjTjLqdD(3B*x+DR4!htlFn=iya>1U* z9;!KDb!OL?{$|g)-*vC6AZ4`YYSqaT1+>yfZPMQsN znBk5r5emTyu=rv5FBR&pg!bJjB@I-@wuXQYH{fKAN?(T^{O6II-Vt%=wXy{65qM@a zt14h72>3-MW4?PI80V@Zm6mCleG!W!N1Wiz0yjrS*@0L*)}L49uldG2?dx3z(S<9a zd&#Du-BYwaZ;}AbDtq17p)NNoDBayq+{I-SkVyH(@X&`+fYREU2e64cHg%FL5TkbV z53M3H6#8oK7Zq!|ZF(0p#-4acGw%|uR`F3voQ202%pz=V2+m!(MZf22^n%GHE83uU z&ge-cQn{=e`!(PDm)inJlpf_Ju?u$m%~S}K)wr@JwF>#2#GcQ}C1&Jdx^hHjL4v6j z%ZWkf^w;*!xy^)He;^T^Nqt7Cl{FDwP>PXMsK>m-vI71#azHWkuGH{*XWxPaBZt2d zJ_g?q0w=Hlyx|P}+lH9VWu}qhI}X80-9dZni9(k%&IXh)?V7^whufAi zD;BtSNe0G`*Ln%v1A+F+8#B1W5wk^ZBg=E#13)Qy4TBXt@ZN7*7m&;_@LIhA4l?#% zx{;98$AHt8#yGS7nlK3wya!Ga0-DpYMU#&nriAxBVw?DU882i z2Gl??4!p-cZ!bV`iEeeT8w(t`B)#EF%v;0eXLfA=Wh2(^3QJEr-Ywo zavnPvE%U*7AYPZMkGS@OgaPKm2M%BY{l$$ZrpWaX6N?Yvljh|SU3*2Nk6;I_wWalv zUVCq_2^ia*IbXbcw(^RFBc5@4z5tcvGyaZ^%7hm7E?oN^&%y;6^XKwSc+Lc^yO6AA z3SSG%HB(%ppB~WjAIm5qJW@h){l;N)cXYE88f$V$KYs0?8L&p*5Ie+{ey0===&w80 z8PrY6GKt6U>=miw*KCMxhsP_kpjhC(XB&$(-8?f7)O0?3x+lwCW7i?c5FvKKYwyRI z$R|1clKQ8;n?9C=O&QT!U8FGP>n6@F14$~Fx_f2~1R+4N{Zis$Pe-AX>iEAA^qMOJ zuUfqdeL#YoO|h`!5Z!HH#)lLUlv_!lJK+2)_#XGMd}NN0LI~t#`Eb){$1Kozk2rCA zUCz8<*Uq$0mT3S2b_d&`Nv3{@TUi%!=g=64Yj-hg5*B&ge<5NX5{;e{zudx>cyunG z0BH8@{-wo4O8q=-S*%hVQ}$Y}*+IWZV#QMj(n&SNtBry8vD~!4wX>4qS)4MV?i0hq z`*bd!<81~c`}m{o_!yq0?LooJKEC^R+(Pp1kl8vw-@d@6PH>Jl4urJ1#5iL`Ti9!1 z@xywh(M1s-9#lCX%Omi)tYkBis%H2^{TBT+C3|Qvft|ccVs^0`pj=DI zuP-07uo&$5DEP^$j6X^cU7LTie3*KMap;2oT7AT9D%%@niNa%A7n}0ybLvY>Yk!=o zB}_$mS?yXa0(PrsguC)EI)x>Kzy)hH(-j-fq6BUq5$C|Fe%Vx7s5$6!r0jbsC!ZLw zMvgdQwUu=?kwm#LQR#4tlwD-wdkt1g;82rFH~|VFdbUB`jZJx`brCCDLNtLM?UkD& z=IoT=^VTEA#`5>5k?|%vXm{$uP+~eU<{YE$CIUmE9fn04(rsxdG-s!9QPKHT1csVy&8{S!Kn!tBOXy| zm50aCM0fwG`ZlJMxDs4TyEt2lTC1p!$^RR&zY0hqua5qfgrb^EJXUYg@@3F_dU5As zT=BtaaUN%-4D?=TXX^ZTbuEqJ!-b-Ab<@f2mJuSormDL{edQXj9!x?-ubqQPELZhn zlj>g9)F6D4_GaF*tsU7K6x|@q0XL86PIat0@zMxWh9xYgp>b*#1QVQM=6T2<=JyH0 z?5vKjV5(~aFu7|+$5!qim=W<03~bu&Ev-S0XWac1ekO;yx{~=dyx%{#0)Q{yF+c&y z9Pw-Df-pOf*FeM++l;&yZYA2KkZ%s$Q30Uy|cH5AGI?H2Thezt$wY1rgF1au#ENI}wZxv6>T5jT(NM zcXzOKL>371A7&TWmea&=+Qb{el=$)Pe*Or=SkVfhJgnNZNIL^b?BKqAvy4>X#9*zy z5yxo?^-8L6m#Mln=ML|Gnl~}w6nbKVOAQ-z^ilYVOelLqLc%Z5Tb)OJ{ZslT5^ty~ z`4=?9GtRo6ceT%S&VA2+*t8e%&dNt@oqdk%0uzQQ}h z@f@eeW~A7WEJS1}b0lwfW>AFHyOkC&15AeJ3;>GVx71rk1x7d0N_`d1#XPI`O!vl2 z_CxIEif%SAjEW!XfYVkytbP(M0zAN4J#NMspHxupJuy|-%vtyfF~fez4yz&{xZ4PhpFnts{o7BKzWsz-wg|1+;o zi@vY2x(YUc2MpG5Sy~-njzJf#7W*dl4UowV4W{NDPd#d+=zQ4ScdH;AkW_2J+{k>C zu|p||VmR{F1NZ59aSv&sqh}e2`12m*PpaUt;OOp|AgnW2bH{e;jWGqxQQkK7g=Tif z3(bQ#sVKdX(cq4YKP%5B?b&lLL7#yz$=XUU~*Qsm_{$P`{>tko^;K$ySs*k`r`_7Fh z!SvDD!_oW7c1ht~Y`AHzsc(8@RFSZAhtKtY@#V+B>ygp%d=TSxX8V45=@Dmjm+%8Z zlGwzpHSVA9-}1?S>t(&r)XILLS$2@$CDn9bT0Kl%C^}E(kQ7n3CLQ_}&2mi1IlU7v zKn^(PqB~4M!fC<0NC#xkoLI4&RG8ar0?q%v!Qked1SyZ-J%UCOO&d&0BTiu>c(1@` zgyv~x;w8!>sAwc2nGvZ)0YnS5t1~{o9xr&qs@N|%K}dt z3@-ix7#qqb)%dvcM1Y8%U`Z01!3ARwTP6;}Ugq6`^8Ij=>Ikn^LEW?ZC#DDE@sP!3 zKn@Uxb+DR_L`ed8OVyH70*4rT@lYze9dRRD3!OQje9?XOqIe9n9q5XQ<{>n;g_II< zwfw^L-3FCovj>p6RZRMHTak#!DzPX_Fz`T2nM>!u3Sf-ZzcRht&}ZQ;KElf$aZ_GC z4N(JE#kq;{$Mg%`7|P$fsnvLF=MW`!Jm=W}>vwn6;(BQqT-HQ8kws#nG)5=gP69E0 zVOjGg0HFjDSP{46^ zTlZCk_Vr}gY|>@3-yOx~4N~Ycqi8P){|HyDXj3vWOp03EIgruEZy`f0Vi6@oJ@ORz zobY53V$Zt+S*rGy{mL1xUzJ`_@LKBwUmPGKsl#Ryby_8fMbSk$?1g9KQc7*W%(gD- z#EcnrpC?nQ8M6x!zw&5AE{T)%BD%E1 z4H1tIZ83J(O3G%uufLmbj;RwK=UG-&&0*k2Mz#(lWEw+KHSBnDc;>h8g2@e5k$6l* z%ElaOrIOsxnTBJd+pEI|0tgT}IoP9(GfN~fd)`Bznw|-(4|KZw2;a?a28>ZGih)KsC>pvJ3?l(HsWjW)#0>lZK2+((M`6JSQ>W6+AR2hIzT6s>^f;L6 zR7cU4-(mf?jYt{$T7%wmhj%3ig`M9UqDi0B9{YtKSM9czE{uWetXmI%oj#LER5 zg_NMUaMhV>+IylJ>oJT$m8moB5n9=}O$QV3i+UT>?%nt0)QFEe1ZFO-?hH4E-E4_X zq0Lo=s&3+@4=d>|)WBm?_d+mOPb?ZL{s&ZI0#@#UNR>{r2I2hfZ1MbBc2lGhf0fKO zlZ>9O_#K`iKlt5^F61Wri_X1ANqLW$Z$tN^hP(TFi!!ToLkm(a6lV^rH#xWO_AeMA zm7w|)u{}SWkAJ=|-|-iPC(o|mxZ&dXSRvgQnuVqT zbtuY`#hns|uj$=db8Ad-ZztX&6_D}>WgJpUq?!3xIJH!G2g~95il}`+vC&n*um<=2 ziVZ4zbVAePq?Btkn!?otrG^?QzMXeISyEL)GAfA4VR!+2c?0 zT;bXaVjh0sq+}R% zi(2=3D!VYcQF}%#PRNdqI@|i)c$HjpDN!-O+|$h#Cw#`xC7wiwhhBY2wL2B(=A(cs zoqRzk>I`g?>hK#J+)kn=6bE_p1nT+Y0Ry&ZjQ?o=a8*mP10AJ$uMo-B0H~uMD%Z$D zknsAAXVY`-&PEh$*@LI5b9jmZVhm3OWzoCftf_4Ep;ii^d2uVfHpZb(-q)Mqj<2oH z6}n)bYDY!dv|=Lo1}jlK+@ox#^X1VM7fj~_MyGyc67R#WgIiM~Q?bm2raTAEix#Qi zXmIc{FtNwCk+jl6b!aEi?CJLo3qshV4FNwhoGjhMBoo2v6v#er`K)pGR`tEG(us5u zI?;T*oX`WJTBrr9r&_;zf9N{ryyfA@*;m7rnuXENh1n$*brA>JNzMbcxD!@aBJa`c zE!~l36^i?x%^siMK!VR8=!jEaX^e9Y%nZ3_S}u%6((7=%SHlIXK8v?vNEZDE&xRI@ zOEh57C&mjnD6xmLND*C66)wv+xzu(yp>5BsJrFps&Wc?YZ^jreAb{=125M_Ae134| z#NLfXb3ebCB^Hz%Sqw(yyi@^_4CO7d10*NvrVuwm(3RAn`!{XFi-p$@aF9;oP~Px1 zp`-5i;#+E#Vu2N)pHv+5#udJ4@Q|LPCse|mSRY_0uO=n~- zRy}e>9wG7LJp>wv?j(!KJ4hPJ((=U+$;95(=t!m($-?a7nyboE*`p9r&8ag}?RyJ@ z-c0EfmZOwc-{h~9MCU|Aj;KgVEfRO za4*hMa~i)xIMF_JuXu6k2j3WvOI<|wqDOlRL*AV4i=3LzLkyH=KH<-U-q6h+SphHi z_?n~eK5=dy7o;L9znNtJV*HbOuN9t-dP`Y08KM#g)wNp*<*w&o2i#*OYVOaiE zxn|o=7cD;p$E5j7JklQD&a{hZOXtVt_Q^G`6$n@5u>-;3tvG`=u|Jpf-HfS}Pf1`j z#d~Mkxt6b*B3|&5K|W{&wPq!q4(xuoN3cdEoOtP(NnbwkC)6782RgzZ8+M5?qTVuS zm-a1eb?^t@t?Fx;s3uID8hhopZ9Y*Kt?h#1Fce33S6H4BWX zt~ybuijcq8zD(UC$PPX-UKs$1FU?6*-?sIx<>BBpAE@k}0PJ0IJJ%F^i2;R*YEGVe zAUz*vZu4nAsxGp0`>P7TyyLeL1)NZo4mU?J8H^-pl}dtnf0+2XFqD5-H~+rd1qU%) z(#lcZbmuVr)EPmmN`ET$wLC)8a{)o2Swr_AKJ!OWxlBU+aOW+IsIx2~PS%J$0w? zB2>1}{FgGmib}sDEiWPa-0GE9t`gr+YB9PX3a%aAhf(c907__9{p%@rp|L<3|5kglf*W@qRq`{BT3}SDPG;Si0e0{Ly~Y~ zbWG{Xba@vmw;6vRoB6ITgvhqe!qQ)f3o`6nEskW0yvWpxacPi&c@F$-9Y4aJLiZ*{CS z9aprE$*a;Sp%6_CpGs2H@_TH?>cN&|1jU|F{$6+!7)wUjqS}uQq*j$)l`GS7zdZXJ z`0iD`z#$15c-Ce(KCw#Ug`eYLDP(e9^y861Ga|PrI#1XVVD!92ov03>wf}g<ZE3BAebc2&UDj!O zAEMsy00@U_YlKTbup!6kJfa1oRLrwF%E6rV#g$6?4`$vXx;sWU)z%X)yqQHil=>?a zWKpe}qF$=8OLsd7!g!sp)ErW(LX#Gkdpdb}03{ir1+L`0-xoD2kFa=q@UyVIMYU*e z&kR3Ei#!Xo=*qEK__Z<}X-rCLCnf1oiEd{!0#fBgAfc!PjVc|^UvwW(zTtYloc|vD zEg74=t8VQG=<G2PMZq&^UcE%~ZBytahFV;|9d+uVqC@G|PUEjZJC!9lZz*yl zcB=7-a69n#JwBtolbf3>HA|xF>Pv++z-N1e%jd8cy=H}9@N7(C;?yuD-MgK}AEO|a z=6nEW6ik9{jr1)}%G~eLY7fpXLA65Bt|WV@JbnW4 zN{~s+_x#`s=@rzFJASkpjW)LFX}2cX7FSrjyzzeD(e8rAy7_F84oQhz5&fk8;-%R< z)Y{ht*Zjv9?+FY~O%N)j1sLLnYP#~L z)@Kvt(Rn~CMYOjNe`S8Ys#kHfZS8pBsAkwWY@0q?8Vwzq3a&s)kMP8c2Ds&D}^uw-R8{N{nIMv-8)XE zk!=r4cMF?)v*Zz!%O50|LP`HCwHgPd?qWzplfSz6MR6C;@brmy_Z}9#1~b{CYculR z{R8VOQ7xPTt|ueSM}=ITFqy|*I?-#_P#^J99;*n2LfyOU#8kuv#F_cbPCl09A_hQ9 zd-p6)mI>fYtU*{D7E*k!dd=1+BfOzLs9gevy1C#Xz{;Fk#Z^bY5>NHS0ddZUPOVi)Y=-YE2JDEYWuu0x# zz|ud}ag|IcYIXMsi<#P=EzluaHbhCj(j+p=Ul?SQ6A@h^yfb!w;c>S6RNW#8YU&DU z6rxyPI*Lg{x|{X>X>`xSyrz`Jkfp<`SgNt*5S13DsqD5&~6+y`5H{j z-)Eu*M@v?y2KLmgZwa zx76}?b02U^E$Utv&<#%|YeKC^L&*rEg#~}IyVXH;{)6(E(G5Bg`MQ843T?Rag~Y1W zp6*o2_;_qD{|t{d876r|I4F2LT|itbzcWS7epeg`#ofuXidks<#jV}38h@8I!uvq! zY^aL!5(%&^4dTAZ^t*IXhggG7>MWnSTOxMaUx7ngK7Z|9n)a^IZ2eMs{^T`3GnGq( zPc9WjJ%gl-obLSC4QfF~I|>eK%v}EUBw$I54%r?VlV9&W99j*WhO@@J zYF$YM8>gem!brd%JxcNhf~Q?dhAjJul3`9D2MMTFuk08Mk_r?GMEX$A4&%?gQME!g zP(Tl#Tma)TuX_Io6{7x>ynSV=RTv!>Wi~STGf$rsGd#I>Ei3qR73RZ`0PPM1t_IP* z>Fn$ic3Bttq>>67!8KkDDTy1phrNse+G z{8YPUp}>Bn}(;!C4VK;F)R7bR~aU4(ECalH9sig-! z6~3sR5-j@dg;iQ-HjF@Ziob08%V-WzxK}0QgA)yd9qkZj7F{k}*el3DyP7PF>Zs>W zM;8ex$yKP33Ly`)bf7lDdA2KBa625eK^Q+0)_q=+99?%Ic+vYn)z*PwEfM}wnlXxEdO~X_a0v{U`*i*|#JIwWnZitFo zqLel95aDWbOx1kOd$qk|5-!1mW4*VqX14$Z(R1~nGm+)4G1#`4bu|oQj9w#YmzfR# zkSq2zKgTdWqQ6*Mr~OX+2!!}jgvI!>V{7Dfq&MsB+qVINzX$*Z3*2ksi1+8Ufh2Xg zYW=K2z79E71zB-G)Y-@@je>(YwHIBs_U90f)d2xOQ&= zQAb^_Oz8mC!WCZ)sfazLDq`fe_#_}eochMC>oUAAR^MM?3zS+0Mb`;0wnmyW=Oh-+ z$k928YOgL43c&h1)R=uI)hO+%hEYkpRqos!f?#Qgz~v4u#8^`9Cv1+S4bBg4kd}9) z3j77lwsf&G9De`2Es8etvz@Msaq!w5kb>n{maPtNx2Rc#a&v*w{x#9HKAWY_4ohn` zf4JmMjfljy9$1cw)Olw%a0iOH4@b_hW;Z@oI=B;xx1pek3Er76fgMzm0^FvLZ`U&j zPS(>eV3X34Gj^pf?-+8mGn8wNl2Sc>KKmFa#%PmAtgBRnQfBOG5WLn3co$rek6n=} zh0Y*VjVxeL$Nsc@6YQXl^kAma)^R91V|_4E;eDCl>wu`}8S*~0O&-xwxD-kAg~$?t zJOVZ-CwC{vs46cIIR;1R_N<{?O!a6Vf3)?9hVOBwi zV)i~gv|-cWy>idd4b(p@cAHcN0{icKc=-1aT*Jn@d7MlP2wZ!m2#j8#dHLtL4@x)g zS97jl7dwX`wT5=*O{Fv!)GTi3;FEgTuLt4*(_&s!bA^D&rW z$)tQ$d+pT(9vxH8>;mo}IE>nx7L!O3Az#dVckjE64)$R8o3anr{fP~I-WdLB(P`{t z`2>BRlJSjS+qeAcEo#U!J$%GYWzdZCfzZl4wj|o78hw9s?uBE2F(x zmU+D9uOp4eU7bg9*H&2R19%^`_D3`o8;0A_<_rfZH5&9q5q|czY8LqAFh$l&E!Q-e zvs*k0q)ej>o%y+3>5fe_b(qC@4c5EI0`DJZBa94QuUu)xg|wT}M$@i#Wc>Y;tfnm9 z#_+~*V|LMFwz|4p3FdrxXjFGv2In|09-ghA!IK_LN22}K>RQ1SY{zeGW8Ub}P`m-H zd&|wCv^@ZuUKg`ygOF=Du~E}uM&3qC4Q~%TmNS27#U4$^#Tk6!iv~Lqjcy#Pc|V5b zXcPsEUUVJ6Ju___Io%u}CBt`q!B4b3>XUP!hC(vy`5kZOQn0-G zzD6)nzL9YzB((OOeBj_0yF9*9+4zXRqdg{jaYaXMuOQ2Dg6TWFy2Nr~&zhZMpfsE* z7VA%2_<8Jl2Lb7Zi|;2o>kvac7e5Qeq*qGV5qdBeUVnyYQG%Rk5>_SwNh*R=T^H)G#%Z#u1_k#sL|Ua zeJGSzf2lHPvs?L(bEfKYlswZxVa{MKFz+ycVI0+Of5i5u_m5Q$!T&4i9>`v=oB47h_`~=_D+9W1ce$W#K#@znZ1i(fRJebY>EeJz`q%!;Gw+J4VrtYkh_HXQwy=2V$kJoHY zUtvx!e)S{6sUVJOJnN(S$z#fGCWayS;;x&g&>_$JtbRB4%iA{@OuJE)xS#H9@-h@W zv;25+mOU!+qh+TyW~r+XruIvD>4Qz_!~$ZxzeQQ?`Q@4kHNUQ8sK@y=)z@Trv9;dr zlnW&ye=_yVvRfd#EeWP8<$>;n{LpWr&TP88!n$RK|8=fdfNn=S#n`1QC1hO@pCF}U zuOu1>o*K`DZZ3Yah< zn6ljz9V1ulJTJWQ)?~ZX?N50&DbF>YGRy4#%z&=DnQBe)gqTU6dYTx_(t=q~qO!Qy z5VyX$-NMGh(nCMxec3T6RBk3h(eM-z`TW<+1paLGzR1BuK}cXe#|mkAyJ3N;zSkm> zFE&R6iJRX4WOYWAHo2xAi@f?@IPcTgq<{sJ3)a;ab6Ip$G}^hSZiuyFj;QG{o_*)^ zNzHvk6}Dw3)bQ?o;}fuf&3!GU!m$6z*Na^G7ZZZP_8V-Hy>;ZDs33bU%SIOUzc2Wd zy}9O}S_bXO-dwXm9J03`ZA|3<@8QsD41d;feQi8`r}7L#A6Wm#IvxCWV@n0B`S!*n z4hGvJx1mD;2D_)w{2$-_&mXdj$YdhZ6PV0)U@#dJ$e=(51u`grVgnfz$e=(51u`g* zLBV>WBukoPiKHw+kVOUmzd=Dcrd@6w|Ke9m3d(cM|6~7{yvO>Xe{Q?J*jR^!dHgK( zz<2By(&Y@|K5g9Tl_;-bZ+jz5`>rB(G4;W;E#>5xUuB^vNR-BbpWFSM3wf4!N zKn4XeD3C#cEGmE`AcF!K6v&`J1_d%GSeJmTW$S+`K{#}Xdi)=~0J6R~Sr+#HHX-xV z%t-kr|BWeaV_VWKn?( z3Lpu{pg;x%GANKifeZ>D3CN(}-xvxmvJ(H}Z!K?Gaklle4wwI*;&NsDt&G3@f1AHu zM><)fl&n!o)*T@$iOQe=l7I{fWKi(m1_ixpEz|$#1!#tp>o1$^1!A%m6j|sc!&?Xv zWKbZ30vQziuYv+)QRx14XMXS%D?-ie%^n$B_;1V>%D7xeQ)PW$vStrig;xdzGALO0 z+p@kdS+j>MW|Kt)GAMu~AcF!K6v&`J1_d%GfF$s53GtmY 500) w = 500; + this.set_size(w, 0.8 * height); + this.move((width - w) / 2, 0); + } + } + + filebrowse.on_browse = function (value, directory) { + if (value == null) { + this.extension.controler.show(); + } else { + if (directory) gpac.last_working_directory = directory; + this.extension.set_movie_url(value); + } + this.file_open_dlg = false; + } + + filebrowse.on_close = function () { + this.extension.controler.show(); + this.extension.file_open_dlg = false; + } + + if (this.history.length) { + filebrowse.go_hist = filebrowse.add_tool('history'); + filebrowse.go_hist.on_click = function () { + var hist_items = []; + var history = this.dlg.extension.history; + for (var i = 0; i < history.length; i++) { + var o = {}; + var f = history[history.length - i - 1]; + var names = f.url.split('/'); + if (names.length == 0) names = f.url.split('\\'); + + o.name = names.pop(); + o.directory = false; + o.path = f.url; + var delim = f.url.slice(-1); + hist_items.push(o); + } + this.dlg.set_label('History'); + this.dlg.browse(hist_items); + } + } + + filebrowse.go_fav = filebrowse.add_tool('favorite'); + filebrowse.go_fav.on_click = function () { + var fav_items = []; + var bookmarks = this.dlg.extension.bookmarks; + for (var i = 0; i < bookmarks.length; i++) { + var o = {}; + var f = bookmarks[bookmarks.length - i - 1]; + var names = f.url.split('/'); + if (names.length == 0) names = f.url.split('\\'); + + o.name = names.pop(); + if (o.name == '') { + o.directory = true; + o.name = names.pop(); + } else { + o.directory = false; + } + o.path = f.url; + var delim = f.url.slice(-1); + fav_items.push(o); + } + this.dlg.set_label('Bookmarks'); + this.dlg.browse(fav_items); + } + if (this.bookmarks.length) filebrowse.go_fav.show(); + else filebrowse.go_fav.hide(); + + + filebrowse.on_long_click = function (filename, path, directory) { + var popup = gw_new_window_full(null, true, ''); + popup.dlg = this; + this.disable(); + popup.area = gw_new_grid_container(popup); + popup.area.dlg = popup; + popup.area.break_at_line = true; + var hist_idx = this.extension.is_in_history(path, true); + + if (hist_idx > -1) { + var item = gw_new_icon_button(popup.area, 'history', 'Remove from history', true, 'listitem'); + item.dlg = popup; + item.set_size(0.9 * this.width, gwskin.default_control_height); + item.index = hist_idx; + item.on_click = function () { + var fb_dlg = this.dlg.dlg; + fb_dlg.extension.history.splice(this.index, 1); + fb_dlg.extension.set_option('PlaybackHistory', gwskin.stringify(fb_dlg.extension.history)); + fb_dlg.go_hist.on_click(); + this.dlg.close(); + } + } + + if (this.extension.history.length) { + var item = gw_new_icon_button(popup.area, 'trash', 'Clear all history', true, 'listitem'); + item.dlg = popup; + item.set_size(0.9 * this.width, gwskin.default_control_height); + item.index = hist_idx; + item.on_click = function () { + var fb_dlg = this.dlg.dlg; + fb_dlg.extension.history = []; + fb_dlg.extension.set_option('PlaybackHistory', gwskin.stringify(fb_dlg.extension.history)); + fb_dlg.close(); + this.dlg.close(); + } + } + + var hist_idx = this.extension.is_in_history(path, false); + item = gw_new_icon_button(popup.area, 'favorite', hist_idx > -1 ? 'Remove from favorites' : 'Add to favorites', true, 'listitem'); + item.dlg = popup; + item.set_size(0.9 * this.width, gwskin.default_control_height); + item.index = hist_idx; + item.on_click = function () { + var fb_dlg = this.dlg.dlg; + if (this.index > -1) { + fb_dlg.extension.bookmarks.splice(this.index, 1); + fb_dlg.extension.set_option('Bookmarks', gwskin.stringify(fb_dlg.extension.bookmarks)); + if (fb_dlg.extension.bookmarks.length == 0) { + fb_dlg.go_fav.hide(); + fb_dlg.browse(fb_dlg.directory); + } + } else { + fb_dlg.extension.add_bookmark(path, false, filename); + fb_dlg.go_fav.show(); + } + fb_dlg.layout(this.dlg.dlg.width, this.dlg.dlg.height); + this.dlg.close(); + } + + + popup.set_size(0.9 * this.width, 0.9 * this.height); + popup.set_alpha(1); + popup.move(this.translation.x, this.translation.y); + + popup.on_close = function () { + this.dlg.enable(); + } + popup.show(); + } + + + filebrowse.go_net = filebrowse.add_tool('remote_location'); + filebrowse.go_net.on_click = function () { + var popup = gw_new_window_full(null, true, 'Enter Adress'); + popup.dlg = this.dlg; + this.dlg.disable(); + popup.area = gw_new_grid_container(popup); + popup.area.dlg = popup; + popup.area.spread_h = true; + + popup.edit = gw_new_text_edit(popup.area, ''); + popup.edit.dlg = popup; + gpac.set_focus(popup.edit); + popup.edit.on_text = function (val) { + if (val != '') { + this.dlg.dlg.on_browse(val, null); + this.dlg.dlg.close(); + } + this.dlg.close(); + } + + popup.on_display_size = function (w, h) { + this.edit.set_size(w, 2 * gwskin.default_text_font_size); + this.set_size(w, 2 * gwskin.default_text_font_size + gwskin.default_icon_height); + this.move(0, h/2-this.height/2); + } + + popup.on_display_size(gw_display_width, gw_display_height); + popup.set_alpha(1.0); + + popup.on_close = function () { + this.dlg.enable(); + } + popup.show(); + } + + + filebrowse.on_display_size(gw_display_width, gw_display_height); + if (gpac.hardware_rgba) filebrowse.set_alpha(0.8); + + this.controler.hide(); + filebrowse.show(); + + return filebrowse; + }; + + +extension.is_in_history = function (url, is_history) { + var search_in = is_history ? this.history : this.bookmarks; + var hist = search_in.filter(function (obj) { return obj.url == url; }); + if (hist.length) { + var index = search_in.indexOf(hist[0]); + return index; + } + return -1; + }; + +extension.add_bookmark = function (url, is_history) { + var store = is_history ? this.history : this.bookmarks; + var hist = store.filter(function (obj) { return obj.url == url; }); + if (hist.length) { + var index = store.indexOf(hist[0]); + if (index > -1) store.splice(index, 1); + hist = hist[0]; + } else { + hist = {}; + hist.url = url; + hist.nb_access = 0; + } + hist.nb_access++; + var t = new Date() + hist.time = t.getTime(); + store.push(hist); + + if (is_history) { + var nb_max = 3; + if (this.history.length > nb_max) { + var rem = this.history.length - nb_max; + this.history.splice(-nb_max, rem); + } + } + + this.set_option(is_history ? 'PlaybackHistory' : 'Bookmarks', gwskin.stringify(store)); + }; diff --git a/gui/extensions/player/init.js b/gui/extensions/player/init.js new file mode 100644 index 0000000..4dfa5a9 --- /dev/null +++ b/gui/extensions/player/init.js @@ -0,0 +1,15 @@ + +obj = { + whoami: "GPAC-GUI-Extension", + name: "Player", + icon: "applications-multimedia.svg", + author: "JeanLF", + description: "Nice test extension", + url: "http://foo.bar", + execjs: ["player.js", "fileopen.js", "playlist.js", "stats.js"], + autostart: true, + config_id: "Player", + requires_gl: false, + version_major: 1, + version_minor: 0 +}; diff --git a/gui/extensions/player/player.js b/gui/extensions/player/player.js new file mode 100644 index 0000000..aaa1a96 --- /dev/null +++ b/gui/extensions/player/player.js @@ -0,0 +1,1436 @@ + +extension = { + GF_STATE_PLAY: 0, + GF_STATE_PAUSE: 1, + GF_STATE_STOP: 2, + GF_STATE_TRICK: 3, + + + movie: null, + movie_control: null, + movie_sensor: null, + UPnP_Enabled: false, + dynamic_scene: false, + movie_connected: false, + controlled_renderer: null, + current_url: null, + local_url: false, + initial_play_done: false, + dictionary: null, + icon_pause: 1, + icon_play: 0, + controler: null, + stat_wnd: null, + buffer_wnd: null, + current_time: 0, + duration: 0, + timeshift_depth: 0, + time_in_tsb: 0, + muted: 0, + file_open_dlg: false, + stoped_url: null, + initial_service_id: 0, + default_addon: null, + history: [], + bookmarks: [], + root_odm: null, + navigation_wnd: null, + initial_loop: false, + initial_speed: 1, + initial_start: 0, + show_stats_init: 0, + services: [], + channels_wnd: null, + reverse_playback_supported: false, + + do_show_controler: function () { + if (this.file_open_dlg) { + alert('Cannot show - File dialog is open'); + return false; + } + gw_hide_dock(); + if (this.controler.visible) { + this.controler.hide(); + } else { + this.controler.show(); + } + }, + + ext_filter_event: function (evt) { + switch (evt.type) { + case GF_EVENT_MOUSEUP: + this.do_show_controler(); + return true; + case GF_EVENT_KEYUP: + if (evt.keycode == gwskin.keys.close) { + this.do_show_controler(); + return true; + } + return false; + case GF_EVENT_QUALITY_SWITCHED: + if (this.stat_wnd) { + this.stat_wnd.quality_changed(); + } + return true; + case GF_EVENT_TIMESHIFT_UPDATE: + if (this.timeshift_depth) { + this.set_time(0); + } + return true; + case GF_EVENT_TIMESHIFT_OVERFLOW: + var msg = ''; + if ((this.state == this.GF_STATE_PAUSE) || (this.movie_control.mediaSpeed != 1)) { + this.set_state(this.GF_STATE_PLAY); + this.set_speed(1); + + msg = gw_new_message(null, 'Timeshift Overflow', 'Falling outside of timeshift buffer: resuming playback'); + msg.set_size(380, gwskin.default_icon_height + 2 * gwskin.default_text_font_size); + msg.show(); + } + return true; + case GF_EVENT_TIMESHIFT_UNDERRUN: + if (this.movie_control.mediaSpeed > 1) { + this.set_speed(1); + var msg = gw_new_message(null, 'Timeshift Underrun', 'Resuming to normal speed'); + msg.set_size(380, gwskin.default_icon_height + 2 * gwskin.default_text_font_size); + msg.show(); + } + return true; + case GF_EVENT_NAVIGATE: + this.set_movie_url(evt.target_url); + return true; + default: + return false; + } + }, + + init_extension: function () { + + /*create media nodes element for playback*/ + var a_movie = new SFNode('OrderedGroup'); + this.movie = new SFNode('Transform2D'); + a_movie.children[0] = this.movie; + a_movie.children[0].children[0] = new SFNode('Inline'); + a_movie.children[0].children[0].url[0] = ''; + this.movie_control = new SFNode('MediaControl') + a_movie.children[0].children[1] = this.movie_control; + this.movie_sensor = new SFNode('MediaSensor') + a_movie.children[0].children[2] = this.movie_sensor; + + gw_insert_media_node(a_movie); + //dictionary of resources to load + this.dictionary = gw_new_container(null); + this.dictionary.hide(); + + this.movie.children[0].extension = this; + + this.movie.children[0].on_scene_size = function (evt) { + var ext = this.extension; + + if (!this.callback_done) { + this.callback_done = true; + + //process the error or connect service + if (evt.error) { + var notif = gw_new_message(null, 'Error opening file!', 'Failed to open ' + this.url[0] + '\n\nReason: ' + gpac.error_string(evt.error)); + notif.show(); + + var url = ext.movie.children[0].url.length ? ext.movie.children[0].url[0] : ''; + //reassign old inline URL + this.url[0] = url; + if (url == '') { + ext.controler.show(); + } else { + this.movie_connected = true; + } + } + + //switch back inline nodes and remove from dictionary + gw_detach_child(this); + //force detach, we don't know when GC will be done + ext.movie.children[0].url[0] = ''; + ext.movie.children[0] = this; + + if (evt.error) return; + + //success ! + ext.current_url = this.url[0]; + ext.set_speed(ext.initial_speed); + if (ext.initial_start >= 0) { + ext.movie_control.mediaStartTime = ext.initial_start; + } else { + ext.movie_control.mediaStartTime = 0; + ext.movie_control.mediaStopTime = ext.initial_start; + } + ext.movie_control.loop = ext.initial_loop; + + ext.movie_control.url[0] = ext.current_url; + ext.movie_sensor.url[0] = ext.current_url; + + ext.timeshift_depth = 0; + ext.time_in_tsb = 0; + ext.initial_loop = false; + ext.initial_speed = 1; + ext.initial_start = 0; + + + if ((ext.current_url.indexOf('gpac://') == 0) && ((ext.current_url.indexOf('://') < 0) || (ext.current_url.indexOf('file://') == 0))) { + ext.local_url = true; + } else { + ext.local_url = false; + } + + ext.root_odm = gpac.get_object_manager(ext.current_url); + ext.reverse_playback_supported = ext.root_odm.reverse_playback_supported; + + gw_background_control(false); + + ext.controler.hide(); + gpac.caption = ext.current_url; + ext.add_bookmark(ext.current_url, true); + + ext.declare_addons(); + + if (ext.initial_service_id) { + var odm = gpac.get_object_manager(ext.current_url); + if (odm) odm.select_service(ext.initial_service_id); + ext.initial_service_id = 0; + } + if (ext.show_stats_init) { + ext.view_stats(); + } + } + + if (!ext.movie_connected) { + ext.movie_connected = true; + gpac.set_3d(evt.type3d ? 1 : 0); + ext.controler.play.switch_icon(ext.icon_pause); + ext.dynamic_scene = evt.dynamic_scene; + //force display size notif on controler to trigger resize of the window + ext.controler.on_display_size(ext.controler.width, ext.controler.height); + } + if (!gpac.fullscreen && evt.width && evt.height) { + var w, h, r_w, r_h; + w = evt.width; + h = evt.height; + + if (w > gpac.screen_width) w = gpac.screen_width; + if (h > gpac.screen_height) h = gpac.screen_height; + + r_w = r_h = 1; + // if (w < min_width) r_w = Math.ceil(min_width / w); + // if (h < min_height) r_h = Math.ceil(min_height / h); + if (r_w < r_h) r_w = r_h; + w = r_w * w; + h = r_w * h; + gpac.set_size(w, h); + } else { + gpac.set_size(evt.width, evt.height, true); + } + ext.streamlist_changed(); + + if (evt.width) { + var e = {}; + e.type = GF_EVENT_SCENE_SIZE; + e.width = evt.width; + e.height = evt.height; + gwlib_filter_event(e); + } + } + this.movie.children[0].on_addon_found = function (evt) { + var e = {}; + e.type = GF_EVENT_ADDON_DETECTED; + e.addon_url = evt.url; + e.scene_url = this.url[0]; + e.discarded = false; + gwlib_filter_event(e); + } + + this.movie.children[0].on_streamlist_changed = function (evt) { + this.extension.streamlist_changed(); + } + this.movie.children[0].on_scene_size_modify = function (evt) { + var e = {}; + e.type = GF_EVENT_SCENE_SIZE; + e.width = evt.width; + e.height = evt.height; + gwlib_filter_event(e); + } + + this.movie.children[0].addEventListener('gpac_scene_attached', this.movie.children[0].on_scene_size, 0); + this.movie.children[0].addEventListener('gpac_addon_found', this.movie.children[0].on_addon_found, 0); + this.movie.children[0].addEventListener('gpac_streamlist_changed', this.movie.children[0].on_streamlist_changed, 0); + this.movie.children[0].addEventListener('gpac_scene_size', this.movie.children[0].on_scene_size_modify, 0); + + + this.movie.children[0].on_media_progress = function (evt) { + if (evt.buffering) { + this.extension.show_buffer(evt.bufferLevel); + this.extension.controler.layout(); + + } + if (evt.total) { + var percent_dload = 100 * evt.loaded / evt.total; + if (percent_dload >= 100) percent_dload = 0; + this.extension.controler.media_line.set_progress(percent_dload); + } + } + + this.movie.children[0].on_media_playing = function (evt) { + this.extension.show_buffer(-1); + + if (!this.extension.initial_play_done) { + this.extension.initial_play_done = true; + + this.extension.controler.play.switch_icon(this.extension.icon_pause); + + if (!this.extension.root_odm) { + this.extension.root_odm = gpac.get_object_manager(this.extension.current_url); + } + if (this.extension.root_odm) { + this.extension.declare_addons(); + } + } + + if (this.extension.root_odm) { + this.extension.set_timeshift_depth(this.extension.root_odm.timeshift_depth); + } + } + + this.movie.children[0].on_media_end = function (evt) { + if (this.extension.duration) { + if (this.extension.movie_control.loop) { + this.extension.movie_control.mediaStartTime = 0; + this.extension.current_time = 0; + } else if (this.extension.playlist_mode && (this.extension.playlist_idx + 1 < this.extension.playlist.length)) { + this.extension.playlist_next(); + } else { + this.extension.set_state(this.extension.GF_STATE_STOP); + } + } + } + + this.movie.children[0].on_media_waiting = function (evt) { + // alert('URL is now buffering'); + } + this.movie.children[0].on_tsb_change = function (evt) { + if (this.extension.root_odm) { + this.extension.set_timeshift_depth(this.extension.root_odm.timeshift_depth); + + var main_addon_url = this.extension.root_odm.main_addon_url; + if (main_addon_url != null) gwskin.pvr_url = main_addon_url; + + } + } + this.movie.children[0].on_main_addon = function (evt) { + this.extension.reload_stats(); + this.extension.controler.layout(); + } + + + this.movie.children[0].addEventListener('progress', this.movie.children[0].on_media_progress, 0); + this.movie.children[0].addEventListener('playing', this.movie.children[0].on_media_playing, 0); + this.movie.children[0].addEventListener('canplay', this.movie.children[0].on_media_playing, 0); + this.movie.children[0].addEventListener('waiting', this.movie.children[0].on_media_waiting, 0); + this.movie.children[0].addEventListener('ended', this.movie.children[0].on_media_end, 0); + this.movie.children[0].addEventListener('gpac_timeshift_depth_changed', this.movie.children[0].on_tsb_change, 0); + this.movie.children[0].addEventListener('gpac_main_addon_state', this.movie.children[0].on_main_addon, 0); + + + this.on_movie_duration = function (value) { + if (value < 0) value = 0; + this.current_duration = value; + this.set_duration(value); + if (this.UPnP_Enabled) UPnP.MovieDuration = value; + } + + this.on_movie_active = function (value) { + if (!value) { + this.movie_control.mediaStartTime = -1; + } + } + + this.on_movie_time = function (value) { + var diff = this.current_time - value; + if (diff < 0) diff = -diff; + /*filter out every 1/2 seconds*/ + if (diff < 0.5) return; + this.current_time = value; + this.set_time(value); + if (this.UPnP_Enabled) UPnP.MovieTime = value; + } + + Browser.addRoute(this.movie_sensor, 'mediaDuration', this, this.on_movie_duration); + Browser.addRoute(this.movie_sensor, 'mediaCurrentTime', this, this.on_movie_time); + Browser.addRoute(this.movie_sensor, 'isActive', this, this.on_movie_active); + + var hist = this.get_option('PlaybackHistory'); + if ((hist != null) && (hist != '')) { + this.history = gwskin.parse(hist); + } + + var bmarks = this.get_option('Bookmarks'); + if ((bmarks != null) && (bmarks != '')) { + this.bookmarks = gwskin.parse(bmarks); + } + + /*create player control UI*/ + var wnd = gw_new_window(null, true, true); + //remember it ! + this.controler = wnd; + wnd.extension = this; + + wnd.set_corners(true, true, false, false); + wnd.set_alpha(0.95); + + /*first set of controls*/ + wnd.infobar = gw_new_grid_container(wnd); + wnd.infobar.spread_h = true; + + /*add our controls in order*/ + + wnd.media_line = gw_new_progress_bar(wnd.infobar, false, true); + wnd.media_line.extension = this; + wnd.media_line.on_slide = function (value, type) { + if (!this.extension.movie_connected && !this.extension.controlled_renderer) { + this.set_value(0); + return; + } + + var duration = this.extension.duration; + var time; + if (duration) { + time = value * duration / 100; + } else if (this.extension.timeshift_depth) { + time = (100 - value) * this.extension.timeshift_depth / 100; + + if (this.extension.controlled_renderer) { + return; + } + if (type != 2) return; + + this.extension.movie_control.mediaStopTime = -time; + this.extension.controler.layout(); + return; + } + + if (this.extension.controlled_renderer) { + this.extension.controlled_renderer.Seek(time); + return; + } + gw_background_control(false); + switch (type) { + //start sliding + case 1: + this.extension.set_state(this.extension.GF_STATE_PAUSE); + this.extension.set_speed(0); + break; + //done sliding + case 2: + this.extension.set_state(this.extension.GF_STATE_PLAY); + this.extension.movie_control.mediaStartTime = time; + this.extension.set_speed(1); + break; + //init slide, go in play mode + default: + if (this.extension.state == this.extension.GF_STATE_STOP) + this.extension.set_state(this.extension.GF_STATE_PLAY); + + this.extension.set_state(this.extension.GF_STATE_PAUSE); + break; + } + } + + wnd.time = gw_new_text(wnd.infobar, '00:00:00'); + gw_object_set_hitable(wnd.time); + wnd.time.extension = this; + wnd.time.reversed = false; + wnd.time.on_down = function (val) { + if (!val) return; + + if (this.extension.timeshift_depth) { + return; + // if (this.extension.movie_control.mediaStopTime < 0) + // this.extension.movie_control.mediaStopTime = 0; + } else { + this.reversed = !this.reversed; + this.extension.set_time(this.extension.current_time); + } + } + + wnd.back_live = gw_new_icon(wnd.infobar, 'live'); + wnd.back_live.extension = this; + wnd.back_live.on_click = function () { + if (this.extension.movie_control.mediaStopTime < 0) { + this.extension.set_time(0); + this.extension.movie_control.mediaStopTime = 0; + this.extension.set_state(this.extension.GF_STATE_PLAY); + //this.extension.controler.layout(); + } + } + + gw_new_separator(wnd.infobar); + + + wnd.stop = gw_new_icon(wnd.infobar, 'stop'); + wnd.stop.extension = this; + wnd.stop.on_click = function () { + this.extension.set_state(this.extension.GF_STATE_STOP); + } + + wnd.rewind = gw_new_icon(wnd.infobar, 'rewind'); + wnd.rewind.extension = this; + wnd.rewind.on_click = function () { + if (!this.extension.movie_control.mediaSpeed) { + this.extension.set_state(this.extension.GF_STATE_PLAY); + } + this.extension.set_state(this.extension.GF_STATE_TRICK); + if (this.extension.movie_control.mediaSpeed > 0) { + this.extension.set_speed(-1.0); + this.extension.controler.layout(); + } else { + this.extension.set_speed(2 * this.extension.movie_control.mediaSpeed); + } + } + + wnd.play = gw_new_icon(wnd.infobar, 'play'); + wnd.play.extension = this; + this.state = this.GF_STATE_PLAY; + wnd.play.add_icon(gwskin.images.pause); + wnd.play.on_click = function () { + this.extension.set_state((this.extension.state == this.extension.GF_STATE_PLAY) ? this.extension.GF_STATE_PAUSE : this.extension.GF_STATE_PLAY); + } + + + wnd.forward = gw_new_icon_button(wnd.infobar, 'seek_forward', '', true, 'icon_label'); + wnd.forward.extension = this; + wnd.forward.on_click = function () { + if (!this.extension.movie_control.mediaSpeed) { + this.extension.set_state(this.extension.GF_STATE_PLAY); + } + this.extension.set_state(this.extension.GF_STATE_TRICK); + if (this.extension.movie_control.mediaSpeed < 0) { + this.extension.set_speed(1.0); + } else { + this.extension.set_speed(2 * this.extension.movie_control.mediaSpeed); + } + } + wnd.forward.on_long_click = function () { + if (this.extension.movie_control.mediaSpeed > 0) { + this.extension.set_state(this.extension.GF_STATE_TRICK); + this.extension.set_speed(this.extension.movie_control.mediaSpeed / 2); + } + } + + wnd.loop = gw_new_icon(wnd.infobar, 'play_once'); + wnd.loop.extension = this; + wnd.loop.add_icon(gwskin.images.play_loop); + // wnd.loop.add_icon(gwskin.images.play_shuffle); + wnd.loop.on_click = function () { + this.extension.movie_control.loop = this.extension.movie_control.loop ? FALSE : TRUE; + this.switch_icon(this.extension.movie_control.loop ? 1 : 0); + } + + wnd.media_list = gw_new_icon(wnd.infobar, 'media'); + wnd.media_list.extension = this; + wnd.media_list.hide(); + + wnd.channels = gw_new_icon(wnd.infobar, 'channels'); + wnd.channels.extension = this; + wnd.channels.hide(); + + + wnd.navigate = gw_new_icon(wnd.infobar, 'navigation'); + wnd.navigate.extension = this; + wnd.navigate.on_click = function () { + this.extension.select_navigation_type(); + } + + wnd.stats = gw_new_icon(wnd.infobar, 'statistics'); + wnd.stats.extension = this; + wnd.stats.on_click = function () { + this.extension.view_stats(); + } + + gw_new_separator(wnd.infobar); + + wnd.snd_low = gw_new_icon(wnd.infobar, 'audio'); + wnd.snd_low.extension = this; + wnd.snd_ctrl = gw_new_slider(wnd.infobar); + wnd.snd_ctrl.extension = this; + wnd.snd_ctrl.stick_to_previous = true; + wnd.snd_low.add_icon('audio_mute'); + wnd.snd_low.on_click = function () { + if (this.extension.muted) { + gpac.volume = this.extension.muted; + this.extension.muted = 0; + this.switch_icon(0); + } else { + this.extension.muted = gpac.volume ? gpac.volume : 1; + gpac.volume = 0; + this.switch_icon(1); + } + } + wnd.snd_ctrl.on_slide = function (value, type) { + if (this.extension.muted) this.extension.controler.snd_low.on_click(); + gpac.volume = value; + } + wnd.snd_ctrl.set_value(gpac.volume); + + wnd.open = null; + if (!gwskin.browser_mode) { + wnd.open = gw_new_icon(wnd.infobar, 'file_open'); + wnd.open.extension = this; + wnd.open.on_click = function () { + this.extension.open_local_file(); + } + } + + wnd.playlist = gw_new_icon(wnd.infobar, 'playlist'); + wnd.playlist.extension = this; + wnd.playlist.on_click = function () { + this.extension.view_playlist(); + } + + wnd.playlist_prev = gw_new_icon(wnd.infobar, 'playlist_prev'); + wnd.playlist_prev.extension = this; + wnd.playlist_prev.on_click = function () { + this.extension.playlist_prev(); + } + + wnd.playlist_next = gw_new_icon(wnd.infobar, 'playlist_next'); + wnd.playlist_next.extension = this; + wnd.playlist_next.on_click = function () { + this.extension.playlist_next(); + } + + + wnd.home = null; + if (!gwskin.browser_mode) { + wnd.home = gw_new_icon(wnd.infobar, 'osmo'); + wnd.home.extension = this; + wnd.home.on_click = function () { + this.extension.controler.hide(); + if (this.extension._evt_filter != null) { + gwlib_remove_event_filter(this.extension._evt_filter); + this.extension._evt_filter = null; + } + gw_show_dock(); + } + } + + + if (this.UPnP_Enabled) { + wnd.remote = gw_new_icon(wnd.infobar, 'remote_display'); + wnd.remote.on_click = function () { select_remote_display('push'); } + } else { + wnd.remote = null; + } + + if (gwskin.mobile_device) { + wnd.fullscreen = null; + wnd.exit = null; + } else { + wnd.fullscreen = gw_new_icon(wnd.infobar, 'fullscreen'); + wnd.fullscreen.add_icon(gwskin.images.fullscreen_back); + wnd.fullscreen.on_click = function () { + gpac.fullscreen = !gpac.fullscreen; + } + wnd.fullscreen.switch_icon(gpac.fullscreen ? 1 : 0); + + if (!gwskin.browser_mode) { + wnd.exit = gw_new_icon(wnd.infobar, 'exit'); + wnd.exit.on_click = function () { gpac.exit(); } + } else { + wnd.exit = null; + } + } + + + wnd.on_size = function (width, height) { + var control_icon_size = gwskin.default_icon_height; + var children = this.infobar.get_children(); + for (i = 0; i < children.length; i++) { + children[i].set_size(control_icon_size, control_icon_size); + } + if (this.time) this.time.set_size(4 * wnd.time.font_size(), control_icon_size); + if (this.snd_ctrl) { + this.snd_ctrl.set_size(2 * control_icon_size, control_icon_size / 2, control_icon_size / 3, control_icon_size / 2); + this.snd_ctrl.set_value(gpac.volume); + } + + var speed = this.extension.movie_control.mediaSpeed; + if (speed < 0) speed = -speed; + if (speed && (speed != 1)) { + if ((speed > 100) || (speed < 1)) + this.forward.set_size(3 * control_icon_size, control_icon_size); + else + this.forward.set_size(2 * control_icon_size, control_icon_size); + } else { + this.forward.set_size(control_icon_size, control_icon_size); + } + } + + wnd.layout = function (width, height) { + var min_w, full_w, time_w; + var control_icon_size = gwskin.default_icon_height; + var is_over = true; + var show_navigate = false; + if (arguments.length == 0) { + width = this.width; + height = this.height; + } + this.move(0, Math.floor((height - gw_display_height) / 2)); + + this.on_size(width, height); + + if (this.fullscreen) + this.fullscreen.switch_icon(gpac.fullscreen ? 1 : 0); + + width -= control_icon_size / 2; + min_w = control_icon_size; + if (this.time.visible) min_w += this.time.width; + if (this.open) min_w += control_icon_size; + if (this.home) min_w += control_icon_size; + if (this.exit && gpac.fullscreen) min_w += control_icon_size; + full_w = 0; + if (this.snd_low) full_w += control_icon_size; + if (this.snd_ctrl) full_w += this.snd_ctrl.width; + if (this.fullscreen) full_w += control_icon_size; + + + if (this.navigate) { + this.navigate.hide(); + if (!this.extension.dynamic_scene && this.extension.movie_connected && (gpac.navigation_type != GF_NAVIGATE_TYPE_NONE)) { + show_navigate = true; + full_w += control_icon_size; + } + } + + if (this.extension.movie_connected) { + if (this.extension.state == this.extension.GF_STATE_STOP) { + this.stats.hide(); + } else { + full_w += control_icon_size; + this.stats.show(); + } + if (this.extension.duration || this.extension.timeshift_depth) { + full_w += control_icon_size; + this.stop.show(); + full_w += control_icon_size; + this.play.show(); + } else { + full_w += control_icon_size; + //this.play.show(); + if (this.extension.state == this.extension.GF_STATE_STOP) { + this.stop.hide(); + this.play.show(); + } else { + this.play.hide(); + this.stop.show(); + } + } + + if (this.extension.root_odm && !this.extension.dynamic_scene && !this.extension.root_odm.is_over) + is_over = false; + + // this.media_list.show(); + + } else { + this.stats.hide(); + this.stop.hide(); + this.play.hide(); + this.media_list.hide(); + } + + if (this.extension.duration) { + if (this.extension.reverse_playback_supported && this.rewind) full_w += control_icon_size; + if (this.forward) full_w += control_icon_size; + if (this.loop) full_w += control_icon_size; + } + else if (this.extension.movie_control.mediaStopTime < 0) { + if (this.forward) full_w += control_icon_size; + } else if (!is_over) { + if (this.forward) full_w += control_icon_size; + } + + if ((this.extension.root_odm && this.extension.root_odm.main_addon_on) || this.extension.movie_control.mediaStopTime < 0) { + full_w += control_icon_size; + this.back_live.show(); + } else { + this.back_live.hide(); + } + + + if (this.remote && UPnP.MediaRenderersCount && (this.extension.current_url != '')) { + full_w += control_icon_size; + } + time_w = this.media_line.visible ? 2 * control_icon_size : 0; + + if (this.exit) { + if (gpac.fullscreen) { + this.exit.show(); + } else { + this.exit.hide(); + } + } + + if (this.media_line.visible) + this.media_line.set_size(width - min_w - full_w, control_icon_size / 3); + + if (this.snd_low) this.snd_low.show(); + if (this.snd_ctrl) this.snd_ctrl.show(); + + this.rewind.hide(); + if (this.extension.reverse_playback_supported) this.rewind.show(); + + if (this.extension.duration) { + if (this.forward) this.forward.show(); + if (this.loop) this.loop.show(); + if (this.stop) this.stop.show(); + } + else if ((this.extension.movie_control.mediaStopTime < 0) || (this.extension.movie_control.mediaSpeed < 0)) { + if (this.extension.time_in_tsb > 2) { + if (this.forward) this.forward.show(); + } else { + if (this.forward) this.forward.hide(); + } + } else if (!is_over) { + if (this.forward) this.forward.show(); + } else { + if (this.forward) this.forward.hide(); + } + if (wnd.fullscreen) wnd.fullscreen.show(); + + if (this.remote) { + if (UPnP.MediaRenderersCount && (this.extension.current_url != '')) { + this.remote.show(); + } else { + this.remote.hide(); + } + } + + if (show_navigate) { + this.navigate.show(); + } + + if (this.extension.duration || this.extension.timeshift_depth) { + this.media_line.show(); + this.time.show(); + } else { + this.media_line.hide(); + this.time.hide(); + } + //this.time.set_size(width - 6*control_icon_size, control_icon_size / 3); + this.media_line.set_size(width - this.time.width - 2 * control_icon_size, control_icon_size / 3); + + // this.infobar.set_size(width, control_icon_size); + this.infobar.set_size(width, height); + this.infobar.move(0, -0.1 * control_icon_size); + } + + wnd.on_display_size = function (w, h) { + var def_width = 640; + if (!gpac.fullscreen) { + if (w < def_width) { + gpac.set_size(480, h); + return; + } + } else { + if (w < def_width) { + def_width = w; + } + } + + // this.set_size(w, 1.2 * gwskin.default_icon_height); + + if (this.extension.movie_connected) { + h = 3.3 * gwskin.default_icon_height; + if (!this.media_line.visible) { + h -= gwskin.default_icon_height; + } + } + else h = 1.1 * gwskin.default_icon_height; + + + this.set_size(def_width, h); + + this.layout(); + } + + wnd.on_event = function (evt) { + if (this.infobar.on_event(evt)) return true; + return false; + } + //make the bar hitable so that clicking on it does not make it disappear + gw_object_set_hitable(wnd); + wnd.set_size(gw_display_width, 2.2 * gwskin.default_icon_height); + this.set_duration(0); + this.set_time(0); + + + this._evt_filter = null; + }, + + start: function () { + if (!this._evt_filter) { + this._evt_filter = this.create_event_filter(this); + gwlib_add_event_filter(this._evt_filter); + } + + if (!this.movie) { + this.init_extension(); + + //check our args + var i, argc = gpac.argc; + var url_arg = null; + + for (i = 1; i < argc; i++) { + var arg = gpac.get_arg(i); + if (!arg) break; + + //that's our file + if (arg.charAt(0) != '-') { + //do not reopen ourselves ! + if (arg.indexOf('gui.bt') >= 0) continue; + + url_arg + if (arg.indexOf('://') < 0) url_arg = 'gpac://' + arg; + else url_arg = arg; + } + + //MP4Client options taking 2 args + else if ((arg == '-rti') || (arg == '-rtix') || (arg == '-c') || (arg == '-cfg') || (arg == '-size') || (arg == '-lf') || (arg == '-log-file') || (arg == '-logs') + || (arg == '-opt') || (arg == '-ifce') || (arg == '-views') || (arg == '-run-for') + ) { + i++; + } else if (arg == '-service') { + this.initial_service_id = parseInt(gpac.get_arg(i + 1)); + i++; + } else if (arg == '-com') { + arg = gpac.get_arg(i + 1); + var idx = arg.indexOf('gpac add '); + + if (idx == 0) { + this.default_addon = arg.substring(9); + } + + i++; + } else if (arg == '-addon') { + this.default_addon = gpac.get_arg(i + 1); + i++; + } else if (arg == '-loop') { + this.initial_loop = true; + } else if (arg == '-stats') { + this.show_stats_init = true; + } else if (arg == '-speed') { + this.initial_speed = Number(gpac.get_arg(i + 1)); + i++; + } else if (arg == '-play-from') { + this.initial_start = Number(gpac.get_arg(i + 1)); + i++; + } + } + + gwskin.media_url = ''; + gwskin.pvr_url = ''; + gwskin.media_time = 0; + gwskin.media_clock = 0; + gwskin.restore_session = this.create_restore_session(this); + + if (url_arg != null) { + this.set_playlist_mode(false); + var def_addon = this.default_addon; + this.set_movie_url(url_arg); + gw_hide_dock(); + this.default_addon = def_addon; + return; + } + this.set_playlist_mode(true); + + /* + var label = ''; + for (i = 1; i < argc; i++) { + label += '#'+i + ': ' + gpac.get_arg(i) + '\n'; + } + var notif = gw_new_message(null, 'GPAC Arguments', label); + notif.show(); + */ + + } + + this.controler.show(); + gw_hide_dock(); + }, + + create_event_filter: function (__anobj) { + return function (evt) { + return __anobj.ext_filter_event(evt); + } + }, + + create_restore_session: function (__anobj) { + return function (url, media_time, media_clock) { + __anobj.set_movie_url(url); + if (media_clock) { + var time_in_tsb = (new Date()).getTime() - media_clock; + if (time_in_tsb >= 0) { + __anobj.initial_start = -time_in_tsb / 1000; + } + + } else { + __anobj.initial_start = media_time; + } + } + }, + + declare_addons: function () { + if (this.default_addon && (this.default_addon != '')) { + var addon_url = this.default_addon; + if (addon_url.indexOf('://') < 0) addon_url = 'gpac://' + addon_url; + this.root_odm.declare_addon(addon_url); + } + }, + + set_time: function (value) { + var h, m, s, str; + str = ''; + if (this.timeshift_depth) { + var pos = 100; + this.time_in_tsb = 0; + + if ((this.movie_control.mediaStopTime < 0) || (this.movie_control.mediaSpeed <= 0)) { + this.time_in_tsb = this.root_odm.timeshift_time; + if (this.timeshift_depth > this.time_in_tsb) { + pos = 100 * (this.timeshift_depth - this.time_in_tsb) / this.timeshift_depth; + } else if (this.time_in_tsb) { + pos = 0; + } + } + this.controler.media_line.set_value(pos); + + gwskin.media_clock = (new Date()).getTime() - this.time_in_tsb * 1000; + + if (!this.time_in_tsb) { + this.controler.time.set_label(''); + this.controler.time.hide(); + this.controler.layout(); + return; + } + + if (!this.controler.time.visible) { + this.controler.time.show(); + this.controler.layout(); + } + if (!this.controler.forward.visible) { + this.controler.forward.show(); + this.controler.layout(); + } + str = '-'; + value = this.time_in_tsb; + + } else { + if (!this.duration) { + if (this.controler.time.visible) { + this.controler.time.hide(); + this.controler.layout(); + } + return; + } + + this.current_time = value; + gwskin.media_time = value; + + if (this.duration) { + this.controler.media_line.set_value(100 * value / this.duration); + } + if (this.controler.time.reversed) { + value = this.duration - value; + str = '-'; + } + } + + h = Math.floor(value / 3600); + value -= h * 3600; + m = Math.floor(value / 60); + value -= m * 60; + s = Math.floor(value); + if (h) { + if (h < 10) str += '0'; + str += h + ':'; + } + if (m < 10) str += '0'; + str += m + ':'; + if (s < 10) str += '0'; + str += s; + this.controler.time.set_label(str); + }, + + set_duration: function (value) { + this.duration = value; + var dlg = this.controler; + if (!value) { + if (this.timeshift_depth > 0) { + return; + } + dlg.time.hide(); + dlg.media_line.hide(); + dlg.rewind.hide(); + dlg.play.hide(); + dlg.forward.hide(); + dlg.loop.hide(); + dlg.time.set_size(0, gwskin.default_icon_height); + dlg.time.set_width(0); + } else { + dlg.time.show(); + dlg.media_line.show(); + if (this.reverse_playback_supported) dlg.rewind.show(); + dlg.stop.show(); + dlg.forward.show(); + dlg.loop.show(); + if (value < 3600) { + dlg.time.set_size(gwskin.default_icon_height / 2, gwskin.default_icon_height); + dlg.time.set_width(3 * dlg.time.font_size()); + } else { + dlg.time.set_size(gwskin.default_icon_height, gwskin.default_icon_height); + dlg.time.set_width(4 * dlg.time.font_size()); + } + } + dlg.on_display_size(gw_display_width, gw_display_height); + }, + set_timeshift_depth: function (value) { + if (this.timeshift_depth == value) return; + + this.timeshift_depth = value; + var dlg = this.controler; + + this.reverse_playback_supported = this.root_odm.reverse_playback_supported; + + if (!value) { + dlg.time.hide(); + dlg.media_line.hide(); + if (dlg.rewind) dlg.rewind.hide(); + if (dlg.forward) dlg.forward.hide(); + dlg.time.set_size(0, gwskin.default_icon_height); + dlg.time.set_width(0); + } else { + dlg.time.show(); + dlg.media_line.show(); + + var w = 3 * dlg.time.font_size(); + if (value > 3600) w += dlg.time.font_size(); + + dlg.time.set_size(w, gwskin.default_icon_height); + dlg.time.set_width(w); + } + dlg.on_display_size(gw_display_width, gw_display_height); + }, + + set_state: function (state) { + if (!this.movie_connected && !this.controlled_renderer) return; + + if (state == this.state) return; + + if (state == this.GF_STATE_STOP) { + if (this.stat_wnd) this.stat_wnd.close_all(); + this.stoped_url = '' + this.current_url; + if (this.controlled_renderer) this.controlled_renderer.Stop(); + else { + this.set_movie_url(''); + /*override movie_connected to avoid auto-resizing*/ + this.movie_connected = true; + } + this.movie_control.mediaStartTime = 0; + this.controler.media_line.set_value(0); + this.controler.play.switch_icon(this.icon_play); + this.state = this.GF_STATE_STOP; + this.set_speed(1); + this.root_odm = null; + return; + } + if (state == this.GF_STATE_PAUSE) { + if (this.state == this.GF_STATE_STOP) return; + if (this.controlled_renderer) this.controlled_renderer.Pause(); + this.state = this.GF_STATE_PAUSE; + this.controler.play.switch_icon(this.icon_play); + this.set_speed(0); + return; + } + //we are playing, resume from stop if needed + if (this.stoped_url) { + if (this.controlled_renderer) { + this.controlled_renderer.Play(); + } else { + this.set_movie_url(this.stoped_url, true); + } + this.stoped_url = null; + //not in trick mode, next pause/play will restart from current time + if (state != this.GF_STATE_TRICK) + this.movie_control.mediaStartTime = -1; + } + + + if (state == this.GF_STATE_PLAY) { + if (this.controlled_renderer) this.controlled_renderer.Play(); + this.state = state; + this.controler.play.switch_icon(this.icon_pause); + if (this.movie_control.mediaSpeed != 1) + this.movie_control.mediaStartTime = -1; + + if (this.timeshift_depth && (this.movie_control.mediaSpeed < 0)) { + this.movie_control.mediaStopTime = -this.root_odm.timeshift_time; + } + + this.set_speed(1); + return; + } + if (state == this.GF_STATE_TRICK) { + this.state = state; + this.controler.play.switch_icon(this.icon_play); + this.movie_control.mediaStartTime = -1; + return; + } + }, + + + set_speed: function (value) { + this.movie_control.mediaSpeed = value; + + if (!this.duration && this.timeshift_depth && !value) { + this.movie_control.mediaStopTime = -0.1; + // + this.movie_control.mediaStartTime = -1; + } + if (value && value != 1) { + if (value > 1) + this.controler.forward.set_label('x' + value); + else + this.controler.forward.set_label('x' + Math.round(100 * value) / 100); + } else { + this.controler.forward.set_label(''); + } + this.controler.layout(); + }, + + set_movie_url: function (url) { + this.initial_play_done = false; + + gwskin.media_url = url; + gwskin.pvr_url = ''; + + if ((url == '') || (url == this.current_url)) { + this.movie.children[0].url[0] = url; + this.movie_control.url[0] = url; + this.movie_sensor.url[0] = url; + if (this.UPnP_Enabled) UPnP.MovieURL = url; + this.movie_connected = (url == '') ? false : true; + gw_background_control(this.movie_connected ? false : true); + gpac.caption = url; + + } else if (this.controlled_renderer == null) { + //resume from stop + if ((arguments.length == 2) && (arguments[1] == true)) { + this.current_url = url; + this.set_speed(1); + this.movie_control.mediaStartTime = 0; + this.movie_control.url[0] = url; + this.movie_sensor.url[0] = url; + this.movie.children[0].url[0] = url; + gw_background_control(false); + + return; + } + + this.default_addon = null; + this.root_odm = null; + + /*create a temp inline holding the previous scene, use it as the main movie and use the old inline to test the resource. + This avoids messing up with event targets already setup*/ + var movie_inline = this.movie.children[0]; + var temp_inline = new SFNode('Inline'); + if (typeof movie_inline.url[0] != 'undefined') + temp_inline.url[0] = movie_inline.url[0]; + + this.movie.children[0] = temp_inline; + + movie_inline.callback_done = false; + this.movie_connected = false; + + /*handle navigation between local files*/ + if ((this.current_url && this.current_url.indexOf('gpac://') >= 0) && (url.indexOf('://') < 0)) { + movie_inline.url[0] = "gpac://" + url; + } else { + movie_inline.url[0] = url; + } + + if (!movie_inline.callback_done) { + gw_add_child(this.dictionary, movie_inline); + } + + return; + + } else { + var uri = UPnP.ShareResource(url); + this.controlled_renderer.Open(uri); + } + this.current_url = url; + + if (url == '') this.controler.show(); + else this.controler.hide(); + + }, + + + show_buffer: function (level) { + if (level < 0) return; + if (level >= 98) { + if (this.buffer_wnd) { + this.buffer_wnd.close(); + this.buffer_wnd = null; + } + return; + } + + if (!this.buffer_wnd) { + this.buffer_wnd = gw_new_window(null, true, true); + this.buffer_wnd.show_effect = 'notif'; + this.buffer_wnd.txt = gw_new_text(this.buffer_wnd, ''); + this.buffer_wnd.on_display_size = function (w, h) { + this.set_size(20 * gwskin.default_text_font_size, 2 * gwskin.default_text_font_size); + this.txt.set_width(20 * gwskin.default_text_font_size); + this.move(0, h / 2 - gwskin.default_text_font_size); + } + this.buffer_wnd.on_display_size(gw_display_width, gw_display_height); + this.buffer_wnd.set_alpha(0.9); + this.buffer_wnd.show(); + + this.buffer_wnd.timer = gw_new_timer(false); + this.buffer_wnd.timer.wnd = this.buffer_wnd; + this.buffer_wnd.timer.set_timeout(gwskin.default_message_timeout, false); + this.buffer_wnd.timer.start(0); + this.buffer_wnd.ext = this; + this.buffer_wnd.timer.on_active = function (val) { + if (!val) { + this.wnd.ext.buffer_wnd = null; + this.wnd.close(); + } + } + } + this.buffer_wnd.timer.stop(gwskin.default_message_timeout); + this.buffer_wnd.txt.set_label('Buffering ' + level + ' %'); + }, + + select_navigation_type: function () { + var nb_items = 0; + var type = gpac.navigation; + if (this.navigation_wnd) { + this.navigation_wnd.close(); + return; + } + var wnd = gw_new_popup(this.controler.navigate, 'up'); + this.navigation_wnd = wnd; + wnd.extension = this; + + wnd.on_close = function () { + this.extension.navigation_wnd = null; + } + + wnd.select = function (type) { + this.extension.navigation_wnd = null; + if (type == 'reset') { + gpac.navigation_type = 0; + } else { + gpac.navigation = type; + } + } + wnd.make_select_item = function (text, type, current_type) { + if (current_type == type) text = '* ' + text; + wnd.add_menu_item(text, function () { this.select(type); }); + } + wnd.add_menu_item('Reset', function () { this.select('reset'); }); + + wnd.make_select_item('None', GF_NAVIGATE_NONE, type); + wnd.make_select_item('Slide', GF_NAVIGATE_SLIDE, type); + wnd.make_select_item('Examine', GF_NAVIGATE_EXAMINE, type); + + if (gpac.navigation_type == GF_NAVIGATE_TYPE_3D) { + wnd.make_select_item('Walk', GF_NAVIGATE_WALK, type); + wnd.make_select_item('Fly', GF_NAVIGATE_FLY, type); + wnd.make_select_item('Pan', GF_NAVIGATE_PAN, type); + wnd.make_select_item('Game', GF_NAVIGATE_GAME, type); + wnd.make_select_item('Orbit', GF_NAVIGATE_ORBIT, type); + wnd.make_select_item('VR', GF_NAVIGATE_VR, type); + } + wnd.on_display_size(gw_display_width, gw_display_height); + wnd.show(); + }, + + streamlist_changed: function () { + this.services = []; + + var root_odm = this.root_odm; + + if (root_odm) { + for (var res_i = 0; res_i < root_odm.nb_resources; res_i++) { + var m = root_odm.get_resource(res_i); + if (!m || !m.service_id) continue; + var res = null; + for (var k = 0; k < this.services.length; k++) { + if (this.services[k].service_id == m.service_id) { + res = this.services[k]; + break; + } + } + if (res == null) { + this.services.push(m); + } + } + } + + if (this.services.length <= 1) { + this.controler.channels.hide(); + this.controler.channels.on_click = function () { } + this.controler.layout(); + return; + } + if (!this.controler.channels.visible) { + this.controler.channels.show(); + this.controler.layout(); + } + + this.controler.channels.on_click = function () { + + if (this.extension.channels_wnd) { + this.extension.channels_wnd.close(); + return; + } + var wnd = gw_new_popup(this.extension.controler.channels, 'up'); + this.extension.channels_wnd = wnd; + wnd.extension = this.extension; + + wnd.on_close = function () { + this.extension.channels_wnd = null; + } + + wnd.make_item = function (text, i) { + wnd.add_menu_item(text, function () { + this.extension.root_odm.select_service(this.extension.services[i].service_id); + }); + } + for (var i = 0; i < this.extension.services.length; i++) { + var text = ''; + var n = this.extension.services[i].service_name; + if (this.extension.root_odm.selected_service == this.extension.services[i].service_id) text += '* '; + if (n == null) n = 'Service ' + this.extension.services[i].service_id; + text += n; + wnd.make_item(text, i); + } + wnd.on_display_size(gw_display_width, gw_display_height); + wnd.show(); + } + + } + + +}; + diff --git a/gui/extensions/player/playlist.js b/gui/extensions/player/playlist.js new file mode 100644 index 0000000..4beea15 --- /dev/null +++ b/gui/extensions/player/playlist.js @@ -0,0 +1,327 @@ + +extension.playlist_wnd = null; + + +extension.playlist = []; +var plist = extension.get_option('Playlist'); + +if ((plist != null) && (plist != '')) { + extension.playlist = gwskin.parse(plist); +} + +extension.playlist_idx = 0; +var plistidx = extension.get_option('PlaylistIndex'); +if (plistidx != null) { + extension.playlist_idx = parseInt(plistidx); +} + +extension.view_playlist = function () { + if (this.playlist_wnd) { + this.playlist_wnd.close(); + this.playlist_wnd = null; + return; + } + + var plist = gw_new_window_full(null, true, 'Playlist'); + this.playlist_wnd = plist; + plist.extension = this; + plist.hide_controler = false; + + this.controler.hide(); + + plist.on_close = function () { + if (! this.hide_controler) + this.extension.controler.show(); + + this.extension.playlist_wnd = null; + this.extension.file_open_dlg = false; + } + + plist.area = gw_new_grid_container(plist); + plist.area.break_at_line = true; + plist.area.dlg = plist; + + plist.go_prev = plist.add_tool('previous'); + plist.go_prev.on_click = function () { + this.dlg.area._move_page(-1); + } + + plist.go_next = plist.add_tool('next'); + plist.go_next.on_click = function () { + this.dlg.area._move_page(1); + } + + plist.add = plist.add_tool('add'); + plist.add.on_click = function () { + this.dlg.browse_files(); + } + plist.browse_files = function() { + this.hide(); + + var fb = this.extension.open_local_file(); + fb.playlist = this; + fb.on_browse = function (value, directory) { + this.playlist.show(); + plist.add_files(value, false, false); + if (directory) gpac.last_working_directory = directory; + + } + fb.on_close = function () { + this.playlist.show(); + } + + + fb.on_long_click = function (filename, path, directory) { + var popup = gw_new_window_full(null, true, ''); + popup.fb = fb; + this.disable(); + popup.area = gw_new_grid_container(popup); + popup.area.dlg = popup; + popup.area.break_at_line = true; + + popup.set_size(0.9 * this.width, 0.9 * this.height); + popup.move(this.translation.x, this.translation.y); + + if (directory) { + var item = gw_new_icon_button(popup.area, 'scan_directory', 'Add directory', true, 'listitem'); + item.set_size(popup.width, gwskin.default_control_height); + item.dlg = popup; + item.on_click = function() { + var filelist = gpac.enum_directory(path, '*', false); + item.dlg.fb.playlist.add_files(filelist, false, false); + item.dlg.fb.close(); + item.dlg.close(); + } + item = gw_new_icon_button(popup.area, 'scan_directory', 'Insert directory', true, 'listitem'); + item.set_size(popup.width, gwskin.default_control_height); + item.dlg = popup; + item.on_click = function() { + var filelist = gpac.enum_directory(path, '*', false); + item.dlg.fb.playlist.add_files(filelist, true, false); + item.dlg.fb.close(); + item.dlg.close(); + } + + } else { + var item = gw_new_icon_button(popup.area, 'add', 'Add file', true, 'listitem'); + item.set_size(popup.width, gwskin.default_control_height); + item.dlg = popup; + item.on_click = function() { + item.dlg.fb.playlist.add_files(path, false, false); + item.dlg.fb.close(); + item.dlg.close(); + } + item = gw_new_icon_button(popup.area, 'add', 'Insert file', true, 'listitem'); + item.set_size(popup.width, gwskin.default_control_height); + item.dlg = popup; + item.on_click = function() { + item.dlg.fb.playlist.add_files(path, true, false); + item.dlg.fb.close(); + item.dlg.close(); + } + } + popup.area.layout(); + popup.set_alpha(1); + + popup.on_close = function () { + this.fb.enable(); + } + popup.show(); + } + } + + + plist.add_object = function(pl_item, is_selected) { + var icon_name = is_selected ? 'play' : gw_guess_mime_icon(pl_item.name); + + var item = gw_new_icon_button(this.area, icon_name, pl_item.name, true, 'listitem'); + + item.set_size(this.width, gwskin.default_control_height); + item.dlg = this; + item.pl_item = pl_item; + item.on_click = function() { + this.dlg.extension.playlist_play(this.pl_item); + this.dlg.hide_controler = true; + this.dlg.close(); + } + this.trash.enable(); + if (plist.extension.playlist.length>1) + this.sort.enable(); + } + + plist.add_files = function(list, is_insert, recursive) { + if (typeof list =='string') { + var obj = {}; + var names = list.split('/'); + if (names.length == 0) names = list.split('\\'); + obj.name = names.pop(); + var len = list.length - obj.name.length; + obj.path = list.slice(0, len); + + if (is_insert) { + this.extension.playlist.splice(this.extension.playlist_idx+1, 0, obj); + } else { + this.extension.playlist.push(obj); + this.add_object(obj, false); + } + } else { + //temp array for sorting, we have issues sorting Arrays creating by native code + var ar = []; + for (var i=0; i b.name; } ); + } else { + ar.sort( function(a, b) { return a.name < b.name; } ); + } + + for (var i=0; i b.name;} ); + wnd._sort_type = 1; + } else { + wnd.extension.playlist.sort( function (a, b) { return a.name < b.name;} ); + wnd._sort_type = 0; + } + wnd.extension.set_option('Playlist', gwskin.stringify(wnd.extension.playlist)); + wnd.refresh_items(); + } + + plist.area.on_page_changed = function () { + if (this.is_first_page()) this.dlg.go_prev.disable(); + else this.dlg.go_prev.enable(); + + if (this.is_last_page()) this.dlg.go_next.disable(); + else this.dlg.go_next.enable(); + } + + plist.trash = plist.add_tool('trash'); + plist.trash.on_click = function () { + this.dlg.area.reset_children(); + this.dlg.extension.playlist = []; + this.dlg.extension.set_option('Playlist', gwskin.stringify(this.dlg.extension.playlist)); + this.dlg.extension.set_option('PlaylistIndex', '0'); + this.dlg.extension.set_playlist_mode(true); + + this.disable(); + } + plist.trash.disable(); + plist.sort.disable(); + + plist.refresh_items = function() { + this.area.reset_children(); + + for (var i=0; i 1) { + wnd.has_select = true; + m.gui.select_label = gw_new_button(wnd.area, 'Quality'); + m.gui.select_label.odm = m; + m.gui.select_label.on_click = function () { + var idx = this.odm.gui.select.value; + if (this.odm.gui.selected_idx == idx) { + this.on_long_click(); + return; + } + + if (idx) { + if (this.odm.gui.qualities[idx - 1].disabled) { + var notif = gw_new_message(null, 'Cannot select representation', 'Representation has been disabled'); + notif.set_size(20 * gwskin.default_text_font_size, (2 * gwskin.default_icon_height + gwskin.default_text_font_size)); + notif.show(); + return; + } + this.odm.select_quality(this.odm.gui.qualities[idx - 1].ID); + } else { + this.odm.select_quality('auto'); + + this.odm.update_qualities(); + } + } + m.gui.select_label.on_long_click = function () { + var idx = this.odm.gui.select.value; + if (!idx) return; + var q = this.odm.gui.qualities[idx - 1]; + + var iw = gw_new_window_full(null, true, 'Representation ' + q.ID + ' info'); + gw_object_set_dragable(iw); + iw.area = gw_new_text_area(iw, ''); + + var label = 'Mime ' + q.mime + ' - codecs ' + q.codec; + label += '\n'; + label += 'Bandwidth: ' + q.bandwidth; + label += '\n'; + label += 'Enabled: ' + !q.disabled; + label += '\n'; + if (q.width) { + label += 'Size ' + q.width + 'x' + q.height + (q.interlaced ? ' interlaced @' : ' progressive @') + q.fps + ' FPS - SAR ' + q.par_num + '/' + q.par_den; + } else { + label += 'Samplerate ' + q.samplerate + ' Hz - ' + q.channels + ' channels'; + } + + iw.area.set_content(label); + + iw.on_display_size = function (width, height) { + var w = 25 * gwskin.default_text_font_size; + var h = 2 * gwskin.default_icon_height + 5 * gwskin.default_text_font_size; + this.set_size(w, h); + } + + iw.on_display_size(gw_display_width, gw_display_height); + iw.set_alpha(0.9); + iw.show(); + } + + m.gui.select = gw_new_spincontrol(wnd.area, true); + m.gui.select.odm = m; + m.gui.select.on_click = function (val) { + this.odm.show_select(val); + } + + + m.update_qualities = function () { + var sel_idx = 0; + this.gui.qualities = []; + for (i = 0; i < this.nb_qualities; i++) { + var q = this.get_quality(i); + if (q) { + this.gui.qualities.push(q); + } + } + this.gui.qualities.sort(function (a, b) { return a.bandwidth - b.bandwidth }); + + for (i = 0; i < this.gui.qualities.length; i++) { + if (this.gui.qualities[i].is_selected) + sel_idx = i + 1; + } + + this.gui.select.min = 0; + this.gui.select.max = m.nb_qualities; + if (this.gui.selected_idx != sel_idx) { + this.show_select(sel_idx); + this.gui.selected_idx = sel_idx; + this.gui.select.value = sel_idx; + } + } + + m.show_select = function (idx) { + if (!idx) { + this.gui.select_label.set_label('Auto'); + } else { + var label = ''; + var q = this.gui.qualities[idx - 1]; + if (!q) return; + + if (q.is_selected) label += '*'; + + if (q.width) { + label += q.height + (q.interlaced ? 'i' : 'p'); + } else if (q.samplerate) { + label += q.samplerate; + if (q.channels) label += '/' + q.channels; + } + if (q.bandwidth < 1000000) label += '@' + Math.round(q.bandwidth / 1000) + 'K'; + else label += '@' + Math.round(q.bandwidth / 10000) / 100 + 'M'; + + this.gui.select_label.set_label(label); + } + } + m.update_qualities(); + + } else { + m.gui.select = null; + m.gui.select_label = null; + m.update_qualities = function () { } + } + + + m.gui.info = gw_new_icon(wnd.area, 'information'); + + m.gui.info.odm = m; + m.gui.info.on_click = function () { + if (this.odm.gui.info_wnd) { + this.odm.gui.info_wnd.close(); + return; + } + var odm = this.odm; + var iw = gw_new_window_full(null, true, '' + odm.type + ' ' + odm.ID + ' statistics:'); + odm.gui.info_wnd = iw; + gw_object_set_dragable(iw); + iw.odm = odm; + + iw.on_close = function (width, height) { + this.timer.stop(); + this.odm.gui.info_wnd = null; + } + + iw.area = gw_new_text_area(iw, ''); + + iw.on_display_size = function (width, height) { + var w = 30 * gwskin.default_text_font_size; + var h = 2 * gwskin.default_icon_height + 11 * gwskin.default_text_font_size; + this.set_size(w, h); + } + + iw.timer = gw_new_timer(false); + iw.timer.wnd = iw; + iw.timer.set_timeout(0.1, true); + iw.timer.on_event = function (val) { + var bw; + var m = this.wnd.odm; + if (!m) return; + var label = ''; + + this.wnd.children[0].spacing = 1.2; + + if (m.width) { + var fps = m.frame_duration; + label += 'Size:' + m.width + 'x' + m.height; + if (m.pixelformat) label += ' (' + m.par + ' ' + m.pixelformat + ')'; + } else { + label += '' + m.samplerate + 'Hz ' + m.channels + ' channels'; + } + label += '\n' + label += 'Status: ' + m.status + ' - clock time: ' + m.clock_time + ' (drift ' + m.clock_drift + ')'; + + label += '\n' + label += 'Composition Memory: ' + m.cb_unit_count + '/' + m.cb_capacity; + + label += '\n' + label += 'Buffer: ' + m.buffer + ' ms (min ' + m.min_buffer + ' - max ' + m.max_buffer + ') ' + m.db_unit_count + ' AUs in DB'; + + label += '\n' + var dec_time = m.total_dec_time / m.dec_frames / 1000; + var max_time = m.max_dec_time / 1000; + label += '' + m.dec_frames + ' frames (' + m.drop_frames + ' dropped) - ' + Math.round(100 * dec_time) / 100 + ' ms/frame (max ' + Math.round(m.max_dec_time / 10) / 100 + ') '; + + if (m.irap_frames && (m.dec_frames != m.irap_frames)) { + label += '\n' + dec_time = m.irap_dec_time / m.irap_frames / 1000; + label += 'Average GOP size: ' + Math.round(m.dec_frames / m.irap_frames) + ' - ' + Math.round(100 * dec_time) / 100 + ' ms/irap (max ' + Math.round(m.irap_max_time / 10) / 100 + ') '; + } + label += '\n' + label += 'Average bitrate: '; + bw = m.avg_bitrate; + if (bw < 8000000) label += '' + Math.round(bw / 1000) + ' kbps'; + else label += '' + Math.round(bw / 1000 / 1000) + ' mbps'; + + label += ' - Maximum '; + bw = m.max_bitrate; + if (bw < 8000000) label += '' + Math.round(bw / 1000) + ' kbps'; + else label += '' + Math.round(bw / 1000 / 1000) + ' mbps'; + + label += '\n' + label += 'Download bandwidth: '; + var bw = m.bandwidth_down; + if (bw < 8000) label += '' + bw + ' kbps'; + else label += '' + Math.round(bw / 1000) + ' mbps'; + + label += '\n' + label += 'Codec: ' + m.codec; + + label += '\n' + + var myurl; + if (m.service_url.indexOf('\\') >= 0) { + myurl = m.service_url.split('\\'); + } else { + myurl = m.service_url.split('/'); + } + + label += 'Service: ' + myurl.pop(); + if (m.service_id) + label += ' - ID ' + m.service_id; + + this.wnd.area.set_content(label); + } + + odm.gui.info_wnd.on_display_size(gw_display_width, gw_display_height); + odm.gui.info_wnd.set_alpha(0.9); + odm.gui.info_wnd.show(); + + } + + m.gui.buffer = null; + m.gui.play = null; + + if (m.selected_service == m.service_id) { + if (m.max_buffer) { + nb_buffering++; + m.gui.buffer = gw_new_gauge(wnd.area, 'Buffer'); + } + if (m.ntp_diff) nb_ntp_diff++; + } else if (!m.is_addon) { + m.gui.play = gw_new_icon(wnd.area, 'play'); + m.gui.play.odm = m; + m.gui.play.wnd = wnd; + m.gui.play.on_click = function () { + this.odm.select_service(this.odm.service_id); + this.wnd.close_all(); + } + } + + nb_http += m.nb_http; + + gw_new_separator(wnd.area); + } + + wnd.http_control = null; + if (nb_http) { + wnd.http_text = gw_new_text(wnd.area, 'HTTP rate', 'lefttext'); + + wnd.http_control = gw_new_slider(wnd.area); + + if (gpac.http_max_bitrate) { + var br = Math.round(100 * gpac.http_max_bitrate / 1000 / 1000) / 100; + if (br > 200) bt = 200; + if (br <= 1) { + v = 30 * br; + } else if (br <= 10) { + v = 30 + 30 * br / 10; + } else if (br < 50) { + v = 60 + 20 * (br - 10) / 40; + } else { + v = 80 + 20 * (br - 50) / 150; + } + wnd.http_control.set_value(v); + + wnd.http_text.set_label('HTTP cap ' + Math.round(100 * gpac.http_max_bitrate / 1000 / 1000) / 100 + ' Kbps'); + + } else { + wnd.http_control.set_value(100); + wnd.http_text.set_label('HTTP cap off'); + } + + wnd.http_control.text = wnd.http_text; + wnd.http_control.on_slide = function (val) { + var br = 0; + if (val <= 30) { + br = val / 30; + } else if (val <= 60) { + br = 1 + 10 * (val - 30) / 30; + } else if (val < 80) { + br = 10 + 40 * (val - 60) / 20; + } else { + br = 50 + 150 * (val - 80) / 20; + } + if (br == 200) { + this.text.set_label('HTTP cap off'); + gpac.http_max_bitrate = Math.round(0); + } else if (br == 0) { + this.text.set_label('HTTP disable'); + gpac.http_max_bitrate = -1; + } else { + this.text.set_label('HTTP cap ' + Math.round(100 * br) / 100 + ' Mbps'); + gpac.http_max_bitrate = Math.round(br * 1000000); + } + } + + gw_new_separator(wnd.area); + } + + wnd.plot = gw_new_plotter(wnd.area); + + + wnd.on_display_size = function (width, height) { + var w; + var h = 2 * gwskin.default_icon_height; + + w = 20 * gwskin.default_text_font_size; + w += 4 * gwskin.default_icon_height; + if (this.has_select) + w += 4 * gwskin.default_icon_height; + + for (var i = 0; i < this.objs.length; i++) { + var aw = w; + + this.objs[i].gui.info.set_size(1.5 * gwskin.default_icon_height, gwskin.default_icon_height); + aw -= this.objs[i].gui.info.width; + + if (this.objs[i].gui.buffer) { + this.objs[i].gui.buffer.set_size(2 * gwskin.default_icon_height, 0.75 * gwskin.default_icon_height); + } + if (this.objs[i].gui.play) { + this.objs[i].gui.play.set_size(gwskin.default_icon_height, gwskin.default_icon_height); + } + aw -= 4 * gwskin.default_icon_height; + + if (this.objs[i].gui.select) { + this.objs[i].gui.select.set_size(gwskin.default_icon_height, gwskin.default_icon_height); + aw -= gwskin.default_icon_height; + this.objs[i].gui.select_label.set_size(4 * gwskin.default_icon_height, 0.75 * gwskin.default_icon_height); + aw -= 4 * gwskin.default_icon_height; + } + + + this.objs[i].gui.txt.set_size(aw, gwskin.default_icon_height); + this.objs[i].gui.txt.set_width(aw); + h += gwskin.default_icon_height; + } + + if (this.plot) { + this.plot.set_size(w, 8 * gwskin.default_icon_height); + h += 8 * gwskin.default_icon_height; + } + + if (wnd.http_control) { + wnd.http_text.set_size(11 * gwskin.default_text_font_size, gwskin.default_icon_height); + wnd.http_control.set_size(w - 11 * gwskin.default_text_font_size, 0.2 * gwskin.default_icon_height); + h += gwskin.default_icon_height; + } + + this.set_size(w, h); + this.move((w - width) / 2, (height - h) / 2); + } + wnd.on_close = function () { + this.timer.stop(); + this.objs = []; + if (this.reload_request) { + var translation = this.extension.stat_wnd.translation; + this.extension.stat_wnd = null; + this.extension.view_stats(); + this.extension.stat_wnd.translation = translation; + } else { + this.extension.stat_wnd = null; + } + } + + wnd.timer = gw_new_timer(false); + wnd.timer.wnd = wnd; + wnd.timer.set_timeout(0.25, true); + + var label = 'Statistics (' + gpac.nb_cores + ' cores - '; + if (gpac.system_memory > 1000000000) label += '' + Math.round(gpac.system_memory / 1000 / 1000 / 1000) + ' GB RAM)'; + else label += '' + Math.round(gpac.system_memory / 1000 / 1000) + ' MB RAM)'; + + wnd.set_label(label); + + wnd.stats = []; + wnd.stats_window = 32; + + if (wnd.plot) { + wnd.s_fps = wnd.plot.add_serie('FPS', 'Hz', 0.8, 0, 0); + if (nb_http) { + wnd.s_bw = wnd.plot.add_serie('BW', 'Mbps', 0.8, 0, 0.8); + } else { + wnd.s_bw = null; + } + wnd.s_bitrate = wnd.plot.add_serie('Rate', 'Kbps', 0, 0.8, 0); + if (nb_buffering) + wnd.s_buf = wnd.plot.add_serie('Buffer', 's', 0, 0, 0.8); + else + wnd.s_buf = null; + + if (nb_ntp_diff) + wnd.s_ntp = wnd.plot.add_serie('NTP diff', 'ms', 0, 0.3, 0.8); + else + wnd.s_ntp = null; + + wnd.s_cpu = wnd.plot.add_serie('CPU', '%', 0, 0.5, 0.5); + wnd.s_mem = wnd.plot.add_serie('MEM', 'MB', 0.5, 0.5, 0); + + } + + wnd.timer.on_event = function (val) { + var wnd = this.wnd; + var nb_buff = 0; + + var stat_obj = null; + //stats every second + if (!(val % 4)) { + if (wnd.stats.length >= wnd.stats_window) { + wnd.stats.splice(0, 1); + } + stat_obj = {}; + wnd.stats.push(stat_obj); + + var t = new Date() + stat_obj.time = Math.round(t.getTime() / 1000); + stat_obj.fps = Math.round(100 * gpac.fps) / 100; + stat_obj.cpu = gpac.cpu; + stat_obj.memory = Math.round(100 * gpac.memory / 1000 / 1000) / 100; + stat_obj.bitrate = 0; + if (wnd.s_bw) { + var b = gpac.http_bitrate; + if (b < 50000) stat_obj.http_bandwidth = Math.round(gpac.http_bitrate / 10) / 100; + else stat_obj.http_bandwidth = Math.round(gpac.http_bitrate / 1000); + } + // stat_obj.buffer = 0; + stat_obj.buffer = 100000; + stat_obj.ntp_diff = 0; + } + + for (var i = 0; i < wnd.objs.length; i++) { + var m = wnd.objs[i]; + + if (m.gui.buffer) { + var label = ' ' + m.type; + + if (m.width) label += ' (' + m.width + 'x' + m.height + ')'; + else if (m.samplerate) label += ' (' + Math.round(m.samplerate / 10) / 100 + ' kHz ' + m.channels + ' ch)'; + else if (m.scalable_enhancement) label += ' (Enh. Layer)'; + + var url = m.service_url; + if ((url.indexOf('udp://') >= 0) || (url.indexOf('rtp://') >= 0) || (url.indexOf('dvb://') >= 0)) + label += ' Broadcast'; + else if ((url.indexOf('file://') >= 0) || (url.indexOf('://') < 0)) + label += ' File'; + else + label += ' Broadband'; + + m.gui.txt.set_label(label); + + var bl; + if (m.max_buffer) { + var speed = wnd.extension.movie_control.mediaSpeed; + if (speed < 0) speed = 1; + else if (speed == 0) speed = 1; + var buf = m.buffer / speed; + bl = 100 * buf / m.max_buffer; + + if (stat_obj) { + if (buf < stat_obj.buffer) { + stat_obj.buffer = buf; + } + //stat_obj.buffer += buf; + //nb_buff++; + } + } + else bl = 100; + m.gui.buffer.set_value(bl); + + m.gui.buffer.set_label('' + Math.round(m.buffer / 10) / 100 + ' s'); + + if (stat_obj) { + bl = m.ntp_diff; + if (bl > stat_obj.ntp_diff) + stat_obj.ntp_diff = bl; + } + } + + if (stat_obj) { + if (m.status != 'Stopped') + stat_obj.bitrate += Math.round(m.avg_bitrate / 1000); + } + } + + if (stat_obj && wnd.stats.length) { + wnd.s_fps.refresh_serie(wnd.stats, 'time', 'fps', wnd.stats_window, 4); + if (wnd.s_bw) { + wnd.s_bw.refresh_serie(this.wnd.stats, 'time', 'http_bandwidth', wnd.stats_window, 1); + } + if (wnd.s_buf) { + if (nb_buff) { + // stat_obj.buffer /= nb_buff; + } + wnd.s_buf.refresh_serie(this.wnd.stats, 'time', 'buffer', wnd.stats_window, 1.5); + } + if (stat_obj.bitrate) { + wnd.s_bitrate.refresh_serie(this.wnd.stats, 'time', 'bitrate', wnd.stats_window, 2); + } else { + wnd.s_bitrate.hide(); + } + if (wnd.s_ntp) { + wnd.s_ntp.refresh_serie(this.wnd.stats, 'time', 'ntp_diff', wnd.stats_window, 3); + } + + wnd.s_cpu.refresh_serie(wnd.stats, 'time', 'cpu', wnd.stats_window, 10); + wnd.s_mem.refresh_serie(wnd.stats, 'time', 'memory', wnd.stats_window, 6); + } + } + + wnd.quality_changed = function () { + for (var i = 0; i < this.objs.length; i++) { + var m = this.objs[i]; + m.update_qualities(); + } + } + wnd.close_all = function () { + for (var i = 0; i < this.objs.length; i++) { + if (this.objs[i].gui.info_wnd) { + this.objs[i].gui.info_wnd.odm = null; + this.objs[i].gui.info_wnd.close(); + } + } + this.objs.length = 0; + this.close(); + } + wnd.on_display_size(gw_display_width, gw_display_height); + wnd.set_alpha(0.9); + wnd.show(); +}; + \ No newline at end of file diff --git a/gui/extensions/widget_manager/init.js b/gui/extensions/widget_manager/init.js index f839212..5dcf24c 100644 --- a/gui/extensions/widget_manager/init.js +++ b/gui/extensions/widget_manager/init.js @@ -1,927 +1,927 @@ -/*container for widgets*/ -widget_display = gw_new_container(); -widget_display.on_event = function(evt) -{ - if(!widget_display.children.length) return false; - return widget_display.children[widget_display.children.length-1].on_event(evt); -} - -widget_tool_size = 18; -widget_min_size = 5*widget_tool_size; -widget_default_size = 100; - - -function check_widget_display(width, height) -{ - var count = WidgetManager.num_widgets; - for (var i=0; i= width/2) x = width/2 - wid.width/2; - - if (y + wid.height/2 >= height/2) y = height/2 - wid.height/2; - else if (y - wid.height/2 <= - height/2) y = -height/2 + wid.height/2; - - if (wid.widget_control) wid.widget_control.move(x, y); - } -} - -function scan_directory(dir) -{ - var i, j, count, list, new_wid, uri; - list = gpac.enum_directory(dir, '.xml;.wgt;.mgt', 0); - for (i=0; i0) { - gw_new_text(info_dlg.area, txt.substring(0, idx), 'text'); - txt = txt.substring(idx+1, txt.length); - } else { - gw_new_text(info_dlg.area, txt, 'text'); - break; - } - } - info.last_idx = info_dlg.area.get_children().length; - info.on_click(); - - if (wid.num_interfaces) { - info = collapsable_list(info_dlg, 'MPEG-U Interfaces', 'button'); - var spacer = gw_new_text(info_dlg.area, '', 'text'); - spacer.hide(); - info.first_idx = info_dlg.area.get_children().length; - for (j=0; j200) ? 200 : width, 20); - } else { - children[i].set_size(width, 16); - } - } - } - - info_dlg.on_event = function(evt) { - if (this.area && this.area.on_event(evt)) return true; - return false; - } - - info_dlg.set_size(320, 240); - gpacui_show_window(info_dlg); -} - - -//widget close function -function widget_close(widget, force_remove) -{ - var is_comp = widget.is_component; - - if (widget.visible) { - widget.visible = false; - WidgetManager.corein_message(widget, 'hide'); - WidgetManager.corein_message(widget, 'deactivate'); - widget.deactivate(); - /*force disconnect of main resource - we do this because we are not sure when the widget_control will be destroyed due to JS GC*/ - if (widget.widget_control) { - widget.widget_control.set_url(''); - widget.widget_control.close(); - } - } - if (!is_comp && (!widget.permanent || force_remove)) { - WidgetManager.unload(widget, force_remove ? true : false); - } -} - -//widget remove function (close and unregister) -function widget_remove(wid) { - if (typeof(wid.icon_dock) != 'undefined') { - wid.icon_dock.close(); - wid.icon_dock = null; - } - widget_close(wid, 1); -} - -function new_migrate_callback(widget) { - return function(renderer) { - WidgetManager.migrate_widget(renderer, widget); - widget_close(widget, 0); - } -} - -function on_widget_load() -{ - WidgetManager.corein_message(this, 'activate'); - WidgetManager.corein_message(this, 'show'); - WidgetManager.corein_message(this, 'setSize', 'width', this.width, 'height', this.height, 'dpi', screen_dpi); -} - - -mpegu_targets = null; - -function select_mpegu_target(callback) -{ - if (mpegu_targets) return; - mpegu_targets = gw_new_file_open(); - mpegu_targets.set_label('Select Remote Display'); - mpegu_targets.callback = callback; - - mpegu_targets.on_close = function() { - mpegu_targets = null; - } - /*override browse function*/ - mpegu_targets._on_mpegu_click = function() { - var target = (this.render_idx<0) ? null : WidgetManager.get_mpegu_service_providers(this.render_idx); - - mpegu_targets.callback(target); - mpegu_targets.callback = null; - mpegu_targets.close(); - mpegu_targets = null; - } - mpegu_targets._browse = function(dir, up) { - var w, h, i, y; - this.area.reset_children(); - - for (i=0; ; i++) { - var target = WidgetManager.get_mpegu_service_providers(i); - if (!target) break; - var icon = 'icons/applications-internet.svg'; - var item = gw_new_icon_button(this.area, icon, target.Name, 'button'); - item.set_size(item.width, item.height); - item.render_idx = i; - item.on_click = this._on_mpegu_click; - } - this.layout(this.width, this.height); - } - mpegu_targets.browse(''); - mpegu_targets.go_up.hide(); - mpegu_targets.set_size(display_width, display_height); - gpacui_show_window(mpegu_targets); -} - - -function new_widget_control(widget) -{ - var ctrl; - - - var inline = gw_new_subscene(null); - ctrl = gw_new_window_full(widget_display, true, null, 'offscreen', inline); - ctrl.set_size(widget.width, widget.height); - - ctrl.inline = inline; - ctrl.tools.spread_h = true; - - ctrl.component_bound = false; - ctrl.widget = widget; - widget.widget_control = ctrl; - widget.visible = true; - - ctrl.on_close = function() { - this.inline.url[0] = ''; - this.widget.widget_control = null; - if (this.widget.discardable) widget_remove(this.widget); - else widget_close(this.widget, 0); - this.widget = null; - } - - ctrl.tools.hide(); - gw_object_set_dragable(ctrl); - - gw_object_set_hitable(ctrl); - ctrl.controls_visible = false; - - this.maximized = false; - ctrl.on_double_click = function() { - if (this.maximized) { - this.maximized = false; - this.move(this.widget.x, this.widget.y); - this.set_size(this.prev_width, this.prev_height); - } else { - this.maximized = true; - this.prev_width = this.widget.width; - this.prev_height = this.widget.height; - this.move(0, 0); - this.set_size(display_width, display_height); - } - this.controls_visible = false; - this.tools.hide(); - } - - ctrl.on_click = function() { - this.controls_visible = ! this.controls_visible; - if (this.controls_visible) this.tools.show(); - else this.tools.hide(); - } - /*push on top*/ - ctrl.on_down = function(value) { - if (value) return; - if (this.widget==null) return; - - //widget is a component, do not push on top but hide some controls - if (this.widget.is_component) { - if (this.component_bound) { - var chldren = this.tools.get_children(); - children[0].hide(); //close - children[1].hide(); //remove - children[4].hide(); //resize - } - return; - } - //otherwise push widget on top - widget_display.push_to_top(this); - //and push components - comps = this.widget.components; - for (i=0; i display_width/2) widget.x = 0; - if (widget.y < -display_height/2) widget.y = 0; - else if (widget.y > display_height/2) widget.y = 0; - ctrl.move(widget.x, widget.y); - - /*this will setup the scene graph for the widget in order to filter input and output communication pins*/ - widget.activate(ctrl.inline); - - ctrl.set_url(widget.main); - - /*send notifications once the widget scene is loaded*/ - widget.on_load = on_widget_load; - - ctrl.show(); - return ctrl; -} - -function flash_window(wnd) { - wnd.time = gw_new_timer(true); - wnd.time.set_timeout(0.25, true); - wnd.time.ctrl = wnd; - wnd.time.on_fraction = function(val) { - var scale = (val<0.5) ? 1+val/2 : 1.5-val/2; - this.ctrl.scale.x = this.ctrl.scale.y = scale; - } - wnd.time.on_active = function (val) { - if (!val) { - this.ctrl.time = null; - this.ctrl = null; - } - } - wnd.time.stop(1); - wnd.time.start(0); -} - -//widget launcher function -function widget_launch(wid) { - var widg_ctrl; - - //assign default size to the widget - if (wid.width == undefined) { - wid.width = wid.defaultWidth; - if (wid.width == 0) wid.width = widget_default_size; - } - if (wid.height == undefined) { - wid.height = wid.defaultHeight; - if (wid.height == 0) wid.height = widget_default_size; - } - if (wid.x== undefined) wid.x = 0; - if (wid.y== undefined) wid.y = 0; - - widg_ctrl = new_widget_control(wid); -} - - -//starts a widget -function on_widget_launch() { - if (this.widget.visible) { - var awid; - if (!this.widget.multipleInstances) return; - awid = WidgetManager.open(this.widget.manifest, null); - widget_launch(awid); - } else { - widget_launch(this.widget); - } - show_dock(false); -} - - -function widget_get_icon(widget) -{ - var icon = 'icons/image-missing.svg'; - var preferredIconType = '.svg'; - - for (var i = 0; i < widget.icons.length; i++) { - icon = widget.icons[i].relocated_src; - if (widget.icons[i].relocated_src.indexOf(preferredIconType) > 0) { - break; - } - } - return icon; -} - -function widget_insert(widget) -{ - /*insert the widget icon*/ - if (widget.permanent && !widget.is_component) - widget_insert_icon(widget); - - /*and load the widget - comment this line to disable auto load of widget*/ - widget_launch(widget); -} - -function __get_int(arg) -{ - return (typeof arg == 'string') ? parseInt(arg) : arg; -} - -function widget_request_size(widget, args) -{ - if (args.length==2) { - w = __get_int(args[0]); - h = __get_int(args[1]); - widget.widget_control.set_size(w, h); - } -} - -function widget_request_show(widget, args) -{ - widget.widget_control.show(); -} -function widget_request_hide(widget, args) -{ - widget.widget_control.hide(); -} -function widget_request_activate(widget, args) -{ - if (!widget.visible) - widget_launch(widget); -} -function widget_request_deactivate(widget, args) -{ - if (widget.visible) - widget_close(widget, 0); -} - -function widget_request_attention(widget, args) -{ - if (widget.visible) { - widget_display.push_to_top(widget.widget_control); - flash_window(widget.widget_control); - } -} - -function widget_request_notification(widget, args) -{ - var notif = gw_new_message(null, ''+widget.name+' Alert!', args[0]); -// widget_display.push_to_top(notif); - gpacui_show_window(notif); - notif.set_size(240, 120); -} - -function widget_refresh_components_layout(ctrl, send_resize, comp_target) -{ - var i; - var x, y, w, h, scale_x, scale_y; - var comps; - - /*local to subscene transformation not known*/ - if (!ctrl.sub_w) return; - if (!ctrl.sub_h) return; - - comps = ctrl.widget.components; - for (i=0; i 1 && args[1] != null) { - alert('Migrating component to ' + UPnP.GetMediaRenderer(parseInt(args[1])).Name); - WidgetManager.migrate_widget(UPnP.GetMediaRenderer(parseInt(args[1])), comp); - widget_close(comp); - } else { - var dlg = select_mpegu_target(new_migrate_callback(comp) ); - } - if (ifce != null) { - wmjs_core_out_invoke_reply(coreOut.migrateComponentMessage, ifce.get_message("migrateComponent"), wid, 1); // send return code 1 = success - } -} - -function widget_migration_targets(wid, args) -{ - var count = UPnP.MediaRenderersCount, codes = new Array(), names = new Array(), descriptions = new Array(), i, i; - - for (i = 0; i < count; i++) { - var render = UPnP.GetMediaRenderer(i); - codes.push(""+i); - names.push(render.Name); - descriptions.push(render.HostName +" "+ render.UUID); - } - i = null; - var ifce_count = wid.num_interfaces, j; - for (j = 0; j < ifce_count; j++) { - var ifce = wid.get_interface(j); - if (ifce.type == "urn:mpeg:mpegu:schema:widgets:core:out:2010") { - i = ifce; - break; - } - } - if (i != null) { - wmjs_core_out_invoke_reply(coreOut.requestMigrationTargetsMessage, i.get_message("requestMigrationTargets"), - wid, codes, names, descriptions); - } -} - - -// -// implementation of core:out activate temporary widget -// -function widget_activate_temporary_widget(wid, args) { - var w = WidgetManager.open(args[0], null); - if (w != null) widget_launch(w); - var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010"); - if (ifce != null) { - wmjs_core_out_invoke_reply(coreOut.activateTemporaryWidgetMessage, ifce.get_message("activateTemporaryWidget"), - wid, (w != null ? 1 : 0)); // send return code 1 = success - } -} - -function setup_extension(extension) -{ - var count, i; - - /*WidgetManager module not present*/ - if (typeof(WidgetManager) == 'undefined') return 0; - - /*load MPEG-U*/ - Browser.loadScript('mpegu-core.js', true); - widget_manager_init(); - - extension.icon = 'applications-system.svg'; - extension.label = 'Widget Manager'; - extension.desc = 'Configure Widgets'; - extension.launch = open_widget_manager; - - extension.initialize = function(extension) { - WidgetManager.on_widget_remove = widget_remove; - WidgetManager.on_widget_add = widget_insert; - WidgetManager.coreOutSetSize = widget_request_size; - WidgetManager.coreOutShow = widget_request_show; - WidgetManager.coreOutHide = widget_request_hide; - WidgetManager.coreOutRequestActivate = widget_request_activate; - WidgetManager.coreOutRequestDeactivate = widget_request_deactivate; - WidgetManager.coreOutShowNotification = widget_request_notification; - WidgetManager.coreOutPlaceComponent = widget_place_component; - WidgetManager.coreOutGetAttention = widget_request_attention; - WidgetManager.coreOutInstallWidget = widget_request_install; - WidgetManager.coreOutMigrateComponent = widget_migrate_component; - WidgetManager.coreOutRequestMigrationTargets = widget_migration_targets; - WidgetManager.coreOutActivateTemporaryWidget = widget_activate_temporary_widget; - - - gpacui_show_window(widget_display); - - /*restore our widgets*/ - count = WidgetManager.num_widgets; - for (i=0; i= width/2) x = width/2 - wid.width/2; + + if (y + wid.height/2 >= height/2) y = height/2 - wid.height/2; + else if (y - wid.height/2 <= - height/2) y = -height/2 + wid.height/2; + + if (wid.widget_control) wid.widget_control.move(x, y); + } +} + +function scan_directory(dir) +{ + var i, j, count, list, new_wid, uri; + list = gpac.enum_directory(dir, '.xml;.wgt;.mgt', 0); + for (i=0; i0) { + gw_new_text(info_dlg.area, txt.substring(0, idx), 'text'); + txt = txt.substring(idx+1, txt.length); + } else { + gw_new_text(info_dlg.area, txt, 'text'); + break; + } + } + info.last_idx = info_dlg.area.get_children().length; + info.on_click(); + + if (wid.num_interfaces) { + info = collapsable_list(info_dlg, 'MPEG-U Interfaces', 'button'); + var spacer = gw_new_text(info_dlg.area, '', 'text'); + spacer.hide(); + info.first_idx = info_dlg.area.get_children().length; + for (j=0; j200) ? 200 : width, 20); + } else { + children[i].set_size(width, 16); + } + } + } + + info_dlg.on_event = function(evt) { + if (this.area && this.area.on_event(evt)) return true; + return false; + } + + info_dlg.set_size(320, 240); + gpacui_show_window(info_dlg); +} + + +//widget close function +function widget_close(widget, force_remove) +{ + var is_comp = widget.is_component; + + if (widget.visible) { + widget.visible = false; + WidgetManager.corein_message(widget, 'hide'); + WidgetManager.corein_message(widget, 'deactivate'); + widget.deactivate(); + /*force disconnect of main resource - we do this because we are not sure when the widget_control will be destroyed due to JS GC*/ + if (widget.widget_control) { + widget.widget_control.set_url(''); + widget.widget_control.close(); + } + } + if (!is_comp && (!widget.permanent || force_remove)) { + WidgetManager.unload(widget, force_remove ? true : false); + } +} + +//widget remove function (close and unregister) +function widget_remove(wid) { + if (typeof(wid.icon_dock) != 'undefined') { + wid.icon_dock.close(); + wid.icon_dock = null; + } + widget_close(wid, 1); +} + +function new_migrate_callback(widget) { + return function(renderer) { + WidgetManager.migrate_widget(renderer, widget); + widget_close(widget, 0); + } +} + +function on_widget_load() +{ + WidgetManager.corein_message(this, 'activate'); + WidgetManager.corein_message(this, 'show'); + WidgetManager.corein_message(this, 'setSize', 'width', this.width, 'height', this.height, 'dpi', screen_dpi); +} + + +mpegu_targets = null; + +function select_mpegu_target(callback) +{ + if (mpegu_targets) return; + mpegu_targets = gw_new_file_open(); + mpegu_targets.set_label('Select Remote Display'); + mpegu_targets.callback = callback; + + mpegu_targets.on_close = function() { + mpegu_targets = null; + } + /*override browse function*/ + mpegu_targets._on_mpegu_click = function() { + var target = (this.render_idx<0) ? null : WidgetManager.get_mpegu_service_providers(this.render_idx); + + mpegu_targets.callback(target); + mpegu_targets.callback = null; + mpegu_targets.close(); + mpegu_targets = null; + } + mpegu_targets._browse = function(dir, up) { + var w, h, i, y; + this.area.reset_children(); + + for (i=0; ; i++) { + var target = WidgetManager.get_mpegu_service_providers(i); + if (!target) break; + var icon = 'icons/applications-internet.svg'; + var item = gw_new_icon_button(this.area, icon, target.Name); + item.set_size(item.width, item.height); + item.render_idx = i; + item.on_click = this._on_mpegu_click; + } + this.layout(this.width, this.height); + } + mpegu_targets.browse(''); + mpegu_targets.go_up.hide(); + mpegu_targets.set_size(display_width, display_height); + gpacui_show_window(mpegu_targets); +} + + +function new_widget_control(widget) +{ + var ctrl; + + + var inline = gw_new_subscene(null); + ctrl = gw_new_window_full(widget_display, true, null, 'offscreen', inline); + ctrl.set_size(widget.width, widget.height); + + ctrl.inline = inline; + ctrl.tools.spread_h = true; + + ctrl.component_bound = false; + ctrl.widget = widget; + widget.widget_control = ctrl; + widget.visible = true; + + ctrl.on_close = function() { + this.inline.url[0] = ''; + this.widget.widget_control = null; + if (this.widget.discardable) widget_remove(this.widget); + else widget_close(this.widget, 0); + this.widget = null; + } + + ctrl.tools.hide(); + gw_object_set_dragable(ctrl); + + gw_object_set_hitable(ctrl); + ctrl.controls_visible = false; + + this.maximized = false; + ctrl.on_double_click = function() { + if (this.maximized) { + this.maximized = false; + this.move(this.widget.x, this.widget.y); + this.set_size(this.prev_width, this.prev_height); + } else { + this.maximized = true; + this.prev_width = this.widget.width; + this.prev_height = this.widget.height; + this.move(0, 0); + this.set_size(display_width, display_height); + } + this.controls_visible = false; + this.tools.hide(); + } + + ctrl.on_click = function() { + this.controls_visible = ! this.controls_visible; + if (this.controls_visible) this.tools.show(); + else this.tools.hide(); + } + /*push on top*/ + ctrl.on_down = function(value) { + if (value) return; + if (this.widget==null) return; + + //widget is a component, do not push on top but hide some controls + if (this.widget.is_component) { + if (this.component_bound) { + var chldren = this.tools.get_children(); + children[0].hide(); //close + children[1].hide(); //remove + children[4].hide(); //resize + } + return; + } + //otherwise push widget on top + widget_display.push_to_top(this); + //and push components + comps = this.widget.components; + for (i=0; i display_width/2) widget.x = 0; + if (widget.y < -display_height/2) widget.y = 0; + else if (widget.y > display_height/2) widget.y = 0; + ctrl.move(widget.x, widget.y); + + /*this will setup the scene graph for the widget in order to filter input and output communication pins*/ + widget.activate(ctrl.inline); + + ctrl.set_url(widget.main); + + /*send notifications once the widget scene is loaded*/ + widget.on_load = on_widget_load; + + ctrl.show(); + return ctrl; +} + +function flash_window(wnd) { + wnd.time = gw_new_timer(true); + wnd.time.set_timeout(0.25, true); + wnd.time.ctrl = wnd; + wnd.time.on_fraction = function(val) { + var scale = (val<0.5) ? 1+val/2 : 1.5-val/2; + this.ctrl.scale.x = this.ctrl.scale.y = scale; + } + wnd.time.on_active = function (val) { + if (!val) { + this.ctrl.time = null; + this.ctrl = null; + } + } + wnd.time.stop(1); + wnd.time.start(0); +} + +//widget launcher function +function widget_launch(wid) { + var widg_ctrl; + + //assign default size to the widget + if (wid.width == undefined) { + wid.width = wid.defaultWidth; + if (wid.width == 0) wid.width = widget_default_size; + } + if (wid.height == undefined) { + wid.height = wid.defaultHeight; + if (wid.height == 0) wid.height = widget_default_size; + } + if (wid.x== undefined) wid.x = 0; + if (wid.y== undefined) wid.y = 0; + + widg_ctrl = new_widget_control(wid); +} + + +//starts a widget +function on_widget_launch() { + if (this.widget.visible) { + var awid; + if (!this.widget.multipleInstances) return; + awid = WidgetManager.open(this.widget.manifest, null); + widget_launch(awid); + } else { + widget_launch(this.widget); + } + show_dock(false); +} + + +function widget_get_icon(widget) +{ + var icon = 'icons/image-missing.svg'; + var preferredIconType = '.svg'; + + for (var i = 0; i < widget.icons.length; i++) { + icon = widget.icons[i].relocated_src; + if (widget.icons[i].relocated_src.indexOf(preferredIconType) > 0) { + break; + } + } + return icon; +} + +function widget_insert(widget) +{ + /*insert the widget icon*/ + if (widget.permanent && !widget.is_component) + widget_insert_icon(widget); + + /*and load the widget - comment this line to disable auto load of widget*/ + widget_launch(widget); +} + +function __get_int(arg) +{ + return (typeof arg == 'string') ? parseInt(arg) : arg; +} + +function widget_request_size(widget, args) +{ + if (args.length==2) { + w = __get_int(args[0]); + h = __get_int(args[1]); + widget.widget_control.set_size(w, h); + } +} + +function widget_request_show(widget, args) +{ + widget.widget_control.show(); +} +function widget_request_hide(widget, args) +{ + widget.widget_control.hide(); +} +function widget_request_activate(widget, args) +{ + if (!widget.visible) + widget_launch(widget); +} +function widget_request_deactivate(widget, args) +{ + if (widget.visible) + widget_close(widget, 0); +} + +function widget_request_attention(widget, args) +{ + if (widget.visible) { + widget_display.push_to_top(widget.widget_control); + flash_window(widget.widget_control); + } +} + +function widget_request_notification(widget, args) +{ + var notif = gw_new_message(null, ''+widget.name+' Alert!', args[0]); +// widget_display.push_to_top(notif); + gpacui_show_window(notif); + notif.set_size(240, 120); +} + +function widget_refresh_components_layout(ctrl, send_resize, comp_target) +{ + var i; + var x, y, w, h, scale_x, scale_y; + var comps; + + /*local to subscene transformation not known*/ + if (!ctrl.sub_w) return; + if (!ctrl.sub_h) return; + + comps = ctrl.widget.components; + for (i=0; i 1 && args[1] != null) { + alert('Migrating component to ' + UPnP.GetMediaRenderer(parseInt(args[1])).Name); + WidgetManager.migrate_widget(UPnP.GetMediaRenderer(parseInt(args[1])), comp); + widget_close(comp); + } else { + var dlg = select_mpegu_target(new_migrate_callback(comp) ); + } + if (ifce != null) { + wmjs_core_out_invoke_reply(coreOut.migrateComponentMessage, ifce.get_message("migrateComponent"), wid, 1); // send return code 1 = success + } +} + +function widget_migration_targets(wid, args) +{ + var count = UPnP.MediaRenderersCount, codes = new Array(), names = new Array(), descriptions = new Array(), i, i; + + for (i = 0; i < count; i++) { + var render = UPnP.GetMediaRenderer(i); + codes.push(""+i); + names.push(render.Name); + descriptions.push(render.HostName +" "+ render.UUID); + } + i = null; + var ifce_count = wid.num_interfaces, j; + for (j = 0; j < ifce_count; j++) { + var ifce = wid.get_interface(j); + if (ifce.type == "urn:mpeg:mpegu:schema:widgets:core:out:2010") { + i = ifce; + break; + } + } + if (i != null) { + wmjs_core_out_invoke_reply(coreOut.requestMigrationTargetsMessage, i.get_message("requestMigrationTargets"), + wid, codes, names, descriptions); + } +} + + +// +// implementation of core:out activate temporary widget +// +function widget_activate_temporary_widget(wid, args) { + var w = WidgetManager.open(args[0], null); + if (w != null) widget_launch(w); + var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010"); + if (ifce != null) { + wmjs_core_out_invoke_reply(coreOut.activateTemporaryWidgetMessage, ifce.get_message("activateTemporaryWidget"), + wid, (w != null ? 1 : 0)); // send return code 1 = success + } +} + +function setup_extension(extension) +{ + var count, i; + + /*WidgetManager module not present*/ + if (typeof(WidgetManager) == 'undefined') return 0; + + /*load MPEG-U*/ + Browser.loadScript('mpegu-core.js', true); + widget_manager_init(); + + extension.icon = 'applications-system.svg'; + extension.label = 'Widget Manager'; + extension.desc = 'Configure Widgets'; + extension.launch = open_widget_manager; + + extension.initialize = function(extension) { + WidgetManager.on_widget_remove = widget_remove; + WidgetManager.on_widget_add = widget_insert; + WidgetManager.coreOutSetSize = widget_request_size; + WidgetManager.coreOutShow = widget_request_show; + WidgetManager.coreOutHide = widget_request_hide; + WidgetManager.coreOutRequestActivate = widget_request_activate; + WidgetManager.coreOutRequestDeactivate = widget_request_deactivate; + WidgetManager.coreOutShowNotification = widget_request_notification; + WidgetManager.coreOutPlaceComponent = widget_place_component; + WidgetManager.coreOutGetAttention = widget_request_attention; + WidgetManager.coreOutInstallWidget = widget_request_install; + WidgetManager.coreOutMigrateComponent = widget_migrate_component; + WidgetManager.coreOutRequestMigrationTargets = widget_migration_targets; + WidgetManager.coreOutActivateTemporaryWidget = widget_activate_temporary_widget; + + + gpacui_show_window(widget_display); + + /*restore our widgets*/ + count = WidgetManager.num_widgets; + for (i=0; i gpac.screen_width) width = gpac.screen_width; - if (height > gpac.screen_height) height = gpac.screen_height; - w = width; - h = height; - r_w = r_h = 1; - if (w < min_width) r_w = Math.ceil(min_width/w); - if (h < min_height) r_h = Math.ceil(min_height/h); - if (r_w < r_h) r_w = r_h; - w = r_w * w; - h = r_w * h; - gpac.set_size(w, h); +function setup_extension_storage(extension) { + var storage_name = 'config:' + extension.ext_description.path + '' + extension.ext_description.name; + + extension.extension_obj.__gpac_storage = gpac.new_storage(storage_name); + + extension.extension_obj.get_option = extension_option_getter(extension.ext_description); + extension.extension_obj.set_option = extension_option_setter(extension.ext_description); } -//Initialize the main UI script +//Initialize our GUI function initialize() { //var icon; var i, count, wid; - gpac.caption = 'Osmo4'; - current_time = 0; min_width = 160; min_height = 80; - - /*load the UI lib*/ - Browser.loadScript('gwlib.js', false); - - browser_mode = gpac.getOption('Temp', 'BrowserMode'); - if (browser_mode && (browser_mode=='yes')) { - browser_mode = true; - } else { - browser_mode = false; + gw_display_width = parseInt(gpac.get_option('General', 'LastWidth')); + gw_display_height = parseInt(gpac.get_option('General', 'LastHeight')); + if (!gpac.fullscreen && (!gw_display_width || !gw_display_height)) { + gw_display_width = 320; + gw_display_height = 240; } - - -// gwskin.tooltip_callback = function(over, label) { alert('' + over ? label : ''); }; - - root.children[0].backColor = gwskin.back_color; - movie.children[0].on_size = function(evt) { - if (!movie_connected) { - movie_connected = true; - gpac.set_3d(evt.type3d ? 1 : 0); - player_control.play.switch_icon(icon_pause); - dynamic_scene = evt.dynamic_scene; - } - if (!gpac.fullscreen) { - compute_movie_size(evt.width, evt.height); - } - } - - movie.children[0].on_media_progress = function(evt) { - if (!current_duration) return; - /*this is not conform to HTML5, we're using the old MediaAccessEvent syntax ...*/ - var percent_dload = 100.0 * evt.loaded / evt.total; - var percent_playback = 100.0 * current_time / current_duration; - //alert('URL data ' + percent_dload + ' - ' + percent_playback + ' playback'); - } - - movie.children[0].on_media_playing = function(evt) { - player_control.play.switch_icon(icon_pause); - } - movie.children[0].on_media_end = function(evt) { - if (player_control.duration && movie_ctrl.loop) { - movie_ctrl.mediaStartTime = 0; - current_time=0; - } - } - - movie.children[0].addEventListener('gpac_scene_attached', movie.children[0].on_size, 0); - movie.children[0].addEventListener('progress', movie.children[0].on_media_progress, 0); - movie.children[0].addEventListener('playing', movie.children[0].on_media_playing, 0); - movie.children[0].addEventListener('canplay', movie.children[0].on_media_playing, 0); - movie.children[0].addEventListener('ended', movie.children[0].on_media_end, 0); - - movie.children[0].on_media_waiting = function(evt) { - alert('URL is now buffering'); - } - movie.children[0].addEventListener('waiting', movie.children[0].on_media_waiting, 0); - - - display_width = parseInt( gpac.getOption('General', 'LastWidth') ); - display_height = parseInt( gpac.getOption('General', 'LastHeight') ); - - if (!gpac.fullscreen && (!display_width || !display_height)) { - display_width = 320; - display_height = 240; - } - - if (!gpac.fullscreen && display_width && display_height) { - gpac.set_size(display_width, display_height); + if (!gpac.fullscreen && gw_display_width && gw_display_height) { + gpac.set_size(gw_display_width, gw_display_height); } else { - display_width = gpac.get_screen_width(); - display_height = gpac.get_screen_height(); + gw_display_width = gpac.screen_width; + gw_display_height = gpac.screen_height; } - screen_dpi = gpac.get_horizontal_dpi(); - - - dictionary = gw_new_container(root); - dictionary.hide(); - - //request event listeners on the window - GPAC specific BIFS extensions !!! + //request event listeners on the window - GPAC specific BIFS extensions !!! We don't allow using the event proc for size events root.addEventListener('resize', on_resize, 0); - root.addEventListener('zoom', on_zoom, 0); - root.addEventListener('scroll', on_scroll, 0); - - Browser.addRoute(movie_sensor, 'mediaDuration', movie_sensor, on_movie_duration); - Browser.addRoute(movie_sensor, 'mediaCurrentTime', movie_sensor, on_movie_time); - Browser.addRoute(movie_sensor, 'isActive', movie_sensor, on_movie_active); - scene_width = 0; + /*load the UI lib*/ + Browser.loadScript('gwlib.js', false); + gwlib_init(ui_root); - /*init UPnP*/ - controlled_renderer = null; - UPnP_Enabled = eval("(typeof(UPnP) != 'undefined');"); - if (UPnP_Enabled) { - UPnP.onMediaRendererAdd = onMediaRendererAdd; - UPnP.onMediaConnect = onMediaConnect; - UPnP.onMediaStop = onMediaStop; - UPnP.onMediaPause = onMediaPause; - UPnP.onMediaPlay = onMediaPlay; - UPnP.onMediaSeek = OnMediaSeek; - UPnP.onMigrate = OnMediaMigrate; - UPnP.onMediaTimeChanged = onMediaTimeChanged; - UPnP.onMediaDurationChanged = onMediaDurationChanged; - UPnP.BindRenderer(); - UPnP.MovieURL = ''; - UPnP.MovieDuration = 0.0; - UPnP.MovieTime = 0.0; - } - - dock = gw_new_grid_container(ui_root); - dock.spread_h = true; - dock.hide(); + //set background color + root.children[0].backColor = gwskin.back_color; - player_control = new_player_control(ui_root); - player_control.hide(); + //register custom event filter + gwlib_add_event_filter(my_filter_event); - uidisplay = gw_new_container(); - uidisplay._name = 'Root Display'; - gw_add_child(ui_root, uidisplay); - - uidisplay.remove_child = function(child) { - this.removeChildren[0] = child; - top_wnd = null; - if (this.children.length && typeof this.children[this.children.length-1].on_event != 'undefined') { - top_wnd = this.children[this.children.length-1]; - } - layout(); - } + //what do we do with tooltips ? +// gwskin.tooltip_callback = function(over, label) { alert('' + over ? label : ''); }; - /*init our internal extensions*/ - var icon = gpacui_insert_dock_icon('Player', 'icons/applications-multimedia.svg'); - icon.on_click = function () { show_dock(false); player_control.show(); }; - - if (UPnP_Enabled) { - icon = gpacui_insert_dock_icon('Control', 'icons/video-display.svg'); - icon.on_click = function () { show_dock(false); select_remote_display('select'); }; + //create the dock containing all launchers + dock = gw_new_grid_container(null); - icon = gpacui_insert_dock_icon('Remote', 'icons/applications-internet.svg'); - icon.on_click = function () { set_movie_url(''); show_dock(false); browse_remote_servers('select'); }; + dock.on_display_size = function (w, h) { + this.on_size(w, h); + this.set_size(w, h); + } + dock.on_size = function (w, h) { + var children = dock.get_children(); + for (var i = 0; i < children.length; i++) { + children[i].set_size(2 * gwskin.default_control_height, gwskin.default_control_height); + } } + /*init all extensions*/ var list = gpac.enum_directory('extensions', '*', 0); for (i=0; i=0) && (url.indexOf('://')<0)) { - test_resource.url[0] = "gpac://"+url; - } else { - test_resource.url[0] = url; - } - /*URL assignment may trigger synchronous replies*/ - if (!test_resource.callback_done) { - gw_add_child(dictionary, test_resource); + extension.icon = insert_dock_icon(extension.name, extension.path + extension.icon); + extension.icon.ext_description = extension; + extension.icon.extension_obj = null; + extension.icon.on_close = function () { + this.ext_description.icon = null; + this.ext_description = null; + } + extension.icon.on_click = function () { + if (!this.extension_obj) { + for (var i = 0; i < this.ext_description.execjs.length; i++) { + gwlog(l_deb, 'Loading UI extension ' + this.ext_description.name + ' - Executing JS ' + this.ext_description.path + this.ext_description.execjs[i]); + if (!i) { + this.extension_obj = Browser.loadScript(this.ext_description.path + this.ext_description.execjs[i]); + this.compatible = (this.extension_obj != null) ? true : false; + if (!this.compatible) break; + + setup_extension_storage(this); + } else { + Browser.loadScript(this.ext_description.path + this.ext_description.execjs[i]); + } + } + + } + if (!this.compatible) { + var w = gw_new_message(null, 'Error', 'Extension ' + this.ext_description.name + ' is not compatible'); + w.show(); + alert('Error'); + this.parent.disable(); + return; + } + + if (this.extension_obj && (typeof this.extension_obj.start != 'undefined')) this.extension_obj.start(); + } } - - return; - } else { - var uri = UPnP.ShareResource(url); - controlled_renderer.Open(uri); - } - current_url = url; - current_time = 0; - - if (url == '') player_control.show(); - else player_control.hide(); + dock.set_size(gw_display_width, gw_display_height); + dock.show(); + + //launch all default ext + for (i=0; imax_playercontrol_width)) w=max_playercontrol_width; - player_control.set_size(w, player_control.height); - - - dock.set_size(display_width, display_height); -// dock.set_size(display_width, display_height); -// if (uidisplay.children.length) uidisplay.children[0].set_size(display_width, display_height); + gwlib_notify_display_size(gw_display_width, gw_display_height); } //resize event callback function on_resize(evt) { - if ((display_width == evt.width) && (display_height == evt.height)) return; - if (evt.width <=100) { - gpac.set_size(100, display_height); - return; - } - if (evt.height <=80) { - gpac.set_size(display_width, 40); - return; - } - - display_width = evt.width; - display_height = evt.height; - if (!gpac.fullscreen) { - gpac.setOption('General', 'LastWidth', ''+display_width); - gpac.setOption('General', 'LastHeight', ''+display_height); - } - layout(); - - for (var i in all_extensions) { - if (typeof all_extensions[i].on_resize != 'undefined') { - all_extensions[i].on_resize(display_width, display_height); - } - } -} - -//zoom event callback -function on_zoom(evt) { - display_width = evt.width; - display_height = evt.height; - layout(); -} -//scroll event callback -function on_scroll(evt) { - layout(); -} - - -function new_player_control(container) -{ - var control_icon_size = gwskin.default_icon_size; - var small_control_icon_size; - var wnd = gw_new_window(container, true, 'osdwindow'); - wnd.connected = false; - this.stoped_url = null; - - small_control_icon_size = control_icon_size; - - wnd.set_corners(true, true, false, false); - - /*first set of controls*/ - wnd.infobar = gw_new_grid_container(wnd); - wnd.infobar.spread_h = true; - - /*add our controls in order*/ - if (1) { - wnd.snd_low = gw_new_icon_button(wnd.infobar, 'icons/audio-volume-low.svg', 'Lower', 'icon'); - wnd.snd_ctrl = gw_new_slider(wnd.infobar); - wnd.snd_low.add_icon('icons/audio-volume-muted.svg'); - wnd.muted = 0; - wnd.snd_low.on_click = function() { - if (player_control.muted) { - gpac.volume = player_control.muted; - player_control.muted = 0; - this.switch_icon(0); - } else { - player_control.muted = gpac.volume ? gpac.volume : 1; - gpac.volume = 0; - this.switch_icon(1); - } + if ((gw_display_width == evt.width) && (gw_display_height == evt.height)) return; + if (evt.width <=100) { + gpac.set_size(100, gw_display_height); + return; } - wnd.snd_ctrl.on_slide = function(value, type) { - if (player_control.muted) player_control.snd_low.on_click(); - gpac.volume = value; + if (evt.height <=80) { + gpac.set_size(gw_display_width, 40); + return; } - wnd.snd_low.set_size(small_control_icon_size, small_control_icon_size); - wnd.snd_ctrl.set_size(2*small_control_icon_size, 2, control_icon_size/3, control_icon_size/3); - wnd.snd_ctrl.set_value(gpac.volume); - } else { - wnd.snd_low = null; - wnd.snd_ctrl = null; - } - - - wnd.set_state = function(state) { - if (!movie_connected && !controlled_renderer) return; - if (state==this.state) return; - - if (state == GF_STATE_STOP) { - this.stoped_url = ''+current_url; - if (controlled_renderer) controlled_renderer.Stop(); - else { - set_movie_url(''); - /*override movie_connected to avoid auto-resizing*/ - movie_connected = true; - } - movie_ctrl.mediaStartTime = 0; - this.media_line.set_value(0); - this.play.switch_icon(icon_play); - this.state = GF_STATE_STOP; - return; - } - if (state==GF_STATE_PAUSE) { - if (this.state==GF_STATE_STOP) return; - if (controlled_renderer) controlled_renderer.Pause(); - movie_ctrl.mediaSpeed = 0; - this.state=GF_STATE_PAUSE; - this.play.switch_icon(icon_play); - return; - } - //we are playing, resume from stop if needed - if (this.stoped_url) { - if (controlled_renderer) { - controlled_renderer.Play(); - } else { - set_movie_url(this.stoped_url); + gw_display_width = evt.width; + gw_display_height = evt.height; + if (!gpac.fullscreen) { + gpac.set_option('General', 'LastWidth', '' + gw_display_width); + gpac.set_option('General', 'LastHeight', '' + gw_display_height); } - this.stoped_url = null; - //not in trick mode, next pause/play will restart from current time - if (state != GF_STATE_TRICK) - movie_ctrl.mediaStartTime = -1; - } - - - if (state==GF_STATE_PLAY) { - if (controlled_renderer) controlled_renderer.Play(); - this.state = state; - movie_ctrl.mediaSpeed = 1; - this.play.switch_icon(icon_pause); - return; - } - if (state==GF_STATE_TRICK) { - this.state = state; - this.play.switch_icon(icon_play); - movie_ctrl.mediaStartTime = -1; - return; - } - } - - wnd.stop = gw_new_icon_button(wnd.infobar, 'icons/media-playback-stop.svg', 'Stop', 'icon'); - wnd.stop.on_click = function() { - player_control.set_state(GF_STATE_STOP); - } - wnd.stop.set_size(small_control_icon_size, small_control_icon_size); - - - if (0) { - wnd.rewind = gw_new_icon_button(wnd.infobar, 'icons/media-seek-backward.svg', 'Rewind', 'icon'); - wnd.rewind.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.rewind = null; - } - - wnd.play = gw_new_icon_button(wnd.infobar, 'icons/media-playback-start.svg', 'Play', 'icon'); - wnd.play.set_size(control_icon_size, control_icon_size); - wnd.state = GF_STATE_PLAY; - wnd.play.add_icon('icons/media-playback-pause.svg'); - wnd.play.on_click = function() { - player_control.set_state( (player_control.state==GF_STATE_PLAY) ? GF_STATE_PAUSE : GF_STATE_PLAY); - } - - if (!browser_mode) { - wnd.forward = gw_new_icon_button(wnd.infobar, 'icons/media-seek-forward.svg', 'Forward', 'icon'); - wnd.forward.on_click = function() { - if (movie_ctrl.mediaSpeed) { - player_control.set_state(GF_STATE_TRICK); - movie_ctrl.mediaSpeed = 2*movie_ctrl.mediaSpeed; - } - } - wnd.forward.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.forward = null; - } - - wnd.media_line = gw_new_progress_bar(wnd.infobar, false, true); - wnd.media_line.on_slide = function(value, type) { - if (!movie_connected && !controlled_renderer) { - this.set_value(0); - return; - } - - var duration = player_control.duration; - if (!duration) return; - var time = value*duration/100; - - if (controlled_renderer) { - controlled_renderer.Seek(time); - return; - } - root.children[0].set_bind = FALSE; - switch (type) { - //sliding - case 1: - player_control.set_state(GF_STATE_PAUSE); - movie_ctrl.mediaStartTime = time; - movie_ctrl.mediaSpeed = 0; - break; - //done sliding - case 2: - player_control.set_state(GF_STATE_PLAY); - if (time!= movie_ctrl.mediaStartTime) movie_ctrl.mediaStartTime = time; - movie_ctrl.mediaSpeed = 1; - break; - //init slide, go in play mode - default: - if (player_control.state==GF_STATE_STOP) - player_control.set_state(GF_STATE_PLAY); - - player_control.set_state(GF_STATE_PAUSE); - movie_ctrl.mediaStartTime = time; - break; - } - } - - - wnd.time = gw_new_text(wnd.infobar, '00:00:00', 'osdwindow'); - gw_object_set_hitable(wnd.time); - wnd.time.reversed = false; - wnd.time.on_down = function(val) { - if (!val) return; - this.reversed = !this.reversed; - player_control.set_time(player_control.current_time); - } - wnd.time.set_size(control_icon_size, control_icon_size); - wnd.time.set_width(4*wnd.time.font_size() ); - - if (0) { - wnd.loop = gw_new_icon_button(wnd.infobar, 'vector/loop.svg', 'Loop', 'icon'); - wnd.loop.on_click = function () { - movie_ctrl.loop = movie_ctrl.loop ? FALSE : TRUE; +/* + var v = 12; + if (gw_display_height<160) { } - wnd.loop.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.loop = null; - } - - wnd.view = gw_new_icon_button(wnd.infobar, 'icons/edit-find.svg', 'Navigation', 'icon'); - wnd.view.on_click = function() { - select_navigation_type(); - } - wnd.view.set_size(small_control_icon_size, small_control_icon_size); - - - if (!browser_mode) { - wnd.open = gw_new_icon_button(wnd.infobar, 'icons/folder.svg', 'Open', 'icon'); - wnd.open.on_click = function () { open_local_file(); } - wnd.open.on_long_click = function () { open_url(); } - wnd.open.set_size(small_control_icon_size, small_control_icon_size); - } else{ - wnd.open = null; - } - - - if (!browser_mode) { - wnd.home = gw_new_icon_button(wnd.infobar, 'icons/go-home.svg', 'Home', 'icon'); - wnd.home.on_click = function() { show_dock(true); } - wnd.home.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.home = null; - } - - - if (UPnP_Enabled) { - wnd.remote = gw_new_icon_button(wnd.infobar, 'icons/video-display.svg', 'Select Display', 'icon'); - wnd.remote.on_click = function () { select_remote_display('push'); } - wnd.remote.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.remote = null; - } - - if (1) { - wnd.fullscreen = gw_new_icon_button(wnd.infobar, 'icons/view-fullscreen.svg', 'Fullscreen', 'icon'); - wnd.fullscreen.on_click = function() { gpac.fullscreen = !gpac.fullscreen; } - wnd.fullscreen.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.fullscreen = null; - } - - if (!browser_mode) { - wnd.exit = gw_new_icon_button(wnd.infobar, gwskin.images.cancel, gwskin.labels.close, 'icon'); - wnd.exit.on_click = function() { gpac.exit(); } - wnd.exit.set_size(small_control_icon_size, small_control_icon_size); - } else { - wnd.exit = null; - } - - - - wnd.layout = function(width, height) { - var min_w, full_w, time_w; - var control_icon_size = gwskin.default_icon_size; - this.move(0, Math.floor( (height-display_height)/2) ); - - width -= control_icon_size/2; - min_w = this.play.width + this.time.width; - if (this.open) min_w += this.open.width; - if (this.home) min_w += this.home.width; - if (this.exit && gpac.fullscreen) min_w += this.exit.width; - full_w = 0; - if (this.snd_low) full_w += this.snd_low.width; - if (this.snd_ctrl) full_w += this.snd_ctrl.width; - if (this.fullscreen) full_w += this.fullscreen.width; - - if (this.view) { - this.view.hide(); - if (!dynamic_scene && movie_connected && (gpac.navigation_type!= GF_NAVIGATE_TYPE_NONE) ) { - full_w+= this.view.width; - } - } - - if (this.duration) { - if (this.stop) full_w += this.stop.width; - if (this.play) full_w += this.play.width; - if (this.rewind) full_w+= this.rewind.width; - if (this.forward) full_w+= this.forward.width; - if (this.loop) full_w += this.loop.width; - } - - if (this.remote && UPnP.MediaRenderersCount && (current_url!='')) { - full_w += this.remote.width; - } - time_w = this.media_line.visible ? 2*control_icon_size : 0; - - if (this.exit) { - if (gpac.fullscreen) { - this.exit.show(); - } else { - this.exit.hide(); + else if (gw_display_height<576) { + v = 24; } - } - - if (min_w + full_w + time_w < width) { - if (this.media_line.visible) - this.media_line.set_size(width - min_w - full_w - control_icon_size/3, control_icon_size/3); - - if (this.snd_low) this.snd_low.show(); - if (this.snd_ctrl) this.snd_ctrl.show(); - if (this.duration) { - if (this.rewind) this.rewind.show(); - if (this.forward) this.forward.show(); - if (this.loop) this.loop.show(); - if (this.stop) this.stop.show(); - } - if (wnd.fullscreen) wnd.fullscreen.show(); - - if (this.remote) { - if (UPnP.MediaRenderersCount && (current_url!='')) { - this.remote.show(); - } else { - this.remote.hide(); - } - } - - if (this.view && !dynamic_scene && movie_connected && (gpac.navigation_type!= GF_NAVIGATE_TYPE_NONE) ) { - this.view.show(); - } - } else { - - if (this.snd_low) this.snd_low.hide(); - if (this.snd_ctrl) this.snd_ctrl.hide(); - if (this.rewind) this.rewind.hide(); - if (this.stop) this.stop.hide(); - if (this.forward) this.forward.hide(); - if (this.loop) this.loop.hide(); - if (this.fullscreen) this.fullscreen.hide(); - if (this.remote) this.remote.hide(); - - if (this.view && movie_connected && (gpac.navigation_type!= GF_NAVIGATE_TYPE_NONE) ) { - if (min_w + time_w + this.view.width < width) { - min_w += this.view.width; - this.view.show(); - } - } - - if (this.remote) { - if (UPnP.MediaRenderersCount && (current_url!='') && (min_w + time_w + this.remote.width < width)) { - min_w += this.remote.width; - this.remote.show(); - } else { - this.remote.hide(); - } - } - - if (this.media_line.visible) - this.media_line.set_size(width - min_w - 5, control_icon_size/3); - - } - width += control_icon_size/2; - this.infobar.set_size(width, height); - } - - wnd.current_time = 0; - wnd.duration = 0; - wnd.set_duration = function(value) { - this.duration = value; - if (!value) { - wnd.time.hide(); - wnd.media_line.hide(); - if (wnd.rewind) wnd.rewind.hide(); - if (wnd.stop) wnd.stop.hide(); - if (wnd.forward) wnd.forward.hide(); - if (wnd.loop) wnd.loop.hide(); - wnd.time.set_size(0, control_icon_size); - wnd.time.set_width(0); - } else { - wnd.time.show(); - wnd.media_line.show(); - if (wnd.rewind) wnd.rewind.show(); - if (wnd.stop) wnd.stop.show(); - if (wnd.forward) wnd.forward.show(); - if (wnd.loop) wnd.loop.show(); - if (value<3600) { - wnd.time.set_size(control_icon_size/2, control_icon_size); - wnd.time.set_width(3*wnd.time.font_size() ); - } else { - wnd.time.set_size(control_icon_size, control_icon_size); - wnd.time.set_width(4*wnd.time.font_size() ); - } + else if (gw_display_height<720) { + v = 32; } - this.layout(this.width, this.height); - } - wnd.set_time = function(value) { - var h, m, s, str; - if (!this.duration) return; - this.current_time = value; - if (this.duration) { - this.media_line.set_value(100*value / this.duration); - } - str=''; - if (this.time.reversed) { - value = this.duration-value; - str='-'; - } - h = Math.floor(value/3600); - value -= h*3600; - m = Math.floor(value / 60); - value -= m*60; - s = Math.floor(value); - if (h) { - if (h<10) str += '0'; - str += h + ':'; - } - if (m<10) str += '0'; - str += m + ':'; - if (s<10) str += '0'; - str += s; - this.time.set_label(str); - } - wnd.on_event = function(evt) { - if (this.infobar.on_event(evt)) return true; - return false; - } - - gw_object_set_hitable(wnd); - wnd.set_size(200, control_icon_size); - wnd.set_duration(0); - wnd.set_time(0); - return wnd; -} - - - -function open_local_file() -{ - var filebrowse = gw_new_file_open(); - filebrowse.filter = '*'; - filebrowse.browse(gpac.last_working_directory); - - filebrowse.on_browse = function(value, directory) { - if (value==null) { - player_control.set_state(this.prev_state); - player_control.show(); - } else { - if (directory) gpac.last_working_directory = directory; - set_movie_url(value); - show_dock(false); + else { + v = 48; } - } - var w = display_width/2; - if (w<200) w = display_width-20; - filebrowse.set_size(w, 3*display_height/4); - if (gpac.hardware_rgba) filebrowse.set_alpha(0.8); - - player_control.hide(); - gpacui_show_window(filebrowse); - - filebrowse.prev_state = player_control.state; - player_control.set_state(GF_STATE_PAUSE); -} - -urldlg = null; - -function open_url() -{ - if (urldlg) return; - urldlg = gw_new_window(null, true, 'window'); - - urldlg.sizer = gw_new_grid_container(urldlg); - - urldlg.icon = gw_new_icon_button(urldlg.sizer, gwskin.images.cancel, gwskin.labels.close, 'icon'); - urldlg.icon.set_size(gwskin.default_icon_size, gwskin.default_icon_size); - urldlg.icon.on_click = function() { - urldlg.close(); - urldlg = null; - } - urldlg.label = gw_new_text(urldlg.sizer, 'URL', 'window'); - urldlg.label.set_size(gwskin.default_icon_size, gwskin.default_icon_size); - urldlg.label.set_width(gwskin.default_icon_size); + gwskin_set_default_control_height(v*2); + gwskin_set_default_icon_height(v); + gwlib_refresh_layout(); - urldlg.edit = gw_new_text_edit(urldlg.sizer, ''); - - urldlg.edit.on_text = function(value) { - if (value != '') set_movie_url(value); - urldlg.close(); - urldlg = null; - } - urldlg.layout = function(width, height) { - var w = width - this.icon.width - this.label.width-5; - this.edit.set_size(w, 4*gwskin.default_icon_size/5); - this.sizer.set_size(width, height); - } - urldlg.close = function() { - this.label = null; - this.icon = null; - this.edit = null; - this.sizer = null; - this.hide(this._on_wnd_close); - } - gpacui_show_window(urldlg); - urldlg.set_size(display_width, gwskin.default_icon_size); -} - -function onMediaRendererAdd(name, uuid, is_add) -{ - if (upnp_renderers) upnp_renderers.browse(''); - if (!is_add && controlled_renderer && (name==controlled_renderer.Name) ) controlled_renderer = null; - - /*redo player control*/ - player_control.layout(player_control.width, player_control.height); - - for (var i in all_extensions) { - if (typeof all_extensions[i].on_upnp_add != 'undefined') all_extensions[i].on_upnp_add(name, uuid, is_add); - } -} - -function onMediaConnect(url, src_ip) -{ - for (var i in all_extensions) { - if (typeof all_extensions[i].on_media_open != 'undefined') { - if (all_extensions[i].on_media_open(url, src_ip)>0) return; - } - } - - { - log(l_inf, 'DLNA URL connect ' + url); - movie_ctrl.mediaStartTime = -1; - set_movie_url(url); - } -} - -function onMediaStop() -{ - log(l_inf, 'DLNA Media Stop'); - movie_ctrl.mediaStartTime = 0; - movie_ctrl.mediaSpeed = 0; -} -function onMediaPause() -{ - log(l_inf, 'DLNA Media pause'); - movie_ctrl.mediaSpeed = 0; - movie_ctrl.mediaStartTime = -1; -} -function onMediaPlay() -{ - log(l_inf, 'DLNA Media Play'); - movie_ctrl.mediaSpeed = 1; -} - -function OnMediaSeek(time) -{ - log(l_inf, 'DLNA Media Seek to '+time); - movie_ctrl.mediaStartTime = time; -} - -function OnMediaMigrate() { - log(l_inf, 'Migration Request received'); - var str = gpac.migrate_url(movie.children[0].url[0]); - set_movie_url(''); - return str; -} - -function onMediaTimeChanged(render_idx, time) -{ - if (!controlled_renderer) return; - if (UPnP.GetMediaRenderer(render_idx).Name==controlled_renderer.Name) { - player_control.set_time(time); - } -} - -function onMediaDurationChanged(render_idx, time) -{ - if (!controlled_renderer) return; - if (UPnP.GetMediaRenderer(render_idx).Name==controlled_renderer.Name) { - player_control.set_duration(time); - } -} - - -function select_remote_display(action_type, callback) -{ - if (upnp_renderers) return; - upnp_renderers = gw_new_file_open(); - upnp_renderers.set_label('Select Remote Display'); - upnp_renderers.action_type = action_type; - if (arguments.length<2) callback=null; - upnp_renderers.callback = callback; - - upnp_renderers.on_close = function() { - upnp_renderers = null; - } - /*override browse function*/ - upnp_renderers._on_upnp_click = function() { - var renderer = (this.render_idx<0) ? null : UPnP.GetMediaRenderer(this.render_idx); - var act_type = upnp_renderers.action_type; - - if (act_type=='callback') { - if (upnp_renderers.callback) upnp_renderers.callback(renderer); - upnp_renderers.callback = null; - upnp_renderers.close(); - upnp_renderers = null; - return; - } - - upnp_renderers.close(); - upnp_renderers = null; - - if (act_type=='select') { - controlled_renderer = renderer; - return; - } - - if ((current_url.indexOf('://') < 0) || (current_url.indexOf('file://') >= 0) ) { - if (! UPnP.MediaServerEnabled) { - log(l_err, 'GPAC Media Server is disabled - Cannot share '+current_url); - return; - } - uri = UPnP.ShareResource(current_url); - log(l_inf, 'Sharing '+current_url+' to renderer '+renderer.Name + ' as resource '+uri); - renderer.Open(uri); - renderer.Seek(current_time); - } else if (gpac.getOption('Network', 'MobileIPEnabled')=='yes') { - uri = gpac.migrate_url(movie.children[0].url[0]); - log(l_inf, 'Migrating '+current_url+' to renderer '+renderer.Name + ' as Mobile IP resource '+uri); - renderer.Open(uri); - } else { - log(l_inf, 'Migrating '+current_url+' to renderer '+renderer.Name); - renderer.Open(current_url); - renderer.Seek(current_time); - } - set_movie_url(''); - player_control.show(); - }; - - upnp_renderers._browse = function(dir, up) { - var w, h, i, y; - this.area.reset_children(); - - if (this.action_type=='select') { - var item = gw_new_icon_button(this.area, controlled_renderer ? 'icons/applications-internet.svg' : 'icons/preferences-desktop-remote-desktop.svg', 'Local Display', 'button'); - item.set_size(item.width, item.height); - item.render_idx = -1; - item.on_click = this._on_upnp_click; - } - for (i=0; i gwskin.long_click_delay)) this.on_long_click(); + else if (this.on_click && this._over) this.on_click(); + } else { + this.last_click = timestamp; + } + } + Browser.addRoute(ts, 'isOver', obj, obj._on_over); + Browser.addRoute(ts, 'isActive', obj, obj._on_active); + + obj._disable_touch = function () { + this.children[this._ts_idx].enabled = false; + } + obj._enable_touch = function () { + this.children[this._ts_idx].enabled = true; + } + obj.new_over_handler = function(callback) { + Browser.addRoute(this.children[this._ts_idx], 'isOver', this, callback); + } +} + +//static +function gw_new_appearance(r, g, b) { var appearance = new SFNode('Appearance'); appearance.material = new SFNode('Material2D'); appearance.material.filled = TRUE; appearance.material.emissiveColor = new SFColor(r, g, b); return appearance; } +//static +function gw_new_lineprops(red, green, blue) { + var lineProps = new SFNode('LineProperties'); + lineProps.lineColor.r = red; + lineProps.lineColor.g = green; + lineProps.lineColor.b = blue; + return lineProps; +} -function gw_make_gradient(type, keys, colors) -{ - var i; - var obj = new SFNode(type=='radial' ? 'RadialGradient' : 'LinearGradient'); - for (i=0; i gw_display_width / 2) + pos.x = gw_display_width / 2 - width / 2; + + if (pos.y + height/2 > gw_display_height / 2) { + if (type == 0) { + pos.y -= child.height + height; + } else { + pos.y = gw_display_height / 2 - height/2; + } + } + else if (pos.y - height/2 < -gw_display_height / 2) { + if (type==1) { + pos.y += child.height + height; + } else { + pos.y = height/2 - gw_display_height / 2; + } + } + + return pos; +} + + +gwskin.tooltip_wnd = null; +gwskin.tooltip_timeout = gw_new_timer(false); + +gwskin.tooltip_exec = function (obj, show) { + + if (!show) return; + + if (!gwskin.tooltip_wnd) { + wnd = gw_new_window(null, true, true, 'tooltip', true); + wnd.label = ''; + gwskin.tooltip_wnd = wnd; + wnd.txt = gw_new_text(gwskin.tooltip_wnd, ''); + wnd.on_display_size = function (w, h) { + width = this.label.length * gwskin.default_text_font_size; + this.set_size(width, 2 * gwskin.default_text_font_size); + this.txt.set_width(width); + this.move(-w / 2 + width / 2, h / 2 - gwskin.default_text_font_size); + } + wnd.on_close = function () { + this.timer = null; + gwskin.tooltip_wnd = null; + } + wnd.on_display_size(gw_display_width, gw_display_height); + wnd.set_alpha(0.9); + wnd.show(); + + wnd.timer = gw_new_timer(false); + wnd.timer.set_timeout(gwskin.default_tooltip_timeout, false); + wnd.timer.start(0); + wnd.timer.on_active = function (val) { + if (!val) gwskin.tooltip_wnd.close(); + } + } + + gwskin.tooltip_wnd.label = obj.get_label(); + gwskin.tooltip_wnd.txt.set_label(gwskin.tooltip_wnd.label); + gwskin.tooltip_wnd.on_display_size(gw_display_width, gw_display_height); + + + var tt = gwskin.tooltip_wnd; + var dy = 1.2 * tt.height; + var pos = gw_get_adjusted_abs_pos(obj, tt.width, 1.2*tt.height, 0); + tt.move(pos.x, pos.y); +} + +gwskin.tooltip_callback = function (obj, show) { + + if (!show) { + gwskin.tooltip_timeout.obj = null; + gwskin.tooltip_timeout.stop(0); + return; + } + gwskin.tooltip_timeout.set_timeout(gwskin.default_tooltip_delay, false); + gwskin.tooltip_timeout.obj = obj; + gwskin.tooltip_timeout.on_active = function (val) { + if (!val && gwskin.tooltip_timeout.obj) { + gwskin.tooltip_exec(gwskin.tooltip_timeout.obj, true); + } + } + gwskin.tooltip_timeout.start(0); +} + +gwskin.default_label_font_size = 18; +gwskin.default_text_font_size = 18; +gwskin.default_font_family = 'SANS'; +gwskin.default_icon_text_spacing = 8; +gwskin.default_control_height = 64; +gwskin.default_icon_height = 48; + + +//create styles +gwskin.styles = []; +var s = { name: 'default' }; +gwskin.styles.push(s); + +s.normal = gw_new_appearance(0.4, 0.6, 1); +s.normal.texture = gw_make_gradient('vertical', [0, 1], [0.0, 0.2, 0.4, 0.0, 0.4, 0.6]); +s.normal.skin = true; if (gwskin.pointing_device) { - gwskin.osdbutton.over = gw_new_appearance(0.7, 0.7, 0.8); - gwskin.osdbutton.over.material.transparency = 0.4; - gwskin.osdbutton.over.skin = true; + s.over = gw_new_appearance(0.0, 1.0, 1); + s.over.texture = gw_make_gradient('vertical', [0, 1], [0.0, 0.2, 0.4, 0.0, 0.8, 1]); + s.over.skin = true; } else { - gwskin.button.over = null; -} -gwskin.osdbutton.down = gw_new_appearance(0.3, 0.3, 0.4); -gwskin.osdbutton.down.material.transparency = 0.3; -gwskin.osdbutton.down.skin = true; -gwskin.osdbutton.text = gw_new_appearance(1, 1, 1); -gwskin.osdbutton.text.skin = true; -gwskin.osdbutton.font = gw_new_fontstyle(gwskin.button.font_size, 1); -gwskin.osdbutton.font.skin = true; - -gwskin.listitem = new Object(); -gwskin.listitem.width = 48; -gwskin.listitem.height = 48; -gwskin.listitem.font_size = 12; -gwskin.listitem.normal = gwskin.button.normal; -gwskin.listitem.over = gwskin.button.over; -gwskin.listitem.down = gwskin.button.down; -gwskin.listitem.text = gwskin.button.text; -gwskin.listitem.font = gw_new_fontstyle(gwskin.listitem.font_size, 0); -gwskin.listitem.font.skin = true; - -gwskin.label = new Object(); -gwskin.label.font_size = 18; -gwskin.label.text = gw_new_appearance(0, 0, 0); -gwskin.label.text.skin = true; -gwskin.label.font = gw_new_fontstyle(gwskin.label.font_size, 1); -gwskin.label.font.skin = true; - -gwskin.text = new Object(); -gwskin.text.font_size = 14; -gwskin.text.text = gw_new_appearance(0, 0, 0); -gwskin.text.text.skin = true; -gwskin.text.font = gw_new_fontstyle(gwskin.text.font_size, 0); -gwskin.text.font.skin = true; - - -gwskin.edit = new Object(); -gwskin.edit.normal = gw_new_appearance(1, 1, 1); -gwskin.edit.font_size = 18; -gwskin.edit.text = gwskin.label.text; -gwskin.edit.font = gw_new_fontstyle(gwskin.edit.font_size, 0); -gwskin.edit.font.style += ' SIMPLE_EDIT'; -gwskin.edit.font.skin = true; - -gwskin.window = new Object(); -gwskin.window.font_size = 14; -gwskin.window.width = 320; -gwskin.window.height = 240; -gwskin.window.normal = gw_new_appearance(0.6, 0.6, 0.6); -//gwskin.window.normal.texture = gw_make_gradient('vertical', [0, 0.85, 1], [0.6, 0.6, 0.6, 1, 1, 1, 0.6, 0.6, 0.6]); -gwskin.window.normal.skin = true; -gwskin.window.text = gwskin.label.text; -gwskin.window.font = gw_new_fontstyle(gwskin.window.font_size, 1); -gwskin.window.font.skin = true; -gwskin.window.hide = gw_window_hide; -gwskin.window.show = gw_window_show; - -gwskin.offscreen = new Object(); -gwskin.offscreen.font_size = 14; -gwskin.offscreen.width = 100; -gwskin.offscreen.height = 100; -gwskin.offscreen.normal = gwskin.appearance_transparent; -gwskin.offscreen.hide = gwskin.window.hide; -gwskin.offscreen.show = gwskin.window.show; - - -gwskin.osdwindow = new Object(); -gwskin.osdwindow.font_size = 14; -gwskin.osdwindow.width = 320; -gwskin.osdwindow.height = 240; -gwskin.osdwindow.normal = gw_new_appearance(0.6, 0.6, 0.6); -gwskin.osdwindow.normal.texture = gw_make_gradient('vertical', [0, 0.15, 0.85, 1], [0.6, 0.6, 0.6, 0, 0, 0, 0, 0, 0, 0.6, 0.6, 0.6]); -gwskin.osdwindow.normal.skin = true; -gwskin.osdwindow.text = gw_new_appearance(1, 1, 1); -gwskin.osdwindow.text.skin = true; -gwskin.osdwindow.font = gw_new_fontstyle(gwskin.osdwindow.font_size, 1); -gwskin.osdwindow.font.justify[1] = 'MIDDLE'; -gwskin.osdwindow.font.skin = true; -gwskin.osdwindow.hide = gw_window_hide; -gwskin.osdwindow.show = gw_window_show; -gwskin.osdwindow.over = gwskin.button.over; -gwskin.osdwindow.down = gwskin.button.down; - -gwskin.progress = new Object(); -gwskin.progress.width = 200; -gwskin.progress.height = 48; -gwskin.progress.normal = gw_new_appearance(0.6, 0.6, 0.6); -gwskin.progress.normal.texture = gw_make_gradient('vertical', [0, 0.5, 1], [0.6, 0.6, 0.6, 0, 0, 0, 0.6, 0.6, 0.6]); -gwskin.progress.normal.skin = true; -gwskin.progress.over = gw_new_appearance(0.7, 0.7, 0.8); -gwskin.progress.over.texture = gw_make_gradient('vertical', [0, 0.5, 1], [0.6, 0.6, 0.6, 0, 0, 1, 0.6, 0.6, 0.6]); -gwskin.progress.over.skin = true; -gwskin.progress.down = gw_new_appearance(0.7, 0.7, 0.8); -gwskin.progress.down.texture = gw_make_gradient('vertical', [0, 0.5, 1], [0.6, 0.6, 0.6, 1, 1, 1, 0.6, 0.6, 0.6]); -gwskin.progress.down.skin = true; -gwskin.progress.text = null; -gwskin.progress.font = null; - -gwskin.icon = new Object(); -gwskin.icon.normal = gwskin.button.normal; -gwskin.icon.over = gwskin.button.over; -gwskin.icon.down = gwskin.button.down; -gwskin.icon.text = null; -gwskin.icon.font = null; -gwskin.icon.width = 32; -gwskin.icon.height = 32; + s.over = null; +} +s.down = gw_new_appearance(0, 0, 1); +s.down.texture = gw_make_gradient('vertical', [0, 1], [0.0, 0.2, 0.4, 0.0, 1, 1]); +s.down.skin = true; +s.disable = gw_new_appearance(0.4, 0.4, 0.4); +s.disable.skin = true; +s.text = gw_new_appearance(1, 1, 1); +s.text.skin = true; +s.font = gw_new_fontstyle(gwskin.default_label_font_size, 1); +s.font.skin = true; + + +//overrite style for button to have its own text color +var s = { name: 'button' }; +gwskin.styles.push(s); +s.text = gw_new_appearance(1, 1, 1); +s.text.skin = true; + +//override style for checkbox to have text alignment to 'begin' +s = { name: 'checkbox' }; +gwskin.styles.push(s); +s.font = gw_new_fontstyle(gwskin.default_label_font_size, 0); +s.font.skin = true; +s.over = gw_new_appearance(0.0, 1.0, 1); +s.over.texture = gw_make_gradient('vertical', [0, 1], [0.0, 0.2, 0.4, 0.0, 0.8, 1]); +s.over.material.lineProps = gw_new_lineprops(0.0, 0.8, 1); +s.over.skin = true; + +//override style for icon to have no text not fonts +s = { name: 'icon' }; +gwskin.styles.push(s); +s.text = null; +s.font = null; + +s = { name: 'root_icon' }; +gwskin.styles.push(s); +s.text = gw_new_appearance(1, 1, 1); +s.text.skin = true; + + +//override listitems to have text alignment to 'begin' +s = { name: 'listitem' }; +gwskin.styles.push(s); +s.font = gw_new_fontstyle(gwskin.default_label_font_size, 0); +s.font.skin = true; + +s = { name: 'edit' }; +gwskin.styles.push(s); +s.normal = gw_new_appearance(1, 1, 1); +s.normal.texture = gw_make_gradient('vertical', [0, 1], [0.0, 0.2, 0.4, 0.0, 0.8, 1]); +s.over = gw_new_appearance(1, 1, 1); +s.over.texture = gw_make_gradient('vertical', [0, 1], [0.0, 0.2, 0.4, 0.0, 0.8, 1]); +s.over.material.lineProps = gw_new_lineprops(0.0, 0.8, 1); +s.text = gw_new_appearance(0, 0, 0); +s.text.skin = true; +s.font = gw_new_fontstyle(gwskin.default_text_font_size, 0); +s.font.style += ' SIMPLE_EDIT'; +s.font.skin = true; + +s = { name: 'window' }; +gwskin.styles.push(s); +s.normal = gw_new_appearance(0.6, 0.6, 0.6); +s.normal.texture = gw_make_gradient('vertical', [0, 0.1, 0.9, 1], [0.6, 0.6, 0.6, 0, 0, 0, 0, 0, 0, 0.6, 0.6, 0.6]); +s.normal.skin = true; +//override font to have middle alignment +s.font = gw_new_fontstyle(gwskin.default_label_font_size, 1); +s.font.skin = true; +s.hide = gw_window_hide; +s.show = gw_window_show; + +tt_s = { name: 'tooltip' }; +gwskin.styles.push(tt_s); +tt_s.normal = gw_new_appearance(0.6, 0.6, 0.6); +tt_s.normal.texture = s.normal.texture; +//tt_s.normal.material.lineProps = gw_new_lineprops(0, 0, 0); +//tt_s.normal.material.lineProps.width = 0.5; +tt_s.font = s.font; +//tt_s.hide = gw_window_hide; +//tt_s.show = gw_window_show; + +s = { name: 'progress' }; +gwskin.styles.push(s); +s.normal = gw_new_appearance(0.6, 0.6, 0.6); +s.normal.texture = gw_make_gradient('vertical', [0, 0.5, 1], [0.0, 0.4, 0.6, 0, 0, 0, 0.0, 0.4, 0.6]); +s.normal.skin = true; +s.over = gw_new_appearance(0.7, 0.7, 0.8); +s.over.texture = gw_make_gradient('vertical', [0, 0.5, 1], [0.0, 1, 1, 0, 0.2, 0.4, 0.0, 1, 1]); +s.over.skin = true; +s.down = gw_new_appearance(0.7, 0.7, 0.8); +s.down.texture = gw_make_gradient('vertical', [0, 0.5, 1], [0.8, 1, 1, 0, 0.4, 0.6, 0.8, 1, 1]); +s.down.skin = true; +//for gauge +s.text = gw_new_appearance(1, 1, 1); +s.text.skin = true; +s.font = gw_new_fontstyle(gwskin.default_label_font_size, 0); +s.font.skin = true; + + +s = { name: 'plot' }; +gwskin.styles.push(s); +s.normal = gw_new_appearance(0.9, 0.9, 0.9); +s.normal.skin = true; +s.text = gw_new_appearance(0, 0, 0); +s.text.skin = true; +s.font = gw_new_fontstyle(gwskin.default_text_font_size, 0); +s.font.skin = true; + + +s = { name: 'text' }; +gwskin.styles.push(s); +s.font = gw_new_fontstyle(gwskin.default_text_font_size, 0); +s.font.justify[1] = 'END'; +s.font.skin = true; + +s = { name: 'lefttext' }; +gwskin.styles.push(s); +s.font = gw_new_fontstyle(gwskin.default_text_font_size, 0); +s.font.skin = true; + +s = { name: 'righttext' }; +gwskin.styles.push(s); +s.font = gw_new_fontstyle(gwskin.default_text_font_size, 0); +s.font.skin = true; gwskin.images = new Object(); -gwskin.images.cancel = 'icons/emblem-unreadable.svg'; -gwskin.images.previous = 'icons/go-previous.svg'; -gwskin.images.next = 'icons/go-next.svg'; -gwskin.images.up = 'icons/go-up.svg'; -gwskin.images.scan_directory = 'icons/emblem-symbolic-link.svg'; -gwskin.images.folder = 'icons/folder.svg'; -gwskin.images.mime_generic = 'icons/applications-multimedia.svg'; -gwskin.images.trash = 'icons/user-trash.svg'; -gwskin.images.add = 'icons/list-add.svg'; -gwskin.images.remove = 'icons/list-remove.svg'; -gwskin.images.remote_display = 'icons/video-display.svg'; -gwskin.images.information = 'icons/dialog-information.svg'; -gwskin.images.resize = 'icons/media-record.svg'; - gwskin.labels = new Object(); -gwskin.labels.file_open = 'Open'; -gwskin.labels.close = 'Close'; + +gwskin.images.trash = 'icons/trash.svg'; +gwskin.labels.trash = 'Delete'; +gwskin.images.add = 'icons/add.svg'; +gwskin.labels.add = 'Add'; +gwskin.images.remove = 'icons/remove.svg'; +gwskin.labels.remove = 'Remove'; +gwskin.images.remote_display = 'icons/monitor.svg'; +gwskin.labels.remote_display = 'Push to remote device'; +gwskin.images.information = 'icons/info.svg'; +gwskin.labels.information = 'Information'; +gwskin.images.resize = 'icons/resize.svg'; +gwskin.labels.resize = 'Resize'; +gwskin.images.cancel = 'icons/cross.svg'; gwskin.labels.cancel = 'Cancel'; -gwskin.labels.up = 'Up'; -gwskin.labels.down = 'Down'; +gwskin.images.close = 'icons/cross.svg'; +gwskin.labels.close = 'Close'; +gwskin.images.previous = 'icons/previous.svg'; +gwskin.labels.previous = 'Previous'; +gwskin.images.next = 'icons/next.svg'; +gwskin.labels.next = 'Next'; +gwskin.images.left = 'icons/left.svg'; gwskin.labels.left = 'Left'; +gwskin.images.right = 'icons/right.svg'; gwskin.labels.right = 'Right'; +gwskin.images.up = 'icons/up.svg'; +gwskin.labels.up = 'Up'; +gwskin.images.down = 'icons/down.svg'; +gwskin.labels.down = 'Down'; +gwskin.images.scan_directory = 'icons/overflowing.svg'; gwskin.labels.scan_directory = 'Select directory'; -gwskin.labels.previous = 'Previous'; -gwskin.labels.next = 'Next'; -gwskin.labels.trash = 'Delete'; -gwskin.labels.remote_display = 'Push to'; -gwskin.labels.information = 'Information'; -gwskin.labels.resize = 'Resize'; +gwskin.images.history = 'icons/overflowing.svg'; +gwskin.labels.history = 'History'; +gwskin.images.media_next = 'icons/media_next.svg'; +gwskin.labels.media_next = 'Next Item'; +gwskin.images.media_prev = 'icons/media_prev.svg'; +gwskin.labels.media_prev = 'Previous Clip'; +gwskin.images.seek_forward = 'icons/seek_forward.svg'; +gwskin.labels.seek_forward = 'Fast Forward'; +gwskin.images.rewind = 'icons/rewind.svg'; +gwskin.labels.rewind = 'Rewind'; +gwskin.images.folder = 'icons/folder.svg'; +gwskin.labels.folder = 'Directory'; +gwskin.images.check = 'icons/check.svg'; +gwskin.labels.check = 'Check'; +gwskin.images.drive = 'icons/harddrive.svg'; +gwskin.labels.drive = 'Storage Drive'; +gwskin.images.device = 'icons/laptop.svg'; +gwskin.labels.device = 'Device'; +gwskin.images.home = 'icons/home.svg'; +gwskin.labels.home = 'Home'; +gwskin.images.osmo = 'icons/osmo.svg'; +gwskin.labels.osmo = 'Home'; +gwskin.images.media = 'icons/more.svg'; +gwskin.labels.media = 'Media'; +gwskin.images.favorite = 'icons/heart.svg'; +gwskin.labels.favorite = 'Favorites'; +gwskin.images.audio = 'icons/audio.svg'; +gwskin.labels.audio = 'Audio On'; +gwskin.images.audio_mute = 'icons/audio_mute.svg'; +gwskin.labels.audio_mute = 'Audio Mute'; +gwskin.images.play = 'icons/play.svg'; +gwskin.labels.play = 'Play'; +gwskin.images.pause = 'icons/pause.svg'; +gwskin.labels.pause = 'Pause'; +gwskin.images.stop = 'icons/stop2.svg'; +gwskin.labels.stop = 'Stop'; +gwskin.images.fullscreen = 'icons/expand.svg'; +gwskin.labels.fullscreen = 'Fullscreen'; +gwskin.images.fullscreen_back = 'icons/shrink.svg'; +gwskin.labels.fullscreen_back = 'Exit Fullscreen'; +gwskin.images.play_once = 'icons/play_single.svg'; +gwskin.labels.play_once = 'Play once'; +gwskin.images.play_loop = 'icons/play_loop.svg'; +gwskin.labels.play_loop = 'Loop'; +gwskin.images.play_shuffle = 'icons/play_shuffle.svg'; +gwskin.labels.play_shuffle = 'Shuffle'; +gwskin.images.navigation = 'icons/navigation.svg'; +gwskin.labels.navigation = 'Navigation'; +gwskin.images.network = 'icons/network.svg'; +gwskin.labels.network = 'Network'; +gwskin.images.file_open = 'icons/tray.svg'; +gwskin.labels.file_open = 'Open'; +gwskin.images.exit = 'icons/power.svg'; +gwskin.labels.exit = 'Exit'; +gwskin.images.remote_location = 'icons/world.svg'; +gwskin.labels.remote_location = 'Enter URL'; +gwskin.images.statistics = 'icons/speed.svg'; +gwskin.labels.statistics = 'Statistics'; +gwskin.images.live = 'icons/live.svg'; +gwskin.labels.live = 'Back to live'; +gwskin.images.sort = 'icons/sort.svg'; +gwskin.labels.sort = 'Sort'; +gwskin.images.playlist = 'icons/list.svg'; +gwskin.labels.playlist = 'Playlist'; +gwskin.images.playlist_next = 'icons/pl_next.svg'; +gwskin.labels.playlist_next = 'Next'; +gwskin.images.playlist_prev = 'icons/pl_prev.svg'; +gwskin.labels.playlist_prev = 'Previous'; +gwskin.images.channels = 'icons/tv.svg'; +gwskin.labels.channels = 'TV Channels'; + + +gwskin.mime_video_default_ext = " mp4 mp4s m4s 3gp 3gpp m2ts ts trp m3u8 mpd avi mov "; +gwskin.mime_audio_default_ext = " m4a mp3 aac wav "; +gwskin.mime_image_default_ext = " jpg jpeg png "; +gwskin.mime_model_default_ext = " bt xmt svg "; + +gwskin.images.mime_video = 'icons/film.svg'; +gwskin.images.mime_audio = 'icons/musical.svg'; +gwskin.images.mime_model = 'icons/app.svg'; +gwskin.images.mime_generic = 'icons/file.svg'; +gwskin.images.mime_image = 'icons/image.svg'; + + gwskin.keys = new Object(); -gwskin.keys.close = 'Enter'; +gwskin.keys.close = 'U+0008'; +gwskin.keys.validate = 'Enter'; +gwskin.last_hitable_obj = null; -function gw_add_child(container, child) +//static +function gwskin_set_white_blue() { - if (container ==null) return; - if (typeof (container.add_child) != 'undefined') { - container.add_child(child); - } else { - container.children[container.children.length] = child; - } - child.parent = container; -} + var s = gwskin.get_class('default'); + + //s.normal.texture.keyValue = [0.0, 0.2, 0.4, 0.0, 0.4, 0.6]; + //if (s.over && s.over.texture) s.over.texture.keyValue = [0.0, 0.2, 0.4, 0.0, 0.8, 1]; + //s.down.texture.keyValue = [0.0, 0.2, 0.4, 0.0, 1, 1]; + + s.text.material.emissiveColor = new SFColor(0, 0, 0); + + //override style for checkbox to have text alignment to 'begin' + s = gwskin.get_class('checkbox'); +// s.over.texture.keyValue = [0.0, 0.2, 0.4, 0.0, 0.8, 1]; + + s = gwskin.get_class('edit'); +// s.normal.texture.keyValue = [0.0, 0.2, 0.4, 0.0, 0.8, 1]; +// s.over.texture.keyValue = [0.0, 0.2, 0.4, 0.0, 0.8, 1]; + s.over.material.lineProps.lineColor = new SFColor(0.0, 0.8, 1); + s.text.material.emissiveColor = new SFColor(0, 0, 0); + + s = gwskin.get_class('window'); + s.normal.material.emissiveColor = new SFColor(1, 1, 1); + gwskin.no_gl_window_back.backColor = new SFColor(1, 1, 1); +// s.normal.texture.keyValue = [0.6, 0.6, 0.6, 0, 0, 0, 0, 0, 0, 0.6, 0.6, 0.6]; + if (s.normal.texture) { + s.normal.texture.keyValue[1] = new SFColor(1, 1, 1); + s.normal.texture.keyValue[2] = new SFColor(1, 1, 1); + } + + s = gwskin.get_class('progress'); +// s.normal.texture.keyValue = [0.0, 0.4, 0.6, 0, 0, 0, 0.0, 0.4, 0.6]; +// s.normal.texture.keyValue[1] = new SFColor(1, 1, 1); +// s.over.texture.keyValue = [0.0, 1, 1, 0, 0.2, 0.4, 0.0, 1, 1]; +// s.over.texture.keyValue[1] = new SFColor(0.4, 0.8, 1); +// s.down.texture.keyValue = [0.0, 0.4, 0.6, 0, 0.2, 0.4, 0.0, 0.4, 0.6]; +// s.down.texture.keyValue[1] = new SFColor(0.4, 0.8, 1); + s.text.material.emissiveColor = new SFColor(1, 1, 1); + + s = gwskin.get_class('root_icon'); + s.text.material.emissiveColor = new SFColor(1, 1, 1); -function gw_detach_child(child) -{ - /*detach all default routes*/ - Browser.deleteRoute(child, 'ALL', null, null); - if (typeof (child._ps2d_idx) != 'undefined') { - Browser.deleteRoute(child.children[child._ps2d_idx], 'ALL', null, null); - } - if (typeof (child._ts_idx) != 'undefined') { - Browser.deleteRoute(child.children[child._ts_idx], 'ALL', null, null); - } - if (typeof (child.dlg) != 'undefined') child.dlg = null; - if (typeof (child.parent) == 'undefined') return; - - var p = child.parent; - child.parent = null; - if (typeof (p.remove_child) != 'undefined') { - p.remove_child(child); - } else { - p.removeChildren[0] = child; - } -} - -function gw_close_child_list(list) -{ - var count = list.length; - if (!count) return; - for (var i=0;i50) fsize = 32; + else if (value>30) fsize = 22; + else if (value > 10) fsize = value - 10; + + gwskin.default_label_font_size = fsize; + gwskin.default_text_font_size = fsize; + + for (var i = 0; i < gwskin.styles.length; i++) { + if ((typeof gwskin.styles[i].font != 'undefined') && gwskin.styles[i].font) { + gwskin.styles[i].font.size = fsize; + } + } } - -function gw_new_rectangle(class_name, style) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'Rectangle'); - var shape = new SFNode('Shape'); - obj.children[0] = shape; - if (arguments.length==1) style='normal'; - shape.appearance = gwskin.get_style(class_name, style); - - if (shape.appearance && (typeof (shape.appearance.skin) == 'undefined')) { - obj.set_alpha = function(alpha) { - this.children[0].appearance.material.transparency = 1-alpha; - } - obj.get_alpha = function() { - return 1 - this.children[0].appearance.material.transparency; - } - obj.set_fill_color = function(r, g, b) { - this.children[0].appearance.material.emissiveColor.r = r; - this.children[0].appearance.material.emissiveColor.g = g; - this.children[0].appearance.material.emissiveColor.b = b; - } - obj.set_strike_color = function(r, g, b) { - if (!this.children[0].appearance.material.lineProps) this.children[0].appearance.material.lineProps = new SFNode('LineProperties'); - this.children[0].appearance.material.lineProps.lineColor.r = r; - this.children[0].appearance.material.lineProps.lineColor.g = g; - this.children[0].appearance.material.lineProps.lineColor.b = b; - } - obj.set_line_width = function(width) { - if (!this.children[0].appearance.material.lineProps) this.children[0].appearance.material.lineProps = new SFNode('LineProperties'); - this.children[0].appearance.material.lineProps.width = width; - } - } else { - obj.set_alpha = function(alpha) {} - obj.set_fill_color = function(r, g, b) {} - obj.set_strike_color = function(r, g, b) {} - obj.set_line_width = function(width) {} - obj.get_alpha = function() { return 1; } - } - - obj.set_style = function(classname, style) { - var app = gwskin.get_style(classname, style); - if (app) this.children[0].appearance = app; - } - - - shape.geometry = new SFNode('Curve2D'); - shape.geometry.point = new SFNode('Coordinate2D'); - - obj.corner_tl = true; - obj.corner_tr = true; - obj.corner_bl = true; - obj.corner_br = true; - obj.set_corners = function(tl, tr, br, bl) { - this.corner_tl = tl; - this.corner_tr = tr; - this.corner_bl = bl; - this.corner_br = br; - } - - obj.set_size = function(w, h) { - var hw, hh, rx_bl, ry_bl, rx_br, ry_br, rx_tl, ry_tl, rx_tr, ry_tr, rx, ry; - var temp; - hw = w/2; - hh = h/2; - this.width = w; - this.height = h; - temp = this.children[0].geometry.type; - temp[0] = 7; - temp[1] = 1; - temp[2] = 7; - temp[3] = 1; - temp[4] = 7; - temp[5] = 1; - temp[6] = 7; - temp[7] = 6;/*close*/ - - /*compute default rx/ry*/ - ry = rx = 10; - if (rx>=hw) rx=hw; - if (ry>=hh) ry=hh; - rx_bl = rx_br = rx_tl = rx_tr = rx; - ry_bl = ry_br = ry_tl = ry_tr = ry; - if (!this.corner_tl) rx_tl = ry_tl = 0; - if (!this.corner_tr) rx_tr = ry_tr = 0; - if (!this.corner_bl) rx_bl = ry_bl = 0; - if (!this.corner_br) rx_br = ry_br = 0; - - temp = this.children[0].geometry.point.point; - temp[0] = new SFVec2f(hw-rx_tr, hh); - temp[1] = new SFVec2f(hw, hh);/*bezier ctrl point or line-to*/ - temp[2] = new SFVec2f(hw, hh-ry_tr); - temp[3] = new SFVec2f(hw, -hh+ry_br); - temp[4] = new SFVec2f(hw, -hh);/*bezier control point*/ - temp[5] = new SFVec2f(hw-rx_br, -hh); - temp[6] = new SFVec2f(-hw+rx_bl, -hh); - temp[7] = new SFVec2f(-hw, -hh);/*bezier control point*/ - temp[8] = new SFVec2f(-hw, -hh+ry_bl); - temp[9] = new SFVec2f(-hw, hh-ry_tl); - temp[10] = new SFVec2f(-hw, hh);/*bezier control point*/ - temp[11] = new SFVec2f(-hw+rx_tl, hh); - } - return obj; -} - -function gw_new_text(parent, label, class_name) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'Text'); - gw_add_child(parent, obj); - obj.children[0] = new SFNode('Transform2D'); - obj.children[0].children[0] = new SFNode('Shape'); - obj.children[0].children[0].appearance = gwskin.get_style(class_name, 'text'); +//static +function gwlib_filter_event(evt) { - obj.children[0].children[0].geometry = new SFNode('Text'); - obj.children[0].children[0].geometry.fontStyle = gwskin.get_font(class_name); + if (gw_ui_root.has_popup && (evt.type == GF_EVENT_MOUSEDOWN)) { + //close all open popups + var count = gw_ui_root.children.length; + for (var i = count; i > 0; i--) { + var c = gw_ui_root.children[i - 1]; + if (typeof c._popup != 'undefined') { + c.close(); + if (count>gw_ui_root.children.length) i--; + } + } + gw_ui_root.has_popup = false; + } + + if (gw_ui_top_wnd && gw_ui_top_wnd.on_event(evt)) return true; + if ((evt.type == GF_EVENT_KEYDOWN) && ((evt.keycode == 'Up') || (evt.keycode == 'Down') || (evt.keycode == 'Right') || (evt.keycode == 'Left'))) + return false; - obj.set_label = function(value) { - this.children[0].children[0].geometry.string.length = 0; - this.children[0].children[0].geometry.string[0] = value; + for (var i = 0; i < gw_event_filters.length; i++) { + if (gw_event_filters[i](evt) == true) return true; } + return false; +} - obj.set_labels = function() { - this.children[0].children[0].geometry.string.length = 0; - for (var i=0; i 0; i--) { + var c = this.children[i - 1]; + if (c == wnd) continue; + if (!c.visible) continue; + + if (typeof c.on_event != 'undefined') { + gw_ui_top_wnd = c; + break; + } + } + if (typeof (wnd._no_focus) == 'boolean') return; + gpac.set_focus(gw_ui_top_wnd); } - obj.set_width = function(value) { - this.children[0].children[0].geometry.maxExtent = -value; - this.width = value; + + gw_ui_root.add_child = function (child) { + this.children[this.children.length] = child; + this.set_focus(child); } - obj.font_size = function(value) { - return this.children[0].children[0].geometry.fontStyle ? this.children[0].children[0].geometry.fontStyle.size : 1; + + gw_ui_root.remove_child = function (child) { + this.remove_focus(child); + this.removeChildren[0] = child; } + gw_ui_top_wnd = null; + gw_event_filters = []; - if (obj.children[0].children[0].appearance && (typeof (obj.children[0].children[0].appearance.skin) == 'undefined')) { - obj.set_color = function(r, g, b) { - this.children[0].children[0].appearance.material.emissiveColor = new SFColor(r, g, b); - } - obj.children[0].set_alpha = function(a) { - this.children[0].children[0].appearance.material.transparency = 1-a; - } - } else { - obj.set_color = function(r, g, b) {} - obj.set_alpha = function(a) {} - } - obj.set_size = function(width, height) { - var justify = this.children[0].children[0].geometry.fontStyle ? this.children[0].children[0].geometry.fontStyle.justify[0] : ''; - if (justify=='BEGIN') { - this.children[0].translation.x = - width / 2; - } else if (justify=='END') { - this.children[0].translation.x = width / 2; - } else { - this.children[0].translation.x = 0; - } - this.width = width; - this.height = height; - } - - if (obj.children[0].children[0].geometry.fontStyle && (typeof (obj.children[0].children[0].geometry.fontStyle.skin) == 'undefined')) { - obj.children[0].set_font_size = function(value) { - this.children[0].children[0].geometry.fontStyle.size = value; - } - obj.children[0].set_align = function(value) { - this.children[0].children[0].geometry.fontStyle.justify[0] = (value==0) ? 'BEGIN' : (value==2) ? 'END' : 'MIDDLE'; - } - } else { - obj.set_font_size = function(value) {} - obj.set_align = function(value) {} - } - if (label) obj.set_label(label); - return obj; -} + gpac.set_event_filter(gwlib_filter_event); + gwskin.has_opengl = (gpac.get_option('Compositor', 'OpenGLMode') != 'disable') ? true : false; + gwskin.browser_mode = (gpac.get_option('Temp', 'BrowserMode') == 'yes') ? true : false; -function gw_new_window(parent, offscreen, class_name) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'Window'); - obj.rect = gw_new_rectangle(class_name); - obj.visible = false; - obj.scale.x = obj.scale.y = 0; - - obj.on_event = function(evt) { return 0; } - - obj.set_style = function(classname, style) { - this.rect.set_style(classname, style); - } - if (! offscreen) { - gw_add_child(obj, rect); - var item = new SFNode('Layer2D'); - setup_gw_object(item, 'Layer'); - gw_add_child(obj, item); - obj.set_size = function(width, height) { - this.width = width; - this.height = height; - this.children[0].set_size(width, height); - this.children[1].size.x = width; - this.children[1].size.y = height; - this.layout(width, height); - } - obj.set_alpha = function(alpha) { - this.children[0].set_alpha(alpha); - } - obj.add_child = function(child) { - this.children[1].children[this.children[1].children.length] = child; - } - obj.remove_child = function(child) { - this.children[1].removeChildren[0] = child; - } - obj._wnd_close = function() { - obj.rect = null; - gw_close_child_list(this.children); - } - } else { - var shape = new SFNode('Shape'); - shape.appearance = new SFNode('Appearance'); - shape.appearance.material = new SFNode('Material2D'); - shape.appearance.material.filled = TRUE; - shape.appearance.texture = new SFNode('CompositeTexture2D'); - shape.appearance.texture.children[0] = obj.rect; - shape.geometry = new SFNode('Bitmap'); - obj.children[0] = shape; - - obj.set_size = function(width, height) { - this.width = width; - this.height = height; - this.children[0].appearance.texture.pixelWidth = width; - this.children[0].appearance.texture.pixelHeight = height; - this.children[0].appearance.texture.children[0].set_size(width, height); - this.layout(width, height); - } - - obj.set_alpha = function(alpha) { - this.children[0].appearance.material.transparency = 1 - alpha; - } - obj.get_alpha = function() { - return 1 - this.children[0].appearance.material.transparency; - } - - obj.add_child = function(child) { - this.children[0].appearance.texture.children[this.children[0].appearance.texture.children.length] = child; - } - obj.remove_child = function(child) { - this.children[0].appearance.texture.removeChildren[0] = child; - } - obj._wnd_close = function() { - obj.rect = null; - gw_close_child_list(this.children[0].appearance.texture.children); - } - } - obj._pre_destroy = obj._wnd_close; - obj.set_corners = function(tl, tr, br, bl) { - this.rect.set_corners(tl, tr, br, bl); - } - - if (typeof gwskin[class_name] != 'undefined') { - if (typeof gwskin[class_name].show != 'undefined') obj.show = gwskin[class_name].show; - if (typeof gwskin[class_name].hide != 'undefined') obj.hide = gwskin[class_name].hide; - } - obj._on_wnd_close = obj.close; - obj.close = function () { - this.hide(this._on_wnd_close); - } - obj.layout = function (w, h) {} - - gw_add_child(parent, obj); - return obj; -} - -function gw_new_icon_button(parent, icon_url, label, class_name, horizontal) -{ - var touch; - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'IconButton'); - - if (arguments.length<5) horizontal = false; - - obj.children[0] = new SFNode('Transform2D'); - obj.children[0].children[0] = new SFNode('Layer2D'); - obj.children[1] = gw_new_rectangle(class_name, 'invisible'); - - obj.children[2] = new SFNode('TouchSensor'); - - if (gwskin.get_font(class_name) != null) { - obj.children[3] = gw_new_text(null, label, class_name); - if (horizontal) { - obj.set_size = function(width, height) { - this.children[0].children[0].size.x = height; - this.children[0].children[0].size.y = height; - this.children[0].translation.x = (height-width)/2; - this.children[1].set_size(width, height); - this.children[3].set_width(width-height); - this.children[3].translation.x = height - width/2; - this.width = width; - this.height = height; - }; - } else { - obj.set_size = function(width, height) { - var fsize = this.children[3].font_size(); - var h = height - fsize; - this.children[0].children[0].size.x = h; - this.children[0].children[0].size.y = h; - this.children[0].translation.y = (height-h)/2; - this.children[1].set_size(3*width/2, height); - this.children[3].set_width(3*width/2); - this.children[3].translation.y = -height/2+fsize/2; - this.width = 3*width/2; - this.height = height; - }; - } - obj.set_label = function(label) { - this.children[3].set_label(label); - } - obj.get_label = function() { - return this.children[3].get_label(); - } - } else { - obj.set_size = function(width, height) { - this.children[0].children[0].size.x = width; - this.children[0].children[0].size.y = height; - this.children[1].set_size(width, height); - this.width = width; - this.height = height; - }; - obj.set_label = function(label) { - this.label = label; - } - obj.get_label = function() { - return this.label; - } - } - - obj._last_ts = 0; - obj.on_long_click = NULL; - obj.on_click = NULL; - obj.on_over = null; - obj.down = false; - obj.over = false; - obj._on_active = function(value, timestamp) { - if (value) { - this.down = true; - this.children[1].set_style(class_name, 'down'); - this._last_ts = timestamp; - } else { - if (this.down && this.over) { - if (this.on_long_click && (timestamp - this._last_ts > gwskin.long_click_delay)) this.on_long_click(); - else if (this.on_click) this.on_click(); - } - this.down = false; - this.children[1].set_style(class_name, (this.over && gwskin.pointing_device) ? 'over' : 'invisible'); - } - }; - obj._on_over = function(value) { - this.over = value; - if (gwskin.pointing_device) { - var app = gwskin.get_style(class_name, 'over'); - if (app) { - this.children[1].set_style(class_name, value ? 'over' : 'invisible'); - } - if (this.on_over) this.on_over(value); - if (gwskin.tooltip_callback) gwskin.tooltip_callback(value, this.get_label() ); - } - }; - Browser.addRoute(obj.children[2], 'isOver', obj, obj._on_over); - Browser.addRoute(obj.children[2], 'isActive', obj, obj._on_active); - - obj.icons = []; - obj.add_icon = function(url) { - - if(typeof url == 'string') { - var inl = gw_load_resource(url); - } else { - var inl = url; - } - this.icons[this.icons.length] = inl; - - if (this.children[0].children[0].children.length==0) { - this.children[0].children[0].children[0] = this.icons[0]; - } - } - obj.switch_icon = function(idx) { - while (idx>this.icons.length) idx-=this.icons.length; - this.children[0].children[0].children[0] = this.icons[idx]; - } - obj._pre_destroy = function() { - for (var i in this.icons) { - gw_unload_resource(this.icons[i]); - } - this.icons.length = 0; - Browser.deleteRoute(this.children[2], 'ALL', null, null); - } - - - if (icon_url) obj.add_icon(icon_url); - obj.set_label(label); - - - if (typeof gwskin[class_name] != 'undefined') { - if (typeof gwskin[class_name].width == 'undefined') gwskin[class_name].width = control_icon_size; - if (typeof gwskin[class_name].height == 'undefined') gwskin[class_name].height = control_icon_size; - obj.set_size(gwskin[class_name].width, gwskin[class_name].height); - } else { - obj.set_size(gwskin.control_icon_size, gwskin.control_icon_size); - } - gw_add_child(parent, obj); - return obj; -} - - -function gw_new_subscene(parent) -{ - var inline = new SFNode('Inline'); - inline._name = 'Subscene'; - inline._pre_destroy = function() { - this.url[0]=''; - this.url.length = 0; - } - inline.connect = function(url) { - this.url.length = 0; - this.url[0]=url; - } - gw_add_child(parent, inline); - return inline; -} + gpac.focus_highlight = false; -function gw_new_button(parent, text, class_name) -{ - var label; - obj = gw_new_rectangle(class_name, 'normal'); - label = gw_new_text(obj, text, class_name); - gw_object_set_hitable(obj); - obj.on_over = function(val) { - if (gwskin.pointing_device) { - this.set_style(class_name, val ? 'over' : 'normal'); - } - if (gwskin.tooltip_callback) gwskin.tooltip_callback(value, this.get_label() ); - } - obj.on_down = function(val) { - this.set_style(class_name, val ? 'down' : (this._over ? 'over' : 'normal') ); - } - - obj._set_size = obj.set_size; - obj.set_size = function(width, height) { - this._set_size(width, height); - this.children[1].set_size(width, height); - this.children[1].set_width(width); - }; - obj.set_label = function(label) { - this.children[1].set_label(label); - } - obj.get_label = function() { - return this.children[1].get_label(); - } - obj.set_labels = function() { - this.children[1].set_labels.apply(this.children[1], arguments); - } - gw_add_child(parent, obj); - return obj; -} - - - -function grid_event_navigate(dlg, children, type) -{ - var i; - if (dlg.current_focus==-1) { - for (i=0; i= -dlg.width/2)) { - dlg.current_focus = i; - gpac.set_focus(children[i]); - return true; - } - } - } - if (type=='Right') { - var orig_focus = dlg.current_focus; - var switch_page = 0; - var tr = children[dlg.current_focus].translation.y - children[dlg.current_focus].height/2; - if (dlg.current_focus + 1 == children.length) return false; - /*goto right item*/ - dlg.current_focus++; - /*check we are not going down*/ - while (1) { - if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y + children[dlg.current_focus].height/2>tr)) - break; - if (dlg.current_focus + 1 == children.length) { - dlg.current_focus = orig_focus; - return false; - } - dlg.current_focus++; - switch_page=1; - } - /*check we haven't move to a new page*/ - if (children[orig_focus].translation.y + children[orig_focus].height/2 <= children[dlg.current_focus].translation.y - children[dlg.current_focus].height/2) { - switch_page=1; - } - gpac.set_focus(children[dlg.current_focus]); - if (switch_page) dlg._move_to(dlg.translate - dlg.width); - return true; - } - - if (type=='Left') { - var orig_focus = dlg.current_focus; - var switch_page = 0; - var tr = children[dlg.current_focus].translation.y + children[dlg.current_focus].height/2; - if (!dlg.current_focus) return false; - /*goto left item*/ - dlg.current_focus--; - /*check we are not going up*/ - while (1) { - if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y - children[dlg.current_focus].height/2 < tr)) - break; - if (!dlg.current_focus) { - dlg.current_focus = orig_focus; - return false; - } - dlg.current_focus--; - switch_page=1; - } - /*check we haven't move to a new page*/ - if (children[orig_focus].translation.y - children[orig_focus].height/2 >= children[dlg.current_focus].translation.y + children[dlg.current_focus].height/2) { - switch_page=1; - } - gpac.set_focus(children[dlg.current_focus]); - if (switch_page) dlg._move_to(dlg.translate + dlg.width); - return true; - } - - if (type=='Down') { - var orig_focus = dlg.current_focus; - var switch_page = 0; - var ty = children[dlg.current_focus].translation.y - children[dlg.current_focus].height/2; - if (dlg.current_focus + 1 == children.length) return false; - dlg.current_focus++; - /*goto next line*/ - while (1) { - if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y - children[dlg.current_focus].height/2 tx)) - break; - if (dlg.current_focus + 1 == children.length) break; - dlg.current_focus++; - } - - gpac.set_focus(children[dlg.current_focus]); - return true; - } - - if (type=='Up') { - var orig_focus = dlg.current_focus; - var switch_page = 0; - var ty = children[dlg.current_focus].translation.y + children[dlg.current_focus].height/2; - if (!dlg.current_focus) return false; - dlg.current_focus--; - /*goto previous line*/ - while (1) { - if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y + children[dlg.current_focus].height/2>ty)) - break; - if (!dlg.current_focus) { - dlg.current_focus = orig_focus; - return false; - } - dlg.current_focus--; - } - /*goto above child*/ - var tx = children[orig_focus].translation.x + children[orig_focus].width/2; - while (1) { - if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.x - children[dlg.current_focus].width/2 < tx)) - break; - if (!dlg.current_focus) { - dlg.current_focus = orig_focus; - return false; - } - dlg.current_focus--; - } - gpac.set_focus(children[dlg.current_focus]); - return true; - } - return false; -} - -function gw_new_grid_container(parent) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'FlipContainer'); - - obj._ps2d = new SFNode('PlaneSensor2D'); - obj._ps2d.maxPosition.x = obj._ps2d.maxPosition.y = -1; - obj._ps2d.autoOffset = TRUE; - - obj.children[0] = new SFNode('Layer2D'); -// obj.children[0].children[0] = gw_new_rectangle('', 'invisible'); - obj.children[0].children[0] = obj._ps2d; - obj.children[0].children[1] = new SFNode('Transform2D'); + gwskin.disable_transparency = false; + //remove window gradients + if (!gwskin.has_opengl && !gpac.hardware_rgba) { + s = gwskin.get_style('window', 'normal'); + s.texture = null; + gwskin.disable_transparency = true; + gwskin.default_window_alpha = 1; + } + + var device = gpac.get_option('General', 'DeviceType'); + + if ((device == 'iOS') || (device == 'Android')) gwskin.mobile_device = true; + else gwskin.mobile_device = false; - obj._move_to = function(value) { - this.translate = value; - if (this.translate>0) this.translate = 0; - else if (this.translate<-this.max_width) this.translate = -this.max_width; - - if (0) { - this.timer = gw_new_timer(true); - this.timer.set_timeout(0.25, false); - this.timer.from = this.children[0].children[1].translation.x; - this.timer.dlg = this; - this.timer.on_fraction = function(val) { - var x = (1-val)*this.from + val*this.dlg.translate; - this.dlg.children[0].children[1].translation.x = x; - - /* - var children = obj.children[0].children[1].children; - for (var i=0; i0.5) ? (2*val - 1) : (1 - 2*val); - } - */ - } - this.timer.on_active = function(val) { - if (!val) { - this.dlg.timer = null; - this.dlg = null; - } - } - this.timer.start(0); - } else { - this.children[0].children[1].translation.x = this.translate; - } - this._ps2d.offset.x = -this.translate; - } - - obj.translate = 0; - obj._on_slide = function(val) { - this.translate = - val.x; - if (this.translate>0) this.translate = 0; - else if (this.translate<-this.max_width) this.translate = -this.max_width; - this.children[0].children[1].translation.x = this.translate; - } - obj._on_active = function(val) { - if (!val) { - var off_x = 0; - while (off_x - this.width/2 > this.translate) off_x -= this.width; - this._move_to(off_x); - } - } - Browser.addRoute(obj._ps2d, 'translation_changed', obj, obj._on_slide); - Browser.addRoute(obj._ps2d, 'isActive', obj, obj._on_active); - obj.children[0].children[2] = obj._ps2d; - - obj.spread_h = false; - obj.spread_v = false; - obj.break_at_hidden = false; - obj.set_size = function(width, height) { - this.width = width; - this.height = height; - this.children[0].size.x = width; - this.children[0].size.y = height; -// this.children[0].children[0].set_size(width, height); - this.nb_visible=0; - this.first_visible=0; - this.layout(); - } - obj.max_width = 0; - obj.layout = function() { - var spread_x, nb_wid_h, start_x, start_y, maxh, width, height, page_x, nb_on_line; - var children = obj.children[0].children[1].children; - width = this.width; - height = this.height; - - page_x = 0; - maxh = 0; - spread_x = -1; - start_x = -width/2; - start_y = height/2; - nb_on_line = 0; - this.current_focus = -1; - for (var i=0; i width) break; - len += children[i+j].width; - if (maxh < children[i+j].height) maxh = children[i+j].height; - j++; - nb_child++; - if (i+j==children.length) break; - } - if (nb_child<=1) { - maxh = children[i].height; - if (this.spread_h) start_x = -len/2; - } - else if (this.spread_h) { - spread_x = (width - len) / (nb_child); - start_x += spread_x/2; - } else { - spread_x = 0; - } - } - - if (!children[i].visible) { - if (nb_on_line && this.break_at_hidden) { - nb_on_line = 0; - spread_x = -1; - start_y -= maxh/2; - start_x = - width/2; - } - continue; - } - if (start_y - maxh < - height/2) { - nb_on_line = 0; - page_x += width; - spread_x = -1; - start_y = height/2; - i--; - continue; - } - children[i].translation.x = start_x + children[i].width/2; - children[i].translation.y = start_y - maxh/2; - -// alert('child i' + i + '/' + children.length + ' size ' + children[i].width + 'x' + children[i].height + ' translation ' + children[i].translation); - start_x += children[i].width + spread_x; - - nb_on_line++; - - if (i+1==children.length) { - break; - } - if (start_x - page_x + children[i+1].width > width/2) { - nb_on_line = 0; - spread_x = -1; - start_y -= maxh; - start_x = - width/2; - } - } - this.max_width = page_x; - this._ps2d.enabled = (this.max_width) ? TRUE : FALSE; - } - - obj.add_child = function(child) { - this.children[0].children[1].children[this.children[0].children[1].children.length] = child; - gw_add_child(child, this._ps2d); - } - obj.remove_child = function(child) { - /*remove ps2d from each child, otherwise we create references which screw up JS GC*/ - if (typeof child.remove_child != 'undefined') child.remove_child(this._ps2d); - else child.removeChildren[0] = this._ps2d; - - this.children[0].children[1].removeChildren[0] = child; - } - - obj.get_children = function() { - return this.children[0].children[1].children; - } - obj.reset_children = function () { - gw_close_child_list(this.children[0].children[1].children); - this.children[0].children[1].children.length = 0; - } - obj._pre_destroy = function() { - Browser.deleteRoute(this._ps2d, 'ALL', null, null); - this.reset_children(); - this.children.length = 0; - this._ps2d = null; - } - - obj.set_focus = function(type) { - grid_event_navigate(this, this.children[0].children[1].children, type); - } - - obj.on_event = function(evt) { - switch (evt.type) { - case GF_EVENT_MOUSEWHEEL: - if (evt.button==1) { - var tr = this.translate + (evt.wheel>0 ? this.width : -this.width); - this._move_to(this.translate + (evt.wheel<0 ? this.width : -this.width) ); - return 1; - } - return 0; - case GF_EVENT_KEYDOWN: - if ((evt.keycode=='Up') || (evt.keycode=='Down') || (evt.keycode=='Right') || (evt.keycode=='Left') ) { - return grid_event_navigate(this, this.children[0].children[1].children, evt.keycode); - } - case GF_EVENT_KEYDOWN: - if ((evt.keycode=='Up') || (evt.keycode=='Down') || (evt.keycode=='Right') || (evt.keycode=='Left') ) { - return grid_event_navigate(this, this.children[0].children[1].children, evt.keycode); - } - return 0; - } - return 0; - } - - gw_add_child(parent, obj); - return obj; -} - - - -function gw_new_progress_bar(parent, vertical, with_progress, class_name) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'ProgressBar'); - var ps2d; - - if (arguments.length<=3) class_name = 'progress'; - if (arguments.length<=2) with_progress = false; - if (arguments.length<=1) vertical = false; - - obj.children[0] = gw_new_rectangle(class_name, 'normal'); - if (with_progress) { - obj.children[1] = gw_new_rectangle(class_name, 'down'); - - obj.set_progress = function(prog) { - if (prog<0) prog=0; - else if (prog>100) prog=100; - this.prog = prog; - prog/=100; - if (this.vertical) { - var pheight = prog*this.height; - this.children[1].set_size(this.width, pheight); - this.children[1].move(0, (this.height-pheight)/2, 0); - } else { - var pwidth = prog*this.width; - this.children[1].set_size(pwidth, this.height); - this.children[1].move((pwidth-this.width)/2, 0); - } - } - } else { - obj.set_progress = function(prog) {} - } - obj.slide_idx = obj.children.length; - obj.children[obj.slide_idx] = gw_new_rectangle(class_name, 'over'); - - obj.children[obj.slide_idx+1] = gw_new_rectangle(class_name, 'invisible'); - ps2d = new SFNode('PlaneSensor2D'); - obj.children[obj.slide_idx+1].children[1] = ps2d; - ps2d.maxPosition.x = -1; - ps2d.maxPosition.y = -1; - - obj.on_slide = function(value, type) { } - - obj._with_progress = with_progress; - obj._sliding = false; - obj._slide_active = function(val) { - obj._sliding = val; - this.on_slide(this.min + (this.max-this.min) * this.frac, val ? 1 : 2); - } - Browser.addRoute(ps2d, 'isActive', obj, obj._slide_active); - - obj._set_trackpoint = function(value) { - if (this.vertical) { - this.frac = value.y/this.height; - } else { - this.frac = value.x/this.width; - } - this.frac += 0.5; - if (this.frac>1) this.frac=1; - else if (this.frac<0) this.frac=0; - - this._set_frac(); - this.on_slide(this.min + (this.max-this.min) * this.frac, 0); - } - Browser.addRoute(ps2d, 'trackPoint_changed', obj, obj._set_trackpoint); - - obj._set_frac = function() { - if (this.vertical) { - var pheight = this.frac*this.height; - if (pheightthis.max-this.min) value = this.max-this.min; - if (this.max==this.min) value = 0; - else value /= (this.max-this.min); - - this.frac = value; - this._set_frac(); - } + if (gwskin.mobile_device) { + var size = gw_display_width; + if (size> gw_display_height) size = gw_display_height; + gwskin_set_default_control_height(size/3); + gwskin_set_default_icon_height(size/3); + } + gwskin_set_white_blue(); + + gwskin._to_string = function (obj) { + var res = ''; + if (obj instanceof Array) { + res = '['; + for (var i = 0; i < obj.length; i++) { + if (i) res += ', '; + res += gwskin._to_string(obj[i]); + } + res += ']'; + } else { + var first = true; + res = '{'; + for (var prop in obj) { + if (!first) res += ', '; + res += '' + prop; + res += ': '; + if (typeof obj[prop] == 'string') { + res += '"'; + res += obj[prop]; + res += '"'; + } else if (typeof obj[prop] == 'function') { + } else if (typeof obj[prop] == 'object') { + res += gwskin._to_string(obj[prop]); + } else { + res += obj[prop]; + } + first = false; + } + res += '}'; + } + return res; + } - obj.vertical = vertical; - obj.set_size = function(w, h) { - this.width = w; - this.height = h; - this.children[0].set_size(w, h); - if (this._with_progress) { - this.children[3].set_size(w, h); - } else { - this.children[2].set_size(w, h); - } - this._set_frac(); - this.set_progress(this.prog); - } - obj.min = 0; - obj.max = 100; - - obj.move = function(x,y) { - this.translation.x = x; - this.translation.y = y; - } - - obj.prog = 0; - obj.frac = 0; - obj.set_size(vertical ? 10 : 200, vertical ? 200 : 10); + gwskin.stringify = function (obj) { + return this._to_string(obj); + } + gwskin.parse = function (serial_obj) { + if (serial_obj.charAt(0) != '(') { + return eval('(' + serial_obj + ')' ); + } + return eval(serial_obj); + } - gw_add_child(parent, obj); - return obj; } -function gw_new_slider(parent, vertical, class_name) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'Slider'); - - if (arguments.length<=2) class_name = 'progress'; - if (arguments.length<=1) vertical = false; - - obj.children[0] = gw_new_rectangle(class_name, 'normal'); - obj.children[1] = gw_new_rectangle(class_name, 'over'); - obj.children[2] = gw_new_rectangle(class_name, 'invisible'); - - var ps2d = new SFNode('PlaneSensor2D'); - obj.children[2].children[1] = ps2d; - ps2d.maxPosition.x = -1; - ps2d.maxPosition.y = -1; - obj.on_slide = function(value, type) { } - - obj.slide_active = function(val) { - this.on_slide(this.min + (this.max-this.min) * this.frac, val ? 1 : 2); - } - Browser.addRoute(ps2d, 'isActive', obj, obj.slide_active); - obj.set_trackpoint = function(value) { - if (vertical) { - this.frac = value.y/(this.height-this.children[1].height); - } else { - this.frac = value.x/(this.width-this.children[1].width); - } - this.frac += 0.5; - if (this.frac>1) this.frac=1; - else if (this.frac<0) this.frac=0; - - if (vertical) { - value.y = (this.frac-0.5) * (this.height-this.children[1].height); - value.x = 0; - } else { - value.x = (this.frac-0.5) * (this.width-this.children[1].width); - value.y = 0; - } - this.children[1].translation = value; - this.on_slide(this.min + (this.max-this.min) * this.frac, 0); - } - Browser.addRoute(ps2d, 'trackPoint_changed', obj, obj.set_trackpoint); - - obj.set_value = function(value) { - if (this.children[2].isActive) return; - - value -= this.min; - if (value<0) value = 0; - else if (value>this.max-this.min) value = this.max-this.min; - if (this.max==this.min) value = 0; - else value /= (this.max-this.min); - - value -= 0.5; - value *= (vertical ? this.height : this.width); - - if (vertical) { - this.children[1].translation.y = value; - } else { - this.children[1].translation.x = value; - } - } - - obj.vertical = vertical; - obj.set_size = function(w, h, cursor_w, cursor_h) { - this.width = w; - this.height = h; - this.children[0].set_size(w, h); - - if (typeof(cursor_w)=='undefined') cursor_w = this.children[1].width; - if (typeof(cursor_h)=='undefined') cursor_h = this.children[1].height; - this.children[1].set_size(cursor_w, cursor_h); - - if (this.vertical) { - this.children[2].set_size(this.children[1].width, h); - } else { - this.children[2].set_size(w, this.children[1].height); - } - } - obj.set_cursor_size = function(w, h) { - this.children[1].set_size(w, h); - } - obj.min = 0; - obj.max = 100; - obj.frac = 0; - obj.set_trackpoint(0); - - obj.move = function(x,y) { - this.translation.x = x; - this.translation.y = y; - } - obj.set_size(vertical ? 10 : 200, vertical ? 200 : 10, 10, 10); - - gw_add_child(parent, obj); - return obj; -} - - -function gw_new_window_full(parent, offscreen, the_label, class_name, child_to_insert) -{ - var wnd = gw_new_window(parent, offscreen, class_name); +function gwlib_add_event_filter(evt_filter) { + if ((arguments.length==2) && (arguments[1]==true)) { + gw_event_filters.unshift(evt_filter); + } else { + gw_event_filters.push(evt_filter); + } +} - if (arguments.length<=4) child_to_insert = null; - if (child_to_insert) { - gw_add_child(wnd, child_to_insert); - } - - wnd.area = null; - - wnd.tools = gw_new_grid_container(wnd); - wnd.tools._name = 'ToolBar'; - wnd.tool_size = gwskin.icon.width; - - wnd.label = null; - if (the_label) { - wnd.label = gw_new_text(wnd.tools, the_label, class_name); - wnd.label.set_size(wnd.tool_size, wnd.tool_size); - wnd.label.set_width(wnd.tool_size); - } - - wnd.set_label = function(label) { - if (wnd.label) wnd.label.set_label(label); - } +function gwlib_remove_event_filter(evt_filter) { + var idx = gw_event_filters.indexOf(evt_filter); + if (idx > -1) gw_event_filters.splice(idx, 1); +} - - wnd.add_tool = function(icon, name) { - var tool = gw_new_icon_button(this.tools, icon, name, 'icon'); - if (this.label) { - this.tools.remove_child(this.label); - this.tools.add_child(this.label); - } - tool.set_size(wnd.tool_size, wnd.tool_size); - tool._name = name; - tool.dlg = this; - return tool; - } +function gwlib_notify_display_size(width, height) { + for (var i = 0; i < gw_ui_root.children.length; i++) { + if (typeof gw_ui_root.children[i].on_display_size != 'undefined') { + gw_ui_root.children[i].on_display_size(width, height); + } + } +} + +function gwlib_refresh_layout() { + for (var i = 0; i < gw_ui_root.children.length; i++) { + if (typeof gw_ui_root.children[i].layout != 'undefined') { + gw_ui_root.children[i].layout(gw_ui_root.children[i].width, gw_ui_root.children[i].height); + } + } +} - - wnd.on_close = null; - var icon = wnd.add_tool(gwskin.images.cancel, gwskin.labels.close); - icon.on_click = function() { - if (this.dlg.on_close) this.dlg.on_close(); - this.dlg.close(); - } - - wnd._pre_destroy = function() { - if (typeof this.predestroy != 'undefined') this.predestroy(); - this.tools = null; - this.label = null; - this.area = null; - this._wnd_close(); - } - - wnd.on_size = null; - wnd.layout = function(width, height) { - var i; - var tools = this.tools.get_children(); - - if (this.area) { - this.area.set_size(width, height - this.tool_size); - this.area.move(0, (this.area.height-height)/2); - } - if (wnd.on_size) wnd.on_size(width, tools.length ? (height - this.tool_size) : height); - - if (this.label) { - var textw = width; - for (i=0; i this.max_height) this._translation_y = this.max_height; - - this.first_visible = -1; - this.last_visible = -1; - - for (var i=0; i this.height/2) { - children[i].scale.x = 0; - } else if (y + children[i].height < -this.height/2) { - children[i].scale.x = 0; - } else { - children[i].move(0, y - children[i].height/2); - children[i].scale.x = 1; - - if (this.first_visible == -1) { - if (y <= this.height/2) this.first_visible = i; - } - if (y - children[i].height >= -this.height/2) this.last_visible = i; - - if (this.selected_idx == i) { - gpac.set_focus(children[i]); - } - } - start_y -= children[i].height; - } -// if (this.selected_idx < this.first_visible) this.selected_idx = this.first_visible; -// else if (this.selected_idx > this.last_visible) this.selected_idx = this.last_visible; - - if (this.selected_idx < this.first_visible) this.selected_idx = -1; - else if (this.selected_idx > this.last_visible) this.selected_idx = -1; - } - obj.add_child = function(child) { - this.children[0].children[this.children[0].children.length] = child; - gw_add_child(child, this._ps2d); - } - obj.remove_child = function(child) { - /*remove ps2d from each child, otherwise we create references which screw up JS GC*/ - if (typeof child.remove_child != 'undefined') child.remove_child(this._ps2d); - else child.removeChildren[0] = this._ps2d; - this.children[0].removeChildren[0] = child; - } - - obj.get_children = function () { - return this.children[0].children; - } - obj.reset_children = function () { - gw_close_child_list(this.children[0].children); - this.children[0].children.length = 0; - } - obj._pre_destroy = function() { - this.reset_children(); - this._ps2d = null; - } - - obj.on_event = function(evt) { - switch (evt.type) { - case GF_EVENT_MOUSEWHEEL: - this._translation_y += (evt.wheel>0) ? -this.height/20 : this.height/20; - this.layout(); - return 1; - case GF_EVENT_KEYDOWN: - var children = this.get_children(); - - if (this.selected_idx < this.first_visible) this.selected_idx = this.first_visible; - else if (this.selected_idx > this.last_visible) this.selected_idx = this.last_visible; - - if (evt.keycode=='Up') { -// alert('sel '+ this.selected_idx + ' first '+this.first_visible+ ' last '+this.last_visible); - if (children[this.selected_idx].translation.y + children[this.selected_idx].height/2 > this.height/2 ) { - this._translation_y -= this.height; - this.layout(); - return 1; - } - if (!this.selected_idx) return 0; - this.selected_idx--; - if (this.selected_idxthis.last_visible) - this._translation_y += children[this.first_visible].height; - this.layout(); - return 1; - } - return 0; - } - return 0; - } - - - gw_add_child(container, obj); - return obj; -} - - -function gw_new_file_open(class_name) -{ - if (arguments.length==0) class_name = 'window'; - - var dlg = gw_new_window_full(null, true, 'Browse FileSystem', 'window'); - - dlg.area = gw_new_listbox(dlg); - - dlg.on_event = function(evt) { - if (evt.type==GF_EVENT_KEYDOWN) { - if (evt.keycode=='Left') { - this._browse(null, true); - return 1; - } - else if (evt.keycode=='Enter') { - var child = this.area.get_selection(); - if (child) child.on_click(); - return 1; - } - } - if (this.area && typeof this.area.on_event != 'undefined') { - return this.area.on_event(evt); - } - } - - dlg.on_close = function () { - if (this.on_browse) { - this.on_browse(null, false); - } - } - - dlg.go_up = dlg.add_tool(gwskin.images.previous, gwskin.labels.up); - dlg.go_up.on_click = function() { - this.dlg._browse(null, true); - } +//static +function gw_add_child(container, child) { + if (container == null) container = gw_ui_root; - dlg.on_directory = null; - dlg.scan_dir = dlg.add_tool(gwskin.images.scan_directory, gwskin.labels.scan_directory); - dlg.scan_dir.on_click = function() { - if (this.dlg.on_directory) this.dlg.on_directory(this.dlg.directory); - this.dlg.close(); - } - - dlg.predestroy = function() { - this.scan_dir = null; - this.go_up = null; - } - - dlg.directory = ''; - dlg.show_directory = false; - dlg.filter = '*'; - - dlg._on_dir_browse = function() { - this.dlg._browse(this.dlg.path + this.filename, false); - } - dlg._on_file_select = function() { - if (this.dlg.on_browse) { - this.dlg.on_browse(this.dlg.path + this.filename, this.dlg.directory); - } - this.dlg.close(); - } - - dlg.browse = function(dir) { - this.directory = dir; - this._browse(dir, false); - } - dlg._browse = function(dir, up) { - var w, h, i, y; - if (dir) this.directory = dir; - - var filelist = gpac.enum_directory(this.directory, this.filter, up); + if (typeof (container.add_child) != 'undefined') { + container.add_child(child); + } else { + container.children[container.children.length] = child; + } + child.parent = container; +} + +//static +function gw_detach_child(child) { + /*detach all default routes*/ + Browser.deleteRoute(child, 'ALL', null, null); + if (typeof (child._ps2d_idx) != 'undefined') { + Browser.deleteRoute(child.children[child._ps2d_idx], 'ALL', null, null); + } + if (typeof (child._ts_idx) != 'undefined') { + Browser.deleteRoute(child.children[child._ts_idx], 'ALL', null, null); + } + if (typeof (child.dlg) != 'undefined') child.dlg = null; + if (typeof (child.parent) == 'undefined') return; + + var p = child.parent; + child.parent = null; + if (typeof (p.remove_child) != 'undefined') { + p.remove_child(child); + } else { + p.removeChildren[0] = child; + } + if (gwskin.last_hitable_obj == child) gwskin.last_hitable_obj = null; +} + +//static +function gw_close_child_list(list) { + var count = list.length; + if (!count) return; + for (var i = 0; i < count; i++) { + var child = list[i]; + if (typeof child.close != 'undefined') child.close(); + else gw_detach_child(child); + + if (list.length < count) { + i -= (count - list.length); + count = list.length; + } + } + //trigger GC whenever we have closed a child list + gpac.trigger_gc(); +} + + +//static +gwskin.get_class = function (class_name) { + if (arguments.length < 1) class_name = 'default'; + + var styles = gwskin.styles.filter(function (obj) { return obj.name == class_name; }); + if (styles.length > 0) { + return styles[0]; + } + return null; +} + +//static +gwskin.get_style = function (class_name, style_name) { + if (arguments.length < 1) class_name = 'default'; + if (arguments.length < 2) style_name = 'normal'; + if (style_name == 'invisible') return gwskin.appearance_transparent; + + var style = null; + var styles = gwskin.styles.filter(function (obj) { return obj.name == class_name; }); + if (styles.length > 0) { + if (typeof styles[0][style_name] != 'undefined') + return styles[0][style_name]; + } else { + gwlog(l_err, 'Non-existing class ' + class_name); + } + + style = gwskin.styles[0]; + if (typeof style[style_name] != 'undefined') + return style[style_name]; + + gwlog(l_err, 'Non-existing style ' + style_name + ' in default class'); + return null; +} + +//static +gwskin.get_font = function (class_name) { + if (arguments.length < 1) class_name = 'default'; + + var styles = gwskin.styles.filter(function (obj) { return obj.name == class_name; }); + if (styles.length > 0) { + if (typeof styles[0].font != 'undefined') { + return styles[0].font; + } + } else { + gwlog(l_err, 'Non-existing class ' + class_name); + } + return gwskin.styles[0].font; +} + +function gw_new_container() { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Container'); + obj.push_to_top = function (wnd) { + this.removeChildren[0] = wnd; + this.addChildren[0] = wnd; + } + return obj; +} + +function gw_new_curve2d(class_name) +{ + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Curve2D'); + var shape = new SFNode('Shape'); + obj.children[0] = shape; + shape.appearance = gw_new_appearance(0, 0, 0); + obj.children[0].appearance.material.filled = false; + obj.children[0].appearance.material.lineProps = new SFNode('LineProperties'); + + obj.set_color = function (r, g, b) { + this.children[0].appearance.material.lineProps.lineColor.r = r; + this.children[0].appearance.material.lineProps.lineColor.g = g; + this.children[0].appearance.material.lineProps.lineColor.b = b; + } + obj.set_line_width = function (width) { + if (!this.children[0].appearance.material.lineProps) this.children[0].appearance.material.lineProps = new SFNode('LineProperties'); + this.children[0].appearance.material.lineProps.width = width; + } + shape.geometry = new SFNode('Curve2D'); + shape.geometry.point = new SFNode('Coordinate2D'); + + obj.reset = function () { + this.children[0].geometry.point.point.length = 0; + this.children[0].geometry.type.length = 0; + } + obj._add_coord = function (x, y) { + var pts = this.children[0].geometry.point.point; + pts[pts.length] = new SFVec2f(x, y); + } + obj.add_move_to = function (x, y) { + this._add_coord(x, y); + //first moveto is implicit + if (this.children[0].geometry.type.length) + this.children[0].geometry.type[this.children[0].geometry.type.length] = 0; + } + obj.add_line_to = function (x, y) { + this._add_coord(x, y); + this.children[0].geometry.type[this.children[0].geometry.type.length] = 1; + } + obj.remove_first = function () { + var pts = this.children[0].geometry.point.point; + if (pts.length < 2) pts.length = 0; + else { + for (var i = 0; i < pts.length - 1; i++) { + pts[i] = pts[i + 1]; + } + pts.length = i; + + pts = this.children[0].geometry.type; + + for (var i = 0; i < pts.length - 1; i++) { + pts[i] = pts[i + 1]; + } + pts.length = i; + } + } + obj.get_num_points = function() { + return this.children[0].geometry.point.point.length; + } + return obj; +} + + +function gw_new_rectangle(class_name, style) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Rectangle'); + var shape = new SFNode('Shape'); + obj.children[0] = shape; + if (arguments.length == 1) style = 'normal'; + + shape.appearance = gwskin.get_style(class_name, style); + + if (shape.appearance && (typeof (shape.appearance.skin) == 'undefined')) { + obj.set_alpha = function (alpha) { + this.children[0].appearance.material.transparency = 1 - alpha; + } + obj.get_alpha = function () { + return 1 - this.children[0].appearance.material.transparency; + } + obj.set_fill_color = function (r, g, b) { + this.children[0].appearance.material.emissiveColor.r = r; + this.children[0].appearance.material.emissiveColor.g = g; + this.children[0].appearance.material.emissiveColor.b = b; + } + obj.set_strike_color = function (r, g, b) { + if (!this.children[0].appearance.material.lineProps) this.children[0].appearance.material.lineProps = new SFNode('LineProperties'); + this.children[0].appearance.material.lineProps.lineColor.r = r; + this.children[0].appearance.material.lineProps.lineColor.g = g; + this.children[0].appearance.material.lineProps.lineColor.b = b; + } + obj.set_line_width = function (width) { + if (!this.children[0].appearance.material.lineProps) this.children[0].appearance.material.lineProps = new SFNode('LineProperties'); + this.children[0].appearance.material.lineProps.width = width; + } + } else { + obj.set_alpha = function (alpha) { } + obj.set_fill_color = function (r, g, b) { } + obj.set_strike_color = function (r, g, b) { } + obj.set_line_width = function (width) { } + obj.get_alpha = function () { return 1; } + } + + obj.set_style = function (classname, style) { + var app = gwskin.get_style(classname, style); + if (app) this.children[0].appearance = app; + } + + + shape.geometry = new SFNode('Curve2D'); + shape.geometry.point = new SFNode('Coordinate2D'); + + obj.corner_tl = true; + obj.corner_tr = true; + obj.corner_bl = true; + obj.corner_br = true; + obj.set_corners = function (tl, tr, br, bl) { + this.corner_tl = tl; + this.corner_tr = tr; + this.corner_bl = bl; + this.corner_br = br; + } + obj.sfv = new SFVec2f(0, 0); + + obj.set_size = function (w, h) { + var hw, hh, rx_bl, ry_bl, rx_br, ry_br, rx_tl, ry_tl, rx_tr, ry_tr, rx, ry; + var temp; + hw = w / 2; + hh = h / 2; + this.width = w; + this.height = h; + temp = this.children[0].geometry.type; + temp[0] = 7; + temp[1] = 1; + temp[2] = 7; + temp[3] = 1; + temp[4] = 7; + temp[5] = 1; + temp[6] = 7; + temp[7] = 6; /*close*/ + + /*compute default rx/ry*/ + ry = rx = 10; + if (rx >= hw) rx = hw; + if (ry >= hh) ry = hh; + rx_bl = rx_br = rx_tl = rx_tr = rx; + ry_bl = ry_br = ry_tl = ry_tr = ry; + if (!this.corner_tl) rx_tl = ry_tl = 0; + if (!this.corner_tr) rx_tr = ry_tr = 0; + if (!this.corner_bl) rx_bl = ry_bl = 0; + if (!this.corner_br) rx_br = ry_br = 0; + + if (shape.geometry.point.point.length < 12) { + shape.geometry.point.point.length = 12; + for (var i = 0; i < 12; i++) { + shape.geometry.point.point[i].x = 0; + } + } + temp = this.children[0].geometry.point.point; + + this.sfv.x = hw - rx_tr; + this.sfv.y = hh; + temp[0] = this.sfv; + this.sfv.x = hw; + this.sfv.y = hh; /*bezier ctrl point or line-to*/ + temp[1] = this.sfv; + this.sfv.x = hw; + this.sfv.y = hh - ry_tr; + temp[2] = this.sfv; + this.sfv.x = hw; + this.sfv.y = -hh + ry_br; + temp[3] = this.sfv; + this.sfv.x = hw; + this.sfv.y = -hh; /*bezier control point*/ + temp[4] = this.sfv; + this.sfv.x = hw - rx_br; + this.sfv.y = -hh; + temp[5] = this.sfv; + this.sfv.x = -hw + rx_bl; + this.sfv.y = -hh; + temp[6] = this.sfv; + this.sfv.x = -hw; + this.sfv.y = -hh; /*bezier control point*/ + temp[7] = this.sfv; + this.sfv.x = -hw; + this.sfv.y = -hh + ry_bl; + temp[8] = this.sfv; + this.sfv.x = -hw; + this.sfv.y = hh - ry_tl; + temp[9] = this.sfv; + this.sfv.x = -hw; + this.sfv.y = hh; /*bezier control point*/ + temp[10] = this.sfv; + this.sfv.x = -hw + rx_tl; + this.sfv.y = hh; + temp[11] = this.sfv; + } + return obj; +} + +function gw_new_text(parent, label, class_name) { + var obj = new SFNode('Transform2D'); + if (arguments.length < 3) class_name = 'default'; + + setup_gw_object(obj, 'Text'); + gw_add_child(parent, obj); + obj.children[0] = new SFNode('Transform2D'); + obj.children[0].children[0] = new SFNode('Shape'); + obj.children[0].children[0].geometry = new SFNode('Text'); + + if (class_name == 'custom') { + class_name = 'default'; + obj.children[0].children[0].appearance = gw_new_appearance(0, 0, 0); + obj.children[0].children[0].geometry.fontStyle = gw_new_fontstyle(gwskin.default_label_font_size, 1); + } else { + obj.children[0].children[0].appearance = gwskin.get_style(class_name, 'text'); + obj.children[0].children[0].geometry.fontStyle = gwskin.get_font(class_name); + } + + + + obj.set_label = function (value) { + this.children[0].children[0].geometry.string.length = 0; + this.children[0].children[0].geometry.string[0] = value; + } + + obj.set_labels = function () { + this.children[0].children[0].geometry.string.length = 0; + for (var i = 0; i < arguments.length; i++) { + this.children[0].children[0].geometry.string[i] = '' + arguments[i]; + } + } + obj.get_label = function () { + var mfs = this.children[0].children[0].geometry.string; + return mfs.length ? this.children[0].children[0].geometry.string[0] : ''; + } + obj.set_width = function (value) { + this.children[0].children[0].geometry.maxExtent = -value; + this.width = value; + } + obj.font_size = function (value) { + return this.children[0].children[0].geometry.fontStyle ? this.children[0].children[0].geometry.fontStyle.size : 1; + } + + if (obj.children[0].children[0].appearance && (typeof (obj.children[0].children[0].appearance.skin) == 'undefined')) { + obj.set_color = function (r, g, b) { + this.children[0].children[0].appearance.material.emissiveColor = new SFColor(r, g, b); + } + obj.children[0].set_alpha = function (a) { + this.children[0].children[0].appearance.material.transparency = 1 - a; + } + obj.set_align = function (val) { + this.children[0].children[0].geometry.fontStyle.justify[0] = val; + } + obj.set_font_size = function (val) { + this.children[0].children[0].geometry.fontStyle.size = val; + } + } else { + obj.set_color = function (r, g, b) { } + obj.set_alpha = function (a) { } + obj.set_align = function (a) { } + obj.set_font_size = function (a) { } + } + obj.set_size = function (width, height) { + var justify = this.children[0].children[0].geometry.fontStyle ? this.children[0].children[0].geometry.fontStyle.justify[0] : ''; + if (justify == 'BEGIN') { + this.children[0].translation.x = -width / 2; + } else if (justify == 'END') { + this.children[0].translation.x = width / 2; + } else { + this.children[0].translation.x = 0; + } + this.children[0].children[0].geometry.maxExtent = -width; + this.width = width; + this.height = height; + } + if (label) obj.set_label(label); + return obj; +} + + +function gw_new_window(parent, offscreen, background, class_name, no_focus) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Window'); + obj.background = null; + obj._is_window = true; + + if (arguments.length < 4) class_name = 'window'; + else if ((arguments.length == 4) && typeof (arguments[3]) == 'boolean') { + obj._no_focus = true; + class_name = 'window'; + } + else if (arguments.length == 5) obj._no_focus = true; + + if (class_name == 'popup') { + class_name = 'window'; + obj._popup = true; + } + + if (background) + obj.background = gw_new_rectangle(class_name); + obj.visible = false; + obj.scale.x = obj.scale.y = 0; + obj._disable_rect = gw_new_rectangle(class_name, 'invisible'); + + obj.on_event = function (evt) { return 0; } + + obj.set_style = function (classname, style) { + if (this.background) + this.background.set_style(classname, style); + } + if (!offscreen) { + if (obj.background) gw_add_child(obj, obj.background); + var item = new SFNode('Layer2D'); + setup_gw_object(item, 'Layer'); + gw_add_child(obj, item); + obj.set_size = function (width, height) { + this.width = width; + this.height = height; + var idx = 0; + if (this.background) { + this.children[0].set_size(width, height); + idx++; + } + this.children[idx].size.x = width; + this.children[idx].size.y = height; + this.layout(width, height); + } + obj.set_alpha = function (alpha) { + if (this.background) { + this.children[0].set_alpha(alpha); + } + } + obj.get_alpha = function () { + if (this.background) { + return this.children[0].get_alpha(); + } + return 0.0; + } + obj.add_child = function (child) { + var idx = this.background ? 1 : 0; + this.children[idx].children[this.children[idx].children.length] = child; + } + obj.remove_child = function (child) { + var idx = this.background ? 1 : 0; + this.children[idx].removeChildren[0] = child; + } + obj._wnd_close = function () { + obj.background = null; + obj._disable_rect = null; + gw_close_child_list(this.children); + } + } else { + var shape = new SFNode('Shape'); + shape.appearance = new SFNode('Appearance'); + shape.appearance.material = new SFNode('Material2D'); + shape.appearance.material.filled = TRUE; + shape.appearance.texture = new SFNode('CompositeTexture2D'); + + if (obj.background) { + //use background to make sure the underlying texture is RGB, not RGBA + if (!gwskin.disable_transparency) { + shape.appearance.texture.children[0] = obj.background; + } else { + shape.appearance.texture.background = gwskin.no_gl_window_back; + + } + } + shape.geometry = new SFNode('Bitmap'); + obj.children[0] = shape; + + obj.set_size = function (width, height) { + this.width = width; + this.height = height; + this.children[0].appearance.texture.pixelWidth = width; + this.children[0].appearance.texture.pixelHeight = height; + this.children[0].appearance.texture.children[0].set_size(width, height); + this.layout(width, height); + } + + obj.set_alpha = function (alpha) { + //disable image blending for offscreens with backgrounds + if (this.background && gwskin.disable_transparency) alpha = 1; + + this.children[0].appearance.material.transparency = 1 - alpha; + } + obj.get_alpha = function () { + return 1 - this.children[0].appearance.material.transparency; + } + + obj.add_child = function (child) { + this.children[0].appearance.texture.children[this.children[0].appearance.texture.children.length] = child; + } + obj.remove_child = function (child) { + this.children[0].appearance.texture.removeChildren[0] = child; + } + obj._wnd_close = function () { + obj.background = null; + obj._disable_rect = null; + gw_close_child_list(this.children[0].appearance.texture.children); + } + } + obj._pre_destroy = obj._wnd_close; + obj.set_corners = function (tl, tr, br, bl) { + if (this.background) + this.background.set_corners(tl, tr, br, bl); + } + + obj._is_disable = false; + obj.disable = function () { + if (this._is_disable) return; + this._is_disable = true; + this._disable_rect.set_size(this.width, this.height); + this.add_child(this._disable_rect); + } + obj.enable = function () { + if (!this._is_disable) return; + this._is_disable = false; + this.remove_child(this._disable_rect); + } + + if (typeof obj._popup != 'boolean') { + var s = gwskin.get_class(class_name); + + if (s) { + if (typeof s.show != 'undefined') obj.show = s.show; + if (typeof s.hide != 'undefined') obj.hide = s.hide; + } + } + + obj.on_close = null; + obj._orig_close = obj.close; + obj._on_wnd_close = function () { + if (this.on_close != null) this.on_close(); + this._orig_close(); + } + obj.close = function () { + this.hide(this._on_wnd_close); + } + obj.layout = function (w, h) { } + + obj.set_alpha(gwskin.default_window_alpha); + gw_add_child(parent, obj); + return obj; +} + +function gw_new_icon_button(parent, icon_url, label, horizontal, class_name) { + var touch; + + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'IconButton'); + + if (arguments.length == 3) { + horizontal = false; + class_name = 'default'; + } + else if (arguments.length == 4) { + if (typeof arguments[3] == 'string') { + class_name = arguments[3]; + horizontal = false; + } else { + class_name = 'default'; + } + } + + obj._icon_root = new SFNode('Transform2D'); + obj._icon_root.children[0] = new SFNode('Layer2D'); + obj._touch = new SFNode('TouchSensor'); + obj._highlight = gw_new_rectangle(class_name, 'invisible'); + + obj._show_highlight = false; + obj._is_icon = false; + obj._tooltip = true; + if (class_name == 'icon') { + obj._is_icon = true; + } + else if (class_name == 'icon_label') { + obj._is_icon = true; + obj._show_highlight = false; + class_name = 'checkbox'; + } + else if (class_name == 'listitem') { + obj._is_icon = true; + obj._show_highlight = true; + obj._tooltip = false; + } else { + obj._highlight = gw_new_rectangle(class_name, 'invisible'); + obj._show_highlight = true; + } + + if (obj._highlight) + obj.children[0] = obj._highlight; + + obj.children[obj.children.length] = obj._icon_root; + obj.children[obj.children.length] = obj._touch; + obj._label = null; + + var skip_label = (label == null) ? true : false; + + if (!skip_label && gwskin.get_font(class_name) != null) { + obj._label = gw_new_text(obj, label, class_name); + if (horizontal) { + obj.set_size = function (width, height) { + this._icon_root.children[0].size.x = height; + this._icon_root.children[0].size.y = height; + this._icon_root.translation.x = (height - width) / 2; + if (this._highlight) + this._highlight.set_size(width, height); + this._label.set_width(width - height); + this._label.translation.x = height - width / 2; + this.width = width; + this.height = height; + }; + } else { + obj.set_size = function (width, height) { + var fsize = this._label.font_size(); + + var h = height - fsize - gwskin.default_icon_text_spacing; + this._icon_root.children[0].size.x = h; + this._icon_root.children[0].size.y = h; + this._icon_root.translation.y = (height - h) / 2; + var w = width; + if (this._highlight) + this._highlight.set_size(w, height); + this._label.set_width(w); + this._label.translation.y = -height / 2 + fsize / 2; + this.width = w; + this.height = height; + }; + } + obj.set_label = function (label) { + this._label.set_label(label); + } + obj.get_label = function () { + return this._label.get_label(); + } + } else { + obj.set_size = function (width, height) { + this._icon_root.children[0].size.x = width; + this._icon_root.children[0].size.y = height; + if (this._highlight) + this._highlight.set_size(width, height); + this.width = width; + this.height = height; + }; + obj.set_label = function (label) { + this.label = label; + } + obj.get_label = function () { + return this.label; + } + } + + obj._last_ts = 0; + obj.on_long_click = NULL; + obj.on_click = NULL; + obj.on_over = null; + obj.down = false; + obj.over = false; + obj._on_active = function (value, timestamp) { + if (value) { + this.down = true; + if (this._is_icon) { + var app = gwskin.get_style(class_name, 'down'); + this._icon_root.children[0].children[0].set_style(app); + } + + if (this._show_highlight) { + this._highlight.set_style(class_name, 'down'); + } + + this._last_ts = timestamp; + } else { + if (this._is_icon) { + var app = gwskin.get_style(class_name, (this.over && gwskin.pointing_device) ? 'over' : 'normal'); + this._icon_root.children[0].children[0].set_style(app); + } + + if (this._show_highlight) { + this._highlight.set_style(class_name, (this.over && gwskin.pointing_device) ? 'over' : 'invisible'); + } + + if (this.down) { + if (this.on_long_click && (timestamp - this._last_ts > gwskin.long_click_delay)) this.on_long_click(); + else if (this.on_click) this.on_click(); + } + this.down = false; + } + }; + obj._on_over = function (value) { + this.over = value; + gw_reset_hit(this, value); + + if (gwskin.pointing_device) { + if (this._is_icon) { + var app = gwskin.get_style(class_name, value ? 'over' : 'normal'); + if (app) { + this._icon_root.children[0].children[0].set_style(app); + } + } + + if (this._show_highlight) { + this._highlight.set_style(class_name, value ? 'over' : 'invisible'); + } + + if (this.on_over) this.on_over(value); + if (this._tooltip && gwskin.tooltip_callback) gwskin.tooltip_callback(this, value); + } + }; + Browser.addRoute(obj._touch, 'isOver', obj, obj._on_over); + Browser.addRoute(obj._touch, 'isActive', obj, obj._on_active); + + obj.icons = []; + obj.add_icon = function (url) { + + if (typeof url == 'string') { + var inl; + if (typeof gwskin.images[url] != 'undefined') { + inl = gw_load_resource(gwskin.images[url], this._is_icon); + } else { + inl = gw_load_resource(url, this._is_icon); + } + } else { + var inl = url; + } + this.icons[this.icons.length] = inl; + + if (this._icon_root.children[0].children.length == 0) { + this._icon_root.children[0].children[0] = this.icons[0]; + } + } + obj.switch_icon = function (idx) { + while (idx > this.icons.length) idx -= this.icons.length; + this._icon_root.children[0].children[0] = this.icons[idx]; + } + obj._pre_destroy = function () { + for (var i in this.icons) { + gw_unload_resource(this.icons[i]); + } + this.icons.length = 0; + this._highlight = null; + this._icons = null; + this._label = null; + Browser.deleteRoute(this._touch, 'ALL', null, null); + this._touch = null; + } + + if (icon_url) obj.add_icon(icon_url); + obj.set_label(label); + + obj.enable = function() { + this._touch.enabled = true; + this._on_over(false); + } + obj.disable = function() { + this._touch.enabled = false; + var app = gwskin.get_style(class_name, 'disable'); + if (app) { + this._icon_root.children[0].children[0].set_style(app); + } + } + + + obj.on_event = function () { return false; } + + if (0 && (typeof gwskin[class_name] != 'undefined') && (typeof gwskin[class_name].height != 'undefined')) { + obj.set_size(gwskin[class_name].height, gwskin[class_name].height); + } else { + obj.set_size(gwskin.default_control_height, gwskin.default_control_height); + } + gw_add_child(parent, obj); + return obj; +} + +function gw_new_icon(parent, icon_name) { + return gw_new_icon_button(parent, gwskin.images[icon_name], gwskin.labels[icon_name], false, 'icon'); +} + +function gw_new_checkbox(parent, label) { + var touch; + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'CheckBox'); + + obj._icon_root = new SFNode('Transform2D'); + obj._icon_root.children[0] = new SFNode('Layer2D'); + obj._touch = new SFNode('TouchSensor'); + + var class_name = 'checkbox'; + + obj.children[0] = gw_new_rectangle(class_name, 'invisible'); + obj.children[1] = obj._icon_root; + gw_new_text(obj, label, class_name); + obj.children[3] = obj._touch; + + obj.set_size = function (width, height) { + this._icon_root.children[0].size.x = height; + this._icon_root.children[0].size.y = height; + this._icon_root.translation.x = (height - width) / 2; + this.children[0].set_size(width, height); + this.children[2].set_width(width - height); + this.children[2].translation.x = (height - width) / 2 + height; + this.width = width; + this.height = height; + }; + + obj.set_label = function (label) { + this.children[2].set_label(label); + } + obj.get_label = function () { + return this.children[2].get_label(); + } + obj.on_check = NULL; + obj.down = false; + obj.over = false; + obj._checked = false; + obj._on_active = function (value, timestamp) { + if (value) { + this.down = true; + } else { + if (this.down && this.over) { + this._set_checked(!this._checked); + if (this.on_check) this.on_check(this._checked); + } + this.down = false; + } + }; + obj._on_over = function (value) { + this.over = value; + gw_reset_hit(this, value); + + if (gwskin.pointing_device) { + var app = gwskin.get_style(class_name, value ? 'over' : (this._checked ? 'down' : 'normal') ); + if (app) { + this._icon_root.children[0].children[0].set_style(app); + } + if (this.on_over) this.on_over(value); + if (gwskin.tooltip_callback) gwskin.tooltip_callback(this, value); + } + }; + Browser.addRoute(obj._touch, 'isOver', obj, obj._on_over); + Browser.addRoute(obj._touch, 'isActive', obj, obj._on_active); + + + obj._set_checked = function (value) { + this._checked = value; + var app = gwskin.get_style(class_name, value ? 'down' : 'normal'); + this._icon_root.children[0].children[0].set_style(app); + } + obj.set_checked = function (value) { + this._set_checked(value); + } + obj._icon_root.children[0].children[0] = gw_load_resource(gwskin.images.check, true); + + obj._pre_destroy = function () { + for (var i in this.icons) { + gw_unload_resource(this.icons[i]); + } + Browser.deleteRoute(this._touch, 'ALL', null, null); + this._touch = null; + this._icon_root = null; + } + obj.set_label(label); + + obj.on_event = function () { return false; } + + if (0 && (typeof gwskin[class_name] != 'undefined') && (typeof gwskin[class_name].height != 'undefined')) { + obj.set_size(gwskin[class_name].height, gwskin[class_name].height); + } else { + obj.set_size(gwskin.default_control_height, gwskin.default_control_height); + } + gw_add_child(parent, obj); + return obj; +} + + + +function gw_new_spincontrol(parent, horizontal) { + var touch; + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'SpinControl'); + + obj.value = 0; + if (arguments.length < 2) horizontal = false; + obj._horizontal = horizontal; + obj.on_click = function () { } + var tool = gw_new_icon(obj, horizontal ? 'right' : 'up'); + + obj.min = 0; + obj.max = -1; + tool.on_click = function () { + if (this.parent.min < this.parent.max) { + if (this.parent.value >= this.parent.max) { + return; + } + } + this.parent.value++; + this.parent.on_click(this.parent.value); + } + tool = gw_new_icon(obj, horizontal ? 'left' : 'down'); + tool.on_click = function () { + if (this.parent.min < this.parent.max) { + if (this.parent.value <= this.parent.min) { + return; + } + } + this.parent.value--; + this.parent.on_click(this.parent.value); + } + + obj.set_size = function (width, height) { + if (this._horizontal) { + this.children[0].set_size(width / 2, height); + this.children[1].set_size(width / 2, height); + this.children[0].translation.x = width / 4; + this.children[1].translation.x = -width / 4; + } else { + this.children[0].set_size(width, height / 2); + this.children[1].set_size(width, height / 2); + this.children[0].translation.y = height / 4; + this.children[1].translation.y = -height / 4; + } + this.width = width; + this.height = height; + }; + obj._idx = 0; + obj.on_event = function (evt) { + if (evt.type == GF_EVENT_KEYDOWN) { + var idx = this._idx; + if (this._horizontal) { + if (evt.keycode == 'Left') idx--; + else if (evt.keycode == 'Right') idx++; + else return false; + } else { + if (evt.keycode == 'Up') idx--; + else if (evt.keycode == 'Down') idx++; + else return false; + } + if (idx < 0) { + return false; + } + if (idx > 1) { + return false; + } + this._idx = idx; + gpac.set_focus(this.children[idx]); + return true; + } + return false; + } + + gw_add_child(parent, obj); + return obj; +} + + + + +function gw_new_subscene(parent) { + var inline = new SFNode('Inline'); + inline._name = 'Subscene'; + inline._pre_destroy = function () { + this.url[0] = ''; + this.url.length = 0; + } + inline.connect = function (url) { + this.url.length = 0; + this.url[0] = url; + } + gw_add_child(parent, inline); + return inline; +} + +function gw_new_button(parent, text, class_name) { + var label; + if (arguments.length < 3) class_name = 'button'; + obj = gw_new_rectangle(class_name, 'normal'); + label = gw_new_text(obj, text, class_name); + gw_object_set_hitable(obj); + obj.on_over = function (value) { + if (gwskin.pointing_device) { + this.set_style(class_name, value ? 'over' : 'normal'); + } + //if (gwskin.tooltip_callback) gwskin.tooltip_callback(this, value); + } + obj.on_down = function (val) { + this.set_style(class_name, val ? 'down' : (this._over ? 'over' : 'normal')); + } + + obj._set_size = obj.set_size; + obj.set_size = function (width, height) { + this._set_size(width, height); + this.children[1].set_size(width, height); + this.children[1].set_width(width); + }; + obj.set_label = function (label) { + this.children[1].set_label(label); + } + obj.get_label = function () { + return this.children[1].get_label(); + } + obj.set_labels = function () { + this.children[1].set_labels.apply(this.children[1], arguments); + } + obj.on_event = function (x, y) { return false; } + + obj.disable = function () { + this._disable_touch(); + } + obj.enable = function () { + this._enable_touch(); + } + + gw_add_child(parent, obj); + return obj; +} + + +function gw_new_gauge(parent, text) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'ProgressBar'); + + if (arguments.length <= 3) class_name = 'progress'; + + obj.children[0] = gw_new_rectangle(class_name, 'normal'); + obj.children[1] = gw_new_rectangle(class_name, 'over'); + gw_new_text(obj, text, class_name); + + + obj._value = 75; + obj._set_size = obj.set_size; + obj.set_size = function (width, height) { + this._set_size(width, height); + this.children[0].set_size(width, height); + + this.children[1].set_size(this._value * width / 100, height); + this.children[1].move((this._value - 100) * width / 200, 0); + + this.children[2].set_size(width, height); + this.children[2].set_width(width); + }; + obj.set_label = function (label) { + this.children[2].set_label(label); + } + obj.get_label = function () { + return this.children[2].get_label(); + } + + obj.set_value = function (val) { + this._value = (val > 100) ? 100 : ((val < 0) ? 0 : val); + this.set_size(this.width, this.height); + } + + obj.on_event = function (x, y) { return false; } + + gw_add_child(parent, obj); + return obj; +} + + + +function grid_event_navigate(dlg, children, type) { + var i; + if (dlg.current_focus == -1) { + if (type == 'Left') return false; + dlg.current_focus = 0; + gpac.set_focus(children[0]); + return true; + } + + if (type == 'Right') { + var orig_focus = dlg.current_focus; + var switch_page = 0; + var tr = children[dlg.current_focus].translation.y - children[dlg.current_focus].height / 2; + if (dlg.current_focus + 1 == children.length) { + dlg.current_focus = orig_focus; + gpac.set_focus(children[dlg.current_focus]); + return false; + } + /*goto right item*/ + dlg.current_focus++; + /*check we are not going down*/ + while (1) { + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2 > tr)) + break; + if (dlg.current_focus + 1 == children.length) { + dlg.current_focus = orig_focus; + gpac.set_focus(children[dlg.current_focus]); + return false; + } + dlg.current_focus++; + switch_page = 1; + } + /*check we haven't move to a new page*/ + if (children[orig_focus].translation.y + children[orig_focus].height / 2 <= children[dlg.current_focus].translation.y - children[dlg.current_focus].height / 2) { + switch_page = 1; + } + + } + else if (type == 'Left') { + var orig_focus = dlg.current_focus; + var switch_page = 0; + var tr = children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2; + if (!dlg.current_focus) { + dlg.current_focus = -1; + gpac.set_focus(null); + return false; + } + /*goto left item*/ + dlg.current_focus--; + /*check we are not going up*/ + while (1) { + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y - children[dlg.current_focus].height / 2 < tr)) + break; + if (!dlg.current_focus) { + dlg.current_focus = orig_focus; + return false; + } + dlg.current_focus--; + switch_page = -1; + } + /*check we haven't move to a new page*/ + if (children[orig_focus].translation.y - children[orig_focus].height / 2 >= children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2) { + switch_page = -1; + } + } + else if (type == 'Down') { + var orig_focus = dlg.current_focus; + var switch_page = 0; + var bottom_y = children[dlg.current_focus].translation.y - children[dlg.current_focus].height / 2; + var top_y = children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2; + if (dlg.current_focus + 1 == children.length) return false; + dlg.current_focus++; + /*goto next line*/ + while (1) { + //next child below current + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y - children[dlg.current_focus].height / 2 < bottom_y)) + break; + //next child above current - we need a page swicth + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2 > top_y)) { + switch_page = 1; + break; + } + //not found + if (dlg.current_focus + 1 == children.length) { + dlg.current_focus = orig_focus; + return false; + } + dlg.current_focus++; + } + /*find closest item on the left*/ + var tx = children[orig_focus].translation.x - children[orig_focus].width / 2; + while (1) { + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.x + children[dlg.current_focus].width / 2 > tx)) + break; + if (dlg.current_focus + 1 == children.length) break; + dlg.current_focus++; + } + } + else if (type == 'Up') { + var orig_focus = dlg.current_focus; + var switch_page = 0; + var bottom_y = children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2; + var top_y = children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2; + if (!dlg.current_focus) return false; + dlg.current_focus--; + /*goto previous line*/ + while (1) { + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2 > top_y)) + break; + //next child below current - we need a page swicth + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.y + children[dlg.current_focus].height / 2 < bottom_y)) { + switch_page = -1; + break; + } + if (!dlg.current_focus) { + dlg.current_focus = orig_focus; + return false; + } + dlg.current_focus--; + } + /*goto above child*/ + var tx = children[orig_focus].translation.x + children[orig_focus].width / 2; + while (1) { + if (children[dlg.current_focus].visible && (children[dlg.current_focus].translation.x - children[dlg.current_focus].width / 2 < tx)) + break; + if (!dlg.current_focus) { + dlg.current_focus = orig_focus; + return false; + } + dlg.current_focus--; + } + } else { + return false; + } + if (switch_page == 1) return dlg.on_next_page(); + else if (switch_page == -1) return dlg.on_prev_page(); + if (typeof children[dlg.current_focus].on_event == 'undefined') { + return grid_event_navigate(dlg, children, type); + } + + gpac.set_focus(children[dlg.current_focus]); + return true; +} + + + +function gw_new_grid_container(parent) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Layout'); + + obj.children[0] = new SFNode('Layer2D'); + obj._container = new SFNode('Transform2D'); + obj.children[0].children[0] = obj._container; + obj._all_children = []; + obj._pages = []; + + obj.on_page_changed = null; + + obj.on_prev_page = function () { + this._move_page(-1); + return true; + }; + obj.on_next_page = function () { + this._move_page(1); + return true; + }; + + obj.is_first_page = function () { + return this._page_idx == 0 ? true : false; + } + obj.is_last_page = function () { + return this._page_idx == (this._pages.length - 1) ? true : false; + } + obj._page_idx = 0; + obj._max_page_idx = 0; + obj._move_page = function (value) { + this._page_idx += value; + var i, child, last_child = 0; + + if (this._page_idx <= 0) { + this._page_idx = 0; + } + + if (this._page_idx * this.width >= this.max_width) { + this._page_idx = this.max_width / this.width; + } + + this._container.translation.x = -this._page_idx * this.width; + this._container.children.length = 0; + if (this._page_idx + 1 >= this._pages.length) { + last_child = this._all_children.length; + } else { + last_child = this._pages[this._page_idx + 1]; + } + + i = 0; + child = this._pages[this._page_idx]; + if (this.current_focus >= 0) { + if (this.current_focus < child) this.current_focus = child; + else if (this.current_focus >= last_child) this.current_focus = last_child - 1; + gpac.set_focus(this._all_children[this.current_focus]); + } + + + while (child < last_child) { + this._container.children[i] = this._all_children[child]; + child++; + i++; + } + if (this.on_page_changed) this.on_page_changed(); + + } - if (filelist.length) { - this.directory = filelist[0].path; - this.set_label(this.directory); - } else { - this.set_label(''); - } + obj.spread_h = false; + obj.spread_v = false; + obj.break_at_hidden = false; + obj.break_at_line = 0; - this.area.reset_children(); - - this.set_label(this.directory); + obj.set_focus_last = function () { + this._page_idx = this._pages.length ? this._pages.length - 1 : 0; + this.current_focus = this._all_children.length; + this._move_page(0); + } + obj.set_focus_first = function () { + this._page_idx = 0; + this.current_focus = 0; + this._move_page(0); + } - this.path = filelist.length ? filelist[0].path : ''; + obj.set_size = function (width, height) { + this.width = width; + this.height = height; + this.children[0].size.x = width; + this.children[0].size.y = height; + this.nb_visible = 0; + this.current_focus = -1; + this.layout(); + } + obj.max_width = 0; + obj.layout = function () { + var spread_x, nb_wid_h, start_x, start_y, maxh, width, height, page_x, nb_on_line; + var children = this._all_children; + var width = this.width; + var height = this.height; + + if (width <= 0) return; + if (height <= 0) return; + + if (typeof this.on_size != 'undefined') + this.on_size(width, height); + + var page_x = 0; + var maxh = 0; + var spread_x = -1; + var start_x = -width / 2; + var init_y = this.height / 2; + var start_y = init_y; + var nb_on_line = 0; + + this._pages = [0]; + + for (var i = 0; i < children.length; i++) { + + //start of line: compute H spread and max V size + if (spread_x == -1) { + var j = 0, len = 0, maxh = 0, nb_child = 0, nb_spread_child = 0; + start_x = -width / 2 + page_x; + while (1) { + if (!children[i + j].visible) { + j++; + if (i + j == children.length) break; + if (this.break_at_hidden) break; + if (typeof (children[i+j-1].__separator) == 'boolean') break; + continue; + } + if (len + children[i + j].width > width) break; + len += children[i + j].width; + if (maxh < children[i + j].height) maxh = children[i + j].height; + j++; + nb_child++; + if ((i + j < children.length) && (typeof children[i+j].stick_to_previous == 'boolean') && children[i+j].stick_to_previous) { + } else { + nb_spread_child++; + } + + if (this.break_at_line) break; + if (i + j == children.length) break; + } + if (nb_child <= 1) { + maxh = children[i].height; + if (this.spread_h && !this.break_at_line) start_x = -len / 2; + } + else if (this.spread_h && nb_spread_child) { + spread_x = (width - len) / (nb_spread_child); + start_x += spread_x / 2; + } else { + spread_x = 0; + } + } + + if (!children[i].visible) { + if (nb_on_line && ( this.break_at_hidden || (typeof (children[i].__separator) == 'boolean')) ) { + + nb_on_line = 0; + spread_x = -1; + start_y -= maxh / 2; + start_x = -width / 2; + } + continue; + } + if (start_y - maxh < -height / 2) { + //push new page only if not empty! (otherwise we've been asked to layout in a too small grid ...) + if (!this._pages.length || this._pages[this._pages.length - 1] < i) { + nb_on_line = 0; + page_x += width; + spread_x = -1; + start_y = init_y; + this._pages.push(i); + i--; + continue; + } + } + children[i].translation.x = start_x + children[i].width / 2; + children[i].translation.y = start_y - maxh / 2; + + if ((i + 1 < children.length) && (typeof children[i + 1].stick_to_previous == 'boolean') && children[i+1].stick_to_previous) { + start_x += children[i].width; + } else { + start_x += children[i].width + spread_x; + } + + nb_on_line++; + + if (i + 1 == children.length) { + break; + } + if ((nb_on_line == nb_child) || (start_x - page_x + children[i + 1].width > width / 2)) { + nb_on_line = 0; + spread_x = -1; + start_y -= maxh; + start_x = -width / 2; + } + } + this.max_width = page_x; + this._move_page(0); + } - for (i=0; i -1) this._all_children.splice(index, 1); + } - if (filelist[i].directory) { - item.on_click = this._on_dir_browse; - } else { - item.on_click = this._on_file_select; + obj.get_children = function () { + return this._all_children; + } + obj.reset_children = function () { + gw_close_child_list(this._all_children); + this._all_children.length = 0; + this._container.children.length = 0; + this._page_idx = 0; + this._max_page_idx = 0; } - } - this.layout(this.width, this.height); - if (this.directory == '') this.go_up.hide(); - else this.go_up.show(); - if (this.show_directory || (this.filter == 'dir')) this.scan_dir.show(); - else this.scan_dir.hide(); + obj.on_event = function (evt) { + switch (evt.type) { + case GF_EVENT_MOUSEWHEEL: + var inc = -evt.wheel; + if (this._pages.length <= 1) return 0; + if ((inc < 0) && (this._page_idx == 0)) return 0; + if ((inc > 0) && (this._page_idx >= this._pages.length - 1)) return 0; + this._move_page((inc < 0) ? -1 : 1); + return 1; + case GF_EVENT_KEYDOWN: + if ((evt.keycode == 'Up') || (evt.keycode == 'Down') || (evt.keycode == 'Right') || (evt.keycode == 'Left')) { + + if ((this.current_focus >= 0) && typeof this._all_children[this.current_focus].on_event != 'undefined') { + var res = this._all_children[this.current_focus].on_event(evt); + if (res) return res; + } + + return grid_event_navigate(this, this._all_children, evt.keycode); + } + if ((evt.keycode == 'PageUp') && (this._page_idx > 0)) { + return this.on_prev_page(); + } + if ((evt.keycode == 'PageDown') && (this._page_idx < this._pages.length)) { + return this.on_next_page(); + } + return 0; + } + return 0; + } + + obj._pre_destroy = function () { + this.reset_children(); + this._container = null; + this._all_children.length = 0; + } - this.tools.layout(this.tools.width, this.tools.height); - } - dlg.scan_dir.hide(); + gw_add_child(parent, obj); + return obj; +} - dlg.on_size = function(width, height) { - dlg.area.set_size(width, height); - } - dlg.set_size(20, 20); - return dlg; +function gw_new_separator(parent) { + var obj = gw_new_container(); + obj.hide(); + obj.show = function() {}; + obj.__separator = true; + gw_add_child(parent, obj); + return obj; } +function gw_new_progress_bar(parent, vertical, with_progress, class_name) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'ProgressBar'); + var ps2d; + + if (arguments.length <= 3) class_name = 'progress'; + if (arguments.length <= 2) with_progress = false; + if (arguments.length <= 1) vertical = false; -function gw_new_text_input(text_data, class_name) -{ - var obj = gw_new_text(null, text_data, 'edit'); - obj.on_text = null; - obj._text_edited = function(val) { - if (this.on_text) this.on_text(val[0]); - } - Browser.addRoute(obj.children[0].children[0].geometry, 'string', obj, obj._text_edited); - return obj; + obj.children[0] = gw_new_rectangle(class_name, 'normal'); + + if (with_progress) { + obj.children[1] = gw_new_rectangle(class_name, 'down'); + if (vertical) { + obj.children[1].set_corners(true, false, false, true); + } else { + obj.children[1].set_corners(true, false, false, true); + } + obj.set_progress = function (prog) { + if (prog < 0) prog = 0; + else if (prog > 100) prog = 100; + this.prog = prog; + prog /= 100; + if (this.vertical) { + var pheight = prog * this.height; + this.children[1].set_size(this.width, pheight); + this.children[1].move(0, (this.height - pheight) / 2, 0); + } else { + var pwidth = prog * this.width; + this.children[1].set_size(pwidth, this.height); + this.children[1].move((pwidth - this.width) / 2, 0); + } + } + } else { + obj.set_progress = function (prog) { } + } + obj.slide_idx = obj.children.length; + obj.children[obj.slide_idx] = gw_new_rectangle(class_name, 'over'); + if (vertical) { + obj.children[obj.slide_idx].set_corners(true, false, false, true); + } else { + obj.children[obj.slide_idx].set_corners(true, false, false, true); + } + obj.children[obj.slide_idx + 1] = gw_new_rectangle(class_name, 'invisible'); + ps2d = new SFNode('PlaneSensor2D'); + obj.children[obj.slide_idx + 1].children[1] = ps2d; + ps2d.maxPosition.x = -1; + ps2d.maxPosition.y = -1; + + obj.on_slide = function (value, type) { } + + obj._with_progress = with_progress; + obj._sliding = false; + obj._slide_active = function (val) { + obj._sliding = val; + this.on_slide(this.min + (this.max - this.min) * this.frac, val ? 1 : 2); + } + Browser.addRoute(ps2d, 'isActive', obj, obj._slide_active); + + obj._set_trackpoint = function (value) { + if (this.vertical) { + this.frac = value.y / this.height; + } else { + this.frac = value.x / this.width; + } + this.frac += 0.5; + if (this.frac > 1) this.frac = 1; + else if (this.frac < 0) this.frac = 0; + + this._set_frac(); + this.on_slide(this.min + (this.max - this.min) * this.frac, 0); + } + Browser.addRoute(ps2d, 'trackPoint_changed', obj, obj._set_trackpoint); + + obj._set_frac = function () { + if (this.vertical) { + var pheight = this.frac * this.height; + if (pheight < this.width) pheight = this.width; + this.children[this.slide_idx].set_size(this.width, pheight); + this.children[this.slide_idx].move(0, (this.height - pheight) / 2, 0); + } else { + var pwidth = this.frac * this.width; + if (pwidth < this.height) pwidth = this.height; + this.children[this.slide_idx].set_size(pwidth, this.height); + this.children[this.slide_idx].move((pwidth - this.width) / 2, 0); + } + } + + obj.set_value = function (value) { + if (this._sliding) return; + + value -= this.min; + if (value < 0) value = 0; + else if (value > this.max - this.min) value = this.max - this.min; + if (this.max == this.min) value = 0; + else value /= (this.max - this.min); + + this.frac = value; + this._set_frac(); + } + + + obj.vertical = vertical; + obj.set_size = function (w, h) { + this.width = w; + this.height = h; + this.children[0].set_size(w, h); + if (this._with_progress) { + this.children[3].set_size(w, h); + } else { + this.children[2].set_size(w, h); + } + this._set_frac(); + this.set_progress(this.prog); + } + obj.min = 0; + obj.max = 100; + + obj.move = function (x, y) { + this.translation.x = x; + this.translation.y = y; + } + obj.on_event = function (x, y) { return false; } + + obj.prog = 0; + obj.frac = 0; + obj.set_size(vertical ? 10 : 200, vertical ? 200 : 10); + + gw_add_child(parent, obj); + return obj; } -function gw_new_text_edit(parent, text_data) -{ - var obj = new SFNode('Transform2D'); - var rect, edit; - setup_gw_object(obj, 'TextEdit'); - rect = gw_new_rectangle('edit'); - gw_add_child(obj, rect); - gw_object_set_hitable(rect); - rect.on_down = function(val) { - if (val) gpac.set_focus( this.parent.children[1] ); - } - - edit = gw_new_text(null, text_data, 'edit') - gw_add_child(obj, edit); - obj.on_text = null; - obj._text_edited = function(val) { - if (this.on_text) this.on_text(val[0]); - }; - Browser.addRoute(obj.children[1].children[0].children[0].geometry, 'string', obj, obj._text_edited); - - obj.set_size = function(w, h) { - this.width = w; - this.height = h; - this.children[0].set_size(w, h); - this.children[1].move(5-w/2, 0); - }; - - gw_add_child(parent, obj); - - /*set focus to our edit node*/ - gpac.set_focus(edit); - - return obj; -} - -function gw_new_text_area(parent, text_data, class_name) -{ - var obj = new SFNode('Transform2D'); - setup_gw_object(obj, 'TextEdit'); +function gw_new_slider(parent, vertical, class_name) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Slider'); + + if (arguments.length <= 2) class_name = 'progress'; + if (arguments.length <= 1) vertical = false; + + obj.children[0] = gw_new_rectangle(class_name, 'normal'); + obj.children[1] = gw_new_rectangle(class_name, 'over'); + obj.children[2] = gw_new_rectangle(class_name, 'invisible'); + + var ps2d = new SFNode('PlaneSensor2D'); + obj.children[2].children[1] = ps2d; + ps2d.maxPosition.x = -1; + ps2d.maxPosition.y = -1; + obj.on_slide = function (value, type) { } + + obj.slide_active = function (val) { + this.on_slide(this.min + (this.max - this.min) * this.frac, val ? 1 : 2); + } + Browser.addRoute(ps2d, 'isActive', obj, obj.slide_active); + obj.set_trackpoint = function (value) { + if (vertical) { + if (this.height == this.children[1].height) return; + this.frac = value.y / (this.height - this.children[1].height); + } else { + if (this.width == this.children[1].width) return; + + this.frac = value.x / (this.width - this.children[1].width); + } + this.frac += 0.5; + if (this.frac > 1) this.frac = 1; + else if (this.frac < 0) this.frac = 0; + if (vertical) { + value.y = (this.frac - 0.5) * (this.height - this.children[1].height); + value.x = 0; + } else { + value.x = (this.frac - 0.5) * (this.width - this.children[1].width); + value.y = 0; + } + this.children[1].translation = value; + this.on_slide(this.min + (this.max - this.min) * this.frac, 0); + } + Browser.addRoute(ps2d, 'trackPoint_changed', obj, obj.set_trackpoint); + + obj.set_value = function (value) { + if (this.children[2].isActive) return; + + value -= this.min; + if (value < 0) value = 0; + else if (value > this.max - this.min) value = this.max - this.min; + if (this.max == this.min) value = 0; + else value /= (this.max - this.min); + + this.frac = value; + + value -= 0.5; + value *= (vertical ? this.height : this.width); + + if (vertical) { + this.children[1].translation.y = value; + } else { + this.children[1].translation.x = value; + } + } + obj.vertical = vertical; + obj.set_size = function (w, h, cursor_w, cursor_h) { + if (this.height && this.width) { + if (this.vertical) { + this.children[1].translation.y *= h; + this.children[1].translation.y /= this.height; + } else { + this.children[1].translation.x *= w; + this.children[1].translation.x /= this.width; + } + } + + this.width = w; + this.height = h; + this.children[0].set_size(w, h); + + if (typeof (cursor_w) == 'undefined') cursor_w = this.children[1].width; + if (typeof (cursor_h) == 'undefined') cursor_h = this.children[1].height; + this.children[1].set_size(cursor_w, cursor_h); + + if (this.vertical) { + this.children[2].set_size(this.children[1].width, h); + } else { + this.children[2].set_size(w, this.children[1].height); + } + } + obj.set_cursor_size = function (w, h) { + this.children[1].set_size(w, h); + } + obj.min = 0; + obj.max = 100; + obj.frac = 0.0; + obj.height = 0; + obj.width = 0; + obj.set_size(vertical ? 10 : 200, vertical ? 200 : 10, 10, 10); + + obj.set_trackpoint(0); + + obj.move = function (x, y) { + this.translation.x = x; + this.translation.y = y; + } + obj.on_event = function (x, y) { return false; } + + gw_add_child(parent, obj); + return obj; +} + + +function gw_new_text_edit(parent, text_data) { + var obj = new SFNode('Transform2D'); + var rect, edit; + setup_gw_object(obj, 'TextEdit'); + rect = gw_new_rectangle('edit'); + gw_add_child(obj, rect); + gw_object_set_hitable(rect); + rect.on_down = function (val) { + if (val) gpac.set_focus(this.parent.children[1]); + } + + edit = gw_new_text(obj, text_data, 'edit') + // gw_add_child(obj, edit); + obj.on_text = null; + obj._text_edited = function (val) { + if (this.on_text) this.on_text(val[0]); + }; + Browser.addRoute(obj.children[1].children[0].children[0].geometry, 'string', obj, obj._text_edited); + + obj.set_size = function (w, h) { + this.width = w; + this.height = h; + this.children[0].set_size(w, h); + this.children[1].move(5 - w / 2, 0); + }; + obj.on_event = function (x, y) { return false; } + + + gw_add_child(parent, obj); + return obj; +} + +function gw_new_text_area(parent, text_data) { + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'TextArea'); + + obj.children[0] = new SFNode('Layout'); + obj.children[0].parent = obj; + obj.children[0].wrap = true; + obj.children[0].spacing = 1.1; + obj.children[0].justify[0] = "JUSTIFY"; + obj.children[0].justify[1] = "FIRST"; + + gw_new_text(obj.children[0], text_data, 'text'); + obj.set_size = function (width, height) { + this.children[0].size.x = width; + this.children[0].size.y = height; + this.width = width; + this.height = height; + } + obj.set_content = function (text) { + this.children[0].children[0].set_label(text); + } + + obj.on_event = function (x, y) { return false; } + + gw_add_child(parent, obj); + return obj; +} + + + +function gw_new_scrolltext_area(parent, text_data) { + var obj = gw_new_text_area(parent, text_data); + /*erase the resize routine*/ + obj._orig_set_size = obj.set_size; + obj.set_size = function (width, height) { + var bounds = this._bounds; + this.width = width; + this.height = Math.ceil(bounds.height); + this._orig_set_size(width, height); + } + + obj.set_content = function (text) { + this.set_label(text); + } + return obj; +} + +function gw_new_window_full(parent, offscreen, the_label, child_to_insert) { + var wnd = gw_new_window(parent, offscreen, true); + + if (arguments.length <= 3) child_to_insert = null; + if (child_to_insert) { + gw_add_child(wnd, child_to_insert); + } + + wnd.area = null; + + wnd.tools = gw_new_grid_container(wnd); + wnd.tools._name = 'ToolBar'; + wnd._has_extra_tools = false; + + wnd.label = null; + if (the_label) { + wnd.label = gw_new_text(wnd.tools, the_label, 'window'); + wnd.label._name = 'Label'; + } + + wnd.set_label = function (label) { + if (wnd.label) wnd.label.set_label(label); + } + + + wnd.add_tool = function (icon, name) { + var tool; + if (typeof gwskin.images[icon] != 'undefined') { + tool = gw_new_icon(this.tools, icon); + } else { + tool = gw_new_icon_button(this.tools, icon, name, false, 'icon'); + } + if (this.label) { + this.tools.remove_child(this.label); + this.tools.add_child(this.label); + } + tool.set_size(gwskin.default_icon_height, gwskin.default_icon_height); + tool._name = name; + tool.dlg = this; + this._has_extra_tools = true; + return tool; + } + + + var icon = wnd.add_tool('close'); + icon.on_click = function () { + this.dlg.close(); + } + wnd._has_extra_tools = false; + + wnd._pre_destroy = function () { + if (typeof this.predestroy != 'undefined') this.predestroy(); + this.tools = null; + this.label = null; + this.area = null; + this._wnd_close(); + } + + wnd.on_size = null; + wnd.layout = function (width, height) { + var i; + var tools = this.tools.get_children(); + var tool_size = gwskin.default_icon_height; - obj.children[0] = new SFNode('Layout'); - obj.children[0].parent = obj; - obj.children[0].wrap = true; - obj.children[0].justify[0] = "JUSTIFY"; - obj.children[0].justify[1] = "FIRST"; + if (this.on_size) this.on_size(width, height - tool_size); - gw_new_text(obj.children[0], text_data,class_name); - obj.set_size = function(width, height) { - this.children[0].size.x = width; - this.children[0].size.y = height; - this.width = width; - this.height = height; - } - obj.set_content = function(text) { - this.children[0].children[0].set_label(text); - } + if (this.area) { + this.area.set_size(width, height - tool_size); + this.area.move(0, (this.area.height - height) / 2); + } + for (i = 0; i < tools.length; i++) { + tools[i].set_size(tool_size, tool_size); + } + + if (this.label) { + var textw = width; + for (i = 0; i < tools.length; i++) { + if ((tools[i] != this.label) && tools[i].visible) + textw -= tools[i].width; + } + textw -= tool_size; + if (textw < 0) textw = 0; + this.label.set_size(textw, tool_size); + this.label.set_width(textw); + } + + this.tools.move(0, (height - tool_size) / 2); + this.tools.set_size(width, tool_size); + } + + wnd.on_event = function (evt) { + if ((evt.type == GF_EVENT_KEYUP) && (evt.keycode == gwskin.keys.close)) { + this.close(); + return 1; + } + if ((evt.type == GF_EVENT_KEYUP) && (evt.keycode == gwskin.keys.validate)) { + if (typeof this.on_validate == 'function') { + this.on_validate(); + return 1; + } + return 0; + } + if (!this._has_extra_tools) { + if (this.area) return this.area.on_event(evt); + return false; + } + + if (!this.area) { + return this.tools.on_event(evt); + } + + var is_left_or_right = (evt.type == GF_EVENT_KEYDOWN) && ((evt.keycode == 'Left') || (evt.keycode == 'Right')) ? 1 : 0; + if (this._focus_is_tools) { + if (this.tools.on_event(evt)) return 1; + if (this.area.on_event(evt)) { + //focus no longer on toolbar but on main content (means this is 'right'), switch order + if (is_left_or_right) { + this._focus_is_tools = false; + } + return 1; + } + } else { + if (this.area.on_event(evt)) return 1; + if (this.tools.on_event(evt)) { + //focus no longer on main but on toolbar content (means this is 'left'), switch order + if (is_left_or_right) { + this._focus_is_tools = true; + } + return 1; + } + } + return 0; + } + wnd._focus_is_tools = true; + return wnd; +} - gw_add_child(parent, obj); - return obj; +function gw_new_message(container, label, content) { + var notif = gw_new_window_full(container, true, label); + notif.area = gw_new_text_area(notif, content); + notif.on_size = function (width, height) { + this.area.set_size(width - 10, height); + } + notif.set_size(0.8 * gw_display_width, 120); + + notif.timer = gw_new_timer(false); + notif.timer.wnd = notif; + notif.timer.set_timeout(gwskin.default_message_timeout, false); + notif.timer.start(0); + notif.timer.on_active = function (val) { + if (!val) this.wnd.close(); + } + notif.show_effect = 'notif'; + notif._no_focus = true; + return notif; } +function gw_new_confirm_wnd(container, label, confirm_yes, confirm_no) { + if (arguments.length < 4) confirm_no = 'no'; + if (arguments.length < 3) confirm_yes = 'yes'; + + var notif = gw_new_window_full(container, true, label); + notif.area = gw_new_grid_container(notif); + notif.area.spread_h = true; + + notif.on_confirm = null; + notif.btn_yes = gw_new_button(notif.area, confirm_yes); + notif.btn_yes.dlg = notif; + notif.btn_yes.on_click = function () { + if (this.dlg.on_confirm) this.dlg.on_confirm(true); + this.dlg.close(); + } + + notif.btn_no = gw_new_button(notif.area, confirm_no); + notif.btn_no.dlg = notif; + notif.btn_no.on_click = function () { + if (this.dlg.on_confirm) this.dlg.on_confirm(false); + this.dlg.close(); + } + notif.on_close = function () { + if (this.on_confirm) this.on_confirm(false); + } + + notif.on_display_size = function (width, height) { + var w = 0.9*width; + if (w>500) w=500; + this.btn_yes.set_size(w / 3, gwskin.default_control_height); + this.btn_no.set_size(w / 3, gwskin.default_control_height); + this.set_size(w, 2 * gwskin.default_control_height); + } + notif.on_display_size(gw_display_width, gw_display_height); + return notif; +} -function gw_new_scrolltext_area(parent, text_data, class_name) +function gw_guess_mime_icon(name) { - var obj = gw_new_listbox(parent); - var child = gw_new_text_area(obj, text_data, class_name); - /*erase the resize routine*/ - child.set_size = function(width, height) { - var bounds = this.children[0]._bounds; - this.children[0].size.x = width; - this.children[0].size.y = Math.ceil(bounds.height); - this.width = width; - this.height = this.children[0].size.y; - } - - obj._orig_set_size = obj.set_size; - obj.set_size = function(width, height) { - this.get_children()[0].set_size(width, height); - this._orig_set_size(width, height); - } - obj.set_content = function(text) { - this.get_children()[0].set_label(text); - } - return obj; -} - - -function gw_new_message(container, label, content) + + var ext = name.split('.').pop(); + var reg = new RegExp(' ' + ext + ' ', "gi"); + //check default extensions + if (gwskin.mime_video_default_ext.match(reg)) return gwskin.images.mime_video; + else if (gwskin.mime_audio_default_ext.match(reg)) return gwskin.images.mime_audio; + else if (gwskin.mime_image_default_ext.match(reg)) return gwskin.images.mime_image; + else if (gwskin.mime_model_default_ext.match(reg)) return gwskin.images.mime_model; + + var idx = 0; + while (1) { + var mime = gpac.get_option('MimeTypes', idx); + if (mime == null) break; + idx++; + var mime_ext = gpac.get_option('MimeTypes', mime).split('"')[1]; + if (!mime_ext.match(reg)) continue; + + if (mime.indexOf('video') != -1) return gwskin.images.mime_video; + else if (mime.indexOf('audio') != -1) return gwskin.images.mime_audio; + else if (mime.indexOf('model') != -1) return gwskin.images.mime_model; + else if (mime.indexOf('image') != -1) return gwskin.images.mime_image; + else if (mime.indexOf('application') != -1) return gwskin.images.mime_model; + + break; + } + return gwskin.images.mime_generic; +} + + +function gw_new_file_dialog(container, label) { + var dlg = gw_new_window_full(container, true, label); + + dlg.area = gw_new_grid_container(dlg); + dlg.area.break_at_line = true; + dlg.area.dlg = dlg; + + dlg.on_close = function () { + if (this.do_sort_wnd) { + this.do_sort_wnd.close(); + } + if (this.on_browse) { + this.on_browse(null, false); + } + } + + + dlg._sort_type = 0; + dlg.do_sort = function (value) { + this._page_idx = 0; + this._max_page_idx = 0; + + switch (value) { + case 0: + this.area._all_children.sort(function (a, b) { var A = a.filename.toLowerCase(); var B = b.filename.toLowerCase(); if (A > B) { return 1; } else if (A < B) { return -1; } else return 0; }); + break; + case 1: + this.area._all_children.sort(function (b, a) { var A = a.filename.toLowerCase(); var B = b.filename.toLowerCase(); if (A > B) { return 1; } else if (A < B) { return -1; } else return 0; }); + break; + case 2: + this.area._all_children.sort(function (a, b) { return a.size - b.size }); + break; + case 3: + this.area._all_children.sort(function (a, b) { return b.size - a.size }); + break; + case 4: + this.area._all_children.sort(function (a, b) { return a.date - b.date }); + break; + case 5: + this.area._all_children.sort(function (a, b) { return b.date - a.date }); + break; + } + this.area.layout(); + } + + dlg.go_up = dlg.add_tool('up'); + dlg.go_up.on_click = function () { + this.dlg._browse(null, true); + } + + dlg.go_prev = dlg.add_tool('previous'); + dlg.go_prev.on_click = function () { + this.dlg.area._move_page(-1); + } + + dlg.go_next = dlg.add_tool('next'); + dlg.go_next.on_click = function () { + this.dlg.area._move_page(1); + } + + dlg.go_root = dlg.add_tool('device'); + dlg.go_root.on_click = function () { + this.dlg._browse('/'); + } + + dlg.sort = dlg.add_tool('sort'); + dlg.sort_wnd = null; + dlg.sort.on_click = function() { + if (this.dlg.sort_wnd) { + this.dlg.sort_wnd.close(); + this.dlg.sort_wnd = null; + return; + } + var wnd = gw_new_popup(this.dlg.sort, 'down'); + this.dlg.sort_wnd = wnd; + + wnd.dlg = this.dlg; + wnd.on_close = function() { + this.dlg.sort_wnd = null; + } + wnd.add_menu_item('by Name', function () { + var wnd = this.dlg; + if (wnd._sort_type==0) wnd._sort_type = 1; + else wnd._sort_type = 0; + wnd.do_sort(wnd._sort_type); + } ); + + wnd.add_menu_item('by Size', function () { + var wnd = this.dlg; + if (wnd._sort_type==2) wnd._sort_type = 3; + else wnd._sort_type = 2; + wnd.do_sort(wnd._sort_type); + } ); + + wnd.add_menu_item('by Date', function () { + var wnd = this.dlg; + if (wnd._sort_type==4) wnd._sort_type = 5; + else wnd._sort_type = 4; + wnd.do_sort(wnd._sort_type); + } ); + + wnd.on_display_size(gw_display_width, gw_display_height); + wnd.show(); + } + + dlg.predestroy = function () { + this.go_up = null; + this.go_next = null; + this.go_prev = null; + this.go_root = null; + this.area.dlg = null; + } + + dlg.directory = ''; + dlg.show_directory = false; + dlg.filter = '*'; + + dlg._on_dir_browse = function () { + if (this.path) { + this.dlg._browse(this.path, false); + } else { + this.dlg._browse(this.dlg.path + this.filename, false); + } + } + dlg._on_file_select = function () { + if (this.dlg.on_browse) { + if (this.path) { + this.dlg.on_browse(this.path, null); + } else { + this.dlg.on_browse(this.dlg.path + this.filename, this.dlg.directory); + } + } + this.dlg.close(); + } + + dlg.area.on_page_changed = function () { + if (this.is_first_page()) this.dlg.go_prev.disable(); + else this.dlg.go_prev.enable(); + + if (this.is_last_page()) this.dlg.go_next.disable(); + else this.dlg.go_next.enable(); + + this.dlg.tools.layout(this.dlg.tools.width, this.dlg.tools.height); + } + + dlg.on_long_click = null; + + dlg.browse = function (dir) { + if (typeof dir == 'string') this.directory = dir; + + this._browse(dir, false); + } + dlg._browse = function (dir, up) { + var w, h, i, y; + var filelist; + var is_listing = ((dir==null) || (typeof dir == 'string')) ? false : true; + + if (is_listing) { + filelist = dir; + this.path = null; + } else { + if (dir) this.directory = dir; + if (up && !this.path) up = false; + filelist = gpac.enum_directory(this.directory, this.filter, up); + + if (filelist.length) { + this.directory = filelist[0].path; + this.set_label(this.directory); + } else { + this.set_label(''); + } + this.path = filelist.length ? filelist[0].path : ''; + } + + this.area.reset_children(); + + for (i = 0; i < filelist.length; i++) { + if (!is_listing && (filelist[i].hidden || filelist[i].system)) continue; + + var icon_name = gwskin.images.mime_generic; + + if ( (!is_listing || (typeof filelist[i].directory == 'boolean')) && (filelist[i].directory || (filelist[i].name.indexOf('.') < 0))) { + if (filelist[i].drive) icon_name = gwskin.images.drive; + else icon_name = gwskin.images.folder; + } else { + icon_name = gw_guess_mime_icon(is_listing ? filelist[i].path : filelist[i].name); + } + + var item = gw_new_icon_button(this.area, icon_name, filelist[i].name, true, 'listitem'); + item.dlg = this; + item.filename = filelist[i].name; + item.directory = filelist[i].directory; + item.set_size(this.width, gwskin.default_control_height); + item.path = is_listing ? filelist[i].path : null; + item.size = typeof filelist[i].size != 'undefined' ? filelist[i].size : 0; + item.date = typeof filelist[i].last_modified != 'undefined' ? filelist[i].last_modified : 0; + + if (filelist[i].directory) { + item.on_click = this._on_dir_browse; + } else { + item.on_click = this._on_file_select; + } + item.on_long_click = function () { + if (this.dlg.on_long_click) { + var path = this.path ? this.path : (this.dlg.directory + this.filename); + this.dlg.on_long_click(this.filename, path, this.directory); + } + } + + } + this.do_sort(this._sort_type); + + if (this.directory == '/') this.go_up.disable(); + else this.go_up.enable(); + + this.tools.layout(this.tools.width, this.tools.height); + } + + dlg.on_size = function (width, height) { + var __children = this.area.get_children(); + for (var i = 0; i < __children.length; i++) { + __children[i].set_size(width, gwskin.default_control_height); + } + this.area.set_size(width, height); + } + + return dlg; +} + + + +function gw_new_plotter(parent) { + var touch; + var obj = new SFNode('Transform2D'); + setup_gw_object(obj, 'Plotter'); + + obj.children[0] = new SFNode('Layer2D'); + + var class_name = 'plot'; + + obj.children[0].children[0] = gw_new_rectangle(class_name, 'normal'); + + obj.set_size = function (width, height) { + this.children[0].size.x = width; + this.children[0].size.y = height; + this.children[0].children[0].set_size(width, height); + + var w = 1; + var h = 1; + + for (var i = 0; i < this.series.length; i++) { + var s = this.series[i]; + s.scale = new SFVec2f(width - this.label_width, height); + s.but.set_size(this.label_width, 0.9*gwskin.default_text_font_size); + s.but.set_font_size(0.9 * gwskin.default_text_font_size); + s.translation.x = -this.label_width / 2; + } + this.width = width; + this.height = height; + } + + obj.label_width = 120; + + obj.series = []; + obj.add_serie = function (legend, units, r, g, b) { + var s = gw_new_curve2d('plot'); + s.set_color(r, g, b); + + s.dlg = this; + s.legend = legend; + s.units = units; + s.max_y = 0; + s.nb_refresh = 0; + + s.refresh_serie = function (serie, name_x, name_y, nb_x, factor) { + var s = serie[0]; + var count = serie.length; + + var first_x = s[name_x]; + + this.nb_refresh += 1; + if (this.nb_refresh == 50) { + this.max_y = 0; + this.nb_refresh += 1; + } + var max_y = this.max_y; + + + if (!factor) factor = 1; + for (var i = 0; i < serie.length; i++) { + var s = serie[i]; + if (max_y < s[name_y]) max_y = s[name_y]; + } + s = serie[0]; + + this.reset(); + for (var i = 0; i < count; i++) { + s = serie[i]; + //get x and y between -0.5 and 0.5, and scale to width + var x = s[name_x] - first_x; + x /= nb_x; + x -= 0.5; + //x *= 0.9; + + var y = s[name_y]; + if (max_y) y /= max_y; + y = -0.9 / 2 + 0.9 * y / factor; + + if (i) { + this.add_line_to(x, y); + } else { + this.add_move_to(x, y); + } + + if (i + 1 == count) { + this.but.move(0.5 * this.dlg.width - this.but.width / 2, (-0.9 / 2 + 0.9 / factor) * this.dlg.height); + this.but.set_label('' + this.legend + ':' + s[name_y] + ' ' + units); + this.but.show(); + } + } + } + this.children[0].children[this.children[0].children.length] = s; + this.series.push(s); + + s.scale.x = this.width; + s.scale.y = this.height; + + + s.but = gw_new_text(this, '' + legend, 'custom'); + s.but.set_align('END'); + s.but.set_color(r, g, b); + s.but.set_size(this.label_width, gwskin.default_text_font_size); + s.but.hide(); + return s; + + } + + + gw_add_child(parent, obj); + return obj; +} + +function gw_new_popup(anchor, type) { - var notif = gw_new_window_full(null, true, label, 'window'); - notif.area = gw_new_scrolltext_area(notif, content, 'window'); - notif.on_size = function(width, height) { - this.area.set_size(width-10, height); - } - notif.on_event = function(evt) { - if ((evt.type==GF_EVENT_KEYUP) && evt.keycode==gwskin.keys.close) { - this.close(); - return 1; - } - return this.area.on_event(evt); - } - notif.set_size(240, 120); - return notif; + var popup = gw_new_window(null, true, false, 'popup'); + popup.area = gw_new_grid_container(popup); + popup.anchor = anchor; + popup.type = (type=='up') ? 0 : 1; + + popup._nb_over = 0; + popup.add_menu_item = function (label, callback) { + var item = gw_new_button(this.area, label, 'window'); + item.wnd = this; + item.on_click = function () { + callback.call(this.wnd); + this.wnd.close(); + } + item.on_over_ex = function (value) { + this.wnd.update_visibility(); + } + item.new_over_handler(item.on_over_ex); + + item.set_corners(false, false, false, false); + return item; + } + popup.reposition = function() { + var pos = gw_get_adjusted_abs_pos(this.anchor, this.width, this.height, this.type); + this.move(pos.x, pos.y); + } + + popup.update_visibility = function() { + var nb_over = 0; + var children = this.area.get_children(); + for (var i=0; imax_s) max_s = s; + } + + for (var i=0; i + + + + + + + diff --git a/gui/icons/app.svg b/gui/icons/app.svg new file mode 100644 index 0000000..206e834 --- /dev/null +++ b/gui/icons/app.svg @@ -0,0 +1,35 @@ + + + + + + + + + + diff --git a/gui/icons/applications-internet.svg b/gui/icons/applications-internet.svg deleted file mode 100644 index 883dbd2..0000000 --- a/gui/icons/applications-internet.svg +++ /dev/null @@ -1,622 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Internet Category - - - Jakub Steiner - - - - - Tuomas Kuosmanen - - - - http://jimmac.musichall.cz - - - internet - tools - applications - category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/applications-system.svg b/gui/icons/applications-system.svg deleted file mode 100644 index 9d76774..0000000 --- a/gui/icons/applications-system.svg +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - System Applications - - - Jakub Steiner - - - http://jimmac.musichall.cz/ - - - system - applications - group - category - admin - root - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/audio-volume-high.svg b/gui/icons/audio-volume-high.svg deleted file mode 100644 index c8b4202..0000000 --- a/gui/icons/audio-volume-high.svg +++ /dev/null @@ -1,643 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Volume - High - - - Jakub Steiner - - - - - Lapo Calamandrei - - - - - - http://www.tango-project.org - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/audio-volume-low.svg b/gui/icons/audio-volume-low.svg deleted file mode 100644 index f29437c..0000000 --- a/gui/icons/audio-volume-low.svg +++ /dev/null @@ -1,641 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Volume - Low - - - Jakub Steiner - - - - - Lapo Calamandrei - - - - - - http://www.tango-project.org - - - - - volume - sound - level - low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/audio-volume-medium.svg b/gui/icons/audio-volume-medium.svg deleted file mode 100644 index e9bcb65..0000000 --- a/gui/icons/audio-volume-medium.svg +++ /dev/null @@ -1,646 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Volume - Medium - - - Jakub Steiner - - - - - Lapo Calamandrei - - - - - - http://www.tango-project.org - - - - - volume - sound - level - medium - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/audio-volume-muted.svg b/gui/icons/audio-volume-muted.svg deleted file mode 100644 index 3e8d570..0000000 --- a/gui/icons/audio-volume-muted.svg +++ /dev/null @@ -1,991 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Volume - Muted - - - Jakub Steiner - - - - - Lapo Calamandrei - - - - - - http://www.tango-project.org - - - - - volume - sound - level - none - mute - muted - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/audio-x-generic.svg b/gui/icons/audio-x-generic.svg deleted file mode 100644 index 239d001..0000000 --- a/gui/icons/audio-x-generic.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Generic Audio - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/audio.svg b/gui/icons/audio.svg new file mode 100644 index 0000000..92ad1e4 --- /dev/null +++ b/gui/icons/audio.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/gui/icons/audio_full.svg b/gui/icons/audio_full.svg new file mode 100644 index 0000000..395493a --- /dev/null +++ b/gui/icons/audio_full.svg @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/gui/icons/audio_mute.svg b/gui/icons/audio_mute.svg new file mode 100644 index 0000000..cf61438 --- /dev/null +++ b/gui/icons/audio_mute.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gui/icons/battery-caution.svg b/gui/icons/battery-caution.svg deleted file mode 100644 index 4eaa58f..0000000 --- a/gui/icons/battery-caution.svg +++ /dev/null @@ -1,625 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Battery - Caution - - - Jakub Steiner - - - http://jimmac.musichall.cz - - - battery - apm - acpi - power management - caution - - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/camera-photo.svg b/gui/icons/camera-photo.svg deleted file mode 100644 index 25435e0..0000000 --- a/gui/icons/camera-photo.svg +++ /dev/null @@ -1,681 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - Photo Camera - - - camera - photo - SLR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/camera-video.svg b/gui/icons/camera-video.svg deleted file mode 100644 index 28259eb..0000000 --- a/gui/icons/camera-video.svg +++ /dev/null @@ -1,1257 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Camera / Video - - - Jakub Steiner - - - http://jimmac.musichall.cz/ - - - camera - camcorder - video - cam - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/check.svg b/gui/icons/check.svg new file mode 100644 index 0000000..63d19c7 --- /dev/null +++ b/gui/icons/check.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/close.svg b/gui/icons/close.svg new file mode 100644 index 0000000..d515dd4 --- /dev/null +++ b/gui/icons/close.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/gui/icons/cross.svg b/gui/icons/cross.svg new file mode 100644 index 0000000..c73567b --- /dev/null +++ b/gui/icons/cross.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/gui/icons/dialog-error.svg b/gui/icons/dialog-error.svg deleted file mode 100644 index 602fa79..0000000 --- a/gui/icons/dialog-error.svg +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Rodney Dawes - - - - - Jakub Steiner, Garrett LeSage - - - - Dialog Error - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/dialog-information.svg b/gui/icons/dialog-information.svg deleted file mode 100644 index 1e957cc..0000000 --- a/gui/icons/dialog-information.svg +++ /dev/null @@ -1,1145 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Info - - - Jakub Steiner - - - - - dialog - info - - - http://jimmac.musichall.cz - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/dialog-warning.svg b/gui/icons/dialog-warning.svg deleted file mode 100644 index 51f7ff3..0000000 --- a/gui/icons/dialog-warning.svg +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Dialog Warning - 2005-10-14 - - - Andreas Nilsson - - - - - Jakub Steiner, Garrett LeSage - - - - - dialog - warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/document-new.svg b/gui/icons/document-new.svg deleted file mode 100644 index 1bfdb16..0000000 --- a/gui/icons/document-new.svg +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - New Document - - - Jakub Steiner - - - http://jimmac.musichall.cz - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/document-print-preview.svg b/gui/icons/document-print-preview.svg deleted file mode 100644 index 9698d5e..0000000 --- a/gui/icons/document-print-preview.svg +++ /dev/null @@ -1,701 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Print Preview - - - Jakub Steiner - - - - http://jimmac.musichall.cz - - - printer - local - laser - bubblejet - inkjet - print - output - cups - lpd - preview - - - - - Corey Woodworth - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/document-print.svg b/gui/icons/document-print.svg deleted file mode 100644 index bb3d43d..0000000 --- a/gui/icons/document-print.svg +++ /dev/null @@ -1,530 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Print Document - - - Jakub Steiner - - - - http://jimmac.musichall.cz - - - document - lpr - print - local - laser - bubblejet - inkjet - print - output - cups - lpd - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/document-save-as.svg b/gui/icons/document-save-as.svg deleted file mode 100644 index 09fa340..0000000 --- a/gui/icons/document-save-as.svg +++ /dev/null @@ -1,661 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Save As - - - Jakub Steiner - - - - - hdd - hard drive - save as - io - store - - - - - http://jimmac.musichall.cz - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/document-save.svg b/gui/icons/document-save.svg deleted file mode 100644 index 6be29c4..0000000 --- a/gui/icons/document-save.svg +++ /dev/null @@ -1,617 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Save - - - Jakub Steiner - - - - - hdd - hard drive - save - io - store - - - - - http://jimmac.musichall.cz - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/down.svg b/gui/icons/down.svg new file mode 100644 index 0000000..599cca7 --- /dev/null +++ b/gui/icons/down.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/gui/icons/edit-find.svg b/gui/icons/edit-find.svg deleted file mode 100644 index a499b48..0000000 --- a/gui/icons/edit-find.svg +++ /dev/null @@ -1,750 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Edit Find - - - edit - find - locate - search - - - - - - Steven Garrity - - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/emblem-symbolic-link.svg b/gui/icons/emblem-symbolic-link.svg deleted file mode 100644 index 45e040b..0000000 --- a/gui/icons/emblem-symbolic-link.svg +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Symbolic Link - - - emblem - symbolic - link - pointer - io - file - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/emblem-unreadable.svg b/gui/icons/emblem-unreadable.svg deleted file mode 100644 index 82a4a4f..0000000 --- a/gui/icons/emblem-unreadable.svg +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Unreadable - - - emblem - access - denied - unreadable - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/expand.svg b/gui/icons/expand.svg new file mode 100644 index 0000000..795e3d2 --- /dev/null +++ b/gui/icons/expand.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/gui/icons/face-surprise.svg b/gui/icons/face-surprise.svg deleted file mode 100644 index b40a301..0000000 --- a/gui/icons/face-surprise.svg +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Face - Shocked - - - emoticon - emote - smiley - stare - shocked - :O - - - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/file.svg b/gui/icons/file.svg new file mode 100644 index 0000000..fee53e5 --- /dev/null +++ b/gui/icons/file.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/gui/icons/film.svg b/gui/icons/film.svg new file mode 100644 index 0000000..0ca8f3a --- /dev/null +++ b/gui/icons/film.svg @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/gui/icons/folder-open.svg b/gui/icons/folder-open.svg deleted file mode 100644 index 237f6f2..0000000 --- a/gui/icons/folder-open.svg +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Folder Icon Accept - 2005-01-31 - - - Jakub Steiner - - - - http://jimmac.musichall.cz - Active state - when files are being dragged to. - - - Novell, Inc. - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/folder.svg b/gui/icons/folder.svg index 2027f56..926bf8b 100644 --- a/gui/icons/folder.svg +++ b/gui/icons/folder.svg @@ -1,422 +1,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Folder Icon - - - - Jakub Steiner - - - - http://jimmac.musichall.cz - - - folder - directory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + diff --git a/gui/icons/go-bottom.svg b/gui/icons/go-bottom.svg deleted file mode 100644 index fe87dc3..0000000 --- a/gui/icons/go-bottom.svg +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go to Bottom - - - go - bottom - - - - - Andreas Nilsson - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-down.svg b/gui/icons/go-down.svg deleted file mode 100644 index 18dadc4..0000000 --- a/gui/icons/go-down.svg +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Down - - - go - lower - down - arrow - pointer - > - - - - - Andreas Nilsson - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-first.svg b/gui/icons/go-first.svg deleted file mode 100644 index e79e0e1..0000000 --- a/gui/icons/go-first.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Previous - - - go - previous - left - arrow - pointer - < - - - - - Andreas Nilsson - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-home.svg b/gui/icons/go-home.svg deleted file mode 100644 index 3520b51..0000000 --- a/gui/icons/go-home.svg +++ /dev/null @@ -1,441 +0,0 @@ - -image/svg+xmlGo HomeJakub Steinerhttp://jimmac.musichall.czhomereturngodefaultuserdirectoryTuomas Kuosmanen - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gui/icons/go-jump.svg b/gui/icons/go-jump.svg deleted file mode 100644 index 3e0517f..0000000 --- a/gui/icons/go-jump.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Jump - - - go - jump - seek - arrow - pointer - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-last.svg b/gui/icons/go-last.svg deleted file mode 100644 index e2331cb..0000000 --- a/gui/icons/go-last.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Next - - - go - next - right - arrow - pointer - > - - - - - Andreas Nilsson - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-next.svg b/gui/icons/go-next.svg deleted file mode 100644 index 989bff5..0000000 --- a/gui/icons/go-next.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Next - - - go - next - right - arrow - pointer - > - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-previous.svg b/gui/icons/go-previous.svg deleted file mode 100644 index f1eb977..0000000 --- a/gui/icons/go-previous.svg +++ /dev/null @@ -1,852 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Previous - - - go - previous - left - arrow - pointer - < - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-top.svg b/gui/icons/go-top.svg deleted file mode 100644 index a25edbb..0000000 --- a/gui/icons/go-top.svg +++ /dev/null @@ -1,972 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Top - - - go - highest - top - arrow - pointer - > - - - - - Andreas Nilsson - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/go-up.svg b/gui/icons/go-up.svg deleted file mode 100644 index 0e3d01d..0000000 --- a/gui/icons/go-up.svg +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Go Up - - - go - higher - up - arrow - pointer - > - - - - - Andreas Nilsson - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/harddrive.svg b/gui/icons/harddrive.svg new file mode 100644 index 0000000..8d563f3 --- /dev/null +++ b/gui/icons/harddrive.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/gui/icons/heart.svg b/gui/icons/heart.svg new file mode 100644 index 0000000..a9fb96a --- /dev/null +++ b/gui/icons/heart.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/gui/icons/home.svg b/gui/icons/home.svg new file mode 100644 index 0000000..8717024 --- /dev/null +++ b/gui/icons/home.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/image-missing.svg b/gui/icons/image-missing.svg deleted file mode 100644 index e585fd8..0000000 --- a/gui/icons/image-missing.svg +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Broken Image - - - image - picture - photo - missing - broken - 404 - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/image.svg b/gui/icons/image.svg new file mode 100644 index 0000000..4314829 --- /dev/null +++ b/gui/icons/image.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/gui/icons/info.svg b/gui/icons/info.svg new file mode 100644 index 0000000..9eb51ef --- /dev/null +++ b/gui/icons/info.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/gui/icons/laptop.svg b/gui/icons/laptop.svg new file mode 100644 index 0000000..e84db8f --- /dev/null +++ b/gui/icons/laptop.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/gui/icons/left.svg b/gui/icons/left.svg new file mode 100644 index 0000000..0d05131 --- /dev/null +++ b/gui/icons/left.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/gui/icons/left_arrow.svg b/gui/icons/left_arrow.svg deleted file mode 100644 index 75f49f1..0000000 --- a/gui/icons/left_arrow.svg +++ /dev/null @@ -1,374 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Seek Backward - - - Lapo Calamandrei - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/list-add.svg b/gui/icons/list-add.svg deleted file mode 100644 index a514a01..0000000 --- a/gui/icons/list-add.svg +++ /dev/null @@ -1,434 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Add - 2006-01-04 - - - Andreas Nilsson - - - http://tango-project.org - - - add - plus - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/list-remove.svg b/gui/icons/list-remove.svg deleted file mode 100644 index 67da191..0000000 --- a/gui/icons/list-remove.svg +++ /dev/null @@ -1,422 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Remove - 2006-01-04 - - - Andreas Nilsson - - - http://tango-project.org - - - remove - delete - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/list.svg b/gui/icons/list.svg new file mode 100644 index 0000000..55fa89b --- /dev/null +++ b/gui/icons/list.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/gui/icons/live.svg b/gui/icons/live.svg new file mode 100644 index 0000000..95bf0fa --- /dev/null +++ b/gui/icons/live.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/gui/icons/media-eject.svg b/gui/icons/media-eject.svg deleted file mode 100644 index eb76b24..0000000 --- a/gui/icons/media-eject.svg +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Playback Start - - - Jakub Steiner - - - - - - media - eject - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-playback-pause.svg b/gui/icons/media-playback-pause.svg deleted file mode 100644 index 56e1d6b..0000000 --- a/gui/icons/media-playback-pause.svg +++ /dev/null @@ -1,630 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Playback Pause - - - Lapo Calamandrei - - - - - - media - pause - playback - video - music - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-playback-start.svg b/gui/icons/media-playback-start.svg deleted file mode 100644 index 09195da..0000000 --- a/gui/icons/media-playback-start.svg +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Playback Start - - - Lapo Calamandrei - - - - - - play - media - music - video - player - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-playback-stop.svg b/gui/icons/media-playback-stop.svg deleted file mode 100644 index 70cb229..0000000 --- a/gui/icons/media-playback-stop.svg +++ /dev/null @@ -1,640 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Playback Pause - - - Lapo Calamandrei - - - - - - media - stop - playback - video - music - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-record.svg b/gui/icons/media-record.svg deleted file mode 100644 index d71e455..0000000 --- a/gui/icons/media-record.svg +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Record - - - Lapo Calamandrei - - - - - - media - player - record - music - sound - video - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-seek-backward.svg b/gui/icons/media-seek-backward.svg deleted file mode 100644 index 04e9f68..0000000 --- a/gui/icons/media-seek-backward.svg +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Seek Backward - - - Lapo Calamandrei - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-seek-forward.svg b/gui/icons/media-seek-forward.svg deleted file mode 100644 index 197db29..0000000 --- a/gui/icons/media-seek-forward.svg +++ /dev/null @@ -1,370 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Seek Forward - - - Lapo Calamandrei - - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-skip-backward.svg b/gui/icons/media-skip-backward.svg deleted file mode 100644 index 7e84148..0000000 --- a/gui/icons/media-skip-backward.svg +++ /dev/null @@ -1,1014 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Skip Backward - - - Lapo Calamandrei - - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media-skip-forward.svg b/gui/icons/media-skip-forward.svg deleted file mode 100644 index 137d948..0000000 --- a/gui/icons/media-skip-forward.svg +++ /dev/null @@ -1,1002 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Skip Forward - - - Lapo Calamandrei - - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/media_next.svg b/gui/icons/media_next.svg new file mode 100644 index 0000000..e123044 --- /dev/null +++ b/gui/icons/media_next.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gui/icons/media_prev.svg b/gui/icons/media_prev.svg new file mode 100644 index 0000000..a92ff95 --- /dev/null +++ b/gui/icons/media_prev.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gui/icons/monitor.svg b/gui/icons/monitor.svg new file mode 100644 index 0000000..99212f8 --- /dev/null +++ b/gui/icons/monitor.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/gui/icons/more.svg b/gui/icons/more.svg new file mode 100644 index 0000000..9b6320d --- /dev/null +++ b/gui/icons/more.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/gui/icons/musical.svg b/gui/icons/musical.svg new file mode 100644 index 0000000..de3f5b6 --- /dev/null +++ b/gui/icons/musical.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/gui/icons/navigation.svg b/gui/icons/navigation.svg new file mode 100644 index 0000000..4414ff6 --- /dev/null +++ b/gui/icons/navigation.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/gui/icons/network.svg b/gui/icons/network.svg new file mode 100644 index 0000000..1a1dae0 --- /dev/null +++ b/gui/icons/network.svg @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/gui/icons/next.svg b/gui/icons/next.svg new file mode 100644 index 0000000..c8e419c --- /dev/null +++ b/gui/icons/next.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/osmo.svg b/gui/icons/osmo.svg new file mode 100644 index 0000000..7688fd2 --- /dev/null +++ b/gui/icons/osmo.svg @@ -0,0 +1,26 @@ + + + + + + diff --git a/gui/icons/overflowing.svg b/gui/icons/overflowing.svg new file mode 100644 index 0000000..1f3c482 --- /dev/null +++ b/gui/icons/overflowing.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/gui/icons/pause.svg b/gui/icons/pause.svg new file mode 100644 index 0000000..82c72f9 --- /dev/null +++ b/gui/icons/pause.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/gui/icons/pl_next.svg b/gui/icons/pl_next.svg new file mode 100644 index 0000000..1d6b7bf --- /dev/null +++ b/gui/icons/pl_next.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/gui/icons/pl_prev.svg b/gui/icons/pl_prev.svg new file mode 100644 index 0000000..8fda5d2 --- /dev/null +++ b/gui/icons/pl_prev.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/gui/icons/play.svg b/gui/icons/play.svg new file mode 100644 index 0000000..7d5ef59 --- /dev/null +++ b/gui/icons/play.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/gui/icons/play_loop.svg b/gui/icons/play_loop.svg new file mode 100644 index 0000000..491f7de --- /dev/null +++ b/gui/icons/play_loop.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/gui/icons/play_shuffle.svg b/gui/icons/play_shuffle.svg new file mode 100644 index 0000000..fdaed78 --- /dev/null +++ b/gui/icons/play_shuffle.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/gui/icons/play_single.svg b/gui/icons/play_single.svg new file mode 100644 index 0000000..17749a0 --- /dev/null +++ b/gui/icons/play_single.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gui/icons/power.svg b/gui/icons/power.svg new file mode 100644 index 0000000..ecb9c1a --- /dev/null +++ b/gui/icons/power.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/gui/icons/preferences-desktop-remote-desktop.svg b/gui/icons/preferences-desktop-remote-desktop.svg deleted file mode 100644 index 848e892..0000000 --- a/gui/icons/preferences-desktop-remote-desktop.svg +++ /dev/null @@ -1,1479 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Remote Desktop - - - Jakub Steiner - - - - - Tuomas Kuosmanen - - - - http://jimmac.musichall.cz - - - vnc - remote - desktop - control - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/preferences-system-windows.svg b/gui/icons/preferences-system-windows.svg deleted file mode 100644 index dc344f7..0000000 --- a/gui/icons/preferences-system-windows.svg +++ /dev/null @@ -1,386 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Windows - - - window - manager - decoration - behavior - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/previous.svg b/gui/icons/previous.svg new file mode 100644 index 0000000..10dc777 --- /dev/null +++ b/gui/icons/previous.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/process-stop.svg b/gui/icons/process-stop.svg deleted file mode 100644 index 72b78f0..0000000 --- a/gui/icons/process-stop.svg +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Stop - 2005-10-16 - - - Andreas Nilsson - - - - - stop - halt - error - - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/remove.svg b/gui/icons/remove.svg new file mode 100644 index 0000000..fb32d72 --- /dev/null +++ b/gui/icons/remove.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/gui/icons/resize.svg b/gui/icons/resize.svg new file mode 100644 index 0000000..84026be --- /dev/null +++ b/gui/icons/resize.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/gui/icons/rewind.svg b/gui/icons/rewind.svg new file mode 100644 index 0000000..fadc30f --- /dev/null +++ b/gui/icons/rewind.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/right.svg b/gui/icons/right.svg new file mode 100644 index 0000000..5d00e08 --- /dev/null +++ b/gui/icons/right.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/gui/icons/right_arrow.svg b/gui/icons/right_arrow.svg deleted file mode 100644 index b1b9fe9..0000000 --- a/gui/icons/right_arrow.svg +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Media Seek Forward - - - Lapo Calamandrei - - - - - - Jakub Steiner - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/seek_forward.svg b/gui/icons/seek_forward.svg new file mode 100644 index 0000000..3593335 --- /dev/null +++ b/gui/icons/seek_forward.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/shrink.svg b/gui/icons/shrink.svg new file mode 100644 index 0000000..6598846 --- /dev/null +++ b/gui/icons/shrink.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/icons/sort.svg b/gui/icons/sort.svg new file mode 100644 index 0000000..f5c7b93 --- /dev/null +++ b/gui/icons/sort.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/gui/icons/speed.svg b/gui/icons/speed.svg new file mode 100644 index 0000000..2a5ce34 --- /dev/null +++ b/gui/icons/speed.svg @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/gui/icons/star.svg b/gui/icons/star.svg new file mode 100644 index 0000000..127e8f7 --- /dev/null +++ b/gui/icons/star.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/icons/stop.svg b/gui/icons/stop.svg new file mode 100644 index 0000000..17aaf15 --- /dev/null +++ b/gui/icons/stop.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/gui/icons/stop2.svg b/gui/icons/stop2.svg new file mode 100644 index 0000000..fdb6357 --- /dev/null +++ b/gui/icons/stop2.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/gui/icons/tennis_ball.svg b/gui/icons/tennis_ball.svg deleted file mode 100644 index e68f1cf..0000000 --- a/gui/icons/tennis_ball.svg +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/tennis_black.svg b/gui/icons/tennis_black.svg deleted file mode 100644 index 66d156b..0000000 --- a/gui/icons/tennis_black.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - image/svg+xml - - Other map symbols - - - Mohamed Ibrahim - - - - - Public Domain - - - - - clker.com - - - - - other map symbols - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gui/icons/tennis_racket.svg b/gui/icons/tennis_racket.svg deleted file mode 100644 index dc242a5..0000000 --- a/gui/icons/tennis_racket.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gui/icons/tennis_racket_color.svg b/gui/icons/tennis_racket_color.svg deleted file mode 100644 index 7cde756..0000000 --- a/gui/icons/tennis_racket_color.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/trash.svg b/gui/icons/trash.svg new file mode 100644 index 0000000..1abcb28 --- /dev/null +++ b/gui/icons/trash.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/gui/icons/tray.svg b/gui/icons/tray.svg new file mode 100644 index 0000000..4015052 --- /dev/null +++ b/gui/icons/tray.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/gui/icons/tv.svg b/gui/icons/tv.svg new file mode 100644 index 0000000..2ed1a3d --- /dev/null +++ b/gui/icons/tv.svg @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/gui/icons/up.svg b/gui/icons/up.svg new file mode 100644 index 0000000..d4b2e38 --- /dev/null +++ b/gui/icons/up.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/gui/icons/user-trash.svg b/gui/icons/user-trash.svg deleted file mode 100644 index 9943ebb..0000000 --- a/gui/icons/user-trash.svg +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Trash Empty - 2003-02-04 - - - Jakub Steiner - - - - - trash - delete - deleted files - waste - recycle - bin - empty - - - - - Novell, Inc. - - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/video-display.svg b/gui/icons/video-display.svg deleted file mode 100644 index 97ea133..0000000 --- a/gui/icons/video-display.svg +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Video Display - - - - Jakub Steiner - - - - - video - display - monitor - LCD - CRT - - - - http://jimmac.musichall.cz/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/video-x-generic.svg b/gui/icons/video-x-generic.svg deleted file mode 100644 index d575550..0000000 --- a/gui/icons/video-x-generic.svg +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Generic Video - - - video - audio - multimedia - movie - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/view-fullscreen.svg b/gui/icons/view-fullscreen.svg deleted file mode 100644 index 2d61d91..0000000 --- a/gui/icons/view-fullscreen.svg +++ /dev/null @@ -1,520 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - View Fullscreen - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gui/icons/world.svg b/gui/icons/world.svg new file mode 100644 index 0000000..116e0b6 --- /dev/null +++ b/gui/icons/world.svg @@ -0,0 +1,64 @@ + + + + + + + + + diff --git a/gui/iphone_wm_gui.js b/gui/iphone_wm_gui.js index 1e0d22d..651f59b 100644 --- a/gui/iphone_wm_gui.js +++ b/gui/iphone_wm_gui.js @@ -40,8 +40,8 @@ function adaptLayoutToSize() { if (l_deb < log_level) { alert("[UI] adaptLayoutToSize"); } - display_width = parseInt( gpac.getOption('General', 'LastWidth') ); - display_height = parseInt( gpac.getOption('General', 'LastHeight') ); + display_width = parseInt(gpac.get_option('General', 'LastWidth')); + display_height = parseInt(gpac.get_option('General', 'LastHeight')); alert("display "+display_width+" "+display_height); if (!gpac.fullscreen && display_width && display_height) { gpac.set_size(display_width, display_height); @@ -485,8 +485,8 @@ function initialize() { alert("[UI] initialize"); } init = false; - var display_width = parseInt(gpac.getOption('Widgets', 'LastWMWidth')); - var display_height = parseInt(gpac.getOption('Widgets', 'LastWMHeight')); + var display_width = parseInt(gpac.get_option('Widgets', 'LastWMWidth')); + var display_height = parseInt(gpac.get_option('Widgets', 'LastWMHeight')); if (display_width && display_height) { gpac.set_size(display_width, display_height); } @@ -834,8 +834,8 @@ function resize() { adjustWhereWidgets(false); previousWidth = document.documentElement.viewport.width; previousHeight = document.documentElement.viewport.height; - gpac.setOption("Widgets", "LastWMWidth", '' + previousWidth); - gpac.setOption("Widgets", "LastWMHeight", '' + previousHeight); + gpac.set_option("Widgets", "LastWMWidth", '' + previousWidth); + gpac.set_option("Widgets", "LastWMHeight", '' + previousHeight); } // diff --git a/gui/webvtt-renderer.js b/gui/webvtt-renderer.js index 0f4ea91..f62c7dc 100644 --- a/gui/webvtt-renderer.js +++ b/gui/webvtt-renderer.js @@ -1,281 +1,281 @@ -/* JavaScript Renderer for WebVTT tracks - Generates GPAC Scene Graph (SVG, BIFS) to display WebVTT cues */ -alert("WebVTT Rendered Loaded"); - -var DEBUG = false; - -var rect = document.documentElement.getRectPresentationTrait("viewBox"); -var width = rect.width; -var height = rect.height; -var xOffset = 5; -var yOffset = 5; -var fontSize = 20; -var textColor = "red"; -var fontFamily = "SANS"; -var lineIncrement = fontSize; -var nbCues = 0; - -var cueArea = document.createElement("g"); -document.documentElement.appendChild(cueArea); - -function reportMessage(msg) { - if (DEBUG) { - alert(msg); - } -} - -function createTextArea(settingsObj) { - reportMessage("Creating textArea with settings: "+settingsObj); - var t = document.createElement("textArea"); - t.setAttribute("x", xOffset+settingsObj.xPosition); - t.setAttribute("y", yOffset); - if (settingsObj.fromTop) { - t.setAttribute("display-align", "before"); - t.setAttribute("height", height-2*yOffset); - } else { - t.setAttribute("display-align", "after"); - t.setAttribute("height", height-2*yOffset-settingsObj.linePosition); - } - t.setAttribute("width", settingsObj.size-2*xOffset); - t.setAttribute("fill", textColor); - t.setAttribute("font-size", fontSize); - t.setAttribute("font-family", fontFamily); - t.setAttribute("text-align", settingsObj.align); - t.setAttribute("line-increment", lineIncrement); - cueArea.appendChild(t); - reportMessage("textArea created: "+t); - return t; -} - -function printObj(o) { - for (var p in o) { - if (o.hasOwnProperty(p)) { - alert(""+p+": "+o[p]); - } - } -} - -function addSpan(parent, cuePart) { - reportMessage("adding tspan to "+parent+" with cuePart: "+ cuePart); - var i; - var span = document.createElement('tspan'); - //alert('adding span for '+parent+': '+cuePart+' token:'+cuePart.token); - if (cuePart.token === undefined) { - span.textContent = cuePart; - } else { - if (cuePart.token === 'i') { - span.setAttribute("font-style", "italic"); - } else if (cuePart.token === 'u') { - span.setAttribute("text-decoration", "underline"); - } else if (cuePart.token === 'b') { - span.setAttribute("font-weight", "bold"); - } - for (i in cuePart.children) { - addSpan(span, cuePart.children[i]); - } - } - parent.appendChild(span); - reportMessage("tspan created "+span); - return span; -} - -function parseCueSettings(cueSettings){ - reportMessage("Parsing cue settings: "+cueSettings); - var obj = {}; - var settingsArray = cueSettings.split(/\s/g); - //.filter(function(set) { return set && !!set.length; }); - - // Convert the Array into an object - var compositeCueSettings = {}; - for (var settingsIndex in settingsArray) { - var nvArray = settingsArray[settingsIndex].split(":"); - compositeCueSettings[nvArray[0]] = nvArray[1]; - } - - // Compute real values - if (compositeCueSettings.line !== undefined) { - if (compositeCueSettings.line.match(/\%/)) { - obj.linePosition = parseFloat(compositeCueSettings.line.replace(/\%/ig,"")); - if (isNaN(obj.linePosition)) { - obj.linePosition = nbCues*lineIncrement; - } else { - obj.linePosition *= height/100; - } - } else { - obj.linePosition = parseFloat(compositeCueSettings.line)*lineIncrement; - if (isNaN(obj.linePosition)) { - obj.linePosition = nbCues*lineIncrement; - } else { - if (obj.linePosition > 0) { - obj.fromTop = true; - } else { - obj.fromTop = false; - obj.linePosition = -obj.linePosition; - } - } - } - } else { - obj.linePosition = nbCues*lineIncrement; - } - reportMessage("linePosition: "+obj.linePosition); - if (compositeCueSettings.position !== undefined) { - obj.xPosition = parseFloat(compositeCueSettings.position.replace(/\%/ig,"")); - if (isNaN(obj.xPosition)) { - obj.xPosition = 50; - } else { - obj.xPosition *= width/100; - } - } else { - obj.xPosition = 50; - } - reportMessage("xPosition: "+obj.xPosition); - if (compositeCueSettings.size !== undefined) { - obj.size = parseFloat(compositeCueSettings.size.replace(/\%/ig,"")); - if (isNaN(obj.size)) { - obj.size = 100; - } else { - obj.size *= width/100; - } - } else { - obj.size = 100; - } - reportMessage("size: "+obj.size); - if (compositeCueSettings.align !== undefined) { - if (compositeCueSettings.align === "middle") { - obj.align = "center"; - } else if (compositeCueSettings.align === "left") { - obj.align = "start"; - } else if (compositeCueSettings.align === "right") { - obj.align = "end"; - } else if (compositeCueSettings.align === "start") { - obj.align = "start"; - } else if (compositeCueSettings.align === "end") { - obj.align = "end"; - } else { - obj.align = "center"; - } - } else { - obj.align = "center"; - } - reportMessage("align: "+obj.align); - reportMessage("cue settings parsed: "+obj); - return obj; -} - -function removeCues() { - cueArea.textContent = ''; - nbCues = 0; -} - -function addCue(id, start, end, settings, payload) { - reportMessage("adding cue: "+id+","+start+","+end+","+settings+","+payload); - var lines = payload.split('\n'); - var settingObj = parseCueSettings(settings); - var tA = createTextArea(settingObj); - for (var lineIndex in lines) { - var parsedCue = parseCue(lines[lineIndex]); - for (var cuePartIndex in parsedCue) { - addSpan(tA, parsedCue[cuePartIndex]); - } - tA.appendChild(document.createElement('tbreak')); - } - nbCues++; - reportMessage("cue added: "+tA); -} - -/* Code adapted from https://raw.github.com/cgiffard/Captionator/master/js/captionator.js */ -var SRTChunkTimestampParser = /(\d{2})?:?(\d{2}):(\d{2})[\.\,](\d+)/; -function parseCue(cueText) { - reportMessage("Parsing cue text: "+cueText); - - var cueStructure = new Array, - cueSplit = [], - splitIndex, - currentToken, - currentContext, - stack = [], - stackIndex = 0, - chunkTimestamp, - timeData, - lastCueTime; - - cueSplit = cueText.split(/(<\/?[^>]+>)/ig); - - currentContext = cueStructure; - for (splitIndex in cueSplit) { - if (cueSplit.hasOwnProperty(splitIndex)) { - currentToken = cueSplit[splitIndex]; - - if (currentToken.substr(0,1) === "<") { - if (currentToken.substr(1,1) === "/") { - // Closing tag - var TagName = currentToken.substr(2).split(/[\s>]+/g)[0]; - if (stack.length > 0) { - // Scan backwards through the stack to determine whether we've got an open tag somewhere to close. - var stackScanDepth = 0; - for (stackIndex = stack.length-1; stackIndex >= 0; stackIndex --) { - var parentContext = stack[stackIndex][stack[stackIndex].length-1]; - stackScanDepth = stackIndex; - if (parentContext.token === TagName) { break; } - } - - currentContext = stack[stackScanDepth]; - stack = stack.slice(0,stackScanDepth); - } else { - // Tag mismatch! - alert("Tag mismatch when parsing WebVTT cue: "+cueText); - } - } else { - // Opening Tag - // Check whether the tag is valid according to the WebVTT specification - // If not, don't allow it (unless the sanitiseCueHTML option is explicitly set to false) - - if (( currentToken.substr(1).match(SRTChunkTimestampParser) || - currentToken.match(/^]+>/i) || - currentToken.match(/^/) || - currentToken.match(/^<(b|i|u|ruby|rt)>/)) ) { - - var tmpObject = { - "token": currentToken.replace(/[<\/>]+/ig,"").split(/[\s\.]+/)[0], - "rawToken": currentToken, - "children": [] - }; - - if (tmpObject.token === "v") { - tmpObject.voice = currentToken.match(/^]+)>/i)[1]; - } else if (tmpObject.token === "c") { - tmpObject.classes = currentToken - .replace(/[<\/>\s]+/ig,"") - .split(/[\.]+/ig) - .slice(1) - .filter(hasRealTextContent); - } else if (!!(chunkTimestamp = tmpObject.rawToken.match(SRTChunkTimestampParser))) { - cueStructure.isTimeDependent = true; - timeData = chunkTimestamp.slice(1); - tmpObject.timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours - parseInt((timeData[1]||0) * 60,10) + // Minutes - parseInt((timeData[2]||0),10) + // Seconds - parseFloat("0." + (timeData[3]||0)); // MS - } - - currentContext.push(tmpObject); - stack.push(currentContext); - currentContext = tmpObject.children; - } - } - } else { - // Text string - currentToken = currentToken - .replace(//g,">") - .replace(/\&/g,"&"); - - currentToken = currentToken.replace(/\n+/g,"
"); - - currentContext.push(currentToken); - } - } - } - reportMessage("cue text parsed: "+cueStructure); - return cueStructure; -} +/* JavaScript Renderer for WebVTT tracks + Generates GPAC Scene Graph (SVG, BIFS) to display WebVTT cues */ +alert("WebVTT Rendered Loaded"); + +var DEBUG = false; + +var rect = document.documentElement.getRectPresentationTrait("viewBox"); +var width = rect.width; +var height = rect.height; +var xOffset = 5; +var yOffset = 5; +var fontSize = 20; +var textColor = "red"; +var fontFamily = "SANS"; +var lineIncrement = fontSize; +var nbCues = 0; + +var cueArea = document.createElement("g"); +document.documentElement.appendChild(cueArea); + +function reportMessage(msg) { + if (DEBUG) { + alert(msg); + } +} + +function createTextArea(settingsObj) { + reportMessage("Creating textArea with settings: "+settingsObj); + var t = document.createElement("textArea"); + t.setAttribute("x", xOffset+settingsObj.xPosition); + t.setAttribute("y", yOffset); + if (settingsObj.fromTop) { + t.setAttribute("display-align", "before"); + t.setAttribute("height", height-2*yOffset); + } else { + t.setAttribute("display-align", "after"); + t.setAttribute("height", height-2*yOffset-settingsObj.linePosition); + } + t.setAttribute("width", settingsObj.size-2*xOffset); + t.setAttribute("fill", textColor); + t.setAttribute("font-size", fontSize); + t.setAttribute("font-family", fontFamily); + t.setAttribute("text-align", settingsObj.align); + t.setAttribute("line-increment", lineIncrement); + cueArea.appendChild(t); + reportMessage("textArea created: "+t); + return t; +} + +function printObj(o) { + for (var p in o) { + if (o.hasOwnProperty(p)) { + alert(""+p+": "+o[p]); + } + } +} + +function addSpan(parent, cuePart) { + reportMessage("adding tspan to "+parent+" with cuePart: "+ cuePart); + var i; + var span = document.createElement('tspan'); + //alert('adding span for '+parent+': '+cuePart+' token:'+cuePart.token); + if (cuePart.token === undefined) { + span.textContent = cuePart; + } else { + if (cuePart.token === 'i') { + span.setAttribute("font-style", "italic"); + } else if (cuePart.token === 'u') { + span.setAttribute("text-decoration", "underline"); + } else if (cuePart.token === 'b') { + span.setAttribute("font-weight", "bold"); + } + for (i in cuePart.children) { + addSpan(span, cuePart.children[i]); + } + } + parent.appendChild(span); + reportMessage("tspan created "+span); + return span; +} + +function parseCueSettings(cueSettings){ + reportMessage("Parsing cue settings: "+cueSettings); + var obj = {}; + var settingsArray = cueSettings.split(/\s/g); + //.filter(function(set) { return set && !!set.length; }); + + // Convert the Array into an object + var compositeCueSettings = {}; + for (var settingsIndex in settingsArray) { + var nvArray = settingsArray[settingsIndex].split(":"); + compositeCueSettings[nvArray[0]] = nvArray[1]; + } + + // Compute real values + if (compositeCueSettings.line !== undefined) { + if (compositeCueSettings.line.match(/\%/)) { + obj.linePosition = parseFloat(compositeCueSettings.line.replace(/\%/ig,"")); + if (isNaN(obj.linePosition)) { + obj.linePosition = nbCues*lineIncrement; + } else { + obj.linePosition *= height/100; + } + } else { + obj.linePosition = parseFloat(compositeCueSettings.line)*lineIncrement; + if (isNaN(obj.linePosition)) { + obj.linePosition = nbCues*lineIncrement; + } else { + if (obj.linePosition > 0) { + obj.fromTop = true; + } else { + obj.fromTop = false; + obj.linePosition = -obj.linePosition; + } + } + } + } else { + obj.linePosition = nbCues*lineIncrement; + } + reportMessage("linePosition: "+obj.linePosition); + if (compositeCueSettings.position !== undefined) { + obj.xPosition = parseFloat(compositeCueSettings.position.replace(/\%/ig,"")); + if (isNaN(obj.xPosition)) { + obj.xPosition = 50; + } else { + obj.xPosition *= width/100; + } + } else { + obj.xPosition = 50; + } + reportMessage("xPosition: "+obj.xPosition); + if (compositeCueSettings.size !== undefined) { + obj.size = parseFloat(compositeCueSettings.size.replace(/\%/ig,"")); + if (isNaN(obj.size)) { + obj.size = 100; + } else { + obj.size *= width/100; + } + } else { + obj.size = 100; + } + reportMessage("size: "+obj.size); + if (compositeCueSettings.align !== undefined) { + if (compositeCueSettings.align === "middle") { + obj.align = "center"; + } else if (compositeCueSettings.align === "left") { + obj.align = "start"; + } else if (compositeCueSettings.align === "right") { + obj.align = "end"; + } else if (compositeCueSettings.align === "start") { + obj.align = "start"; + } else if (compositeCueSettings.align === "end") { + obj.align = "end"; + } else { + obj.align = "center"; + } + } else { + obj.align = "center"; + } + reportMessage("align: "+obj.align); + reportMessage("cue settings parsed: "+obj); + return obj; +} + +function removeCues() { + cueArea.textContent = ''; + nbCues = 0; +} + +function addCue(id, start, end, settings, payload) { + reportMessage("adding cue: "+id+","+start+","+end+","+settings+","+payload); + var lines = payload.split('\n'); + var settingObj = parseCueSettings(settings); + var tA = createTextArea(settingObj); + for (var lineIndex in lines) { + var parsedCue = parseCue(lines[lineIndex]); + for (var cuePartIndex in parsedCue) { + addSpan(tA, parsedCue[cuePartIndex]); + } + tA.appendChild(document.createElement('tbreak')); + } + nbCues++; + reportMessage("cue added: "+tA); +} + +/* Code adapted from https://raw.github.com/cgiffard/Captionator/master/js/captionator.js */ +var SRTChunkTimestampParser = /(\d{2})?:?(\d{2}):(\d{2})[\.\,](\d+)/; +function parseCue(cueText) { + reportMessage("Parsing cue text: "+cueText); + + var cueStructure = new Array, + cueSplit = [], + splitIndex, + currentToken, + currentContext, + stack = [], + stackIndex = 0, + chunkTimestamp, + timeData, + lastCueTime; + + cueSplit = cueText.split(/(<\/?[^>]+>)/ig); + + currentContext = cueStructure; + for (splitIndex in cueSplit) { + if (cueSplit.hasOwnProperty(splitIndex)) { + currentToken = cueSplit[splitIndex]; + + if (currentToken.substr(0,1) === "<") { + if (currentToken.substr(1,1) === "/") { + // Closing tag + var TagName = currentToken.substr(2).split(/[\s>]+/g)[0]; + if (stack.length > 0) { + // Scan backwards through the stack to determine whether we've got an open tag somewhere to close. + var stackScanDepth = 0; + for (stackIndex = stack.length-1; stackIndex >= 0; stackIndex --) { + var parentContext = stack[stackIndex][stack[stackIndex].length-1]; + stackScanDepth = stackIndex; + if (parentContext.token === TagName) { break; } + } + + currentContext = stack[stackScanDepth]; + stack = stack.slice(0,stackScanDepth); + } else { + // Tag mismatch! + alert("Tag mismatch when parsing WebVTT cue: "+cueText); + } + } else { + // Opening Tag + // Check whether the tag is valid according to the WebVTT specification + // If not, don't allow it (unless the sanitiseCueHTML option is explicitly set to false) + + if (( currentToken.substr(1).match(SRTChunkTimestampParser) || + currentToken.match(/^]+>/i) || + currentToken.match(/^/) || + currentToken.match(/^<(b|i|u|ruby|rt)>/)) ) { + + var tmpObject = { + "token": currentToken.replace(/[<\/>]+/ig,"").split(/[\s\.]+/)[0], + "rawToken": currentToken, + "children": [] + }; + + if (tmpObject.token === "v") { + tmpObject.voice = currentToken.match(/^]+)>/i)[1]; + } else if (tmpObject.token === "c") { + tmpObject.classes = currentToken + .replace(/[<\/>\s]+/ig,"") + .split(/[\.]+/ig) + .slice(1) + .filter(hasRealTextContent); + } else if (!!(chunkTimestamp = tmpObject.rawToken.match(SRTChunkTimestampParser))) { + cueStructure.isTimeDependent = true; + timeData = chunkTimestamp.slice(1); + tmpObject.timeIn = parseInt((timeData[0]||0) * 60 * 60,10) + // Hours + parseInt((timeData[1]||0) * 60,10) + // Minutes + parseInt((timeData[2]||0),10) + // Seconds + parseFloat("0." + (timeData[3]||0)); // MS + } + + currentContext.push(tmpObject); + stack.push(currentContext); + currentContext = tmpObject.children; + } + } + } else { + // Text string + currentToken = currentToken + .replace(//g,">") + .replace(/\&/g,"&"); + + currentToken = currentToken.replace(/\n+/g,"
"); + + currentContext.push(currentToken); + } + } + } + reportMessage("cue text parsed: "+cueStructure); + return cueStructure; +} diff --git a/include/gpac/avparse.h b/include/gpac/avparse.h index 05d87b4..376bedb 100644 --- a/include/gpac/avparse.h +++ b/include/gpac/avparse.h @@ -174,6 +174,15 @@ static const u32 GF_M4ASampleRates[] = 16000, 12000, 11025, 8000, 7350, 0, 0, 0 }; +/*new values should now be defined in 23001-8*/ +static const u32 GF_M4ANumChannels[] = +{ + 1, 2, 3, 4, 5, 6, 8, 2, 3, 4, 7, 8, 24, 8, 12, 10, 12, 14 +}; + +/*returns channel config value (as written in AAC DSI) for the given number of channels*/ +u32 gf_m4a_get_channel_cfg(u32 nb_chan); + /*get Audio type from dsi. return audio codec type:*/ typedef struct { @@ -210,12 +219,14 @@ typedef struct u32 sample_rate; u32 framesize; u32 channels; + u16 substreams; //bit-mask, used for channel map > 5.1 /*only set if full parse*/ u8 fscod, bsid, bsmod, acmod, lfon, brcode; } GF_AC3Header; Bool gf_ac3_parser(u8 *buffer, u32 buffer_size, u32 *pos, GF_AC3Header *out_hdr, Bool full_parse); Bool gf_ac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse); +Bool gf_eac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse); u32 gf_ac3_get_channels(u32 acmod); u32 gf_ac3_get_bitrate(u32 brcode); diff --git a/include/gpac/bifs.h b/include/gpac/bifs.h index 0db9540..79fc9e9 100644 --- a/include/gpac/bifs.h +++ b/include/gpac/bifs.h @@ -93,6 +93,8 @@ u8 gf_bifs_encoder_get_version(GF_BifsEncoder *codec, u16 ESID); /*Encodes current graph as a scene replace*/ GF_Err gf_bifs_encoder_get_rap(GF_BifsEncoder *codec, char **out_data, u32 *out_data_length); +GF_Err gf_bifs_encoder_set_source_url(GF_BifsEncoder *codec, const char *src_url); + #endif /*GPAC_DISABLE_BIFS_ENC*/ #endif /*GPAC_DISABLE_BIFS*/ diff --git a/include/gpac/bitstream.h b/include/gpac/bitstream.h index f35cfbd..0343f22 100644 --- a/include/gpac/bitstream.h +++ b/include/gpac/bitstream.h @@ -236,7 +236,7 @@ u16 gf_bs_read_u16_le(GF_BitStream *bs); /*! * \brief variable length integer reading * - * Reads an integer coded on a variable number of 4-bits chunks. The number of chunks is given by the number of non-0 bits at the begining. + * Reads an integer coded on a variable number of 4-bits chunks. The number of chunks is given by the number of non-0 bits at the beginning. * \param bs the target bitstream * \return the integer value read. */ @@ -433,7 +433,7 @@ void gf_bs_skip_bytes(GF_BitStream *bs, u64 nbBytes); /*! *\brief bitstream seeking * - *Seeks the bitstream to a given offset after the begining of the stream. This will perform alignment of the bitstream in all modes. + *Seeks the bitstream to a given offset after the beginning of the stream. This will perform alignment of the bitstream in all modes. *\warning Results are unpredictable if seeking beyond the bitstream end is performed. *\param bs the target bitstream *\param offset buffer/file offset to seek to @@ -459,7 +459,7 @@ void gf_bs_truncate(GF_BitStream *bs); * otherwise, bitstream is not aligned and bits are peeked from current state *\return the integer value read */ -u32 gf_bs_peek_bits(GF_BitStream *bs, u32 numBits, u32 byte_offset); +u32 gf_bs_peek_bits(GF_BitStream *bs, u32 numBits, u64 byte_offset); /*! *\brief bit reservoir query diff --git a/include/gpac/cache.h b/include/gpac/cache.h index a0378d4..dade6aa 100644 --- a/include/gpac/cache.h +++ b/include/gpac/cache.h @@ -191,7 +191,7 @@ u32 gf_cache_get_content_length( const DownloadedCacheEntry entry); * \param httpRequest The HTTP GET request to populate. The request must have been allocated enough to handle the cache arguments * \return GF_OK if everything went fine, GF_BAD_PARAM if parameters are wrong */ -GF_Err appendHttpCacheHeaders(const DownloadedCacheEntry entry, char * httpRequest); +GF_Err gf_cache_append_http_headers(const DownloadedCacheEntry entry, char * httpRequest); /* * Cache Management functions @@ -234,6 +234,10 @@ u32 gf_cache_get_sessions_count_for_cache_entry(const DownloadedCacheEntry entry u64 gf_cache_get_start_range( const DownloadedCacheEntry entry ); u64 gf_cache_get_end_range( const DownloadedCacheEntry entry ); + +Bool gf_cache_are_headers_processed(const DownloadedCacheEntry entry); +GF_Err gf_cache_set_headers_processed(const DownloadedCacheEntry entry); + /*! @} */ #ifdef __cplusplus diff --git a/include/gpac/color.h b/include/gpac/color.h index 1820200..194e6d0 100644 --- a/include/gpac/color.h +++ b/include/gpac/color.h @@ -32,7 +32,8 @@ extern "C" { #endif #include -#include +#include +#include /*! @@ -64,12 +65,14 @@ typedef struct s32 pitch_y; /*!Pixel format of the video framebuffer*/ u32 pixel_format; - /*!pointer to the begining of the video memory (top-left corner)*/ + /*!pointer to the beginning of the video memory (top-left corner)*/ char *video_buffer; /*!indicates that the video data reside on systems memory or video card one*/ Bool is_hardware_memory; - /*!indicates U and V (and optionnal alpha) buffers in case of planar video with seperated component. If not set, all components are in the video_buffer pointer*/ + /*!indicates U and V (and optional alpha) buffers in case of planar video with separated component. If not set, all components are in the video_buffer pointer*/ char *u_ptr, *v_ptr, *a_ptr; + /*! alpha value for this surface*/ + u8 global_alpha; } GF_VideoSurface; /*!\brief Video Window object @@ -144,6 +147,18 @@ typedef u32 GF_Color; /*!\hideinitializer transfoms a 32-bits color into a 15-bits one.\note alpha component is lost*/ #define GF_COL_TO_444(c) (((GF_COL_R(c) & 240)<<4) + ((GF_COL_G(c) & 240)) + ((GF_COL_B(c)>>4) & 240) ) +/*!Parses color from HTML name or hexa representation + *\param name name of the color to parse + *\return @GF_Color value with alpha set to 0xFF if successfull, 0 otherwise +*/ +GF_Color gf_color_parse(const char *name); + +/*!Gets color from HTML name or hexa representation + *\param col color to identify + *\return name of the color if successfull, NULL otherwise +*/ +const char *gf_color_get_name(GF_Color col); + /*!Inits a color matrix to identity*/ void gf_cmx_init(GF_ColorMatrix *_this); /*!Inits all coefficients of a color matrix diff --git a/include/gpac/compositor.h b/include/gpac/compositor.h index e0fb3cd..e30d8dc 100644 --- a/include/gpac/compositor.h +++ b/include/gpac/compositor.h @@ -54,8 +54,12 @@ void gf_sc_set_fps(GF_Compositor *sr, Double fps); /*set the root scene graph of the compositor - if NULL remove current and reset simulation time*/ GF_Err gf_sc_set_scene(GF_Compositor *sr, GF_SceneGraph *scene_graph); -/*if the compositor doesn't use its own thread for visual, this will perform a render pass*/ -Bool gf_sc_draw_frame(GF_Compositor *sr, u32 *ms_till_next); +/*if the compositor doesn't use its own thread for visual, this will perform a render pass +return 1 if there are pending tasks (frame late, fonts pending, etc) or 0 if everything was ready while drawing the frame*/ +Bool gf_sc_draw_frame(GF_Compositor *sr, Bool no_video_flush, s32 *ms_till_next); + +/*flushes the video to screen - typically used after @gf_sc_draw_frame without flush*/ +void gf_sc_flush_video(GF_Compositor *compositor); /*inits rendering info for the node - shall be called for all nodes the parent system doesn't handle*/ void gf_sc_on_node_init(GF_Compositor *sr, GF_Node *node); @@ -118,7 +122,7 @@ GF_Err gf_sc_get_offscreen_buffer(GF_Compositor *sr, GF_VideoSurface *framebuffe GF_Err gf_sc_release_screen_buffer(GF_Compositor *sr, GF_VideoSurface *framebuffer); /*renders one frame*/ -void gf_sc_simulation_tick(GF_Compositor *sr); +void gf_sc_render_frame(GF_Compositor *sr); /*forces graphics cache recompute*/ void gf_sc_reset_graphics(GF_Compositor *sr); diff --git a/include/gpac/configuration.h b/include/gpac/configuration.h index 209751a..2c58fc3 100644 --- a/include/gpac/configuration.h +++ b/include/gpac/configuration.h @@ -32,125 +32,125 @@ /*this file defines all common macros for libgpac compilation except for symbian32 which uses .mmp directives ... */ +/*Configuration for visual studio, 32/64 bits */ +#if defined(WIN32) && !defined(_WIN32_WCE) -/*visual studio and xcode*/ -#if defined(WIN32) || defined(_WIN32_WCE) || defined(GPAC_CONFIG_DARWIN) || defined(GPAC_CONFIG_ANDROID) - -/*enables GPAC memory tracking in debug mode only*/ -#if defined(DEBUG) || defined(_DEBUG) -#define GPAC_MEMORY_TRACKING -#endif - -/*SSL enabled - no 64 bit support yet*/ -#if defined(WIN32) && !defined(_WIN64) #define GPAC_HAS_SSL -#endif -/*spidermonkey enabled*/ #define GPAC_HAS_SPIDERMONKEY -#ifdef GPAC_CONFIG_DARWIN -#define MOZILLA_1_8_BRANCH -#define XP_UNIX -#endif - -/*libjpeg enabled*/ #define GPAC_HAS_JPEG -/*pnj enabled*/ #define GPAC_HAS_PNG -/*IPv6 enabled - for win32, this is evaluated at compile time, !! do not uncomment !!*/ - +/*always enable memory tracking on windows*/ +//#define GPAC_MEMORY_TRACKING -//iOS compilation -#if defined(GPAC_CONFIG_DARWIN) && defined(GPAC_IPHONE) +/*Win32 IPv6 is evaluated at compile time, !! do not uncomment !!*/ +//#define GPAC_HAS_IPV6 -#define GPAC_USE_OGL_ES -#define GPAC_FIXED_POINT #define GPAC_HAS_GLU -/*lazy definition of extra libs for iOS*/ -#define GPAC_HAS_FAAD -//#define GPAC_HAS_MAD -#define GPAC_HAS_SDL -#define GPAC_HAS_FREETYPE -#endif //end iOS flags +/*Configuration for WindowsCE 32 bits */ +#elif defined(_WIN32_WCE) -//OSX compilation -#if defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_IPHONE) +#ifndef GPAC_FIXED_POINT +#define GPAC_FIXED_POINT +#endif -#define GPAC_HAS_IPV6 -#define GPAC_HAS_SSL +/*use intel fixed-point*/ +//#define GPAC_USE_IGPP +/*use intel fixed-point with high precision*/ +//#define GPAC_USE_IGPP_HP -#ifdef __LP64__ -#define GPAC_64_BITS +#if defined(GPAC_USE_IGPP) && defined(GPAC_USE_IGPP_HP) +#error "Only one of GPAC_USE_IGPP and GPAC_USE_IGPP_HP can be defined" #endif -#endif //end OSX flags +#if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) +#define GPAC_USE_GLES1X +#endif -//Android test compilation without any extra lib -#if defined(GPAC_CONFIG_ANDROID) -#define GPAC_ANDROID +#define GPAC_HAS_SPIDERMONKEY +#define GPAC_HAS_JPEG +#define GPAC_HAS_PNG + +/*comment this line if you don't have a GLU32 version for Windows Mobile*/ +//#define GPAC_HAS_GLU -#define GPAC_HAS_IPV6 -#define GPAC_USE_OGL_ES -#define GPAC_FIXED_POINT -#undef GPAC_HAS_SPIDERMONKEY -#undef GPAC_HAS_PNG -#undef GPAC_HAS_JPEG +/*Configuration for Android */ +#elif defined(GPAC_CONFIG_ANDROID) -#endif //end OSX flags +#ifndef GPAC_ANDROID +#define GPAC_ANDROID +#endif + +#define GPAC_HAS_IPV6 +#define GPAC_USE_GLES1X +/*don't use fixed-point version on Android, not needed*/ +//#define GPAC_FIXED_POINT +#define GPAC_HAS_SPIDERMONKEY +#define GPAC_HAS_JPEG +#define GPAC_HAS_PNG +/*Configuration for XCode OSX (not iOS) */ +#elif defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_IPHONE) -//WinCE flags -#if defined(_WIN32_WCE) +#define GPAC_HAS_IPV6 +#define GPAC_HAS_SSL -#ifndef GPAC_FIXED_POINT -#define GPAC_FIXED_POINT +//64-bits OSX +#ifdef __LP64__ +#define GPAC_64_BITS #endif -/*use intel fixed-point*/ -//#define GPAC_USE_IGPP -/*use intel fixed-point with high precision*/ -//#define GPAC_USE_IGPP_HP +#define GPAC_HAS_SPIDERMONKEY +#define GPAC_HAS_JPEG +#define GPAC_HAS_PNG -#if defined(GPAC_USE_IGPP) && defined(GPAC_USE_IGPP_HP) -#error "Only one of GPAC_USE_IGPP and GPAC_USE_IGPP_HP can be defined" -#endif +/*Configuration for XCode iOS*/ +#elif defined(GPAC_CONFIG_DARWIN) && defined(GPAC_IPHONE) -#if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) -#define GPAC_USE_OGL_ES +//64-bits iOS +#ifdef __LP64__ +#define GPAC_64_BITS #endif -#endif //WinCE flags - +#define GPAC_HAS_SPIDERMONKEY +#define GPAC_HAS_JPEG +#define GPAC_HAS_PNG +#define GPAC_USE_GLES1X +/*don't use fixed-point version on iOS, not needed*/ +//#define GPAC_FIXED_POINT +#define GPAC_HAS_GLU -#endif /*defined(WIN32) || defined(_WIN32_WCE) || defined(GPAC_CONFIG_DARWIN)*/ +/*extra libs supported on iOS*/ +#define GPAC_HAS_FAAD +#define GPAC_HAS_MAD +#define GPAC_HAS_FFMPEG +#define GPAC_HAS_SDL +#define GPAC_HAS_FREETYPE -#if defined(__SYMBIAN32__) +/*Configuration for Symbian*/ +#elif defined(__SYMBIAN32__) #ifndef GPAC_FIXED_POINT #define GPAC_FIXED_POINT #endif -#endif +#define GPAC_HAS_SPIDERMONKEY +#define GPAC_HAS_JPEG +#define GPAC_HAS_PNG -#if defined(_WIN32_WCE) -/*comment this line if you don't have a GLU32 version for Windows Mobile*/ -//#define GPAC_HAS_GLU -#elif defined(WIN32) -#define GPAC_HAS_GLU +#else +#error "Unknown target platform used with static configuration file" #endif -#if defined(_WIN64) -#define GPAC_X64 -#endif /*disables player */ //#define GPAC_DISABLE_PLAYER @@ -247,7 +247,7 @@ //#define GPAC_DISABLE_ISOM_FRAGMENTS /*disables scene graph */ -//GPAC_DISABLE_SCENEGRAPH +//#define GPAC_DISABLE_SCENEGRAPH /*disables scene graph textual dump*/ //#define GPAC_DISABLE_SCENE_DUMP @@ -279,5 +279,6 @@ /*disables VOBSUB */ //#define GPAC_DISABLE_VOBSUB + #endif /*_GF_CONFIG_H_*/ diff --git a/include/gpac/constants.h b/include/gpac/constants.h index 5bcca2c..5de2b0c 100644 --- a/include/gpac/constants.h +++ b/include/gpac/constants.h @@ -40,6 +40,22 @@ extern "C" { * @{ */ +/*! + * \brief Supported file types + * \hideinitializer + * + * Supported file types in most operations (file playback, editing, saving ...). +*/ +typedef enum { + GF_FILE_TYPE_NOT_SUPPORTED = 0, + GF_FILE_TYPE_ISO_MEDIA = 1, + GF_FILE_TYPE_BT_WRL_X3DV = 2, + GF_FILE_TYPE_XMT_X3D = 3, + GF_FILE_TYPE_SVG = 4, + GF_FILE_TYPE_SWF = 5, + GF_FILE_TYPE_LSR_SAF = 6, +} GF_FileType; + /*! * \brief Supported media stream types @@ -75,6 +91,9 @@ enum GF_STREAM_FONT = 0x0C, /*!MPEG-4 Streaming Text Stream*/ GF_STREAM_TEXT = 0x0D, + + /* From 0x20 to Ox3F, this is the user private range */ + /*!Nero Digital Subpicture Stream*/ GF_STREAM_ND_SUBPIC = 0x38, @@ -115,7 +134,7 @@ enum */ GF_STREAM_PRIVATE_MEDIA = 0x21, - /*used internally to signal the the OTI carries a 4CC code, typically media subtype (stsd entry in file format)*/ + /*used internally to signal that the OTI carries a 4CC code, typically media subtype (stsd entry in file format)*/ GF_STREAM_4CC = 0xF0 }; @@ -191,7 +210,7 @@ typedef enum /*!Stereo RGBA. Component ordering in bytes is R-G-B-A. */ GF_PIXEL_RGBAS = GF_4CC('R', 'G', 'A', 'S'), - /*internal format for OpenGL using pachek RGB 24 bit plus planaer depth plane at the end of the image*/ + /*internal format for OpenGL using pachek RGB 24 bit plus planar depth plane at the end of the image*/ GF_PIXEL_RGB_24_DEPTH = GF_4CC('R', 'G', 'B', 'd'), /*!YUV packed format*/ diff --git a/include/gpac/dash.h b/include/gpac/dash.h index fbc698f..c7f51e6 100644 --- a/include/gpac/dash.h +++ b/include/gpac/dash.h @@ -62,6 +62,14 @@ typedef enum GF_DASH_EVENT_BUFFER_DONE, GF_DASH_EVENT_SEGMENT_AVAILABLE, + + /*event sent when quality has been switched for the given group*/ + GF_DASH_EVENT_QUALITY_SWITCH, + + /*position in timeshift buffer has changed (eg, paused)*/ + GF_DASH_EVENT_TIMESHIFT_UPDATE, + /*event sent when timeshift buffer is overflown - the group_idx param contains the max number of dropped segments of all representations droped by the client, or -1 if play pos is ahead of live */ + GF_DASH_EVENT_TIMESHIFT_OVERFLOW, } GF_DASHEventType; /*structure used for all IO operations for DASH*/ @@ -76,6 +84,10 @@ struct _gf_dash_io /*signals errors or specific actions to perform*/ GF_Err (*on_dash_event)(GF_DASHFileIO *dashio, GF_DASHEventType evt, s32 group_idx, GF_Err setup_error); + /*used to check whether a representation is supported or not. Function returns 1 if supported, 0 otheriwse + if this callback is not set, the representation is assumed to be supported*/ + Bool (*dash_codec_supported)(GF_DASHFileIO *dashio, const char *codec, u32 width, u32 height, Bool is_interlaced, u32 fps_num, u32 fps_denum, u32 sample_rate); + /*called whenever a file has to be deleted*/ void (*delete_cache_file)(GF_DASHFileIO *dashio, GF_DASHFileIOSession session, const char *cache_url); @@ -117,9 +129,13 @@ typedef struct __dash_client GF_DashClient; typedef enum { + //selects the lowest quality when starting - if one of the representation does not have video (HLS), it may be selected GF_DASH_SELECT_QUALITY_LOWEST, + //selects the highest quality when starting GF_DASH_SELECT_QUALITY_HIGHEST, + //selects the lowest bandwidth when starting - if one of the representation does not have video (HLS), it will NOT be selected GF_DASH_SELECT_BANDWIDTH_LOWEST, + //selects the highest bandwidth when starting GF_DASH_SELECT_BANDWIDTH_HIGHEST } GF_DASHInitialSelectionMode; @@ -131,7 +147,7 @@ typedef enum @disable_switching: turn off bandwidth switching algorithm @first_select_mode: indicates which representation to select upon startup @enable_buffering: forces buffering of segments for the duration indicated in the MPD before calling back the user - @initial_time_shift_percent: sets initial buffering: if between 0 and 100, this is a percentage of the time shift window of the session. If greater than 100, this is a time shift in milliseconds. + @initial_time_shift_value: sets initial buffering: if between 0 and 100, this is a percentage of the time shift window of the session. If greater than 100, this is a time shift in milliseconds. */ GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, u32 max_cache_duration, @@ -139,7 +155,7 @@ GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, Bool keep_files, Bool disable_switching, GF_DASHInitialSelectionMode first_select_mode, - Bool enable_buffering, u32 initial_time_shift_percent); + Bool enable_buffering, u32 initial_time_shift_value); /*delete the DASH client*/ void gf_dash_del(GF_DashClient *dash); @@ -152,6 +168,9 @@ void gf_dash_close(GF_DashClient *dash); /*returns URL of the DASH manifest file*/ const char *gf_dash_get_url(GF_DashClient *dash); +/*tells whether we are playing some Apple HLS M3U8*/ +Bool gf_dash_is_m3u8(GF_DashClient *dash); + /*get title and source for this MPD*/ void gf_dash_get_info(GF_DashClient *dash, const char **title, const char **source); @@ -165,7 +184,10 @@ Bool gf_dash_is_running(GF_DashClient *dash); Double gf_dash_get_duration(GF_DashClient *dash); /*check that the given file has the right XML root element*/ Bool gf_dash_check_mpd_root_type(const char *local_url); - +/*sets timeshift for the presentation - this function does not trigger a seek, this has to be done by the caller + @ms_in_timeshift: if between 0 and 100, this is a percentage of the time shift window of the session. If greater than 100, this is a time shift in milliseconds. +*/ +GF_Err gf_dash_set_timeshift(GF_DashClient *dash, u32 ms_in_timeshift); /*returns the number of groups. A group is a set of media resources that are alternate of each other in terms of bandwidth/quality.*/ u32 gf_dash_get_group_count(GF_DashClient *dash); @@ -183,13 +205,48 @@ Bool gf_dash_is_group_selectable(GF_DashClient *dash, u32 idx); void gf_dash_group_select(GF_DashClient *dash, u32 idx, Bool select); /*performs selection of representations based on language code*/ -void gf_dash_groups_set_language(GF_DashClient *dash, const char *lang_3cc); +void gf_dash_groups_set_language(GF_DashClient *dash, const char *lang_code_rfc_5646); /*returns the mime type of the media resources in this group*/ const char *gf_dash_group_get_segment_mime(GF_DashClient *dash, u32 idx); -/*returns the URL of tyhe first media resource to play (init segment or first media segment depending on format). start_range and end_range are optional*/ +/*returns the URL of the first media resource to play (init segment or first media segment depending on format). start_range and end_range are optional*/ const char *gf_dash_group_get_segment_init_url(GF_DashClient *dash, u32 idx, u64 *start_range, u64 *end_range); +/*returns the URL and IV associated with the first media segment if any (init segment or first media segment depending on format). key_IV is optional*/ +const char *gf_dash_group_get_segment_init_keys(GF_DashClient *dash, u32 idx, bin128 *key_IV); + +/*returns the language of the group, or NULL if none associated*/ +const char *gf_dash_group_get_language(GF_DashClient *dash, u32 idx); + +/*returns the language of the group, or NULL if none associated*/ +u32 gf_dash_group_get_audio_channels(GF_DashClient *dash, u32 idx); + +/*get time shift buffer depth of the group - (u32) -1 means infinity*/ +u32 gf_dash_group_get_time_shift_buffer_depth(GF_DashClient *dash, u32 idx); + +/*get current time in time shift buffer in seconds - 0 means 'live point' +this gets the maximum value (further in the past) of all representations playing*/ +Double gf_dash_get_timeshift_buffer_pos(GF_DashClient *dash); + +typedef enum +{ + GF_MPD_DESC_ACCESSIBILITY, + GF_MPD_DESC_AUDIOCONFIG, + GF_MPD_DESC_CONTENT_PROTECTION, + GF_MPD_DESC_ESSENTIAL_PROPERTIES, + GF_MPD_DESC_SUPPLEMENTAL_PROPERTIES, + GF_MPD_DESC_FRAME_PACKING, + GF_MPD_DESC_ROLE, + GF_MPD_DESC_RATING, + GF_MPD_DESC_VIEWPOINT +} GF_DashDescriptorType; + +//enumerate descriptors of the given type: +//group_idx: index of the group for which descriptors are enumerated +//desc_type: type of descriptor being checked, one of the above +//role_idx: index of the descriptor being checked for this type +Bool gf_dash_group_enum_descriptor(GF_DashClient *dash, u32 group_idx, GF_DashDescriptorType desc_type, u32 role_idx, const char **desc_id, const char **desc_scheme, const char **desc_value); + /*returns the URL and byte range of the next media resource to play in this group. If switching occured, sets switching_index to the new representation index. If no bitstream switching is possible, also set the url and byte range of the media file required to intialize @@ -198,7 +255,7 @@ original_url is optional and may be used to het the URI of the segment */ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32 dependent_representation_index, const char **url, u64 *start_range, u64 *end_range, s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range, - const char **original_url, Bool *has_next_segment); + const char **original_url, Bool *has_next_segment, const char **key_url, bin128 *key_IV); /*same as gf_dash_group_get_next_segment_location but query the current downloaded segment*/ GF_EXPORT @@ -207,7 +264,9 @@ GF_Err gf_dash_group_probe_current_download_segment_location(GF_DashClient *dash /*returns 1 if segment numbers loops at this level (not allowed but happens when looping captures ...*/ Bool gf_dash_group_loop_detected(GF_DashClient *dash, u32 idx); -/*returns number of seconds at which playback shall start */ +/*returns number of seconds at which playback shall start for the group in the current period +the first segment available for the period will be so that gf_dash_group_get_start_range is in this range after the caller +adjusts it with PTO (eg the returned time is in period timeline, not media timeline */ Double gf_dash_group_get_start_range(GF_DashClient *dash, u32 idx); /*discards the first media resource in the queue of this group*/ @@ -225,7 +284,7 @@ GF_Err gf_dash_group_get_presentation_time_offset(GF_DashClient *dash, u32 idx, Bool gf_dash_in_last_period(GF_DashClient *dash); /*return value: 1 if the period switching has been requested (due to seeking), - 2 if the switching is in progress (all groups will soon be destroyed and plyback will be stoped and restarted) + 2 if the switching is in progress (all groups will soon be destroyed and plyback will be stopped and restarted) 0 if no switching is requested */ u32 gf_dash_get_period_switch_status(GF_DashClient *dash); @@ -233,15 +292,17 @@ u32 gf_dash_get_period_switch_status(GF_DashClient *dash); void gf_dash_request_period_switch(GF_DashClient *dash); /*returns 1 if the DASH engine is currently setting up a period (creating groups and fetching initial segments)*/ Bool gf_dash_in_period_setup(GF_DashClient *dash); -/*seeks playback to the given time. If period changes, all playback is stopped and restarted*/ +/*seeks playback to the given time. If period changes, all playback is stopped and restarted +If the session is dynamic (live), the start_range is ignored and recomputed from current UTC clock to be at the live point. If timeshifting is desired, use @gf_dash_set_timeshift before seeking.*/ void gf_dash_seek(GF_DashClient *dash, Double start_range); -/*gets playback start range for the first segment to play after the seek has been done. This is the amount of data to skip from the first segment to be played*/ -Double gf_dash_get_playback_start_range(GF_DashClient *dash); /*when seeking, this flag is set when the seek is outside of the previously playing segment.*/ Bool gf_dash_group_segment_switch_forced(GF_DashClient *dash, u32 idx); /*get video info for this group if video*/ GF_Err gf_dash_group_get_video_info(GF_DashClient *dash, u32 idx, u32 *max_width, u32 *max_height); +/*sets playback speed of the session. Speed is used in adaptation logic*/ +void gf_dash_set_speed(GF_DashClient *dash, Double speed); + /*returns the start_time of the first segment in the queue (usually the one being played)*/ Double gf_dash_group_current_segment_start_time(GF_DashClient *dash, u32 idx); @@ -252,7 +313,7 @@ void gf_dash_allow_local_mpd_update(GF_DashClient *dash, Bool allow_local_mpd_up GF_Err gf_dash_group_get_representation_info(GF_DashClient *dash, u32 idx, u32 representation_idx, u32 *width, u32 *height, u32 *audio_samplerate, u32 *bandwidth, const char **codecs); /*gets media buffering info for all active representations*/ -void gf_dash_get_buffer_info_buffering(GF_DashClient *dash, u32 *total_buffer, u32 *media_buffered); +void gf_dash_get_buffer_info(GF_DashClient *dash, u32 *total_buffer, u32 *media_buffered); /*updates media bandwidth for the given group*/ GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 idx); @@ -291,6 +352,53 @@ void gf_dash_debug_group(GF_DashClient *dash, s32 group_index); //indicates typical buffering used by the user app . This allows fetching data earlier in live mode, if the timeshiftbuffer allows for it void gf_dash_set_user_buffer(GF_DashClient *dash, u32 buffer_time_ms); +//indicates the number of segments to wait before switching up bandwidth. The default value is 1 (ie stay in current +//bandwidth or one more segment before switching up, event if download rate is enough) +//seting to 0 means the switch will happen instantly, but this is more prone to quality changes due to network variations +void gf_dash_set_switching_probe_count(GF_DashClient *dash, u32 switch_probe_count); + +/*returns active period start in ms*/ +u32 gf_dash_get_period_start(GF_DashClient *dash); +/*returns active period duration in ms*/ +u32 gf_dash_get_period_duration(GF_DashClient *dash); + +//returns number of quality available for the given group +u32 gf_dash_group_get_num_qualities(GF_DashClient *dash, u32 idx); + + +typedef struct +{ + u32 bandwidth; + const char *ID; + const char *mime; + const char *codec; + u32 width; + u32 height; + Bool interlaced; + u32 fps_den, fps_num; + u32 par_num; + u32 par_den; + u32 sample_rate; + u32 nb_channels; + Bool disabled; + Bool is_selected; +} GF_DASHQualityInfo; + +//returns number of quality available for the given group +GF_Err gf_dash_group_get_quality_info(GF_DashClient *dash, u32 idx, u32 quality_idx, GF_DASHQualityInfo *quality); + +//returns 1 if automatic quality switching is enabled +Bool gf_dash_get_automatic_switching(GF_DashClient *dash); + +//sets automatic quality switching enabled or disabled +GF_Err gf_dash_set_automatic_switching(GF_DashClient *dash, Bool enable_switching); + +//selects quality of given ID +GF_Err gf_dash_group_select_quality(GF_DashClient *dash, u32 idx, const char *ID); + +//gets download rate in bytes per second for the given group +u32 gf_dash_group_get_download_rate(GF_DashClient *dash, u32 idx); + #endif //GPAC_DISABLE_DASH_CLIENT diff --git a/include/gpac/download.h b/include/gpac/download.h index 70f7eeb..a99c596 100644 --- a/include/gpac/download.h +++ b/include/gpac/download.h @@ -439,8 +439,7 @@ const char *gf_dm_sess_get_original_resource_name(GF_DownloadSession *sess); * \param end_range end position of a byte range * \return GF_OK if everything went fine, an error otherwise */ -GF_Err gf_dm_wget_with_cache(GF_DownloadManager * dm, - const char *url, const char *filename, u64 start_range, u64 end_range); +GF_Err gf_dm_wget_with_cache(GF_DownloadManager * dm, const char *url, const char *filename, u64 start_range, u64 end_range, char **redirected_url); /*! * \brief Same as gf_dm_wget_with_cache, but initializes the GF_DownloadManager by itself. @@ -451,7 +450,7 @@ GF_Err gf_dm_wget_with_cache(GF_DownloadManager * dm, * \param end_range end position of a byte range * \return GF_OK if everything went fine, an error otherwise */ -GF_Err gf_dm_wget(const char *url, const char *filename, u64 start_range, u64 end_range); +GF_Err gf_dm_wget(const char *url, const char *filename, u64 start_range, u64 end_range, char **redirected_url); /*! *\brief Reset session @@ -528,6 +527,16 @@ void gf_dm_set_data_rate(GF_DownloadManager *dm, u32 rate_in_bits_per_sec); u32 gf_dm_get_data_rate(GF_DownloadManager *dm); +/* + *\brief gets cumultaed download rate for all sessions + * + *Gets the cumultated bitrate in of all active sessions. + *\param dm the download manager object + *\return the cumulated rate in bits per sec. + */ +u32 gf_dm_get_global_rate(GF_DownloadManager *dm); + + /* *\brief fetches remote file in memory * @@ -539,6 +548,23 @@ u32 gf_dm_get_data_rate(GF_DownloadManager *dm); *\return error code if any */ GF_Err gf_dm_get_file_memory(const char *url, char **out_data, u32 *out_size, char **out_mime); + + +/* + *\brief Get header sizes and times stats for the session + * + *Get header sizes and times stats for the session + *\param sess the current session + *\param req_hdr_size request header size in bytes. May be NULL. + *\param rsp_hdr_size response header size in bytes. May be NULL. + *\param connect_time connection time in micro seconds. May be NULL. + *\param reply_time ellapsed time between request sent and response header received, in micro seconds. May be NULL. + *\param download_time download time since request sent, in micro seconds. May be NULL. + *\return error code if any + */ +GF_Err gf_dm_sess_get_header_sizes_and_times(GF_DownloadSession *sess, u32 *req_hdr_size, u32 *rsp_hdr_size, u32 *connect_time, u32 *reply_time, u32 *download_time); + + /*! @} */ #ifdef __cplusplus diff --git a/include/gpac/events.h b/include/gpac/events.h index 372e3fd..a2e2de5 100644 --- a/include/gpac/events.h +++ b/include/gpac/events.h @@ -33,7 +33,7 @@ extern "C" { #endif -#include +#include #include #include @@ -150,7 +150,7 @@ typedef struct u8 type; s32 x, y; /*0: absolute positionning, 1: relative move, 2: use alignment constraints*/ - Bool relative; + u32 relative; /*0: left/top, 1: middle, 2: right/bottom*/ u8 align_x, align_y; } GF_EventMove; @@ -283,7 +283,7 @@ typedef struct { typedef struct { /*GF_EVENT_FROM_SERVICE*/ u8 type; - //cf GF_EVT_FORWARDED_ * + //cf GF_EVT_FORWARDED_ * u8 forward_type; /*original type of event as forwarded by the service*/ u32 service_event_type; diff --git a/include/gpac/events_constants.h b/include/gpac/events_constants.h index e8da544..d202724 100644 --- a/include/gpac/events_constants.h +++ b/include/gpac/events_constants.h @@ -184,10 +184,12 @@ typedef enum { if scene size hasn't changed (seeking or other) this event is not sent */ GF_EVENT_SCENE_SIZE, - GF_EVENT_SHOWHIDE, /*window show/hide (minimized or other). This is also sent to the user to signal focus switch in fullscreen*/ + GF_EVENT_SHOWHIDE, /*window show/hide (minimized or other). */ + GF_EVENT_SHOWHIDE_NOTIF, /*window has been show/hide (minimized or other). This is sent to the user to signal focus switch in fullscreen*/ GF_EVENT_SET_CURSOR, /*set mouse cursor*/ GF_EVENT_SET_CAPTION, /*set window caption*/ GF_EVENT_MOVE, /*move window*/ + GF_EVENT_MOVE_NOTIF, /*move window*/ GF_EVENT_REFRESH, /*window needs repaint (whenever needed, eg restore, hide->show, background refresh, paint)*/ GF_EVENT_QUIT, /*app is being closed - associated structure is evt.message to carry any potential reason for quiting*/ /*video hw setup message: @@ -229,6 +231,17 @@ typedef enum { GF_EVENT_TEXT_EDITING_START, GF_EVENT_TEXT_EDITING_END, + GF_EVENT_QUALITY_SWITCHED, + //fire when timeshift depth changes + GF_EVENT_TIMESHIFT_DEPTH, + //fire when position in timeshift buffer changes + GF_EVENT_TIMESHIFT_UPDATE, + //fire when position overflows the timeshift buffer + GF_EVENT_TIMESHIFT_OVERFLOW, + //fire when position underruns the timeshift buffer (eg fast forward / seek in the future) + GF_EVENT_TIMESHIFT_UNDERRUN, + GF_EVENT_MAIN_ADDON_STATE, + GF_EVENT_FROM_SERVICE, GF_EVENT_ADDON_DETECTED, diff --git a/include/gpac/html5_mse.h b/include/gpac/html5_mse.h index dccc2a6..44b500b 100644 --- a/include/gpac/html5_mse.h +++ b/include/gpac/html5_mse.h @@ -132,8 +132,10 @@ typedef struct struct _html_mediasource *parent; +#ifndef GPAC_DISABLE_SVG /* Object used to fire JavaScript events to */ GF_DOMEventTarget *evt_target; +#endif } GF_HTML_SourceBufferList; typedef enum @@ -178,8 +180,10 @@ typedef struct _html_mediasource /* Node the MediaSource is attached to */ GF_Node *node; +#ifndef GPAC_DISABLE_SVG /* object implementing Event Target Interface */ GF_DOMEventTarget *evt_target; +#endif } GF_HTML_MediaSource; GF_HTML_MediaSource *gf_mse_media_source_new(); diff --git a/include/gpac/ietf.h b/include/gpac/ietf.h index ad94531..467e0b7 100644 --- a/include/gpac/ietf.h +++ b/include/gpac/ietf.h @@ -512,6 +512,9 @@ typedef struct tagRTP_HEADER { u32 SSRC; /*in our basic client, CSRC should always be NULL*/ u32 CSRC[16]; + + /*internal to out lib*/ + u64 recomputed_ntp_ts; } GF_RTPHeader; @@ -602,7 +605,7 @@ returns amount of data read (raw UDP packet size)*/ u32 gf_rtp_read_rtp(GF_RTPChannel *ch, char *buffer, u32 buffer_size); u32 gf_rtp_read_rtcp(GF_RTPChannel *ch, char *buffer, u32 buffer_size); -/*decodes an RTP packet and gets the begining of the RTP payload*/ +/*decodes an RTP packet and gets the beginning of the RTP payload*/ GF_Err gf_rtp_decode_rtp(GF_RTPChannel *ch, char *pck, u32 pck_size, GF_RTPHeader *rtp_hdr, u32 *PayloadStart); /*decodes an RTCP packet and update timing info, send RR too*/ @@ -1092,7 +1095,7 @@ enum You should ONLY modify the GF_SLHeader while packetizing, all the rest is private to the tool. Also note that AU start/end is automatically updated, therefore you should only - set CTS-DTS-OCR-sequenceNumber (which is automatically incremented when spliting a payload) + set CTS-DTS-OCR-sequenceNumber (which is automatically incremented when splitting a payload) -padding-idle infos SL flags are computed on the fly, but you may wish to modify them in case of packet drop/... at the encoder side @@ -1195,7 +1198,7 @@ typedef struct __tag_rtp_packetizer GP_RTPPacketizer; @offset_from_orig: start offset in input buffer @OnData: to call each time data is added to current RTP packet (either extra data from payload or data from input when not using referencing) - @is_head: signal the data added MUST be inserted at the begining of the payload. Otherwise data + @is_head: signal the data added MUST be inserted at the beginning of the payload. Otherwise data is concatenated as received */ GP_RTPPacketizer *gf_rtp_builder_new(u32 rtp_payt, diff --git a/include/gpac/internal/bifs_dev.h b/include/gpac/internal/bifs_dev.h index 3fefc56..308592f 100644 --- a/include/gpac/internal/bifs_dev.h +++ b/include/gpac/internal/bifs_dev.h @@ -191,6 +191,8 @@ struct __tag_bifs_enc /*keep track of DEF/USE*/ GF_List *encoded_nodes; Bool is_encoding_command; + + char *src_url; }; GF_Err gf_bifs_enc_commands(GF_BifsEncoder *codec, GF_List *comList, GF_BitStream *bs); diff --git a/include/gpac/internal/compositor_dev.h b/include/gpac/internal/compositor_dev.h index fab6bdc..0605442 100644 --- a/include/gpac/internal/compositor_dev.h +++ b/include/gpac/internal/compositor_dev.h @@ -211,9 +211,10 @@ struct __tag_compositor u32 last_frame_time, caret_next_draw_time; Bool show_caret; Bool text_edit_changed; + //sampled value of audio clock used in bench mode only u32 scene_sampled_clock; u32 last_click_time; - u32 next_frame_delay; + s32 ms_until_next_frame; s32 frame_delay; Bool video_frame_pending; Bool fullscreen_postponed; @@ -401,6 +402,7 @@ struct __tag_compositor /*highlight fill and stroke colors (ARGB)*/ u32 highlight_fill, highlight_stroke; Fixed highlight_stroke_width; + Bool disable_focus_highlight; /*picking info*/ @@ -479,7 +481,7 @@ struct __tag_compositor Bool disable_gl_cull; /*YUV textures in OpenGL are disabled (soft YUV->RGB )*/ Bool disable_yuvgl; - //use PBO to start pushing textures at the begining of the render pass + //use PBO to start pushing textures at the beginning of the render pass Bool enable_pbo; u32 default_navigation_mode; @@ -494,6 +496,8 @@ struct __tag_compositor u32 offscreen_width, offscreen_height; + Bool shader_only_mode; + #ifdef GPAC_USE_TINYGL void *tgl_ctx; #endif @@ -509,6 +513,9 @@ struct __tag_compositor struct _gf_sc_texture_handler *hybgl_txh; GF_Mesh *hybgl_mesh; GF_Mesh *hybgl_mesh_background; + + char *screen_buffer; + u32 screen_buffer_alloc_size; #endif Bool texture_from_decoder_memory; @@ -549,6 +556,7 @@ typedef struct void gf_sc_queue_dom_event(GF_Compositor *compositor, GF_Node *node, GF_DOM_Event *evt); void gf_sc_queue_dom_event_on_target(GF_Compositor *compositor, GF_DOM_Event *evt, GF_DOMEventTarget *target, GF_SceneGraph *sg); +void gf_sc_queue_event(GF_Compositor *compositor, GF_Event *evt); /*base stack for timed nodes (nodes that activate themselves at given times) @UpdateTimeNode: shall be setup by the node handler and is called once per simulation frame @@ -625,7 +633,7 @@ typedef struct _gf_sc_texture_handler /*image data for natural media*/ char *data; - u32 width, height, stride, pixelformat, pixel_ar; + u32 size, width, height, stride, pixelformat, pixel_ar; Bool is_flipped; Bool raw_memory; @@ -793,6 +801,9 @@ struct _traversing_state GF_ColorMatrix color_mat; /* Contains the viewbox transform, used for svg ref() transform */ GF_Matrix2D vb_transform; + + /*only used for bitmap drawing*/ + GF_ColorKey *col_key; /*if set all nodes shall be redrawn - set only at specific places in the tree*/ Bool invalidate_all; @@ -1024,6 +1035,7 @@ u32 gf_afc_process(GF_AudioFilterChain *afc, u32 nb_bytes); void gf_afc_unload(GF_AudioFilterChain *afc); void gf_afc_reset(GF_AudioFilterChain *afc); + /*the audio renderer*/ typedef struct _audio_render { @@ -1031,18 +1043,26 @@ typedef struct _audio_render Bool disable_resync; Bool disable_multichannel; + Bool clock_use_audio_out; - /*startup time (the audio renderer is used when present as the system clock)*/ - u32 startTime; /*frozen time counter if set*/ Bool Frozen; - u32 FreezeTime; + /*startup time, used when no audio output is set*/ + u64 start_time; + /*freeze time, used when no audio output is set*/ + u64 freeze_time; + + /*system clock compute when audio output is present*/ + u32 current_time, bytes_per_second, time_at_last_config; + //number of bytes requested by sound card since last reconfig + u64 bytes_requested; /*final output*/ GF_AudioMixer *mixer; Bool need_reconfig; /*client*/ GF_User *user; + u32 config_forced; GF_List *audio_listeners; /*audio thread if output not self-threaded*/ @@ -1054,17 +1074,23 @@ typedef struct _audio_render GF_AudioFilterChain filter_chain; u32 nb_filled, nb_used; + + Bool step_mode; + } GF_AudioRenderer; /*creates audio renderer*/ GF_AudioRenderer *gf_sc_ar_load(GF_User *user); /*deletes audio renderer*/ void gf_sc_ar_del(GF_AudioRenderer *ar); -/*control audio renderer - CtrlType: - 0: pause - 1: resume - 2: clean HW buffer and play -*/ + +enum +{ + GF_SC_AR_PAUSE=0, + GF_SC_AR_RESUME, + GF_SC_AR_RESET_HW_AND_PLAY, +}; +/*control audio renderer*/ void gf_sc_ar_control(GF_AudioRenderer *ar, u32 CtrlType); /*set volume and pan*/ void gf_sc_ar_set_volume(GF_AudioRenderer *ar, u32 Volume); @@ -1086,6 +1112,9 @@ void gf_sc_ar_remove_src(GF_AudioRenderer *ar, GF_AudioInterface *source); void gf_sc_ar_reconfig(GF_AudioRenderer *ar); u32 gf_sc_ar_get_delay(GF_AudioRenderer *ar); +void gf_sc_flush_next_audio(GF_Compositor *compositor); +Bool gf_sc_check_audio_pending(GF_Compositor *compositor); + /*the sound node interface for intensity & spatialization*/ typedef struct _soundinterface { @@ -1161,6 +1190,8 @@ GF_Err compositor_2d_get_video_access(GF_VisualManager *surf); void compositor_2d_release_video_access(GF_VisualManager *surf); void compositor_2d_init_callbacks(GF_Compositor *compositor); GF_Rect compositor_2d_update_clipper(GF_TraverseState *tr_state, GF_Rect this_clip, Bool *need_restore, GF_Rect *original, Bool for_layer); +Bool compositor_2d_check_attached(GF_VisualManager *visual); +void compositor_2d_clear_surface(GF_VisualManager *visual, GF_IRect *rc, u32 BackColor, Bool is_offscreen); #ifndef GPAC_DISABLE_3D void compositor_2d_reset_gl_auto(GF_Compositor *compositor); diff --git a/include/gpac/internal/dvb_mpe_dev.h b/include/gpac/internal/dvb_mpe_dev.h index 3d55bac..084bb65 100644 --- a/include/gpac/internal/dvb_mpe_dev.h +++ b/include/gpac/internal/dvb_mpe_dev.h @@ -81,7 +81,7 @@ typedef struct { u32 address_mask; u8 address[4]; u8 slash_mask; - u32 rx_port[10]; /* list of the adress port */ + u32 rx_port[10]; /* list of the address port */ } GF_M2TS_IP_Target; typedef struct @@ -131,8 +131,8 @@ typedef struct u32 u32_TTL; /* (Time To Live) when = 0 , the packet is ignored and error message */ u32 u32_protocol; /* TCP = 6, UDP = 17, ICMP = 1 */ u32 u32_crc; - u8 u8_tx_adr[4]; /* source adress */ - u8 u8_rx_adr[4]; /* destination adress */ + u8 u8_tx_adr[4]; /* source address */ + u8 u8_rx_adr[4]; /* destination address */ u32 u32_size_option; /* size of the option before payload */ u32 u32_padding; /* = 1 if where read padding columns */ u32 u32_sum; @@ -200,7 +200,7 @@ void gf_m2ts_ip_platform_init(GF_M2TS_IP_PLATFORM * ip_platform); u32 gf_m2ts_ipdatagram_reader(u8 *datagram, GF_M2TS_IP_Packet *ip_packet, u32 offset); void gf_m2ts_process_ipdatagram(MPE_FEC_FRAME *mff,GF_M2TS_Demuxer *ts); -Bool gf_m2ts_compare_ip(u8 rx_ip_adress[4], u8 ip_adress_bootstrap[4]); +Bool gf_m2ts_compare_ip(u8 rx_ip_address[4], u8 ip_address_bootstrap[4]); struct _sock_entry { diff --git a/include/gpac/internal/isomedia_dev.h b/include/gpac/internal/isomedia_dev.h index 5d37786..093fd4a 100644 --- a/include/gpac/internal/isomedia_dev.h +++ b/include/gpac/internal/isomedia_dev.h @@ -114,6 +114,7 @@ enum GF_ISOM_BOX_TYPE_CRHD = GF_4CC( 'c', 'r', 'h', 'd' ), GF_ISOM_BOX_TYPE_CTTS = GF_4CC( 'c', 't', 't', 's' ), GF_ISOM_BOX_TYPE_CPRT = GF_4CC( 'c', 'p', 'r', 't' ), + GF_ISOM_BOX_TYPE_KIND = GF_4CC( 'k', 'i', 'n', 'd' ), GF_ISOM_BOX_TYPE_CHPL = GF_4CC( 'c', 'h', 'p', 'l' ), GF_ISOM_BOX_TYPE_URL = GF_4CC( 'u', 'r', 'l', ' ' ), GF_ISOM_BOX_TYPE_URN = GF_4CC( 'u', 'r', 'n', ' ' ), @@ -129,6 +130,7 @@ enum GF_ISOM_BOX_TYPE_HMHD = GF_4CC( 'h', 'm', 'h', 'd' ), GF_ISOM_BOX_TYPE_HINT = GF_4CC( 'h', 'i', 'n', 't' ), GF_ISOM_BOX_TYPE_MDIA = GF_4CC( 'm', 'd', 'i', 'a' ), + GF_ISOM_BOX_TYPE_ELNG = GF_4CC( 'e', 'l', 'n', 'g' ), GF_ISOM_BOX_TYPE_MDAT = GF_4CC( 'm', 'd', 'a', 't' ), GF_ISOM_BOX_TYPE_MDHD = GF_4CC( 'm', 'd', 'h', 'd' ), GF_ISOM_BOX_TYPE_MINF = GF_4CC( 'm', 'i', 'n', 'f' ), @@ -178,6 +180,7 @@ enum GF_ISOM_BOX_TYPE_MVEX = GF_4CC( 'm', 'v', 'e', 'x' ), GF_ISOM_BOX_TYPE_MEHD = GF_4CC( 'm', 'e', 'h', 'd' ), GF_ISOM_BOX_TYPE_TREX = GF_4CC( 't', 'r', 'e', 'x' ), + GF_ISOM_BOX_TYPE_TREP = GF_4CC( 't', 'r', 'e', 'p' ), GF_ISOM_BOX_TYPE_MOOF = GF_4CC( 'm', 'o', 'o', 'f' ), GF_ISOM_BOX_TYPE_MFHD = GF_4CC( 'm', 'f', 'h', 'd' ), GF_ISOM_BOX_TYPE_TRAF = GF_4CC( 't', 'r', 'a', 'f' ), @@ -377,6 +380,7 @@ enum GF_ISOM_BOX_TYPE_VTTC = GF_4CC( 'v', 't', 't', 'C' ), GF_ISOM_BOX_TYPE_VTCU = GF_4CC( 'v', 't', 't', 'c' ), GF_ISOM_BOX_TYPE_VTTE = GF_4CC( 'v', 't', 't', 'e' ), + GF_ISOM_BOX_TYPE_VTTA = GF_4CC( 'v', 't', 't', 'a' ), GF_ISOM_BOX_TYPE_CTIM = GF_4CC( 'c', 't', 'i', 'm' ), GF_ISOM_BOX_TYPE_IDEN = GF_4CC( 'i', 'd', 'e', 'n' ), GF_ISOM_BOX_TYPE_STTG = GF_4CC( 's', 't', 't', 'g' ), @@ -386,8 +390,8 @@ enum GF_ISOM_BOX_TYPE_STPP = GF_4CC( 's', 't', 'p', 'p' ), GF_ISOM_BOX_TYPE_SBTT = GF_4CC( 's', 'b', 't', 't' ), - GF_ISOM_BOX_TYPE_STSE = GF_4CC( 's', 't', 's', 'e' ), - GF_ISOM_BOX_TYPE_STTC = GF_4CC( 's', 't', 't', 'C' ), + GF_ISOM_BOX_TYPE_STXT = GF_4CC( 's', 't', 'x', 't' ), + GF_ISOM_BOX_TYPE_TXTC = GF_4CC( 't', 'x', 't', 'C' ), GF_ISOM_BOX_TYPE_PRFT = GF_4CC( 'p', 'r', 'f', 't' ), @@ -409,6 +413,8 @@ enum GF_ISOM_BOX_UUID_TENC = GF_4CC( 'T', 'E', 'N', 'C' ), GF_ISOM_BOX_UUID_TFRF = GF_4CC( 'T', 'F', 'R', 'F' ), GF_ISOM_BOX_UUID_TFXD = GF_4CC( 'T', 'F', 'X', 'D' ), + + GF_ISOM_BOX_TYPE_MP3 = GF_4CC( '.', 'm', 'p', '3' ), }; @@ -610,6 +616,12 @@ typedef struct __tag_media_box u64 BytesMissing; } GF_MediaBox; +typedef struct +{ + GF_ISOM_FULL_BOX + char *extended_language; +} GF_ExtendedLanguageBox; + typedef struct { GF_ISOM_FULL_BOX @@ -619,7 +631,8 @@ typedef struct typedef struct { GF_ISOM_FULL_BOX - u32 reserved; + u16 balance; + u16 reserved; } GF_SoundMediaHeaderBox; typedef struct @@ -799,7 +812,9 @@ typedef struct u32 bufferSizeDB; u32 maxBitrate; u32 avgBitrate; -} GF_MPEG4BitRateBox; +} GF_BitRateBox; + +GF_BitRateBox *gf_isom_sample_entry_get_bitrate(GF_SampleEntryBox *ent, Bool create); typedef struct { @@ -829,7 +844,6 @@ typedef struct GF_ISOM_SAMPLE_ENTRY_FIELDS GF_LASERConfigurationBox *lsr_config; - GF_MPEG4BitRateBox *bitrate; GF_MPEG4ExtensionDescriptorsBox *descr; /*used for hinting when extracting the OD stream...*/ @@ -910,7 +924,6 @@ typedef struct GF_HEVCConfigurationBox *hevc_config; GF_HEVCConfigurationBox *shvc_config; - GF_MPEG4BitRateBox *bitrate; /*ext descriptors*/ GF_MPEG4ExtensionDescriptorsBox *descr; /*internally emulated esd*/ @@ -1035,21 +1048,28 @@ typedef struct { GF_ISOM_SAMPLE_ENTRY_FIELDS GF_DIMSSceneConfigBox *config; - GF_MPEG4BitRateBox *bitrate; GF_DIMSScriptTypesBox *scripts; } GF_DIMSSampleEntryBox; -/*base sample entry box (never used but for typecasting)*/ +typedef struct +{ + GF_ISOM_FULL_BOX + char *config; +} GF_TextConfigBox; + +/*base metadata sample entry box for METT, METX, SBTT, STXT and STPP*/ typedef struct { GF_ISOM_SAMPLE_ENTRY_FIELDS char *content_encoding; //optional - char *mime_type_or_namespace; //not optional - char *xml_schema_loc; // optional - GF_MPEG4BitRateBox *bitrate; // optional + char *mime_type; //for anything except metx + char *xml_namespace; //for metx and sttp only + char *xml_schema_loc; // for metx and sttp only + GF_TextConfigBox *config; //optional for anything except metx and sttp } GF_MetaDataSampleEntryBox; + typedef struct { GF_ISOM_FULL_BOX @@ -1267,6 +1287,7 @@ typedef struct __tag_media_info_box u32 dataEntryIndex; } GF_MediaInformationBox; +GF_Err stbl_AppendDependencyType(GF_SampleTableBox *stbl, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant); typedef struct { @@ -1282,6 +1303,13 @@ typedef struct char *notice; } GF_CopyrightBox; +typedef struct +{ + GF_ISOM_FULL_BOX + char *schemeURI; + char *value; +} GF_KindBox; + typedef struct { @@ -1614,6 +1642,7 @@ typedef struct __tag_mvex_box { GF_ISOM_BOX GF_List *TrackExList; + GF_List *TrackExPropList; GF_MovieExtendsHeaderBox *mehd; GF_ISOFile *mov; } GF_MovieExtendsBox; @@ -1630,6 +1659,13 @@ typedef struct GF_TrackBox *track; } GF_TrackExtendsBox; +/*the TrackExtends contains default values for the track fragments*/ +typedef struct +{ + GF_ISOM_FULL_BOX + u32 trackID; +} GF_TrackExtensionPropertiesBox; + /*indicates the seq num of this fragment*/ typedef struct { @@ -1744,7 +1780,10 @@ typedef struct u32 Duration; u32 size; u32 flags; - u32 CTS_Offset; + s32 CTS_Offset; + + /*internal*/ + u32 SAP_type; } GF_TrunEntry; typedef struct @@ -2309,7 +2348,11 @@ GF_PIFFSampleEncryptionBox *gf_isom_create_piff_psec_box(u8 version, u32 flags, GF_SampleEncryptionBox * gf_isom_create_samp_enc_box(u8 version, u32 flags); void gf_isom_cenc_get_default_info_ex(GF_TrackBox *trak, u32 sampleDescriptionIndex, u32 *default_IsEncrypted, u8 *default_IV_size, bin128 *default_KID); +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID); +#else +GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, void *traf, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID); +#endif GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *ptr); @@ -2520,6 +2563,7 @@ struct __tag_isom { /*if true 3GPP text streams are read as MPEG-4 StreamingText*/ u8 convert_streaming_text; u8 is_jp2; + u8 force_co64; Bool keep_utc; /*main boxes for fast access*/ @@ -2623,15 +2667,15 @@ GF_Err stbl_GetSampleDTS(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS); GF_Err stbl_GetSampleDTS_and_Duration(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS, u32 *duration); /*find a RAP or set the prev / next RAPs if vars are passed*/ -GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, u8 *IsRAP, u32 *prevRAP, u32 *nextRAP); +GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP); /*same as above but only look for open-gop RAPs and GDR (roll)*/ -GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, u8 *IsRAP, u32 *prevRAP, u32 *nextRAP); +GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP); GF_Err stbl_GetSampleInfos(GF_SampleTableBox *stbl, u32 sampleNumber, u64 *offset, u32 *chunkNumber, u32 *descIndex, u8 *isEdited); GF_Err stbl_GetSampleShadow(GF_ShadowSyncBox *stsh, u32 *sampleNumber, u32 *syncNum); GF_Err stbl_GetPaddingBits(GF_PaddingBitsBox *padb, u32 SampleNumber, u8 *PadBits); u32 stbl_GetSampleFragmentCount(GF_SampleFragmentBox *stsf, u32 sampleNumber); u32 stbl_GetSampleFragmentSize(GF_SampleFragmentBox *stsf, u32 sampleNumber, u32 FragmentIndex); -GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *stbl, u32 SampleNumber, u32 *dependsOn, u32 *dependedOn, u32 *redundant); +GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *stbl, u32 SampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant); /*unpack sample2chunk and chunk offset so that we have 1 sample per chunk (edition mode only)*/ @@ -2658,8 +2702,8 @@ GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex, u8 RequestTrack(GF_MovieBox *moov, u32 TrackID); /*Track-Media setup*/ GF_Err NewMedia(GF_MediaBox **mdia, u32 MediaType, u32 TimeScale); -GF_Err Media_ParseODFrame(GF_MediaBox *mdia, GF_ISOSample *sample, GF_ISOSample **od_samp); -GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, GF_ISOSample *sample, u32 StreamDescIndex, u32 syncShadowNumber); +GF_Err Media_ParseODFrame(GF_MediaBox *mdia, const GF_ISOSample *sample, GF_ISOSample **od_samp); +GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, const GF_ISOSample *sample, u32 StreamDescIndex, u32 syncShadowNumber); GF_Err Media_CreateDataRef(GF_DataReferenceBox *dref, char *URLname, char *URNname, u32 *dataRefIndex); /*update a media sample. ONLY in edit mode*/ GF_Err Media_UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, Bool data_only); @@ -2967,6 +3011,7 @@ GF_Box *dinf_New(); GF_Box *url_New(); GF_Box *urn_New(); GF_Box *cprt_New(); +GF_Box *kind_New(); GF_Box *chpl_New(); GF_Box *hdlr_New(); GF_Box *iods_New(); @@ -3018,6 +3063,7 @@ void url_del(GF_Box *); void urn_del(GF_Box *); void chpl_del(GF_Box *); void cprt_del(GF_Box *); +void kind_del(GF_Box *); void hdlr_del(GF_Box *); void iods_del(GF_Box *); void trak_del(GF_Box *); @@ -3069,6 +3115,7 @@ GF_Err url_Write(GF_Box *s, GF_BitStream *bs); GF_Err urn_Write(GF_Box *s, GF_BitStream *bs); GF_Err chpl_Write(GF_Box *s, GF_BitStream *bs); GF_Err cprt_Write(GF_Box *s, GF_BitStream *bs); +GF_Err kind_Write(GF_Box *s, GF_BitStream *bs); GF_Err hdlr_Write(GF_Box *s, GF_BitStream *bs); GF_Err iods_Write(GF_Box *s, GF_BitStream *bs); GF_Err trak_Write(GF_Box *s, GF_BitStream *bs); @@ -3120,6 +3167,7 @@ GF_Err url_Size(GF_Box *); GF_Err urn_Size(GF_Box *); GF_Err chpl_Size(GF_Box *); GF_Err cprt_Size(GF_Box *); +GF_Err kind_Size(GF_Box *); GF_Err hdlr_Size(GF_Box *); GF_Err iods_Size(GF_Box *); GF_Err trak_Size(GF_Box *); @@ -3171,6 +3219,7 @@ GF_Err url_Read(GF_Box *s, GF_BitStream *bs); GF_Err urn_Read(GF_Box *s, GF_BitStream *bs); GF_Err chpl_Read(GF_Box *s, GF_BitStream *bs); GF_Err cprt_Read(GF_Box *s, GF_BitStream *bs); +GF_Err kind_Read(GF_Box *s, GF_BitStream *bs); GF_Err hdlr_Read(GF_Box *s, GF_BitStream *bs); GF_Err iods_Read(GF_Box *s, GF_BitStream *bs); GF_Err trak_Read(GF_Box *s, GF_BitStream *bs); @@ -3202,6 +3251,7 @@ GF_Err uuid_Read(GF_Box *s, GF_BitStream *bs); GF_Err void_Read(GF_Box *s, GF_BitStream *bs); GF_Err stsf_Read(GF_Box *s, GF_BitStream *bs); GF_Err pdin_Read(GF_Box *s, GF_BitStream *bs); +GF_Err gnra_Read(GF_Box *s, GF_BitStream *bs); #ifndef GPAC_DISABLE_ISOM_HINTING @@ -3517,6 +3567,7 @@ GF_Err twrp_Size(GF_Box *s); #ifndef GPAC_DISABLE_VTT /*WebVTT boxes*/ GF_Box *boxstring_New(u32 type); +GF_Box *boxstring_new_with_data(u32 type, const char *string); GF_Box *vtcu_New(); GF_Box *vtte_New(); GF_Box *wvtt_New(); @@ -3563,23 +3614,7 @@ typedef struct GF_StringBox *config; } GF_WebVTTSampleEntryBox; -typedef struct -{ - GF_ISOM_SAMPLE_ENTRY_FIELDS - char *xmlnamespace; // not optional - char *schema_location; // optional - char *auxiliary_mime_types; // optional - GF_MPEG4BitRateBox *bitrate;// not optional -} GF_XMLSubtitleSampleEntryBox; - -typedef struct -{ - GF_ISOM_SAMPLE_ENTRY_FIELDS - char *content_encoding; //optional - char *mime_type; //not optional - GF_MPEG4BitRateBox *bitrate; // optional - GF_StringBox *config; -} GF_SimpleTextSampleEntryBox; +GF_WebVTTSampleEntryBox *gf_webvtt_isom_get_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex); GF_List *gf_webvtt_parse_cues_from_data(const char *data, u32 dataLength, u64 start); @@ -3736,6 +3771,7 @@ GF_Err dinf_dump(GF_Box *a, FILE * trace); GF_Err url_dump(GF_Box *a, FILE * trace); GF_Err urn_dump(GF_Box *a, FILE * trace); GF_Err cprt_dump(GF_Box *a, FILE * trace); +GF_Err kind_dump(GF_Box *a, FILE * trace); GF_Err hdlr_dump(GF_Box *a, FILE * trace); GF_Err iods_dump(GF_Box *a, FILE * trace); GF_Err trak_dump(GF_Box *a, FILE * trace); @@ -3928,19 +3964,12 @@ GF_Err metx_Write(GF_Box *s, GF_BitStream *bs); GF_Err metx_Size(GF_Box *s); GF_Err metx_dump(GF_Box *a, FILE * trace); -GF_Box *stse_New(); -void stse_del(GF_Box *s); -GF_Err stse_Read(GF_Box *s, GF_BitStream *bs); -GF_Err stse_Write(GF_Box *s, GF_BitStream *bs); -GF_Err stse_Size(GF_Box *s); -GF_Err stse_dump(GF_Box *a, FILE * trace); - -GF_Box *stpp_New(); -void stpp_del(GF_Box *s); -GF_Err stpp_Read(GF_Box *s, GF_BitStream *bs); -GF_Err stpp_Write(GF_Box *s, GF_BitStream *bs); -GF_Err stpp_Size(GF_Box *s); -GF_Err stpp_dump(GF_Box *a, FILE * trace); +GF_Box *txtc_New(); +void txtc_del(GF_Box *s); +GF_Err txtc_Read(GF_Box *s, GF_BitStream *bs); +GF_Err txtc_Write(GF_Box *s, GF_BitStream *bs); +GF_Err txtc_Size(GF_Box *s); +GF_Err txtc_dump(GF_Box *a, FILE * trace); GF_Box *tsel_New(); void tsel_del(GF_Box *s); @@ -4132,6 +4161,14 @@ GF_Err prft_dump(GF_Box *a, FILE * trace); //exported for sgpd comparison in traf merge void sgpd_write_entry(u32 grouping_type, void *entry, GF_BitStream *bs); +GF_Box *trep_New(); +void trep_del(GF_Box *); +GF_Err trep_Write(GF_Box *s, GF_BitStream *bs); +GF_Err trep_Size(GF_Box *s); +GF_Err trep_Read(GF_Box *s, GF_BitStream *bs); +GF_Err trep_dump(GF_Box *a, FILE * trace); + + /* Adobe's protection boxes */ @@ -4190,6 +4227,13 @@ GF_Err adaf_Write(GF_Box *s, GF_BitStream *bs); GF_Err adaf_Size(GF_Box *s); GF_Err adaf_dump(GF_Box *a, FILE * trace); +GF_Box *elng_New(); +void elng_del(GF_Box *s); +GF_Err elng_Read(GF_Box *s, GF_BitStream *bs); +GF_Err elng_Write(GF_Box *s, GF_BitStream *bs); +GF_Err elng_Size(GF_Box *s); +GF_Err elng_dump(GF_Box *a, FILE * trace); + #endif /*GPAC_DISABLE_ISOM*/ #ifdef __cplusplus diff --git a/include/gpac/internal/laser_dev.h b/include/gpac/internal/laser_dev.h index 86d3aab..1cd06a2 100644 --- a/include/gpac/internal/laser_dev.h +++ b/include/gpac/internal/laser_dev.h @@ -28,6 +28,7 @@ #define _GF_LASER_DEV_H_ #include +#include #ifndef GPAC_DISABLE_LASER diff --git a/include/gpac/internal/m3u8.h b/include/gpac/internal/m3u8.h index 5fbb103..716f647 100644 --- a/include/gpac/internal/m3u8.h +++ b/include/gpac/internal/m3u8.h @@ -1,8 +1,8 @@ /** * GPAC - Multimedia Framework C SDK * - * Authors: Pierre Souchay - Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2010-2012 + * Authors: Pierre Souchay - Jean Le Feuvre - Romain Bouqueau + * Copyright (c) Telecom ParisTech 2010-2012, Romain Bouqueau * All rights reserved * * This file is part of GPAC @@ -24,160 +24,89 @@ */ #ifndef M3U8_PLAYLIST_H #define M3U8_PLAYLIST_H + #include #include -/** - * Global Structure - * - * For a stream with multiple bandwidths and multiple programs - * - * VariantPlayList - * | - * |_ program id 1 - * | | - * | |_ bandwidth X : playlistElement1 - * | |- bandwidth Y : playlistElement2 - * | - * |- program id 2 - * | - * |_ bandwidth Z : playlistElement - * - * For a "normal" playlist - * - * VariantPlayList - * | - * |_ program id 1 - * | - * |_ bandwidth 0 : playlistElement1 - * - * Where PlaylistElement can be : - * - a stream (real resource) - * - a playlist (list of PlaylistElements itself) - */ -#define M3U8_UNKOWN_MIME_TYPE "unknown" +#define M3U8_UNKNOWN_MIME_TYPE "unknown" /** - * Basic Stream structure + * Basic Media structure */ -typedef struct s_stream { - u8 i; -} Stream; +typedef struct s_media { + int i; //unused: C requires that a struct or union has at least one member +} Media; /** * The playlist contains a list of elements to play */ -typedef struct s_playList { - int currentMediaSequence; - int target_duration; - int mediaSequenceMin; - int mediaSequenceMax; - int computed_duration; - char is_ended; - GF_List * elements; -} Playlist; +struct s_playList { + int current_media_seq; + int media_seq_min; + int media_seq_max; + double target_duration; + double computed_duration; + Bool is_ended; + GF_List *elements; /*PlaylistElement*/ +}; +typedef struct s_playList Playlist; -typedef enum e_playlistElementType { TYPE_PLAYLIST, TYPE_STREAM, TYPE_UNKNOWN} PlaylistElementType; +typedef enum e_playlistElementType { TYPE_PLAYLIST, TYPE_MEDIA, TYPE_UNKNOWN } PlaylistElementType; +typedef enum e_playlistElementDRMMethod { DRM_NONE, DRM_AES_128 } PlaylistElementDRMMethod; /** * The Structure containing the playlist element */ -typedef struct s_playlistElement { - int durationInfo; - u64 byteRangeStart, byteRangeEnd; +struct s_playlistElement { + double duration_info; + u64 byte_range_start, byte_range_end; int bandwidth, width, height; - char * title; - char * codecs; - char * url; - PlaylistElementType elementType; + char *title; + char *codecs; + char *language; + char *audio_group; + char *video_group; + char *url; + PlaylistElementDRMMethod drm_method; + char *key_uri; + bin128 key_iv; + GF_Err load_error; + PlaylistElementType element_type; union { Playlist playlist; - Stream stream; + Media media; } element; +}; +typedef struct s_playlistElement PlaylistElement; -} PlaylistElement; - -typedef struct s_program { - int programId; - GF_List * bitrates; - int currentBitrateIndex; - int computed_duration; -} Program; - +struct s_stream { + int stream_id; //may be a real PROGRAM_ID, or a converted GROUP_ID with GROUP_ID_TO_PROGRAM_ID + GF_List *variants; /*PlaylistElement*/ + double computed_duration; +}; +typedef struct s_stream Stream; /** * The root playlist, can contains several PlaylistElements structures */ -typedef struct s_variantPlaylist { - GF_List * programs; - int currentProgram; - Bool playlistNeedsRefresh; -} VariantPlaylist; - -/** - * Creates a new playlist - * \return NULL if playlist could not be allocated - * -Playlist * playlist_new(); -*/ -/** - * Deletes a given playlist and all of its sub elements - * -GF_Err playlist_del(Playlist *); -*/ - -/** - * Deletes an Playlist element - */ -GF_Err playlist_element_del(PlaylistElement *); +struct s_masterPlaylist { + GF_List *streams; /*Stream*/ + int current_stream; + Bool playlist_needs_refresh; +}; +typedef struct s_masterPlaylist MasterPlaylist; -/** - * Creates a new program properly initialized - */ -Program * program_new(int programId); /** - * Deletes the specified program - */ -GF_Err program_del(Program * program); - -/** - * Creates an Playlist element. - * This element can be either a playlist of a stream according to first parameter. - * \return NULL if element could not be created. Elements will be deleted recusively - */ -PlaylistElement * playlist_element_new(PlaylistElementType elementType, const char * url, const char * title, const char *codecs, int durationInfo, u64 byteRangeStart, u64 byteRangeEnd); - -/** - * Creates a new VariantPlaylist - * \return NULL if VariantPlaylist element could not be allocated - */ -VariantPlaylist * variant_playlist_new (); - -/** - * Deletes the given VariantPlaylist and all of its sub elements - */ -GF_Err variant_playlist_del(VariantPlaylist *); - -GF_Err playlist_element_dump(const PlaylistElement * e, int indent); - -GF_Err variant_playlist_dump(const VariantPlaylist *); - -Program * variant_playlist_find_matching_program(const VariantPlaylist *, const u32 programId); - -Program * variant_playlist_get_current_program(const VariantPlaylist *); - - - -/** - * Parse the given playlist file + * Parse the given m3u8 playlist file * \param file The file from cache to parse * \param playlist The playlist to fill. If argument is null, and file is valid, playlist will be allocated * \param baseURL The base URL of the playlist * \return GF_OK if playlist valid */ -GF_Err parse_root_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL); +GF_Err gf_m3u8_parse_master_playlist(const char *file, MasterPlaylist **playlist, const char *baseURL); + /** * Parse the given playlist file as a subplaylist of an existing playlist * \param file The file from cache to parse @@ -187,7 +116,11 @@ GF_Err parse_root_playlist(const char * file, VariantPlaylist ** playlist, const * \param sub_playlist existing subplaylist element in the playlist in which the playlist is parsed * \return GF_OK if playlist valid */ -GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL, Program * in_program, PlaylistElement *sub_playlist); +GF_Err gf_m3u8_parse_sub_playlist(const char *file, MasterPlaylist **playlist, const char *baseURL, Stream *in_program, PlaylistElement *sub_playlist); -#endif /* M3U8_PLAYLIST_H */ +/** + * Deletes the given MasterPlaylist and all of its sub elements + */ +GF_Err gf_m3u8_master_playlist_del(MasterPlaylist *playlist); +#endif /* M3U8_PLAYLIST_H */ diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index 2f2a6e3..b405b87 100644 --- a/include/gpac/internal/media_dev.h +++ b/include/gpac/internal/media_dev.h @@ -55,9 +55,12 @@ u32 gf_media_nalu_is_start_code(GF_BitStream *bs); /*returns size of chunk between current and next startcode (excluding startcode sizes), 0 if no more startcodes (eos)*/ u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs); +/*returns size of chunk between current startcode and end of payload (0x000000) - if no trailing bytes are found, returns the same as gf_media_nalu_next_start_code_bs*/ +u32 gf_media_nalu_payload_end_bs(GF_BitStream *bs); + /*return nb bytes from current data until the next start code and set the size of the next start code (3 or 4 bytes) returns data_len if no startcode found and sets sc_size to 0 (last nal in payload)*/ -u32 gf_media_nalu_next_start_code(u8 *data, u32 data_len, u32 *sc_size); +u32 gf_media_nalu_next_start_code(const u8 *data, u32 data_len, u32 *sc_size); /*returns NAL unit type - bitstream must be sync'ed!!*/ u8 AVC_NALUType(GF_BitStream *bs); diff --git a/include/gpac/internal/mesh.h b/include/gpac/internal/mesh.h index 6212b4c..c5a844a 100644 --- a/include/gpac/internal/mesh.h +++ b/include/gpac/internal/mesh.h @@ -134,7 +134,7 @@ enum }; /*indexes as used in glDrawElements - note that integer type is not allowed with oglES*/ -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #define IDX_TYPE u16 #else #define IDX_TYPE u32 diff --git a/include/gpac/internal/mpd.h b/include/gpac/internal/mpd.h index 1f6403e..c252a6d 100644 --- a/include/gpac/internal/mpd.h +++ b/include/gpac/internal/mpd.h @@ -41,12 +41,26 @@ typedef struct u32 dummy; } GF_MPD_ContentComponent; -/*TODO*/ + +//some elments are typically overloaded in XML, we keep the attributes / childrne nodes here. The attributes list is NULL if no extensions were found, otherwise it is a list of @GF_XMLAttribute. +//The children list is NULL if no extensions were found, otherwise it is a list of @GF_XMLNode +#define MPD_EXTENSIBLE \ + GF_List *attributes; \ + GF_List *children; \ + typedef struct { + MPD_EXTENSIBLE +} GF_MPD_ExtensibleVirtual; + +typedef struct +{ + MPD_EXTENSIBLE + char *scheme_id_uri; /*MANDATORY*/ char *value; char *id; + } GF_MPD_Descriptor; /*TODO*/ @@ -85,6 +99,9 @@ typedef struct { char *sourceURL; GF_MPD_ByteRange *byte_range; + + //GPAC internal - indicates the URL has already been solved + Bool is_resolved; } GF_MPD_URL; typedef struct @@ -92,6 +109,12 @@ typedef struct u32 num, den; } GF_MPD_Fractional; +typedef struct +{ + u32 trackID; + char *stsd; + s64 mediaOffset; +} GF_MPD_ISOBMFInfo; #define GF_MPD_SEGMENT_BASE \ u32 timescale; \ @@ -102,7 +125,7 @@ typedef struct Double availability_time_offset; \ GF_MPD_URL *initialization_segment; \ GF_MPD_URL *representation_index; \ - + typedef struct { @@ -116,7 +139,7 @@ typedef struct u32 start_number; \ GF_MPD_SegmentTimeline *segment_timeline; \ GF_MPD_URL *bitstream_switching_url; \ - + typedef struct { GF_MPD_MULTIPLE_SEGMENT_BASE @@ -129,6 +152,8 @@ typedef struct char *index; GF_MPD_ByteRange *index_range; u64 duration; + char *key_url; + bin128 key_iv; } GF_MPD_SegmentURL; typedef struct @@ -181,6 +206,7 @@ typedef enum GF_List *content_protection; \ GF_List *essential_properties; \ GF_List *supplemental_properties; \ + GF_List *isobmf_tracks; \ typedef struct { GF_MPD_COMMON_ATTRIBUTES_ELEMENTS @@ -200,6 +226,11 @@ typedef struct Bool disabled; char *cached_init_segment_url; u64 init_start_range, init_end_range; + u32 probe_switch_count; + char *init_segment_data; + u32 init_segment_size; + char *key_url; + bin128 key_IV; } GF_DASH_RepresentationPlayback; typedef struct { @@ -302,6 +333,8 @@ typedef enum { } GF_MPD_Type; typedef struct { + MPD_EXTENSIBLE + char *ID; char *profiles; /*MANDATORY*/ GF_MPD_Type type; @@ -334,6 +367,7 @@ typedef struct { } GF_MPD; GF_Err gf_mpd_init_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *base_url); +GF_Err gf_mpd_complete_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *base_url); GF_MPD *gf_mpd_new(); void gf_mpd_del(GF_MPD *mpd); @@ -341,6 +375,11 @@ void gf_mpd_del(GF_MPD *mpd); void gf_mpd_segment_url_free(void *ptr); void gf_mpd_segment_base_free(void *ptr); +void gf_mpd_period_free(void *_item); + +GF_Err gf_mpd_write_file(GF_MPD *mpd, char *file_name); + + typedef struct _gf_file_get GF_FileDownload; struct _gf_file_get { @@ -356,5 +395,24 @@ struct _gf_file_get /*converts M3U8 to MPD - getter is optional (download will still be processed if NULL)*/ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, const char *mpd_file, u32 reload_count, char *mimeTypeForM3U8Segments, Bool do_import, Bool use_mpd_templates, GF_FileDownload *getter); -#endif // _MPD_H_ + +typedef enum +{ + GF_MPD_RESOLVE_URL_MEDIA, + GF_MPD_RESOLVE_URL_INIT, + GF_MPD_RESOLVE_URL_INDEX, + //same as GF_MPD_RESOLVE_URL_MEDIA but does not replace $Time$ and $Number$ + GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE, +} GF_MPD_URLResolveType; + +/*resolves a URL based for a given segment, based on the MPD url, the type of resolution + item_index: current downloading index of the segment + nb_segments_removed: number of segments removed when pruging the MPD after updates (can be 0). The start number will be offset by this value +*/ +GF_Err gf_mpd_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set, GF_MPD_Period *period, const char *mpd_url, GF_MPD_URLResolveType resolve_type, u32 item_index, u32 nb_segments_removed, + char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url, char **out_key_url, bin128 *key_iv); + + + +#endif // _MPD_H_ diff --git a/include/gpac/internal/scenegraph_dev.h b/include/gpac/internal/scenegraph_dev.h index c063304..1e6f068 100644 --- a/include/gpac/internal/scenegraph_dev.h +++ b/include/gpac/internal/scenegraph_dev.h @@ -45,27 +45,6 @@ extern "C" { #endif -#ifdef GPAC_HAS_SPIDERMONKEY - -/*WIN32 and WinCE config (no configure script)*/ -#if defined(WIN32) || defined(_WIN32_WCE) || defined(__SYMBIAN32__) -#ifndef XP_PC -#define XP_PC -#endif -#ifndef XP_WIN -#define XP_WIN -#endif -/*WINCE specific config*/ -#if defined(_WIN32_WCE) -#include -#define XP_WINCE -#endif -#endif - -/*other platforms should be setup through configure*/ - -#endif - void gf_node_setup(GF_Node *p, u32 tag); @@ -471,6 +450,7 @@ typedef struct u8 FieldType; u8 has_been_accessed; void *field_pointer; + void (*on_event_in)(GF_Node *pThis, struct _route *route); /*eventInHandler*/ } GF_ProtoField; @@ -873,7 +853,8 @@ typedef struct allocate them again and again when getting properties. Garbage collection is performed (if needed) on these objects after each eventIn execution*/ GF_List *js_cache; - struct JSObject *event; + //Event object, whose private is the pointer to current event being executed + struct JSObject *the_event; #endif void (*JS_PreDestroy)(GF_Node *node); @@ -1014,7 +995,7 @@ void dom_js_load(GF_SceneGraph *scene, struct JSContext *c, struct JSObject *glo to releases all resources used by DOM JS)*/ void dom_js_unload(); /*unloads DOM core before the JSContext is being destroyed */ -void dom_js_pre_destroy(struct JSContext *c, GF_SceneGraph *sg, GF_Node *script_or_handler_node); +void gf_sg_js_dom_pre_destroy(struct JSContext *c, GF_SceneGraph *sg, GF_Node *script_or_handler_node); /*defines a new global object "document" of type Document*/ void dom_js_define_document(struct JSContext *c, struct JSObject *global, GF_SceneGraph *doc); diff --git a/include/gpac/internal/smjs_api.h b/include/gpac/internal/smjs_api.h index bf9c649..683dc7e 100644 --- a/include/gpac/internal/smjs_api.h +++ b/include/gpac/internal/smjs_api.h @@ -28,12 +28,52 @@ #include +/*WIN32 and WinCE config (no configure script)*/ +#if defined(WIN32) || defined(_WIN32_WCE) || defined(__SYMBIAN32__) +# ifndef XP_PC +# define XP_PC +# endif +# ifndef XP_WIN +# define XP_WIN +# endif +/*WINCE specific config*/ +# if defined(_WIN32_WCE) +# include +# define XP_WINCE +# endif +#endif + +//Android config #ifdef GPAC_ANDROID -#ifndef XP_UNIX -#define XP_UNIX +# ifndef XP_UNIX +# define XP_UNIX +# endif #endif + +//iOS config +#ifdef GPAC_IPHONE +# ifndef XP_UNIX +# define XP_UNIX +# endif +# ifndef IPHONE_OS +# define IPHONE_OS +# endif +# ifndef DARWIN +# define DARWIN +# endif +#endif + +/*OSX config*/ +#if defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_IPHONE) +# define MOZILLA_1_8_BRANCH +# ifndef XP_UNIX +# define XP_UNIX +# endif #endif + +/*other platforms should be setup through ./configure and have appropriated defines in config.h*/ + #if defined(DEBUG) && defined(GPAC_CONFIG_DARWIN) #undef DEBUG #endif @@ -179,6 +219,7 @@ typedef double jsdouble; #define SMJS_GET_PRIVATE(__ctx, __obj) JS_GetPrivate(__obj) #define SMJS_SET_PRIVATE(__ctx, __obj, __val) JS_SetPrivate(__obj, __val) #define SMJS_GET_PARENT(__ctx, __obj) JS_GetParent(__obj) +#define SMJS_GET_CLASS(__ctx, __obj) JS_GetClass(__obj) #ifdef USE_FFDEV_15 @@ -198,6 +239,7 @@ typedef double jsdouble; #define SMJS_GET_PRIVATE(__ctx, __obj) JS_GetPrivate(__ctx, __obj) #define SMJS_SET_PRIVATE(__ctx, __obj, __val) JS_SetPrivate(__ctx, __obj, __val) #define SMJS_GET_PARENT(__ctx, __obj) JS_GetParent(__ctx, __obj) +#define SMJS_GET_CLASS(__ctx, __obj) JS_GetClass(__ctx, __obj) #ifdef USE_FFDEV_11 #define JS_ClearContextThread(__ctx) @@ -250,6 +292,7 @@ typedef double jsdouble; #define SMJS_GET_PRIVATE(__ctx, __obj) JS_GetPrivate(__ctx, __obj) #define SMJS_SET_PRIVATE(__ctx, __obj, __val) JS_SetPrivate(__ctx, __obj, __val) #define SMJS_GET_PARENT(__ctx, __obj) JS_GetParent(__ctx, __obj) +#define SMJS_GET_CLASS(__obj) JS_GetClass(__obj) #endif @@ -293,6 +336,19 @@ JSBool gf_sg_js_has_instance(JSContext *c, JSObject *obj, jsval val, JSBool *vp) #define GF_JS_InitClass(cx, obj, parent_proto, clasp, constructor, nargs, ps, fs, static_ps, static_fs) \ (clasp)->_proto = JS_InitClass(cx, obj, parent_proto, &(clasp)->_class, constructor, nargs, ps, fs, static_ps, static_fs); + +#define SMJS_GET_NUMBER(val, _d) { \ + if (!JSVAL_IS_NUMBER(val) || (val == JS_GetNaNValue(c)) ) { \ + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JS] Value is not a number while assigning @ file %s line %d \n", __FILE__, __LINE__)); \ + return JS_FALSE; \ + } \ + JS_ValueToNumber(c, val, &_d); \ + if (_d != _d) { \ + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JS] Value is not a number while assigning @ file %s line %d \n", __FILE__, __LINE__)); \ + return JS_FALSE; \ + } \ + } \ + JSObject *gf_sg_js_global_object(JSContext *cx, GF_JSClass *__class); #ifdef __cplusplus diff --git a/include/gpac/internal/swf_dev.h b/include/gpac/internal/swf_dev.h index cbd4e20..84de33e 100644 --- a/include/gpac/internal/swf_dev.h +++ b/include/gpac/internal/swf_dev.h @@ -189,7 +189,7 @@ struct SWFReader /* MP4 user */ void *user; GF_Err (*add_sample)(void *user, const char *data, u32 length, u64 timestamp, Bool isRap); - GF_Err (*add_header)(void *user, const char *data, u32 length); + GF_Err (*add_header)(void *user, const char *data, u32 length, Bool isHeader); }; @@ -198,8 +198,16 @@ SWFFont *swf_find_font(SWFReader *read, u32 fontID); GF_Err swf_parse_sprite(SWFReader *read); GF_Err swf_parse_tag(SWFReader *read); +#ifndef GPAC_DISABLE_VRML GF_Err swf_to_bifs_init(SWFReader *read); +#endif + +#ifndef GPAC_DISABLE_SVG GF_Err swf_to_svg_init(SWFReader *read, u32 flags, Float angle); +GF_Err swf_svg_write_text_sample(void *user, const char *data, u32 length, u64 timestamp, Bool isRap); +GF_Err swf_svg_write_text_header(void *user, const char *data, u32 length, Bool isHeader); +#endif + SWFReader *gf_swf_reader_new(const char *path, const char *filename); GF_Err gf_swf_read_header(SWFReader *read); @@ -207,7 +215,7 @@ void gf_swf_reader_del(SWFReader *read); GF_Err gf_swf_reader_set_user_mode(SWFReader *read, void *user, GF_Err (*add_sample)(void *user, const char *data, u32 length, u64 timestamp, Bool isRap), - GF_Err (*add_header)(void *user, const char *data, u32 length)); + GF_Err (*add_header)(void *user, const char *data, u32 length, Bool isheader)); typedef struct { diff --git a/include/gpac/internal/terminal_dev.h b/include/gpac/internal/terminal_dev.h index abf0dcd..14248a9 100644 --- a/include/gpac/internal/terminal_dev.h +++ b/include/gpac/internal/terminal_dev.h @@ -88,6 +88,8 @@ struct _net_service GF_DownloadSession *pending_service_session; Bool is_paused; + //used when term_set_speed is called before + Fixed set_speed; /*used by DASH until we rewrite the input module API: if set to 1 during a disconnect() call, the root scene of the service and all sub-objects will be disconnected @@ -140,6 +142,7 @@ struct _scene /*OD codec - specific to MPEG-4*/ struct _generic_codec *od_codec; + GF_Mutex *mx_resources; /*all sub resources of this scene (eg, list of GF_ObjectManager), namespace of this scene. This includes both external resources (urls) and ODs sent in MPEG-4 systems*/ GF_List *resources; @@ -177,6 +180,9 @@ struct _scene /*duration of inline scene*/ u64 duration; + /*max timeshift of all objects*/ + u32 timeshift_depth; + /*WorldInfo node or node*/ void *world_info; @@ -222,9 +228,16 @@ struct _scene GF_List *keynavigators; #endif + Bool disable_hitcoord_notif; + + u32 addon_position, addon_size_factor; - GF_AddonMedia *active_addon; GF_List *declared_addons; + //set when content is replaced by an addon (DASH PVR mode) + Bool main_addon_selected; + u32 sys_clock_at_main_activation, obj_clock_at_main_activation; + + Bool pause_at_first_frame; }; GF_Scene *gf_scene_new(GF_Scene *parentScene); @@ -238,8 +251,10 @@ void gf_scene_attach_to_compositor(GF_Scene *scene); struct _mediaobj *gf_scene_get_media_object(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines); struct _mediaobj *gf_scene_get_media_object_ex(GF_Scene *scene, MFURL *url, u32 obj_type_hint, Bool lock_timelines, struct _mediaobj *sync_ref, Bool force_new_if_not_attached, GF_Node *node_ptr); void gf_scene_setup_object(GF_Scene *scene, GF_ObjectManager *odm); -/*updates scene duration based on settings*/ +/*updates scene duration based on sub objects*/ void gf_scene_set_duration(GF_Scene *scene); +/*updates scene timeshift based on sub objects*/ +void gf_scene_set_timeshift_depth(GF_Scene *scene); /*locate media object by ODID (non dynamic ODs) or URL (dynamic ODs)*/ struct _mediaobj *gf_scene_find_object(GF_Scene *scene, u16 ODID, char *url); /*returns scene time in sec - exact meaning of time depends on standard used*/ @@ -254,13 +269,17 @@ void gf_scene_regenerate(GF_Scene *scene); void gf_scene_select_object(GF_Scene *scene, GF_ObjectManager *odm); /*restarts dynamic scene from given time: scene graph is not reseted, objects are just restarted instead of closed and reopened. If a media control is present on inline, from_time is overriden by MC range*/ -void gf_scene_restart_dynamic(GF_Scene *scene, u64 from_time); +void gf_scene_restart_dynamic(GF_Scene *scene, s64 from_time, Bool restart_only, Bool disable_addon_check); + /*exported for compositor: handles filtering of "self" parameter indicating anchor only acts on container inline scene not root one. Returns 1 if handled (cf user.h, navigate event)*/ Bool gf_scene_process_anchor(GF_Node *caller, GF_Event *evt); void gf_scene_force_size_to_video(GF_Scene *scene, GF_MediaObject *mo); -Bool gf_scene_check_clocks(GF_ClientService *ns, GF_Scene *scene); +//check clock status. +//If @check_buffering is 0, returns 1 if all clocks have seen eos, 0 otherwise +//If @check_buffering is 1, returns 1 if no clock is buffering, 0 otheriwse +Bool gf_scene_check_clocks(GF_ClientService *ns, GF_Scene *scene, Bool check_buffering); void gf_scene_notify_event(GF_Scene *scene, u32 event_type, GF_Node *n, void *dom_evt, GF_Err code, Bool no_queueing); @@ -268,6 +287,9 @@ void gf_scene_mpeg4_inline_restart(GF_Scene *scene); GF_Node *gf_scene_get_subscene_root(GF_Node *inline_node); +void gf_scene_select_main_addon(GF_Scene *scene, GF_ObjectManager *odm, Bool set_on, u32 current_clock_time); +void gf_scene_reset_addons(GF_Scene *scene); + #ifndef GPAC_DISABLE_VRML /*extern proto fetcher*/ @@ -437,6 +459,11 @@ struct _tag_terminal u32 bench_mode; u32 prefered_audio_codec_oti; + + u32 low_latency_buffer_max; + + u32 nb_calls_in_event_proc; + u32 disconnect_request_status; }; @@ -526,8 +553,13 @@ struct _object_clock s32 drift; u32 data_timeout; Bool probe_ocr; + Bool broken_pcr; u32 last_TS_rendered; u32 service_id; + + //media time in ms corresponding to the init tmiestamp of the clock + u32 media_time_at_init; + Bool has_media_time_shift; }; /*destroys clock*/ @@ -546,8 +578,8 @@ void gf_clock_reset(GF_Clock *ck); void gf_clock_stop(GF_Clock *ck); /*return clock time in ms*/ u32 gf_clock_time(GF_Clock *ck); -/*return elapsed time in ms since start of the clock*/ -u32 gf_clock_elapse_time(GF_Clock *ck); +/*return media time in ms*/ +u32 gf_clock_media_time(GF_Clock *ck); /*sets clock time - FIXME: drift updates for OCRs*/ void gf_clock_set_time(GF_Clock *ck, u32 TS); /*return clock time in ms without drift adjustment - used by audio objects only*/ @@ -640,6 +672,8 @@ struct _es_channel u32 stream_state; /*the AU in reception is RAP*/ Bool IsRap; + /*the AU in reception is only need for seeking*/ + Bool SeekFlag; /*signal that next AU is an AU start*/ Bool NextIsAUStart; /*if codec resilient, packet drops are not considered as fatal for AU reconstruction (eg no wait for RAP)*/ @@ -697,9 +731,10 @@ struct _es_channel u32 resync_drift; s32 prev_pcr_diff; + u64 last_pcr; /*TSs as received from network - these are used for cache storage*/ - u64 net_dts, net_cts; + u64 net_dts, net_cts, sender_ntp; Bool last_au_was_seek; Bool no_timestamps; @@ -742,8 +777,9 @@ void gf_es_config_drm(GF_Channel *ch, GF_NetComDRMConfig *isma_cryp); void gf_es_dispatch_raw_media_au(GF_Channel *ch, char *payload, u32 payload_size, u32 cts); /*returns true if this stream owns its clock, false if it simply refers to it*/ Bool gf_es_owns_clock(GF_Channel *ch); -void gf_es_reset_timing(GF_Channel *ch); -/*reset all timestamps in CB*/ +/*reset all timestamps in decoder buffer to 0*/ +void gf_es_reset_timing(GF_Channel *ch, Bool reset_buffer); +/*reset all timestamps in CB to 0*/ void gf_cm_reset_timing(GF_CompositionMemory *cb); /*reset timing of all objects associated with this clock*/ void gf_clock_discontinuity(GF_Clock *ck, GF_Scene *scene, Bool is_pcr_discontinuity); @@ -751,6 +787,8 @@ void gf_clock_discontinuity(GF_Clock *ck, GF_Scene *scene, Bool is_pcr_discontin void gf_es_buffer_on(GF_Channel *ch); //turns off buffering on the stream void gf_es_buffer_off(GF_Channel *ch); +//updates buffer info on the stream +void gf_es_update_buffering(GF_Channel *ch, Bool update_info); /* decoder stuff @@ -766,8 +804,8 @@ enum For video, the output is kept alive, For audio, the output is reseted (don't want audio loop ;)*/ GF_ESM_CODEC_EOS = 2, /*pause: the decoder is stopped but the CB is kept intact - THIS IS NOT USED AS A CODEC STATUS, but only for signaling that the CB shouldn't - be reseted - the real status of a "paused" decoder is STOP*/ + The decoder will be in PAUSE mode until its CB is full, and it will then move to STOP mode. + If no CB, this is equivalent to STOP mode*/ GF_ESM_CODEC_PAUSE = 3, /*Buffer: transition state: the decoder runs (fetch data/decode) but the clock is not running (no composition). This is used for rebuffering channels (rtp...)*/ @@ -785,6 +823,9 @@ enum /*set when codec is identified as RAW, meaning all AU comming from the network are directly dispatched to the composition memory*/ GF_ESM_CODEC_IS_RAW_MEDIA = 1<<3, + + /*set when input channels have very low buffering requirement, in which case the codec has to discard all possible late data*/ + GF_ESM_CODEC_IS_LOW_LATENCY = 1<<4, }; struct _generic_codec @@ -833,17 +874,26 @@ struct _generic_codec Bool direct_vout; /*statistics*/ - u32 last_stat_start, cur_bit_size, tot_bit_size, stat_start; + u32 last_stat_start, cur_bit_size, stat_start; u32 avg_bit_rate, max_bit_rate; - u32 nb_dec_frames; - u64 total_dec_time, max_dec_time; + u32 nb_dec_frames, nb_iframes; + //decode times in us + u64 total_dec_time, total_iframes_time; + u32 max_dec_time, max_iframes_time; u32 first_frame_time, last_frame_time; /*number of frames dropped at the presentation*/ - u32 nb_droped; + u32 nb_dropped; /*we detect if the same image is sent again and again to the decoder (using last_unit_signature)*/ u32 nb_repeted_frames; - /*we detect if the same image is sent again and again to the decoder (using last_unit_signature)*/ + /*min frame duration based on DTS diff*/ u32 min_frame_dur; + /*speed at which the avg_dec_time was computed*/ + Fixed check_speed; + //when set, only I-frames are decoded, one out of drop_modulo if not 0. + //If set to 2, all frames are discarded + u32 decode_only_rap; + u32 drop_modulo, drop_count; + u32 consecutive_late_frames, consecutive_ontime_frames; /*for CTS reconstruction (channels not using SL): we cannot just update timing at each frame, not precise enough since we use ms and not microsec TSs*/ @@ -899,6 +949,15 @@ enum /*flag set for first play request*/ GF_ODM_INITIAL_BROADCAST_PLAY = (1<<11), + + /*flag set until ODM is setup*/ + GF_ODM_NOT_SETUP = (1<<12), + + /*flag set when ODM is setup*/ + GF_ODM_PAUSED = (1<<13), + + /*flag set when ODM is setup*/ + GF_ODM_PAUSE_QUEUED = (1<<14), }; enum @@ -957,18 +1016,24 @@ struct _od_manager /*number of channels with connection not yet acknowledge*/ u32 pending_channels; u32 state; - /* during playback: timing as evaluated by the composition memory or the scene codec */ - u32 current_time; + /* during playback: timing as evaluated by the composition memory or the scene codec - this is the timestamp + media time at clock init*/ + u32 media_current_time; /*full object duration 0 if unknown*/ u64 duration; /* upon start: media start time as requested by scene compositor (eg not media control) set to -1 upon stop to postpone stop request */ - u64 media_start_time, media_stop_time; + u64 media_start_time; + s64 media_stop_time; + + /*full object timeshift depth in ms, 0 if no timeshift, (u32) -1 is infinity */ + u32 timeshift_depth; u32 action_type; + Fixed set_speed; + // u32 raw_media_frame_pending; GF_Semaphore *raw_frame_sema; @@ -987,10 +1052,11 @@ struct _od_manager Bool scalable_addon; //for a regular ODM, this indicates that the current scalable_odm associated - struct _od_manager *scalable_odm; + struct _od_manager *upper_layer_odm; + //for a scalable ODM, this indicates the lower layer odm associated + struct _od_manager *lower_layer_odm; }; - GF_ObjectManager *gf_odm_new(); void gf_odm_del(GF_ObjectManager *ODMan); void gf_odm_lock(GF_ObjectManager *odm, u32 LockIt); @@ -1007,6 +1073,10 @@ GF_Err gf_odm_setup_es(GF_ObjectManager *odm, GF_ESD *esd, GF_ClientService *ser void gf_odm_remove_es(GF_ObjectManager *odm, u16 ES_ID); /*set stream duration - updates object duration accordingly*/ void gf_odm_set_duration(GF_ObjectManager *odm, GF_Channel *, u64 stream_duration); + +/*set time shift buffer duration */ +void gf_odm_set_timeshift_depth(GF_ObjectManager *odm, GF_Channel *, u32 time_shift_ms); + /*signals end of stream on channels*/ void gf_odm_on_eos(GF_ObjectManager *odm, GF_Channel *); /*start Object streams and queue object for network PLAY @@ -1026,7 +1096,7 @@ void gf_odm_pause(GF_ObjectManager *odm); /*resume object (mediaControl use only)*/ void gf_odm_resume(GF_ObjectManager *odm); /*set object speed*/ -void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed); +void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed, Bool adjust_clock_speed); /*returns the clock of the media stream (video, audio or bifs), NULL otherwise */ struct _object_clock *gf_odm_get_media_clock(GF_ObjectManager *odm); /*adds segment descriptors targeted by the URL to the list and sort them - the input list must be empty*/ @@ -1043,7 +1113,7 @@ void gf_odm_signal_eos(GF_ObjectManager *odm); void gf_odm_reset_media_control(GF_ObjectManager *odm, Bool signal_reset); /*GF_MediaObject: link between real object manager and scene. although there is a one-to-one mapping between a -MediaObject and an ObjectManager, we have to keep them seperated in order to handle OD remove commands which destroy +MediaObject and an ObjectManager, we have to keep them separated in order to handle OD remove commands which destroy ObjectManagers. */ struct _mediaobj { @@ -1086,6 +1156,12 @@ struct _mediaobj Reset upon creation of the decoder. */ void *node_ptr; + + + /*currently valid properties of the object*/ + u32 width, height, stride, pixel_ar, pixelformat; + Bool is_flipped; + u32 sample_rate, num_channels, bits_per_sample, channel_config; }; GF_MediaObject *gf_mo_new(); @@ -1117,14 +1193,35 @@ void gf_term_service_media_event_with_download(GF_ObjectManager *odm, GF_EventTy u32 gf_mo_get_od_id(MFURL *url); void gf_scene_generate_views(GF_Scene *scene, char *url, char *parent_url); +//sets pos and size of addon +// size is 1/2 height (0), 1/3 (1) or 1/4 (2) +// pos is bottom-left(0), top-left (1) bottom-right (2) or top-right (3) +void gf_scene_set_addon_layout_info(GF_Scene *scene, u32 position, u32 size_factor); void gf_scene_register_associated_media(GF_Scene *scene, GF_AssociatedContentLocation *addon_info); void gf_scene_notify_associated_media_timeline(GF_Scene *scene, GF_AssociatedContentTiming *addon_time); //returns media time in sec for the addon - timestamp_based is set to 1 if no timeline has been found (eg sync is based on direct timestamp comp) -Double gf_scene_adjust_time_for_addon(GF_Scene *scene, u32 clock_time, GF_AddonMedia *addon, Bool *timestamp_based); -u64 gf_scene_adjust_timestamp_for_addon(GF_Scene *scene, u64 orig_ts, GF_AddonMedia *addon); +Double gf_scene_adjust_time_for_addon(GF_AddonMedia *addon, Double clock_time, u32 *timestamp_based); +s64 gf_scene_adjust_timestamp_for_addon(GF_AddonMedia *addon, u64 orig_ts); void gf_scene_select_scalable_addon(GF_Scene *scene, GF_ObjectManager *odm); -void gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts); +/*check if the associated addon has to be restarted, based on the timestamp of the main media (used for scalable addons only). Returns 1 if the addon has been restarted*/ +Bool gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts); + + +//exported for gpac.js, resumes to main content +void gf_scene_resume_live(GF_Scene *subscene); + +enum +{ + //addon to overlay + GF_ADDON_TYPE_ADDITIONAL = 0, + //main content duplicated for PVR purposes + GF_ADDON_TYPE_MAIN, + //scalable decoding - reassembly before the decoder(s) + GF_ADDON_TYPE_SCALABLE, + //multiview reconstruction - reassembly after the decoder(s) + GF_ADDON_TYPE_MULTIVIEW, +}; struct _gf_addon_media { @@ -1136,6 +1233,7 @@ struct _gf_addon_media Double activation_time; Bool enabled; + //object(s) have been started (PLAY command sent) - used to filter out AUs in scalabmle addons Bool started; Bool timeline_ready; @@ -1149,19 +1247,19 @@ struct _gf_addon_media u64 past_media_pts, past_media_pts_scaled; Bool loop_detected; - //0: not scalable - //1: layered coding scalable enhancement (reassembly before the decoder) - //2: view enhancement (reassembly after the decoder) - u32 scalable_type; + u32 addon_type; }; +void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons); + + + GF_Err gf_codec_process_private_media(GF_Codec *codec, u32 TimeAvailable); Bool gf_codec_is_scene_or_image(GF_Codec *codec); void gf_scene_set_service_id(GF_Scene *scene, u32 service_id); -void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons); #ifdef __cplusplus } diff --git a/include/gpac/iso639.h b/include/gpac/iso639.h index 8c1177c..eaf98b3 100644 --- a/include/gpac/iso639.h +++ b/include/gpac/iso639.h @@ -26,501 +26,48 @@ #ifndef _GF_ISO_639_H #define _GF_ISO_639_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <gpac/setup.h> + +/*! + * Gets number of supported language codes + * \return the number of supported language codes +*/ +u32 gf_lang_get_count(); +/*! + * Finds language by name or code + * \param lang_or_rfc_5646_code the langauage name, ISO 639 code or RFC 5646 code + * \return the index of the language, or -1 if not supported +*/ +s32 gf_lang_find(const char *lang_or_rfc_5646_code); -/*ISO 639 code names - - first string is readable english name of the language - - second string is 3-char code of language as per ISO/IEC 639-2/T - - third string is 2-char code of language as per ISO/IEC 639-1, and may be empty +/*! + * Gets the langauge name for the given index + * \param lang_idx the langauge 0-based IDX + * \return the name of the language */ -static const char *GF_ISO639_Lang[] = -{ - "Abkhazian","abk","ab", - "Achinese","ace","", - "Acoli","ach","", - "Adangme","ada","", - "Adyghe; Adygei","ady","", - "Afar","aar","aa", - "Afrihili","afh","", - "Afrikaans","afr","af", - "Afro-Asiatic languages","afa","", - "Ainu","ain","", - "Akan","aka","ak", - "Akkadian","akk","", - "Albanian","sqi","sq", - "Aleut","ale","", - "Algonquian languages","alg","", - "Altaic languages","tut","", - "Amharic","amh","am", - "Angika","anp","", - "Apache languages","apa","", - "Arabic","ara","ar", - "Aragonese","arg","an", - "Arapaho","arp","", - "Arawak","arw","", - "Armenian","hye","hy", - "Aromanian; Arumanian; Macedo-Romanian","rup","", - "Artificial languages","art","", - "Assamese","asm","as", - "Asturian; Bable; Leonese; Asturleonese","ast","", - "Athapascan languages","ath","", - "Australian languages","aus","", - "Austronesian languages","map","", - "Avaric","ava","av", - "Avestan","ave","ae", - "Awadhi","awa","", - "Aymara","aym","ay", - "Azerbaijani","aze","az", - "Balinese","ban","", - "Baltic languages","bat","", - "Baluchi","bal","", - "Bambara","bam","bm", - "Bamileke languages","bai","", - "Banda languages","bad","", - "Bantu languages","bnt","", - "Basa","bas","", - "Bashkir","bak","ba", - "Basque","eus","eu", - "Batak languages","btk","", - "Beja; Bedawiyet","bej","", - "Belarusian","bel","be", - "Bemba","bem","", - "Bengali","ben","bn", - "Berber languages","ber","", - "Bhojpuri","bho","", - "Bihari languages","bih","bh", - "Bikol","bik","", - "Bini; Edo","bin","", - "Bislama","bis","bi", - "Blin; Bilin","byn","", - "Blissymbols; Blissymbolics; Bliss","zbl","", - "BokmÃ¥l, Norwegian; Norwegian BokmÃ¥l","nob","nb", - "Bosnian","bos","bs", - "Braj","bra","", - "Breton","bre","br", - "Buginese","bug","", - "Bulgarian","bul","bg", - "Buriat","bua","", - "Burmese","mya","my", - "Caddo","cad","", - "Catalan; Valencian","cat","ca", - "Caucasian languages","cau","", - "Cebuano","ceb","", - "Celtic languages","cel","", - "Central American Indian languages","cai","", - "Central Khmer","khm","km", - "Chagatai","chg","", - "Chamic languages","cmc","", - "Chamorro","cha","ch", - "Chechen","che","ce", - "Cherokee","chr","", - "Cheyenne","chy","", - "Chibcha","chb","", - "Chichewa; Chewa; Nyanja","nya","ny", - "Chinese","zho","zh", - "Chinook jargon","chn","", - "Chipewyan; Dene Suline","chp","", - "Choctaw","cho","", - "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic","chu","cu", - "Chuukese","chk","", - "Chuvash","chv","cv", - "Classical Newari; Old Newari; Classical Nepal Bhasa","nwc","", - "Classical Syriac","syc","", - "Coptic","cop","", - "Cornish","cor","kw", - "Corsican","cos","co", - "Cree","cre","cr", - "Creek","mus","", - "Creoles and pidgins","crp","", - "Creoles and pidgins, English based","cpe","", - "Creoles and pidgins, French-based","cpf","", - "Creoles and pidgins, Portuguese-based","cpp","", - "Crimean Tatar; Crimean Turkish","crh","", - "Croatian","hrv","hr", - "Cushitic languages","cus","", - "Czech","ces","cs", - "Dakota","dak","", - "Danish","dan","da", - "Dargwa","dar","", - "Delaware","del","", - "Dinka","din","", - "Divehi; Dhivehi; Maldivian","div","dv", - "Dogri","doi","", - "Dogrib","dgr","", - "Dravidian languages","dra","", - "Duala","dua","", - "Dutch, Middle (ca.1050-1350)","dum","", - "Dutch; Flemish","nld","nl", - "Dyula","dyu","", - "Dzongkha","dzo","dz", - "Eastern Frisian","frs","", - "Efik","efi","", - "Egyptian (Ancient)","egy","", - "Ekajuk","eka","", - "Elamite","elx","", - "English","eng","en", - "English, Middle (1100-1500)","enm","", - "English, Old (ca.450-1100)","ang","", - "Erzya","myv","", - "Esperanto","epo","eo", - "Estonian","est","et", - "Ewe","ewe","ee", - "Ewondo","ewo","", - "Fang","fan","", - "Fanti","fat","", - "Faroese","fao","fo", - "Fijian","fij","fj", - "Filipino; Pilipino","fil","", - "Finnish","fin","fi", - "Finno-Ugrian languages","fiu","", - "Fon","fon","", - "French","fra","fr", - "French, Middle (ca.1400-1600)","frm","", - "French, Old (842-ca.1400)","fro","", - "Friulian","fur","", - "Fulah","ful","ff", - "Ga","gaa","", - "Gaelic; Scottish Gaelic","gla","gd", - "Galibi Carib","car","", - "Galician","glg","gl", - "Ganda","lug","lg", - "Gayo","gay","", - "Gbaya","gba","", - "Geez","gez","", - "Georgian","kat","ka", - "German","deu","de", - "German, Middle High (ca.1050-1500)","gmh","", - "German, Old High (ca.750-1050)","goh","", - "Germanic languages","gem","", - "Gilbertese","gil","", - "Gondi","gon","", - "Gorontalo","gor","", - "Gothic","got","", - "Grebo","grb","", - "Greek, Ancient (to 1453)","grc","", - "Greek, Modern (1453-)","ell","el", - "Guarani","grn","gn", - "Gujarati","guj","gu", - "Gwich'in","gwi","", - "Haida","hai","", - "Haitian; Haitian Creole","hat","ht", - "Hausa","hau","ha", - "Hawaiian","haw","", - "Hebrew","heb","he", - "Herero","her","hz", - "Hiligaynon","hil","", - "Himachali languages; Western Pahari languages","him","", - "Hindi","hin","hi", - "Hiri Motu","hmo","ho", - "Hittite","hit","", - "Hmong; Mong","hmn","", - "Hungarian","hun","hu", - "Hupa","hup","", - "Iban","iba","", - "Icelandic","isl","is", - "Ido","ido","io", - "Igbo","ibo","ig", - "Ijo languages","ijo","", - "Iloko","ilo","", - "Inari Sami","smn","", - "Indic languages","inc","", - "Indo-European languages","ine","", - "Indonesian","ind","id", - "Ingush","inh","", - "Interlingua (International Auxiliary Language Association)","ina","ia", - "Interlingue; Occidental","ile","ie", - "Inuktitut","iku","iu", - "Inupiaq","ipk","ik", - "Iranian languages","ira","", - "Irish","gle","ga", - "Irish, Middle (900-1200)","mga","", - "Irish, Old (to 900)","sga","", - "Iroquoian languages","iro","", - "Italian","ita","it", - "Japanese","jpn","ja", - "Javanese","jav","jv", - "Judeo-Arabic","jrb","", - "Judeo-Persian","jpr","", - "Kabardian","kbd","", - "Kabyle","kab","", - "Kachin; Jingpho","kac","", - "Kalaallisut; Greenlandic","kal","kl", - "Kalmyk; Oirat","xal","", - "Kamba","kam","", - "Kannada","kan","kn", - "Kanuri","kau","kr", - "Kara-Kalpak","kaa","", - "Karachay-Balkar","krc","", - "Karelian","krl","", - "Karen languages","kar","", - "Kashmiri","kas","ks", - "Kashubian","csb","", - "Kawi","kaw","", - "Kazakh","kaz","kk", - "Khasi","kha","", - "Khoisan languages","khi","", - "Khotanese; Sakan","kho","", - "Kikuyu; Gikuyu","kik","ki", - "Kimbundu","kmb","", - "Kinyarwanda","kin","rw", - "Kirghiz; Kyrgyz","kir","ky", - "Klingon; tlhIngan-Hol","tlh","", - "Komi","kom","kv", - "Kongo","kon","kg", - "Konkani","kok","", - "Korean","kor","ko", - "Kosraean","kos","", - "Kpelle","kpe","", - "Kru languages","kro","", - "Kuanyama; Kwanyama","kua","kj", - "Kumyk","kum","", - "Kurdish","kur","ku", - "Kurukh","kru","", - "Kutenai","kut","", - "Ladino","lad","", - "Lahnda","lah","", - "Lamba","lam","", - "Land Dayak languages","day","", - "Lao","lao","lo", - "Latin","lat","la", - "Latvian","lav","lv", - "Lezghian","lez","", - "Limburgan; Limburger; Limburgish","lim","li", - "Lingala","lin","ln", - "Lithuanian","lit","lt", - "Lojban","jbo","", - "Low German; Low Saxon; German, Low; Saxon, Low","nds","", - "Lower Sorbian","dsb","", - "Lozi","loz","", - "Luba-Katanga","lub","lu", - "Luba-Lulua","lua","", - "Luiseno","lui","", - "Lule Sami","smj","", - "Lunda","lun","", - "Luo (Kenya and Tanzania)","luo","", - "Lushai","lus","", - "Luxembourgish; Letzeburgesch","ltz","lb", - "Macedonian","mkd","mk", - "Madurese","mad","", - "Magahi","mag","", - "Maithili","mai","", - "Makasar","mak","", - "Malagasy","mlg","mg", - "Malay","msa","ms", - "Malayalam","mal","ml", - "Maltese","mlt","mt", - "Manchu","mnc","", - "Mandar","mdr","", - "Mandingo","man","", - "Manipuri","mni","", - "Manobo languages","mno","", - "Manx","glv","gv", - "Maori","mri","mi", - "Mapudungun; Mapuche","arn","", - "Marathi","mar","mr", - "Mari","chm","", - "Marshallese","mah","mh", - "Marwari","mwr","", - "Masai","mas","", - "Mayan languages","myn","", - "Mende","men","", - "Mi'kmaq; Micmac","mic","", - "Minangkabau","min","", - "Mirandese","mwl","", - "Mohawk","moh","", - "Moksha","mdf","", - "Mon-Khmer languages","mkh","", - "Mongo","lol","", - "Mongolian","mon","mn", - "Mossi","mos","", - "Multiple languages","mul","", - "Munda languages","mun","", - "N'Ko","nqo","", - "Nahuatl languages","nah","", - "Nauru","nau","na", - "Navajo; Navaho","nav","nv", - "Ndebele, North; North Ndebele","nde","nd", - "Ndebele, South; South Ndebele","nbl","nr", - "Ndonga","ndo","ng", - "Neapolitan","nap","", - "Nepal Bhasa; Newari","new","", - "Nepali","nep","ne", - "Nias","nia","", - "Niger-Kordofanian languages","nic","", - "Nilo-Saharan languages","ssa","", - "Niuean","niu","", - "No linguistic content; Not applicable","zxx","", - "Nogai","nog","", - "Norse, Old","non","", - "North American Indian languages","nai","", - "Northern Frisian","frr","", - "Northern Sami","sme","se", - "Norwegian","nor","no", - "Norwegian Nynorsk; Nynorsk, Norwegian","nno","nn", - "Nubian languages","nub","", - "Nyamwezi","nym","", - "Nyankole","nyn","", - "Nyoro","nyo","", - "Nzima","nzi","", - "Occitan (post 1500)","oci","oc", - "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)","arc","", - "Ojibwa","oji","oj", - "Oriya","ori","or", - "Oromo","orm","om", - "Osage","osa","", - "Ossetian; Ossetic","oss","os", - "Otomian languages","oto","", - "Pahlavi","pal","", - "Palauan","pau","", - "Pali","pli","pi", - "Pampanga; Kapampangan","pam","", - "Pangasinan","pag","", - "Panjabi; Punjabi","pan","pa", - "Papiamento","pap","", - "Papuan languages","paa","", - "Pedi; Sepedi; Northern Sotho","nso","", - "Persian","fas","fa", - "Persian, Old (ca.600-400 B.C.)","peo","", - "Philippine languages","phi","", - "Phoenician","phn","", - "Pohnpeian","pon","", - "Polish","pol","pl", - "Portuguese","por","pt", - "Prakrit languages","pra","", - "Provençal, Old (to 1500);Occitan, Old (to 1500)","pro","", - "Pushto; Pashto","pus","ps", - "Quechua","que","qu", - "Rajasthani","raj","", - "Rapanui","rap","", - "Rarotongan; Cook Islands Maori","rar","", - "Reserved for local use","qaa-qtz","", - "Romance languages","roa","", - "Romanian; Moldavian; Moldovan","ron","ro", - "Romansh","roh","rm", - "Romany","rom","", - "Rundi","run","rn", - "Russian","rus","ru", - "Salishan languages","sal","", - "Samaritan Aramaic","sam","", - "Sami languages","smi","", - "Samoan","smo","sm", - "Sandawe","sad","", - "Sango","sag","sg", - "Sanskrit","san","sa", - "Santali","sat","", - "Sardinian","srd","sc", - "Sasak","sas","", - "Scots","sco","", - "Selkup","sel","", - "Semitic languages","sem","", - "Serbian","srp","sr", - "Serer","srr","", - "Shan","shn","", - "Shona","sna","sn", - "Sichuan Yi; Nuosu","iii","ii", - "Sicilian","scn","", - "Sidamo","sid","", - "Sign Languages","sgn","", - "Siksika","bla","", - "Sindhi","snd","sd", - "Sinhala; Sinhalese","sin","si", - "Sino-Tibetan languages","sit","", - "Siouan languages","sio","", - "Skolt Sami","sms","", - "Slave (Athapascan)","den","", - "Slavic languages","sla","", - "Slovak","slk","sk", - "Slovenian","slv","sl", - "Sogdian","sog","", - "Somali","som","so", - "Songhai languages","son","", - "Soninke","snk","", - "Sorbian languages","wen","", - "Sotho, Southern","sot","st", - "South American Indian languages","sai","", - "Southern Altai","alt","", - "Southern Sami","sma","", - "Spanish; Castilian","spa","es", - "Sranan Tongo","srn","", - "Sukuma","suk","", - "Sumerian","sux","", - "Sundanese","sun","su", - "Susu","sus","", - "Swahili","swa","sw", - "Swati","ssw","ss", - "Swedish","swe","sv", - "Swiss German; Alemannic; Alsatian","gsw","", - "Syriac","syr","", - "Tagalog","tgl","tl", - "Tahitian","tah","ty", - "Tai languages","tai","", - "Tajik","tgk","tg", - "Tamashek","tmh","", - "Tamil","tam","ta", - "Tatar","tat","tt", - "Telugu","tel","te", - "Tereno","ter","", - "Tetum","tet","", - "Thai","tha","th", - "Tibetan","bod","bo", - "Tigre","tig","", - "Tigrinya","tir","ti", - "Timne","tem","", - "Tiv","tiv","", - "Tlingit","tli","", - "Tok Pisin","tpi","", - "Tokelau","tkl","", - "Tonga (Nyasa)","tog","", - "Tonga (Tonga Islands)","ton","to", - "Tsimshian","tsi","", - "Tsonga","tso","ts", - "Tswana","tsn","tn", - "Tumbuka","tum","", - "Tupi languages","tup","", - "Turkish","tur","tr", - "Turkish, Ottoman (1500-1928)","ota","", - "Turkmen","tuk","tk", - "Tuvalu","tvl","", - "Tuvinian","tyv","", - "Twi","twi","tw", - "Udmurt","udm","", - "Ugaritic","uga","", - "Uighur; Uyghur","uig","ug", - "Ukrainian","ukr","uk", - "Umbundu","umb","", - "Uncoded languages","mis","", - "Undetermined","und","", - "Upper Sorbian","hsb","", - "Urdu","urd","ur", - "Uzbek","uzb","uz", - "Vai","vai","", - "Venda","ven","ve", - "Vietnamese","vie","vi", - "Volapük","vol","vo", - "Votic","vot","", - "Wakashan languages","wak","", - "Walloon","wln","wa", - "Waray","war","", - "Washo","was","", - "Welsh","cym","cy", - "Western Frisian","fry","fy", - "Wolaitta; Wolaytta","wal","", - "Wolof","wol","wo", - "Xhosa","xho","xh", - "Yakut","sah","", - "Yao","yao","", - "Yapese","yap","", - "Yiddish","yid","yi", - "Yoruba","yor","yo", - "Yupik languages","ypk","", - "Zande languages","znd","", - "Zapotec","zap","", - "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki","zza","", - "Zenaga","zen","", - "Zhuang; Chuang","zha","za", - "Zulu","zul","zu", - "Zuni","zun","", - NULL -}; +const char *gf_lang_get_name(u32 lang_idx); +/*! + * Gets the 2 character code for the given index + * \param lang_idx the langauge 0-based IDX + * \return the 2 character code of the language +*/ +const char *gf_lang_get_2cc(u32 lang_idx); + +/*! + * Gets the 3 character code for the given index + * \param lang_idx the langauge 0-based IDX + * \return the 3 character code of the language +*/ +const char *gf_lang_get_3cc(u32 lang_idx); + + +#ifdef __cplusplus +} +#endif #endif diff --git a/include/gpac/isomedia.h b/include/gpac/isomedia.h index 5f8f6a5..1d9ce06 100644 --- a/include/gpac/isomedia.h +++ b/include/gpac/isomedia.h @@ -72,9 +72,9 @@ enum /*Movie Options for file writing*/ enum { - /*FLAT: the MediaData (MPEG4 ESs) is stored at the begining of the file*/ + /*FLAT: the MediaData (MPEG4 ESs) is stored at the beginning of the file*/ GF_ISOM_STORE_FLAT = 1, - /*STREAMABLE: the MetaData (File Info) is stored at the begining of the file + /*STREAMABLE: the MetaData (File Info) is stored at the beginning of the file for fast access during download*/ GF_ISOM_STORE_STREAMABLE, /*INTERLEAVED: Same as STREAMABLE, plus the media data is mixed by chunk of fixed duration*/ @@ -202,10 +202,10 @@ enum GF_ISOM_SUBTYPE_HVT1 = GF_4CC( 'h', 'v', 't', '1' ), /*3GPP(2) extension subtypes*/ - GF_ISOM_SUBTYPE_3GP_H263 = GF_4CC( 's', '2', '6', '3' ), + GF_ISOM_SUBTYPE_3GP_H263 = GF_4CC( 's', '2', '6', '3' ), GF_ISOM_SUBTYPE_3GP_AMR = GF_4CC( 's', 'a', 'm', 'r' ), GF_ISOM_SUBTYPE_3GP_AMR_WB = GF_4CC( 's', 'a', 'w', 'b' ), - GF_ISOM_SUBTYPE_3GP_EVRC = GF_4CC( 's', 'e', 'v', 'c' ), + GF_ISOM_SUBTYPE_3GP_EVRC = GF_4CC( 's', 'e', 'v', 'c' ), GF_ISOM_SUBTYPE_3GP_QCELP = GF_4CC( 's', 'q', 'c', 'p' ), GF_ISOM_SUBTYPE_3GP_SMV = GF_4CC( 's', 's', 'm', 'v' ), @@ -213,12 +213,15 @@ enum GF_ISOM_SUBTYPE_3GP_DIMS = GF_4CC( 'd', 'i', 'm', 's' ), GF_ISOM_SUBTYPE_AC3 = GF_4CC( 'a', 'c', '-', '3' ), + GF_ISOM_SUBTYPE_MP3 = GF_4CC( '.', 'm', 'p', '3' ), GF_ISOM_SUBTYPE_LSR1 = GF_4CC( 'l', 's', 'r', '1' ), GF_ISOM_SUBTYPE_WVTT = GF_4CC( 'w', 'v', 't', 't' ), - GF_ISOM_SUBTYPE_STSE = GF_4CC( 's', 't', 's', 'e' ), + GF_ISOM_SUBTYPE_STXT = GF_4CC( 's', 't', 'x', 't' ), GF_ISOM_SUBTYPE_STPP = GF_4CC( 's', 't', 'p', 'p' ), GF_ISOM_SUBTYPE_SBTT = GF_4CC( 's', 'b', 't', 't' ), + GF_ISOM_SUBTYPE_METT = GF_4CC( 'm', 'e', 't', 't' ), + GF_ISOM_SUBTYPE_METX = GF_4CC( 'm', 'e', 't', 'x' ), }; @@ -302,6 +305,19 @@ enum /*the isomedia file*/ typedef struct __tag_isom GF_ISOFile; +/*Random Access Point flag*/ +typedef enum { + RAP_REDUNDANT = -1, + RAP_NO = 0, + RAP = 1, + SAP_TYPE_1 = 1, + SAP_TYPE_2 = 2, + SAP_TYPE_3 = 3, + SAP_TYPE_4 = 4, + SAP_TYPE_5 = 5, + SAP_TYPE_6 = 6 +} SAPType; + /*media sample object*/ typedef struct { @@ -313,13 +329,7 @@ typedef struct u64 DTS; /*relative offset for composition if needed*/ s32 CTS_Offset; - /*Random Access Point flag: - 0: not random access - 1: regular RAP, - 2: sample is a redundant RAP. If set when adding the sample, this will create a sample dependency entry - 3: specific RAP (CRA/BLA in HEVC) - */ - u8 IsRAP; + SAPType IsRAP; } GF_ISOSample; @@ -349,7 +359,7 @@ GF_Err gf_isom_last_error(GF_ISOFile *the_file); u32 gf_isom_probe_file(const char *fileName); /*Opens an isoMedia File. -tmp_dir: for the 2 edit modes only, specifies a location for temp file. If NULL, the librairy will use the default +tmp_dir: for the 2 edit modes only, specifies a location for temp file. If NULL, the library will use the default OS temporary file management schemes.*/ GF_ISOFile *gf_isom_open(const char *fileName, u32 OpenMode, const char *tmp_dir); @@ -552,6 +562,8 @@ u32 gf_isom_get_sample_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNum /*returns sync flag of sample*/ u8 gf_isom_get_sample_sync(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber); +GF_Err gf_isom_get_sample_flags(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *is_leading, u32 *dependsOn, u32 *dependedOn, u32 *redundant); + /*gets a sample given a desired decoding time IN MEDIA TIME SCALE and set the StreamDescIndex of this sample this index allows to retrieve the stream description if needed (2 media in 1 track) @@ -739,17 +751,30 @@ GF_Err gf_isom_get_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptio User Data Manipulation (cf write API too) */ +//returns the number of entries in UDTA of the track if trackNumber is not 0, or of the movie otherwise +u32 gf_isom_get_udta_count(GF_ISOFile *movie, u32 trackNumber); + +//returns the type (box 4CC and UUID if any) of the given entry in UDTA of the track if trackNumber is not 0, or of the movie otherwise. udta_idx is 1-based index. +GF_Err gf_isom_get_udta_type(GF_ISOFile *movie, u32 trackNumber, u32 udta_idx, u32 *UserDataType, bin128 *UUID); + /* Gets the number of UserDataItems with the same ID / UUID in the desired track or in the movie if trackNumber is set to 0*/ u32 gf_isom_get_user_data_count(GF_ISOFile *the_file, u32 trackNumber, u32 UserDataType, bin128 UUID); /* Gets the UserData for the specified item from the track or the movie if trackNumber is set to 0 data is allocated by the function and is yours to free -you musty pass (userData != NULL && *userData=NULL)*/ +you musty pass (userData != NULL && *userData=NULL) + +if UserDataIndex is 0, all boxes with type==UserDataType will be serialized (including box header and size) in the buffer +*/ GF_Err gf_isom_get_user_data(GF_ISOFile *the_file, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex, char **userData, u32 *userDataSize); -/*gets 3char media language code - @three_char_code must be at least 4 char long*/ -GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char *three_char_code); +/*gets the media language code (3 chars if old files, longer if BCP-47 */ +GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char **lang); + +/* gets the i-th track kind (0-based) */ +u32 gf_isom_get_track_kind_count(GF_ISOFile *the_file, u32 trackNumber); +GF_Err gf_isom_get_track_kind(GF_ISOFile *the_file, u32 trackNumber, u32 index, char **scheme, char **value); /*Unknown sample description*/ typedef struct @@ -858,7 +883,10 @@ GF_Err gf_isom_set_track_id(GF_ISOFile *the_file, u32 trackNumber, u32 trackID); GF_Err gf_isom_rewrite_track_dependencies(GF_ISOFile *movie, u32 trackNumber); /*Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several)*/ -GF_Err gf_isom_add_sample(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample); +GF_Err gf_isom_add_sample(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ISOSample *sample); + +//copies all sample dependency, subSample and sample group information from the given sampleNumber in source file to the last added sample in dest file +GF_Err gf_isom_copy_sample_info(GF_ISOFile *dst, u32 dst_track, GF_ISOFile *src, u32 src_track, u32 sampleNumber); /*Add sync shadow sample to a track. - There must be a regular sample with the same DTS. @@ -898,6 +926,9 @@ GF_Err gf_isom_set_handler_name(GF_ISOFile *the_file, u32 trackNumber, const cha are of same sizes (typically in 3GP speech tracks)*/ GF_Err gf_isom_refresh_size_info(GF_ISOFile *file, u32 trackNumber); +/*return the duration of the movie, 0 if error*/ +GF_Err gf_isom_update_duration(GF_ISOFile *the_file); + /*Update Sample functions*/ /*update a given sample of the media. @@ -930,12 +961,20 @@ InterleaveTime is in MovieTimeScale*/ GF_Err gf_isom_set_interleave_time(GF_ISOFile *the_file, u32 InterleaveTime); u32 gf_isom_get_interleave_time(GF_ISOFile *the_file); +/*forces usage of 64 bit chunk offsets*/ +void gf_isom_force_64bit_chunk_offset(GF_ISOFile *the_file, Bool set_on); + /*set the copyright in one language.*/ GF_Err gf_isom_set_copyright(GF_ISOFile *the_file, const char *threeCharCode, char *notice); /*deletes copyright (1-based indexes)*/ GF_Err gf_isom_remove_copyright(GF_ISOFile *the_file, u32 index); +/*add a kind type to the track */ +GF_Err gf_isom_add_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value); +/*removes a kind type to the track, all if NULL params */ +GF_Err gf_isom_remove_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value); + /*changes the handler type of the media*/ GF_Err gf_isom_set_media_type(GF_ISOFile *movie, u32 trackNumber, u32 new_type); @@ -984,6 +1023,9 @@ GF_Err gf_isom_remove_edit_segments(GF_ISOFile *the_file, u32 trackNumber); is updated to maintain a continous timeline*/ GF_Err gf_isom_remove_edit_segment(GF_ISOFile *the_file, u32 trackNumber, u32 seg_index); +/*Updates edit list after track edition: all edit entries with aduration or media starttime larger than the media duration are clamped to media duration*/ +GF_Err gf_isom_update_edit_list_duration(GF_ISOFile *file, u32 track); + /* User Data Manipulation @@ -1011,6 +1053,9 @@ GF_Err gf_isom_remove_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID); /*adds track, moov (trackNumber=0) or file-level (trackNumber=0xFFFFFFFF) UUID box of given type*/ GF_Err gf_isom_add_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID, char *data, u32 data_size); +/*Add a user data item in the desired track or in the movie if TrackNumber is 0, using a serialzed buffer of ISOBMFF boxes*/ +GF_Err gf_isom_add_user_data_boxes(GF_ISOFile *the_file, u32 trackNumber, char *data, u32 DataLength); + /* Update of the Writing API for IsoMedia Version 2 */ @@ -1067,8 +1112,8 @@ GF_Err gf_isom_modify_cts_offset(GF_ISOFile *the_file, u32 trackNumber, u32 samp /*remove CTS offset table (used for B-frames)*/ GF_Err gf_isom_remove_cts_info(GF_ISOFile *the_file, u32 trackNumber); -/*set 3char code media language*/ -GF_Err gf_isom_set_media_language(GF_ISOFile *the_file, u32 trackNumber, char *three_char_code); +/*set 3-char or BCP-47 code media language*/ +GF_Err gf_isom_set_media_language(GF_ISOFile *the_file, u32 trackNumber, char *code); /*removes given stream description*/ GF_Err gf_isom_remove_sample_description(GF_ISOFile *the_file, u32 trackNumber, u32 streamDescIndex); @@ -1123,6 +1168,9 @@ GF_Err gf_isom_change_mpeg4_description(GF_ISOFile *the_file, u32 trackNumber, u /*Add a system descriptor to the ESD of a stream - you have to delete the descriptor*/ GF_Err gf_isom_add_desc_to_description(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_Descriptor *theDesc); +/*updates average and max bitrate - if 0 for max, removes bitrate info*/ +GF_Err gf_isom_update_bitrate(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, u32 average_bitrate, u32 max_bitrate, u32 decode_buffer_size); + /*Default extensions*/ @@ -1146,7 +1194,7 @@ GF_Err gf_isom_clone_sample_description(GF_ISOFile *the_file, u32 trackNumber, G /*clones all sampleDescription entries in new track, after an optional reset of existing entries*/ GF_Err gf_isom_clone_sample_descriptions(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, Bool reset_existing); -/*special shortcut: clones a track (everything except media data and sample info (DTS? CTS, RAPs, etc...) +/*special shortcut: clones a track (everything except media data and sample info (DTS, CTS, RAPs, etc...) also clones sampleDescriptions @keep_data_ref: if set, external data references are kept, otherwise they are removed (track media data will be self-contained) @dest_track: track number of cloned track*/ @@ -1177,12 +1225,21 @@ GF_Err gf_isom_reset_data_offset(GF_ISOFile *movie, u64 *top_box_start); /*releases current movie segment - this closes the associated file IO object. If reset_tables is set, sample information for all tracks setup as segment are destroyed, along with all PSSH boxes. This allows keeping the memory -footprint low when playing segments. Note however that seeking in the file is then no longer possible +footprint low when playing segments. Note however that seeking in the file is then no longer; possible WARNING - the sample count is not reset after the release of tables. This means you need to keep counting samples.*/ GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables); + +/*Flags for gf_isom_open_segment*/ +enum +{ + /*FLAT: the MediaData (MPEG4 ESs) is stored at the beginning of the file*/ + GF_ISOM_SEGMENT_NO_ORDER_FLAG = 1, + GF_ISOM_SEGMENT_SCALABLE_FLAG = 1<<1, +}; + /*opens a new segment file. Access to samples in previous segments is no longer possible if end_range>start_range, restricts the URL to the given byterange when parsing*/ -GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, Bool is_scalable_segment); +GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, u32 flags); /*returns track ID of the traf containing the highest enhancement layer for the given base track*/ u32 gf_isom_get_highest_track_in_scalable_segment(GF_ISOFile *movie, u32 for_base_track); @@ -1260,7 +1317,7 @@ fragment media data for all tracks*/ GF_Err gf_isom_start_fragment(GF_ISOFile *movie, Bool moof_first); /*starts a new segment in the file. If SegName is given, the output will be written in the SegName file. If memory_mode is set, all samples writing is done in memory rather than on disk*/ -GF_Err gf_isom_start_segment(GF_ISOFile *movie, char *SegName, Bool memory_mode); +GF_Err gf_isom_start_segment(GF_ISOFile *movie, const char *SegName, Bool memory_mode); /*sets the baseMediaDecodeTime of the first sample of the given track*/ GF_Err gf_isom_set_traf_base_media_decode_time(GF_ISOFile *movie, u32 TrackID, u64 decode_time); @@ -1299,7 +1356,7 @@ enum GF_ISOM_TRAF_DATA_CACHE }; -/*set options. Options can be set at the begining of each new fragment only, and for the +/*set options. Options can be set at the beginning of each new fragment only, and for the lifetime of the fragment*/ GF_Err gf_isom_set_fragment_option(GF_ISOFile *the_file, u32 TrackID, u32 Code, u32 param); @@ -1319,7 +1376,7 @@ MUST be provided (in case of regular tracks, this was computed internally by the */ -GF_Err gf_isom_fragment_add_sample(GF_ISOFile *the_file, u32 TrackID, GF_ISOSample *sample, +GF_Err gf_isom_fragment_add_sample(GF_ISOFile *the_file, u32 TrackID, const GF_ISOSample *sample, u32 StreamDescriptionIndex, u32 Duration, u8 PaddingBits, u16 DegradationPriority, Bool redundantCoding); @@ -1436,7 +1493,7 @@ GF_Err gf_isom_end_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u8 IsRando /****************************************************************** PacketHandling functions Data can be added at the end or at the beginning of the current packet - by setting AtBegin to 1 the data will be added at the begining + by setting AtBegin to 1 the data will be added at the beginning This allows constructing the packet payload before any meta-data ******************************************************************/ @@ -1588,7 +1645,7 @@ returns an error if not supported, or GF_EOS when no more packets are available currently only RTP reader is supported @pck_data, @pck_size: output packet data (must be freed by caller) - contains all info to be sent on the wire, eg for RTP contains the RTP header and the data -@disposable (optional): indicates that the packet can be droped when late (B-frames & co) +@disposable (optional): indicates that the packet can be dropped when late (B-frames & co) @repeated (optional): indicates this is a repeated packet (same one has already been sent) @trans_ts (optional): indicates the transmission time of the packet, expressed in hint timescale, taking into account the ts_offset specified in gf_isom_reset_hint_reader. Depending on packets this may not be the same @@ -1683,7 +1740,7 @@ enum GF_ISOM_NALU_EXTRACT_INSPECT, /*above mode is applied and PPS/SPS/... are appended in the front of every IDR*/ GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG = 1<<16, - /*above mode is applied and all start codes are rewritten*/ + /*above mode is applied and all start codes are rewritten (xPS inband as well)*/ GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG = 2<<16, /*above mode is applied and VDRD NAL unit is inserted before SVC slice*/ GF_ISOM_NALU_EXTRACT_VDRD_FLAG = 1<<18, @@ -1742,7 +1799,12 @@ GF_Err gf_isom_text_set_streaming_mode(GF_ISOFile *the_file, Bool do_convert); /*exports text track to given format @dump_type: 0 for TTXT, 1 for srt, 2 for SVG */ -GF_Err gf_isom_text_dump(GF_ISOFile *the_file, u32 track, FILE *dump, u32 dump_type); +typedef enum { + GF_TEXTDUMPTYPE_TTXT = 0, + GF_TEXTDUMPTYPE_SRT = 1, + GF_TEXTDUMPTYPE_SVG = 2, +} GF_TextDumpType; +GF_Err gf_isom_text_dump(GF_ISOFile *the_file, u32 track, FILE *dump, GF_TextDumpType dump_type); #endif /*returns encoded TX3G box (text sample description for 3GPP text streams) as needed by RTP or other standards: @@ -1778,6 +1840,29 @@ void gf_isom_delete_generic_subtitle_sample(GF_GenericSubtitleSample *generic_su GF_Err gf_isom_new_webvtt_description(GF_ISOFile *movie, u32 trackNumber, GF_TextSampleDescriptor *desc, char *URLname, char *URNname, u32 *outDescriptionIndex); GF_Err gf_isom_update_webvtt_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, const char *config); +GF_Err gf_isom_stxt_get_description(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const char **mime, const char **encoding, const char **config); +GF_Err gf_isom_new_stxt_description(GF_ISOFile *movie, u32 trackNumber, u32 type, const char *mime, const char *encoding, const char *config, u32 *outDescriptionIndex); +GF_Err gf_isom_update_stxt_description(GF_ISOFile *movie, u32 trackNumber, const char *encoding, const char *config, u32 DescriptionIndex); + +GF_Err gf_isom_xml_subtitle_get_description(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, + const char **xmlnamespace, const char **xml_schema_loc, const char **mimes); +GF_Err gf_isom_new_xml_subtitle_description(GF_ISOFile *movie, u32 trackNumber, + const char *xmlnamespace, const char *xml_schema_loc, const char *auxiliary_mimes, + u32 *outDescriptionIndex); +GF_Err gf_isom_update_xml_subtitle_description(GF_ISOFile *movie, u32 trackNumber, + u32 descriptionIndex, GF_GenericSubtitleSampleDescriptor *desc); + + + +typedef enum +{ + GF_ISOM_TEXT_FLAGS_OVERWRITE = 0, + GF_ISOM_TEXT_FLAGS_TOGGLE, + GF_ISOM_TEXT_FLAGS_UNTOGGLE, +} GF_TextFlagsMode; +//sets text display flags according to given mode. If SampleDescriptionIndex is 0, sets the flags for all text descriptions. +GF_Err gf_isom_text_set_display_flags(GF_ISOFile *file, u32 track, u32 SampleDescriptionIndex, u32 flags, GF_TextFlagsMode op_type); + #ifndef GPAC_DISABLE_ISOM_WRITE /*Create a new TextSampleDescription in the file. @@ -1845,12 +1930,10 @@ text sample content is kept untouched*/ GF_ISOSample *gf_isom_text_to_sample(GF_TextSample * tx_samp); -GF_Err gf_isom_generic_subtitle_reset(GF_GenericSubtitleSample *samp); -GF_ISOSample *gf_isom_generic_subtitle_to_sample(GF_GenericSubtitleSample * tx_samp); -GF_Err gf_isom_generic_subtitle_sample_add_text(GF_GenericSubtitleSample *samp, char *text_data, u32 text_len); +GF_GenericSubtitleSample *gf_isom_new_xml_subtitle_sample(); +void gf_isom_delete_xml_subtitle_sample(GF_GenericSubtitleSample * samp); GF_Err gf_isom_xml_subtitle_reset(GF_GenericSubtitleSample *samp); -GF_Err gf_isom_new_xml_subtitle_description(GF_ISOFile *movie, u32 trackNumber, char *xmlnamespace, char *xml_schema_loc, char *mimes, u32 *outDescriptionIndex); GF_ISOSample *gf_isom_xml_subtitle_to_sample(GF_GenericSubtitleSample * tx_samp); GF_Err gf_isom_xml_subtitle_sample_add_text(GF_GenericSubtitleSample *samp, char *text_data, u32 text_len); @@ -2118,11 +2201,11 @@ GF_Err gf_isom_set_meta_primary_item(GF_ISOFile *file, Bool root_meta, u32 track Timed Meta-Data extensions ********************************************************************/ -GF_Err gf_isom_get_timed_meta_data_info(GF_ISOFile *file, u32 track, u32 sampleDescription, Bool *is_xml, const char **mime_or_namespace, const char **content_encoding, const char **schema_loc); +GF_Err gf_isom_get_xml_metadata_description(GF_ISOFile *file, u32 track, u32 sampleDescription, const char **_namespace, const char **schema_loc, const char **content_encoding); #ifndef GPAC_DISABLE_ISOM_WRITE /*create a new timed metat data sample description for this track*/ -GF_Err gf_isom_timed_meta_data_config_new(GF_ISOFile *movie, u32 trackNumber, Bool is_xml, char *mime_or_namespace, char *content_encoding, char *schema_loc, char *URLname, char *URNname, u32 *outDescriptionIndex); +GF_Err gf_isom_new_xml_metadata_description(GF_ISOFile *movie, u32 trackNumber, const char *_namespace, const char *schema_loc, const char *content_encoding, u32 *outDescriptionIndex); #endif /*GPAC_DISABLE_ISOM_WRITE*/ @@ -2131,8 +2214,10 @@ GF_Err gf_isom_timed_meta_data_config_new(GF_ISOFile *movie, u32 trackNumber, Bo ********************************************************************/ enum { - /*probe is only used ti check if iTunes info are present*/ + /*probe is only used to check if iTunes info are present*/ GF_ISOM_ITUNE_PROBE = 0, + /*probe is only used to remove all tags*/ + GF_ISOM_ITUNE_ALL = 1, GF_ISOM_ITUNE_ALBUM = GF_4CC( 0xA9, 'a', 'l', 'b' ), GF_ISOM_ITUNE_ARTIST = GF_4CC( 0xA9, 'A', 'R', 'T' ), GF_ISOM_ITUNE_COMMENT = GF_4CC( 0xA9, 'c', 'm', 't' ), diff --git a/include/gpac/math.h b/include/gpac/maths.h similarity index 99% rename from include/gpac/math.h rename to include/gpac/maths.h index 29dd00a..99df188 100644 --- a/include/gpac/math.h +++ b/include/gpac/maths.h @@ -31,7 +31,7 @@ extern "C" { #endif /*! - * \file <gpac/math.h> + * \file <gpac/maths.h> * \brief math and trigo functions. */ diff --git a/include/gpac/media_tools.h b/include/gpac/media_tools.h index 5175a69..4d8664a 100644 --- a/include/gpac/media_tools.h +++ b/include/gpac/media_tools.h @@ -47,7 +47,7 @@ GF_ESD *gf_media_map_esd(GF_ISOFile *mp4, u32 track); * \brief Get RFC 6381 description for @track from @movie. * \parama szCodec a pointer to an already allocated string. */ -GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCodec); +GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCodec, Bool force_inband_xps, Bool force_sbr); #endif #ifndef GPAC_DISABLE_ISOM_WRITE @@ -116,6 +116,15 @@ enum THE RESULTING FILE IS NOT COMPLIANT*/ GF_IMPORT_FORCE_SYNC = 1<<16, + /*keep trailing 0 bytes in AU payloads when any*/ + GF_IMPORT_KEEP_TRAILING = 1<<17, + + /*forces inband parameter sets*/ + GF_IMPORT_FORCE_XPS_INBAND = 1<<18, + + /*do not compute edit list for B-frames video tracks*/ + GF_IMPORT_NO_EDIT_LIST = 1<<19, + /*when set, only updates tracks info and return*/ GF_IMPORT_PROBE_ONLY = 1<<20, /*only set when probing, signals several frames per sample possible*/ @@ -126,6 +135,8 @@ enum GF_IMPORT_NO_DURATION = 1<<23, /*when set IP packets found in MPE sections will be sent to the local network */ GF_IMPORT_MPE_DEMUX = 1<<24, + + /*when set by user during import, will abort*/ GF_IMPORT_DO_ABORT = 1<<31 }; @@ -282,10 +293,12 @@ GF_Err gf_media_split_hevc_tiles(GF_ISOFile *file); typedef struct { char *file_name; - char representationID[100]; - char periodID[100]; - char xlink[100]; - char role[100]; + char *representationID; + char *periodID; + u32 nb_baseURL; + char **baseURL; + char *xlink; + char *role; u32 nb_rep_descs; char **rep_descs; u32 nb_p_descs; @@ -295,6 +308,7 @@ typedef struct u32 nb_as_c_descs; char **as_c_descs; u32 bandwidth; + Double period_duration; } GF_DashSegmenterInput; typedef enum @@ -304,7 +318,8 @@ typedef enum GF_DASH_PROFILE_ONDEMAND, GF_DASH_PROFILE_MAIN, - /* DASH-AVC/264 profiles */ + /* industry profiles */ + GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE, GF_DASH_PROFILE_AVC264_LIVE, GF_DASH_PROFILE_AVC264_ONDEMAND, @@ -315,23 +330,36 @@ typedef enum typedef enum { - GF_DASH_BSMODE_NONE = 0, + GF_DASH_BSMODE_DEFAULT, //=inband for live profile and none for onDemand + GF_DASH_BSMODE_NONE, GF_DASH_BSMODE_INBAND, GF_DASH_BSMODE_MERGED, + GF_DASH_BSMODE_MULTIPLE_ENTRIES, GF_DASH_BSMODE_SINGLE } GF_DashSwitchingMode; + +typedef enum +{ + GF_DASH_STATIC = 0, + GF_DASH_DYNAMIC, + //can only be used when DASH segmenter context is used, will close the period + GF_DASH_DYNAMIC_LAST, + GF_DASH_DYNAMIC_DEBUG, +} GF_DashDynamicMode; + GF_Err gf_dasher_segment_files(const char *mpd_name, GF_DashSegmenterInput *inputs, u32 nb_inputs, GF_DashProfile profile, const char *mpd_title, const char *mpd_source, const char *mpd_copyright, const char *mpd_moreInfoURL, const char **mpd_base_urls, u32 nb_mpd_base_urls, u32 use_url_template, Bool use_segment_timeline, Bool single_segment, Bool single_file, GF_DashSwitchingMode bitstream_switching_mode, Bool segments_start_with_rap, Double dash_duration_sec, char *seg_rad_name, char *seg_ext, u32 segment_marker_4cc, Double frag_duration_sec, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool fragments_start_with_rap, const char *tmp_dir, - GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double subduration, Double min_buffer, - u32 ast_shift_sec, u32 dash_scale, Bool fragments_in_memory, u32 initial_moof_sn, u64 initial_tfdt, Bool no_fragments_defaults, Bool pssh_moof, Bool samplegroups_in_traf); + GF_Config *dash_ctx, GF_DashDynamicMode dash_mode, Double mpd_update_time, u32 time_shift_depth, Double subduration, Double min_buffer, + s32 ast_offset_ms, u32 dash_scale, Bool fragments_in_memory, u32 initial_moof_sn, u64 initial_tfdt, Bool no_fragments_defaults, + Bool pssh_moof, Bool samplegroups_in_traf, Bool single_traf_per_moof, Double mpd_live_duration, Bool insert_utc, Bool real_time, const char *dash_profile_extension); /*returns time to wait until end of currently generated segments*/ -u32 gf_dasher_next_update_time(GF_Config *dash_ctx, u32 mpd_update_time); +u32 gf_dasher_next_update_time(GF_Config *dash_ctx, Double mpd_update_time); #ifndef GPAC_DISABLE_ISOM_WRITE diff --git a/include/gpac/mediaobject.h b/include/gpac/mediaobject.h index 7405f80..65227af 100644 --- a/include/gpac/mediaobject.h +++ b/include/gpac/mediaobject.h @@ -98,15 +98,27 @@ GF_Err gf_mo_get_raw_image_planes(GF_MediaObject *mo, u8 **pY_or_RGB, u8 **pU, u /*returns min frame duration for his object or 0 if unknown*/ u32 gf_mo_get_min_frame_dur(GF_MediaObject *mo); +typedef enum +{ + //never resync the content of the decoded media buffer (used fo audio) + //if clock is paused do not fetch + GF_MO_FETCH = 0, + //always resync the content of the decoded media buffer to the current time (used for video) + GF_MO_FETCH_RESYNC, + //never resync the content of the decoded media buffer (used fo audio) + //if clock is paused, do fetch (used for audio extraction) + GF_MO_FETCH_PAUSED +} GF_MOFetchMode; + /*fetch media data */ -char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestamp, u32 *size, s32 *ms_until_pres, s32 *ms_until_next); +char *gf_mo_fetch_data(GF_MediaObject *mo, GF_MOFetchMode resync, Bool *eos, u32 *timestamp, u32 *size, s32 *ms_until_pres, s32 *ms_until_next); /*release given amount of media data - nb_bytes is used for audio - drop_mode can take the following values: -1: do not drop -0: do not force drop: the unlocked frame it will be droped based on object time (typically video) -1: force drop : the unlocked frame will be droped if all bytes are consumed (typically audio) +0: do not force drop: the unlocked frame it will be dropped based on object time (typically video) +1: force drop : the unlocked frame will be dropped if all bytes are consumed (typically audio) 2: the frame will be stated as a discraded frame */ void gf_mo_release_data(GF_MediaObject *mo, u32 nb_bytes, s32 drop_mode); @@ -139,6 +151,8 @@ Bool gf_mo_is_private_media(GF_MediaObject *mo); /*set destination window for harware codecs directly outputing to video out - returns 1 if video size has changed*/ Bool gf_mo_set_position(GF_MediaObject *mo, GF_Window *src, GF_Window *dst); +s32 gf_mo_get_clock_drift(GF_MediaObject *mo); + enum { /*this is set to 0 by the OD manager whenever a change occur in the media (w/h change, SR change, etc) diff --git a/include/gpac/module.h b/include/gpac/module.h index 500800f..1a09593 100644 --- a/include/gpac/module.h +++ b/include/gpac/module.h @@ -150,7 +150,7 @@ typedef struct */ #ifdef GPAC_STATIC_MODULES -#define GPAC_MODULE_STATIC_DELARATION(__name) \ +#define GPAC_MODULE_STATIC_DECLARATION(__name) \ GF_InterfaceRegister *gf_register_module_##__name() { \ GF_InterfaceRegister *reg; \ GF_SAFEALLOC(reg, GF_InterfaceRegister); \ @@ -162,7 +162,7 @@ typedef struct } \ #else -#define GPAC_MODULE_STATIC_DELARATION(__name) +#define GPAC_MODULE_STATIC_DECLARATION(__name) #endif /*! *\brief module manager construtcor @@ -182,6 +182,77 @@ GF_ModuleManager *gf_modules_new(const char *directory, GF_Config *cfgFile); *\param pm the module manager */ void gf_modules_del(GF_ModuleManager *pm); + +/*! + *\brief load a static module given its interface function + * + *\param pm the module manager + *\param register_module the register interface function + */ +GF_Err gf_module_load_static(GF_ModuleManager *pm, GF_InterfaceRegister *(*register_module)()); + +/*! + *\brief declare a module for loading + * + * When using GPAC as a static library, if GPAC_MODULE_CUSTOM_LOAD is + * defined, this macro can be used with GF_MODULE_STATIC_DECLARE() and + * gf_module_refresh() to load individual modules. + * + * It's first needed to call GF_MODULE_STATIC_DECLARE() with the name + * of the module you need to load outside of any function. This macro + * will declare the prototype of the module registration function so + * it should only be used outside functions. + * + * Then in your GPAC initialization code, you need to call + * GF_MODULE_LOAD_STATIC() with your GPAC module manager and the + * module name. + * + * Finally, you'll need to call gf_modules_refresh() with your module + * manager. + * + * \code + * GF_MODULE_STATIC_DECLARE(aac_in); + * GF_MODULE_STATIC_DECLARE(audio_filter); + * GF_MODULE_STATIC_DECLARE(ffmpeg); + * ... + * + * void prepare() { + * GF_User user; + * ... + * user.modules = gf_modules_new("/data/gpac/modules", user.config); + * + * GF_MODULE_LOAD_STATIC(user.modules, aac_in); + * GF_MODULE_LOAD_STATIC(user.modules, audio_filter); + * GF_MODULE_LOAD_STATIC(user.modules, ffmpeg); + * ... + * gf_modules_refresh(user.modules); + * ... + * } + * \endcode + * \see GF_MODULE_LOAD_STATIC() gf_modules_refresh() + */ +#ifdef __cplusplus +#define GF_MODULE_STATIC_DECLARE(_name) \ + extern "C" GF_InterfaceRegister *gf_register_module_##_name() +#else +#define GF_MODULE_STATIC_DECLARE(_name) \ + GF_InterfaceRegister *gf_register_module_##_name() +#endif +/*! + *\brief load a static module given its name + * + * Use this function to load a statically compiled + * module. GF_MODULE_STATIC_DECLARE() should be called before and + * gf_modules_refresh() after loading all the needed modules. + * + *\param _pm the module manager + *\param _name the module name + *\see GF_MODULE_STATIC_DECLARE() gf_modules_refresh() + */ +#define GF_MODULE_LOAD_STATIC(_pm, _name) \ + gf_module_load_static(_pm,gf_register_module_##_name) + + /*! *\brief refreshes modules * @@ -255,6 +326,7 @@ GF_BaseInterface *gf_modules_load_interface_by_name(GF_ModuleManager *pm, const *\brief interface shutdown * *Closes an interface + *\param interface_obj the interface to close */ GF_Err gf_modules_close_interface(GF_BaseInterface *interface_obj); @@ -298,4 +370,3 @@ GF_Config *gf_modules_get_config(GF_BaseInterface *ifce); #endif /*_GF_MODULE_H_*/ - diff --git a/include/gpac/modules/audio_out.h b/include/gpac/modules/audio_out.h index a282659..20fd282 100644 --- a/include/gpac/modules/audio_out.h +++ b/include/gpac/modules/audio_out.h @@ -140,7 +140,7 @@ struct _tag_audio_filter GF_DECL_MODULE_INTERFACE /*sets the current filter. The filterstring is opaque to libgpac and is taken as given - in the GPAC configuration file, where filters are listed as a ';;' seperated list in the "Filter" key of + in the GPAC configuration file, where filters are listed as a ';;' separated list in the "Filter" key of the [Audio] section. @returns: 1 is this module can handle the filterstring, 0 otherwise. */ diff --git a/include/gpac/modules/codec.h b/include/gpac/modules/codec.h index 47204ff..fd9dd96 100644 --- a/include/gpac/modules/codec.h +++ b/include/gpac/modules/codec.h @@ -151,7 +151,15 @@ enum GF_CODEC_MEDIA_SWITCH_QUALITY, /*special cap indicating the codec should abort processing as soon as possible because it is about to be destroyed*/ - GF_CODEC_ABORT + GF_CODEC_ABORT, + + /*sets current hitpoint on the video texture. hitpoint is an integer (valueInt) containing: + the X coord in upper 16 bits, ranging from 0 to 0xFFFF + the Y coord in lower 16 bits, ranging from 0 to 0xFFFF + x,y are in normalized texture coordinates (0,0 bottom left, 1,1 top right) + return GF_NOT_SUPPORTED if your codec does'nt handle this + */ + GF_CODEC_INTERACT_COORDS, }; diff --git a/include/gpac/modules/service.h b/include/gpac/modules/service.h index e4c38a0..f9b7814 100644 --- a/include/gpac/modules/service.h +++ b/include/gpac/modules/service.h @@ -75,6 +75,8 @@ typedef enum /*map net time (OTB) to media time (up only) - this is needed by some signaling protocols when the real play range is not the requested one */ GF_NET_CHAN_MAP_TIME, + /*same as map time, but does not trigger realignment of timestamps in the terminal - only used to solve TS->OTB for display purposes*/ + GF_NET_CHAN_SET_MEDIA_TIME, /*reconfiguration of channel comming from network (up only) - this is used to override the SL config if it differs from the one specified at config*/ GF_NET_CHAN_RECONFIG, @@ -100,6 +102,8 @@ typedef enum GF_NET_SERVICE_INFO, /*checks if there is an audio stream in the service - term->net only*/ GF_NET_SERVICE_HAS_AUDIO, + /*checks if the service can support reverse playback (speed<0) - term->service only*/ + GF_NET_SERVICE_CAN_REVERSE_PLAYBACK, /*send by the terminal to indicate the channel(s) on this service need more data - term->net only*/ GF_NET_SERVICE_FLUSH_DATA, @@ -108,9 +112,12 @@ typedef enum /*instructs the service to get the migration info - term->net only*/ GF_NET_SERVICE_MIGRATION_INFO, - /*When using DASH or playlists, query the next file to concatenate to thecurrent one net->proxy only*/ + /*switches quality up or down or a given ID*/ GF_NET_SERVICE_QUALITY_SWITCH, + /*queries quality in the service*/ + GF_NET_SERVICE_QUALITY_QUERY, + /*When using DASH or playlists, query the next file to concatenate to thecurrent one net->proxy only*/ GF_NET_SERVICE_QUERY_NEXT, /*When using DASH, query the media range of the url passed in ConnectService - this is only used for local @@ -135,6 +142,12 @@ typedef enum GF_NET_SERVICE_EVENT, //sets nalu mode GF_NET_CHAN_NALU_MODE, + + /*request current position in TSB - 0 means 'at the live point'*/ + GF_NET_GET_TIMESHIFT, + + /*seek request from service on all channels*/ + GF_NET_SERVICE_SEEK, } GF_NET_CHAN_CMD; /*channel command for all commands that don't need params: @@ -161,8 +174,12 @@ typedef struct Bool dash_segment_switch; /*indicates this is the first PLAY on an elemnt inserted from bcast*/ Bool initial_broadcast_play; - /*indicates the range is given in timestamps, no media time */ - Bool is_timestamp_based; + /* + 0: range is in media time + 1: range is in timesatmps + 2: range is in media time but timestamps should not be shifted (hybrid dash only for now) + */ + u32 timestamp_based; } GF_NetComPlay; @@ -197,7 +214,7 @@ typedef struct type (multicast, vod, ...) - below buffer_min the stream will pause if possible until buffer_max is reached note the app will fill in default values before querying*/ u32 min, max; - /*only used with GF_NET_CHAN_BUFFER_QUERY - amount of media in decoding buffer, in ms*/ + /*only used with GF_NET_CHAN_BUFFER_QUERY and GF_NET_BUFFER_QUERY- amount of media in decoding buffer, in ms. This value is adjusted by the current playback speed, eg if playing at 2x the occupancy is (media time in buffers) / 2 */ u32 occupancy; } GF_NetComBuffer; @@ -208,6 +225,8 @@ typedef struct LPNETCHANNEL on_channel; /*duration in sec*/ Double duration; + /*time shift buffer depth in ms, (u32) -1 is infinity*/ + u32 time_shift_buffer; } GF_NetComDuration; /*GF_NET_CHAN_GET_DSI*/ @@ -228,6 +247,16 @@ typedef struct u32 padding_bytes; } GF_NetComPadding; +/*GF_NET_GET_TIMESHIFT*/ +typedef struct +{ + u32 command_type; + LPNETCHANNEL on_channel; + //time in sec in the timeshift buffer - 0 means live point + Double time; +} GF_NetComTimeShift; + + /*GF_NET_SERVICE_PROXY_DATA_RECEIVE*/ typedef struct @@ -314,7 +343,8 @@ typedef struct __netstatcom Float pck_loss_percentage; /*channel port, control channel port if any (eg RTCP)*/ u16 port, ctrl_port; - /*bandwidth used by channel & its control channel if any (both up and down) - expressed in bits per second*/ + /*bandwidth used by channel & its control channel if any (both up and down) - expressed in bits per second + for HTTP connections, typically only bw_down is used*/ u32 bw_up, bw_down, ctrl_bw_down, ctrl_bw_up; /*set to 0 if channel is not part of a multiplex. Otherwise set to the multiplex port, and above port info shall be identifiers in the multiplex - note that multiplexing overhead is ignored @@ -337,6 +367,7 @@ typedef struct __netinfocom u32 command_type; /*currently NULL only*/ LPNETCHANNEL on_channel; + u32 service_id; /*packed trackNumber(16 bits)/totaltrack(16 bits)*/ u32 track_info; u32 genre; @@ -347,9 +378,13 @@ typedef struct __netinfocom const char *name; const char *writer; const char *provider; + //as in MPEG_DASH role + const char *role; + const char *accessibility; + const char *rating; } GF_NetComInfo; -/*GF_NET_CHAN_GET_PIXEL_AR*/ +/*GF_NET_SERVICE_HAS_AUDIO*/ typedef struct { u32 command_type; @@ -367,7 +402,7 @@ typedef struct } GF_NetComMigration; /*GF_NET_SERVICE_EVENT*/ -typedef struct +typedef struct { u32 command_type; @@ -404,6 +439,10 @@ typedef struct const char *next_url_init_or_switch_segment; u64 switch_start_range, switch_end_range; + /*set to key URL for current segment, or NULL if none*/ + const char *key_url; + /*set to key IV for current segment, or NULL if none*/ + bin128 *key_IV; Bool has_next; /*module->proxy: indicates that currently downloaded segment should be checked. @@ -421,12 +460,46 @@ typedef struct typedef struct { u32 command_type; - /*currently NULL only*/ + /*NULL only when request, or channel for witch quality has been changed for notif*/ LPNETCHANNEL on_channel; - /*out: next url to play after current one*/ + //switch quality up or down - request only Bool up; + + Bool set_auto; + //or ID of the quality to switch, as indicated in query quality + const char *ID; } GF_NetQualitySwitch; + +/*GF_NET_SERVICE_QUALITY_QUERY*/ +typedef struct +{ + u32 command_type; + /*media object for which qualities are checked*/ + LPNETCHANNEL on_channel; + + //1-based index of quality to query + //if 0, the command is used to query the number of quality for the object + u32 index; + + //all out params + u32 bandwidth; + const char *ID; + const char *mime; + const char *codec; + u32 width; + u32 height; + Bool interlaced; + Double fps; + u32 par_num; + u32 par_den; + u32 sample_rate; + u32 nb_channels; + Bool disabled; + Bool is_selected; + Bool automatic; +} GF_NetQualityQuery; + /*GF_NET_SERVICE_STATUS_PROXY*/ typedef struct { @@ -467,6 +540,7 @@ typedef struct const char *external_URL; Bool is_announce, is_splicing; Bool reload_external; + Bool enable_if_defined; Double activation_countdown; } GF_AssociatedContentLocation; @@ -507,6 +581,7 @@ typedef union __netcommand GF_NetComDuration duration; GF_NetComGetDSI get_dsi; GF_NetComPadding pad; + GF_NetComTimeShift timeshift; GF_NetComMapTime map_time; GF_NetComStats net_stats; GF_NetComDRMConfig drm_cfg; @@ -524,6 +599,7 @@ typedef union __netcommand GF_AssociatedContentTiming addon_time; GF_NALUExtractMode nalu_mode; GF_NetComSendEvent send_event; + GF_NetQualityQuery quality_query; } GF_NetworkCommand; /* diff --git a/include/gpac/modules/video_out.h b/include/gpac/modules/video_out.h index d832897..af9cd98 100644 --- a/include/gpac/modules/video_out.h +++ b/include/gpac/modules/video_out.h @@ -147,7 +147,7 @@ typedef struct _video_out without destroying the GL context. If the GL context is destroyed, the module should send an event of the same type to the player. - This function is also called with a NULL event at the begining of each rendering cycle, in order to allow event + This function is also called with a NULL event at the beginning of each rendering cycle, in order to allow event handling for modules uncapable of safe multithreading (eg X11) */ GF_Err (*ProcessEvent)(struct _video_out *vout, GF_Event *event); @@ -202,7 +202,7 @@ typedef struct _video_out - /*set of above HW flags*/ + /*set of above HW flags - some of the caps may change depeinding on the current video setup*/ u32 hw_caps; /*main pixel format of video board (informative only)*/ u32 pixel_format; diff --git a/include/gpac/mpeg4_odf.h b/include/gpac/mpeg4_odf.h index 8700e7c..9a16649 100644 --- a/include/gpac/mpeg4_odf.h +++ b/include/gpac/mpeg4_odf.h @@ -436,7 +436,15 @@ enum GF_TXT_SCROLL_DIRECTION = 0x00000180, GF_TXT_KARAOKE = 0x00000800, GF_TXT_VERTICAL = 0x00020000, - GF_TXT_FILL_REGION = 0x00040000 + GF_TXT_FILL_REGION = 0x00040000, + + GF_TXT_NO_SCALE = 0x2, + GF_TXT_MOVIE_BACK_COLOR = 0x8, + GF_TXT_CONTINUOUS_SCROLL = 0x200, + GF_TXT_DROP_SHADOW = 0x1000, + GF_TXT_FILL_ANTIALIAS = 0x2000, + GF_TXT_SOME_SAMPLES_FORCED = 0x40000000, + GF_TXT_ALL_SAMPLES_FORCED = 0x80000000, }; typedef struct @@ -551,6 +559,9 @@ typedef struct { /*carousel configuration*/ u32 carousel_period_plus_one; u16 aggregate_on_esid; + + /*original source URL*/ + char *src_url; } GF_MuxInfo; typedef struct diff --git a/include/gpac/mpegts.h b/include/gpac/mpegts.h index c1cb34e..02a1f52 100644 --- a/include/gpac/mpegts.h +++ b/include/gpac/mpegts.h @@ -238,9 +238,9 @@ enum /*MPEG-2 Descriptor tags*/ enum { - GF_M2TS_AFDESC_LOCATION_DESCRIPTOR = 0x00, - GF_M2TS_AFDESC_TIMELINE_DESCRIPTOR = 0x01, - GF_M2TS_AFDESC_BASEURL_DESCRIPTOR = 0x02, + GF_M2TS_AFDESC_TIMELINE_DESCRIPTOR = 0x04, + GF_M2TS_AFDESC_LOCATION_DESCRIPTOR = 0x05, + GF_M2TS_AFDESC_BASEURL_DESCRIPTOR = 0x06, }; #define SECTION_HEADER_LENGTH 3 /* header till the last bit of the section_length field */ @@ -267,8 +267,8 @@ typedef struct __gf_dvb_tuner GF_Tuner; /*Maximum number of service in a TS*/ #define GF_M2TS_MAX_SERVICES 65535 -/*Maximum size of the buffer in UDP */ -#define UDP_BUFFER_SIZE 0x40000 +/*Maximum size of the buffer in UDP is set to 348*188 bytes*/ +#define UDP_BUFFER_SIZE 65424 /*returns readable name for given stream type*/ const char *gf_m2ts_get_stream_name(u32 streamType); @@ -399,6 +399,7 @@ enum GF_M2TS_TABLE_END = 1<<1, GF_M2TS_TABLE_FOUND = 1<<2, GF_M2TS_TABLE_UPDATE = 1<<3, + //both update and repeat flags may be set if data has changed GF_M2TS_TABLE_REPEAT = 1<<4, }; @@ -432,6 +433,7 @@ typedef struct __m2ts_demux_table GF_List *sections; + u32 table_size; } GF_M2TS_Table; @@ -460,6 +462,8 @@ typedef struct GF_M2TS_SectionFilter u32 service_id; gf_m2ts_section_callback process_section; + + Bool demux_restarted; } GF_M2TS_SectionFilter; enum metadata_carriage { @@ -511,6 +515,8 @@ typedef struct /*MPEG-2 TS program object*/ typedef struct { + GF_M2TS_Demuxer *ts; + GF_List *streams; u32 pmt_pid; u32 pcr_pid; @@ -570,7 +576,10 @@ enum GF_M2TS_ES_FIRST_DTS = 1<<17, /*flag used to signal next discontinuity on stream should be ignored*/ - GF_M2TS_ES_IGNORE_NEXT_DISCONTINUITY = 1<<18 + GF_M2TS_ES_IGNORE_NEXT_DISCONTINUITY = 1<<18, + + /*Flag used by importers/readers to mark streams that have been seen already in PMT process (update/found)*/ + GF_M2TS_ES_ALREADY_DECLARED = 1<<19 }; /*Abstract Section/PES stream object, only used for type casting*/ @@ -651,7 +660,7 @@ typedef struct tag_m2ts_pes u32 lang; /*object info*/ - u32 vid_w, vid_h, vid_par, aud_sr, aud_nb_ch, aud_obj_type; + u32 vid_w, vid_h, vid_par, aud_sr, aud_nb_ch, aud_aac_obj_type, aud_aac_sr_idx; u32 depends_on_pid; @@ -694,16 +703,21 @@ typedef struct tag_m2ts_pes /*used by several reframers to store their parsing state*/ u32 frame_state; /*LATM stuff - should be moved out of mpegts*/ - unsigned char *buf; + unsigned char *buf, *reassemble_buf; u32 buf_len; + u32 reassemble_len, reassemble_alloc; u64 prev_PTS; GF_M2TS_DVB_Subtitling_Descriptor sub; GF_M2TS_MetadataDescriptor *metadata_descriptor; - + //pointer to last received temi char *temi_tc_desc; u32 temi_tc_desc_len, temi_tc_desc_alloc_size; + + //last decoded temi (may be one ahead of time as the last received TEMI) + GF_M2TS_TemiTimecodeDescriptor temi_tc; + Bool temi_pending; } GF_M2TS_PES; /*SDT information object*/ @@ -859,14 +873,11 @@ struct tag_m2ts_demux /*local file playing*/ FILE *file; char filename[GF_MAX_PATH]; + //start/end in ms u32 start_range, end_range; u64 file_size; u64 pos_in_stream; Double duration; - u32 nb_playing; - Bool file_regulate; - u64 pcr_last; - u32 stb_at_last_pcr; u32 nb_pck; Bool loop_demux; const char *ts_data_chunk; @@ -876,6 +887,8 @@ struct tag_m2ts_demux /* "Network" = "MobileIP", "DefaultMCastInterface" */ Bool MobileIPEnabled; const char *network_type; + //for sockets, we need to reopen them after resume/restart.... + char *socket_url; /* Set it to 1 if the TS is meant to be played during the demux */ Bool demux_and_play; /* End of M2TSIn */ @@ -904,6 +917,9 @@ struct tag_m2ts_demux /* analyser */ FILE *pes_out; + + Bool prefix_present; + Bool direct_mpe; Bool dvb_h_demux; @@ -929,17 +945,21 @@ struct tag_m2ts_demux char* dsmcc_root_dir; GF_List* dsmcc_controler; - Bool segment_switch; + Bool abort_parsing; + Bool table_reset; //duration estimation u64 first_pcr_found; u16 pcr_pid; u64 nb_pck_at_pcr; + + Bool paused; }; GF_M2TS_Demuxer *gf_m2ts_demux_new(); void gf_m2ts_demux_del(GF_M2TS_Demuxer *ts); void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *ts); +void gf_m2ts_reset_parsers_for_program(GF_M2TS_Demuxer *ts, GF_M2TS_Program *prog); GF_ESD *gf_m2ts_get_esd(GF_M2TS_ES *es); GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, u32 mode); u32 gf_m2ts_pes_get_framing_mode(GF_M2TS_PES *pes); @@ -948,11 +968,14 @@ GF_Err gf_m2ts_process_data(GF_M2TS_Demuxer *ts, char *data, u32 data_size); u32 gf_dvb_get_freq_from_url(const char *channels_config_path, const char *url); void gf_m2ts_demux_dmscc_init(GF_M2TS_Demuxer *ts); +void gf_m2ts_pause_demux(GF_M2TS_Demuxer *ts, Bool do_pause); GF_M2TS_SDT *gf_m2ts_get_sdt_info(GF_M2TS_Demuxer *ts, u32 program_id); Bool gf_m2ts_crc32_check(char *data, u32 len); +/*aborts parsing of the current data (typically needed when parsing done by a different thread). If force_reset_pes is set, all pending pes data is discarded*/ +void gf_m2ts_abort_parsing(GF_M2TS_Demuxer *ts, Bool force_reset_pes); typedef struct @@ -1105,7 +1128,7 @@ typedef struct __m2ts_mux_stream { GF_ESIPacket curr_pck; /*current packet being processed - does not belong to the packet fifo*/ u32 pck_offset; - u32 next_payload_size, copy_from_next_packets; + u32 next_payload_size, copy_from_next_packets, next_next_payload_size; u32 pes_data_len, pes_data_remain; Bool force_new; Bool discard_data; @@ -1134,7 +1157,6 @@ typedef struct __m2ts_mux_stream { GF_SLHeader sl_header; u32 last_aac_time; - /*list of GF_M2TSDescriptor to add to the MPEG-2 stream. By default set to NULL*/ GF_List *loop_descriptors; } GF_M2TS_Mux_Stream; @@ -1296,8 +1318,6 @@ void gf_m2ts_mux_enable_sdt(GF_M2TS_Mux *mux, u32 refresh_rate_ms); /******************* Demux DVB ****************************/ -#define UDP_BUFFER_SIZE 0x40000 - #ifdef GPAC_HAS_LINUX_DVB #include <fcntl.h> @@ -1323,9 +1343,6 @@ struct __gf_dvb_tuner { }; -// DVB buffer size 188x20 -#define DVB_BUFFER_SIZE 3760 - #endif //GPAC_HAS_LINUX_DVB diff --git a/include/gpac/network.h b/include/gpac/network.h index a10660f..829ef2a 100644 --- a/include/gpac/network.h +++ b/include/gpac/network.h @@ -169,6 +169,23 @@ void gf_utc_time_since_1970(u32 *sec, u32 *msec); */ void gf_net_get_ntp(u32 *sec, u32 *frac); + +/*! + *\brief gets NTP time + * + *Gets NTP (Network Time Protocol) timestamp (high 32 bit is seconds, low 32 bit is fraction) + \return NTP timestamp + */ +u64 gf_net_get_ntp_ts(); + +/*! + * + *Gets diff in milliseconds between NTP time and current time + \param ntp NTP timestamp + \return diff in milliseconds with the current time + */ +s32 gf_net_get_ntp_diff_ms(u64 ntp); + /*! * Socket options * \hideinitializer @@ -424,11 +441,41 @@ u32 gf_net_has_ipv6(); *\brief checks address type * *Checks if an address is an IPV6 or IPV4 one. + *\param address Adress to check *\return true 1 if address is IPV6 one, 0 otherwise */ Bool gf_net_is_ipv6(const char *address); +/*! + *host to network conversion of integer + * + *\param integrer to convert + *\return converted integer + */ +u32 gf_htonl(u32 val); +/*! + *network to host conversion of integer + * + *\param integrer to convert + *\return converted integer + */ +u32 gf_ntohl(u32 val); +/*! + *host to network conversion of short integer + * + *\param short integrer to convert + *\return converted integer + */ +u16 gf_htons(u16 val); +/*! + *network to host conversion of short integer + * + *\param short integrer to convert + *\return converted integer + */ +u16 gf_tohs(u16 val); + /*! * \brief MobileIP Callback * diff --git a/include/gpac/options.h b/include/gpac/options.h index 685962c..05b0f72 100644 --- a/include/gpac/options.h +++ b/include/gpac/options.h @@ -65,6 +65,8 @@ enum GF_STATE_PLAYING = 0, /*terminal is playing*/ GF_STATE_PAUSED, /*terminal is paused*/ GF_STATE_STEP_PAUSE, /*get/set only: terminal will pause after next frame (simulation tick). On get, indicates that rendering step hasn't performed yet*/ + + GF_STATE_PLAY_LIVE = 10 //set only: indicates resume shall restart from live point if any rather than pause point }; /*refresh mode*/ @@ -246,6 +248,8 @@ enum GF_OPT_MEDIA_CACHE, /*get/set Play state - cf above states for set*/ GF_OPT_PLAY_STATE, + /*get only: returns 1 if main addon is playing, 0 if regular scene is playing*/ + GF_OPT_MAIN_ADDON, /*get/set benvch mode - if enabled, video frames are drawn as soon as possible witthout checking synchronisation*/ GF_OPT_VIDEO_BENCH, /*get/set OpenGL force mode - returns error if OpenGL is not supported*/ @@ -271,6 +275,8 @@ enum /*max HTTP download rate in bits per second, 0 if no limit*/ GF_OPT_HTTP_MAX_RATE, + /*set only (value: boolean). If set, the main audio mixer can no longer be reconfigured. */ + GF_OPT_FORCE_AUDIO_CONFIG, /* 3D ONLY OPTIONS */ /*set/get raster outline flag (value: boolean) - when set, no vectorial outlining is done, only diff --git a/include/gpac/path2d.h b/include/gpac/path2d.h index 7ed62c8..81855ba 100644 --- a/include/gpac/path2d.h +++ b/include/gpac/path2d.h @@ -38,7 +38,7 @@ extern "C" { #endif -#include <gpac/math.h> +#include <gpac/maths.h> #include <gpac/tools.h> @@ -557,7 +557,7 @@ enum */ typedef struct { - /*begining of the structure is casted in MFFloat in BIFS, DO NOT CHANGE ORDER*/ + /*beginning of the structure is casted in MFFloat in BIFS, DO NOT CHANGE ORDER*/ /*! Number of dashes in the pattern*/ u32 num_dash; diff --git a/include/gpac/scene_manager.h b/include/gpac/scene_manager.h index 348e1a1..8204fe0 100644 --- a/include/gpac/scene_manager.h +++ b/include/gpac/scene_manager.h @@ -212,7 +212,7 @@ enum }; /*loader type, usually detected based on file ext*/ -enum +typedef enum { GF_SM_LOAD_BT = 1, /*BT loader*/ GF_SM_LOAD_VRML, /*VRML97 loader*/ @@ -226,14 +226,14 @@ enum GF_SM_LOAD_QT, /*MOV->MPEG-4 converter (only cubic QTVR for now)*/ GF_SM_LOAD_MP4, /*MP4 memory loader*/ GF_SM_LOAD_XBL -}; +} GF_SceneManager_LoadType; typedef struct __scene_loader GF_SceneLoader; struct __scene_loader { /*loader type, one of the above value. If not set, detected based on file extension*/ - u32 type; + GF_SceneManager_LoadType type; /*scene graph worked on - may be NULL if ctx is present*/ GF_SceneGraph *scene_graph; @@ -258,6 +258,9 @@ struct __scene_loader media are extracted to original file directory*/ const char *localPath; + /* carrying svgOutFile when the loader is used by a SceneDumper */ + const char *svgOutFile; + /*loader flags*/ u32 flags; @@ -321,6 +324,8 @@ typedef struct 2: BIFS */ u32 auto_quant; + + const char *src_url; } GF_SMEncodeOptions; /* @@ -336,7 +341,7 @@ GF_Err gf_sm_encode_to_file(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOp #ifndef GPAC_DISABLE_SCENE_DUMP /*scene dump mode*/ -enum +typedef enum { /*BT*/ GF_SM_DUMP_BT = 0, @@ -358,12 +363,14 @@ enum GF_SM_DUMP_AUTO_TXT, /*automatic selection of MPEG4 vs X3D, xml mode*/ GF_SM_DUMP_AUTO_XML, -}; + /* disables dumping the scene */ + GF_SM_DUMP_NONE +} GF_SceneDumpFormat; -/*dumps scene context to BT or XMT +/*dumps scene context to a given format @rad_name: file name & loc without extension - if NULL dump will happen in stdout @dump_mode: one of the above*/ -GF_Err gf_sm_dump(GF_SceneManager *ctx, char *rad_name, u32 dump_mode); +GF_Err gf_sm_dump(GF_SceneManager *ctx, char *rad_name, GF_SceneDumpFormat dump_mode); typedef struct _scenedump GF_SceneDumper; @@ -374,7 +381,7 @@ typedef struct _scenedump GF_SceneDumper; @dump_mode: if set, dumps in XML format otherwise regular text returns NULL if can't create a file */ -GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char indent_char, u32 dump_mode); +GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char indent_char, GF_SceneDumpFormat dump_mode); void gf_sm_dumper_set_extra_graph(GF_SceneDumper *sdump, GF_SceneGraph *extra); void gf_sm_dumper_del(GF_SceneDumper *bd); diff --git a/include/gpac/scenegraph.h b/include/gpac/scenegraph.h index 4213f02..3db612b 100644 --- a/include/gpac/scenegraph.h +++ b/include/gpac/scenegraph.h @@ -1,4 +1,3 @@ - /* * GPAC - Multimedia Framework C SDK * @@ -33,7 +32,7 @@ extern "C" { #endif #include <gpac/list.h> -#include <gpac/math.h> +#include <gpac/maths.h> /* TAG definitions are static, in order to be able to mix nodes from different standard diff --git a/include/gpac/scenegraph_svg.h b/include/gpac/scenegraph_svg.h index 1021950..a57bab4 100644 --- a/include/gpac/scenegraph_svg.h +++ b/include/gpac/scenegraph_svg.h @@ -339,7 +339,7 @@ typedef struct /*DOM event used in VRML (GPAC's internal)*/ Bool is_vrml; /*media event*/ - GF_DOMMediaEvent *media_event; + GF_DOMMediaEvent media_event; /*number of listeners triggered by the event*/ u32 consumed; @@ -347,6 +347,9 @@ typedef struct /*for GF_EVENT_ATTR_MODIFIED*/ GF_FieldInfo *attr; GF_Err error_state; + + /* ADDON_DETECTED event*/ + const char *addon_url; } GF_DOM_Event; /*fires event on the specified node diff --git a/include/gpac/scenegraph_vrml.h b/include/gpac/scenegraph_vrml.h index 0db0a28..dde565b 100644 --- a/include/gpac/scenegraph_vrml.h +++ b/include/gpac/scenegraph_vrml.h @@ -32,7 +32,7 @@ extern "C" { #endif #include <gpac/scenegraph.h> -#include <gpac/math.h> +#include <gpac/maths.h> /* All extensions for VRML/MPEG-4/X3D graph structure @@ -316,6 +316,10 @@ enum */ GF_SG_VRML_SCRIPT_FUNCTION, + /*special event only used in routes for binding eventOut/exposedFields to generic functions. + A route with ToField.FieldType set to this value holds a pointer to a function object. + */ + GF_SG_VRML_GENERIC_FUNCTION, GF_SG_VRML_UNKNOWN }; @@ -372,7 +376,7 @@ compatible with the base GF_ParentNode node All grouping nodes (with "children" field) implement the following: addChildren: chain containing nodes to add passed as eventIn - handled internally through ROUTE -void (*on_addChildren)(GF_Node *pNode): add eventIn signaler - this is handled internally by the scene_graph and SHALL +void (*on_addChildren)(GF_Node *pNode): add feventIn signaler - this is handled internally by the scene_graph and SHALL NOT BE OVERRIDEN since it takes care of node(s) routing removeChildren: chain containing nodes to remove passed as eventIn - handled internally through ROUTE @@ -477,6 +481,8 @@ note that this must be called by the user to be effective,; otherwise the max ro from the routes present in scene*/ void gf_sg_set_max_defined_route_id(GF_SceneGraph *sg, u32 ID); +/*create a new route from a node output to a given callback/function*/ +void gf_sg_route_new_to_callback(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, void *cbk, void ( *route_callback) (void *param, GF_FieldInfo *from_field) ); /*activates all routes currently triggered - this follows the event cascade model of VRML/MPEG4: - routes are collected during eventOut generation @@ -658,6 +664,10 @@ Bool gf_node_proto_is_grouping(GF_Node *node); /*tags a hardcoded proto as being a grouping node*/ GF_Err gf_node_proto_set_grouping(GF_Node *node); +/*assigns callback to an eventIn field of an hardcoded proto*/ +GF_Err gf_node_set_proto_eventin_handler(GF_Node *node, u32 fieldIndex, void (*event_in_cbk)(GF_Node *pThis, struct _route *route) ); + + #ifdef __cplusplus } diff --git a/include/gpac/setup.h b/include/gpac/setup.h index e255d85..f2f4f95 100644 --- a/include/gpac/setup.h +++ b/include/gpac/setup.h @@ -300,6 +300,8 @@ typedef u8 bin128[16]; #define GF_EPSILON_FLOAT FLT_EPSILON #define GF_SHORT_MAX SHRT_MAX #define GF_SHORT_MIN SHRT_MIN +#define GF_INT_MAX INT_MAX +#define GF_INT_MIN INT_MIN #ifndef MIN #define MIN(X, Y) ((X)<(Y)?(X):(Y)) @@ -325,12 +327,13 @@ typedef enum { /*GPAC memory tracking*/ #if defined(GPAC_MEMORY_TRACKING) -void *gf_mem_malloc(size_t size, char *filename, int line); -void *gf_mem_calloc(size_t num, size_t size_of, char *filename, int line); -void *gf_mem_realloc(void *ptr, size_t size, char *filename, int line); -void gf_mem_free(void *ptr, char *filename, int line); -char *gf_mem_strdup(const char *str, char *filename, int line); +void *gf_mem_malloc(size_t size, const char *filename, int line); +void *gf_mem_calloc(size_t num, size_t size_of, const char *filename, int line); +void *gf_mem_realloc(void *ptr, size_t size, const char *filename, int line); +void gf_mem_free(void *ptr, const char *filename, int line); +char *gf_mem_strdup(const char *str, const char *filename, int line); void gf_memory_print(void); /*prints the state of current allocations*/ +u64 gf_memory_size(); /*gets memory allocated in bytes*/ #define gf_free(ptr) gf_mem_free(ptr, __FILE__, __LINE__) #define gf_malloc(size) gf_mem_malloc(size, __FILE__, __LINE__) @@ -340,11 +343,11 @@ void gf_memory_print(void); /*prints the state of current allocations*/ #else -#define gf_malloc malloc -#define gf_calloc calloc -#define gf_realloc realloc -#define gf_free free -#define gf_strdup strdup +void* gf_malloc(size_t size); +void* gf_calloc(size_t num, size_t size_of); +void* gf_realloc(void *ptr, size_t size); +void gf_free(void *ptr); +char* gf_strdup(const char *str); #endif @@ -537,7 +540,7 @@ void gf_memory_print(void); /*prints the state of current allocations*/ # endif #endif -#ifndef GPAC_HAS_SPIDERMONKEY +#if !defined(GPAC_HAS_SPIDERMONKEY) || defined(GPAC_DISABLE_SVG) # ifndef GPAC_DISABLE_MSE # define GPAC_DISABLE_MSE # endif diff --git a/include/gpac/sync_layer.h b/include/gpac/sync_layer.h index 10de1ff..56a6427 100644 --- a/include/gpac/sync_layer.h +++ b/include/gpac/sync_layer.h @@ -102,6 +102,8 @@ typedef struct u32 instantBitrate; u16 degradationPriority; + /*Everything below this comment is internal to GPAC*/ + /*this is NOT part of standard SL, only used internally: signals duration of access unit if known this is usefull for streams with very random updates, to prevent buffering for instance a subtitle stream which is likely to have no updates during the first minutes... expressed in media timescale*/ @@ -116,9 +118,14 @@ typedef struct u32 saiz; /*version_number are pushed from m2ts sections to the mpeg4sl layer so as to handle mpeg4 stream dependencies*/ u8 m2ts_version_number_plus_one; + //0: not mpeg-2 TS PCR, 1: MEPG-2 TS PCR, 2: MPEG-2 TS PCR with discontinuity u8 m2ts_pcr; /* HTML5 MSE Packet info */ s64 timeStampOffset; + //ntp at sender/producer side for this packet, 0 otherwise + u64 sender_ntp; + //set for AUs which should be decodedd but not presented during seek + u8 seekFlag; } GF_SLHeader; diff --git a/include/gpac/term_info.h b/include/gpac/term_info.h index f32fdeb..0a14ef9 100644 --- a/include/gpac/term_info.h +++ b/include/gpac/term_info.h @@ -94,6 +94,7 @@ typedef struct >=0: amount of media data present in buffer, in ms */ s32 buffer; + u32 min_buffer, max_buffer; /*number of AUs in DB (cumulated on all input channels)*/ u32 db_unit_count; /*number of CUs in composition memory (if any) and CM capacity*/ @@ -113,9 +114,13 @@ typedef struct /*average birate over last second and max bitrate over one second at decoder input - expressed in bits per sec*/ u32 avg_bitrate, instant_bitrate, max_bitrate; - u32 nb_dec_frames, nb_droped; + u32 nb_dec_frames, nb_dropped; u32 first_frame_time, last_frame_time; - u64 max_dec_time, total_dec_time; + u64 total_dec_time, irap_total_dec_time; + u32 max_dec_time, irap_max_dec_time; + u32 au_duration; + u32 nb_iraps; + s32 ntp_diff; /*set if ISMACryp present on the object - will need refinement for IPMPX... 0: not protected - 1: protected and OK - 2: protected and DRM failed*/ diff --git a/include/gpac/terminal.h b/include/gpac/terminal.h index 52d046f..d502501 100644 --- a/include/gpac/terminal.h +++ b/include/gpac/terminal.h @@ -111,7 +111,7 @@ GF_Err gf_term_get_visual_output_size(GF_Terminal *term, u32 *width, u32 *height /*process shortcuts*/ void gf_term_process_shortcut(GF_Terminal *term, GF_Event *ev); -void gf_term_set_speed(GF_Terminal *term, Fixed speed); +GF_Err gf_term_set_speed(GF_Terminal *term, Fixed speed); /*sends a set of scene commands (BT, XMT, X3D, LASeR+XML) to the scene type indicates the language used - accepted values are @@ -148,11 +148,17 @@ for until next frame should be drawn before returning. */ u32 gf_term_process_step(GF_Terminal *term); -/*decodes all pending media and render frame until no scene changes are detected. +/*decodes all pending media and render frame until no scene changes are detected and no clocks is buffering. +This does not flush the backbuffer to the front buffer, you have to call @gf_term_process_flush_video for this NOTE: This can only be used when the terminal runs without visual thread (GF_TERM_NO_VISUAL_THREAD flag set) */ GF_Err gf_term_process_flush(GF_Terminal *term); +/*flushes video backbuffer to screen. This is typically used after gf_term_process_flush, once the screen buffer is no longer needed +NOTE: This can only be used when the terminal runs without visual thread (GF_TERM_NO_VISUAL_THREAD flag set) +*/ +GF_Err gf_term_process_flush_video(GF_Terminal *term); + /*post user interaction to terminal*/ /*NOT NEEDED WHEN THE TERMINAL IS HANDLING THE DISPLAY WINDOW (cf user.h)*/ Bool gf_term_user_event(GF_Terminal *term, GF_Event *event); @@ -203,6 +209,10 @@ this will call all decoders to adjust their quality levels VERY BASIC INTERFACE*/ void gf_term_switch_quality(GF_Terminal *term, Bool up); + +/*get global clock in milliseconds*/ +u32 gf_term_get_clock(GF_Terminal *term); + #ifdef __cplusplus } #endif diff --git a/include/gpac/thread.h b/include/gpac/thread.h index 2b14617..f3207c7 100644 --- a/include/gpac/thread.h +++ b/include/gpac/thread.h @@ -105,7 +105,7 @@ typedef u32 (*gf_thread_run)(void *par); */ GF_Err gf_th_run(GF_Thread *th, gf_thread_run run, void *par); /*! - *\brief thread stoping + *\brief thread stopping * *Waits for the thread exit until return *\param th the thread object @@ -254,14 +254,14 @@ GF_Semaphore *gf_sema_new(u32 MaxCount, u32 InitCount); */ void gf_sema_del(GF_Semaphore *sm); /* - *\brief semaphore notifivation + *\brief semaphore notification. * *Notifies the semaphore of a certain amount of releases. *\param sm the semaphore object *\param nb_rel sm the number of release to notify - *\return the number of previous notification count in the semaphore + *\return GF_TRUE if success, GF_FALSE otherwise */ -u32 gf_sema_notify(GF_Semaphore *sm, u32 nb_rel); +Bool gf_sema_notify(GF_Semaphore *sm, u32 nb_rel); /* *\brief semaphore wait * diff --git a/include/gpac/token.h b/include/gpac/token.h index 2d427f1..b072f44 100644 --- a/include/gpac/token.h +++ b/include/gpac/token.h @@ -51,7 +51,7 @@ extern "C" { * *Gets the next string component comprised in a given set of characters *\param Buffer source string to scan - *\param Start char offset from begining of buffer where tokenization shall start + *\param Start char offset from beginning of buffer where tokenization shall start *\param Separator separator characters to use *\param Container output buffer location *\param ContainerSize output buffer allocated size @@ -63,7 +63,7 @@ s32 gf_token_get(const char* Buffer, s32 Start, const char* Separator, char* Con * *Gets the next string component comprised in a given set of characters, removing surrounding characters *\param Buffer source string to scan - *\param Start char offset from begining of buffer where tokenization shall start + *\param Start char offset from beginning of buffer where tokenization shall start *\param Separator separator characters to use *\param strip_set surrounding characters to remove *\param Container output buffer location @@ -76,7 +76,7 @@ s32 gf_token_get_strip(const char* Buffer, s32 Start, const char* Separator, con * *Gets one line from buffer and remove delimiters CR, LF and CRLF *\param buffer source string to scan - *\param start char offset from begining of buffer where tokenization shall start + *\param start char offset from beginning of buffer where tokenization shall start *\param size size of the input buffer to analyze *\param line_buffer output buffer location *\param line_buffer_size output buffer allocated size @@ -88,7 +88,7 @@ s32 gf_token_get_line(const char *buffer, u32 start, u32 size, char *line_buffer * *Locates a pattern in the buffer *\param Buffer source string to scan - *\param Start char offset from begining of buffer where tokenization shall start + *\param Start char offset from beginning of buffer where tokenization shall start *\param Size size of the input buffer to analyze *\param Pattern pattern to locate *\return position of the first char in the buffer after the pattern, or -1 if pattern could not be found diff --git a/include/gpac/tools.h b/include/gpac/tools.h index c68e356..9d6b277 100644 --- a/include/gpac/tools.h +++ b/include/gpac/tools.h @@ -123,12 +123,22 @@ size_t gf_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); * \brief large file opening * * Opens a large file (>4GB) - * \param file_name Same semantics as gf_f64_open - * \param mode Same semantics as gf_f64_open + * \param file_name Same semantics as fopen + * \param mode Same semantics as fopen * \return stream handle of the file object * \note You only need to call this function if you're suspecting the file to be a large one (usually only media files), otherwise use regular stdio. */ -FILE *gf_f64_open(const char *file_name, const char *mode); +FILE *gf_fopen(const char *file_name, const char *mode); + +/*! + * \brief file closing + * + * Closes a file + * \param file file to close + * \note You only need to call this function if you're suspecting the file to be a large one (usually only media files), otherwise use regular stdio. +*/ +s32 gf_fclose(FILE *file); + /*! * \brief large file position query * @@ -137,7 +147,7 @@ FILE *gf_f64_open(const char *file_name, const char *mode); * \return position in the file * \note You only need to call this function if you're suspecting the file to be a large one (usually only media files), otherwise use regular stdio. */ -u64 gf_f64_tell(FILE *f); +u64 gf_ftell(FILE *f); /*! * \brief large file seeking * @@ -148,7 +158,7 @@ u64 gf_f64_tell(FILE *f); * \return new position in the file * \note You only need to call this function if you're suspecting the file to be a large one (usually only media files), otherwise use regular stdio. */ -u64 gf_f64_seek(FILE *f, s64 pos, s32 whence); +u64 gf_fseek(FILE *f, s64 pos, s32 whence); /*! @} */ @@ -685,6 +695,33 @@ void gf_sys_init(Bool enable_memory_tracker); * \note This can be called several times but the system will be closed when no more users are counted. */ void gf_sys_close(); + +/*! + * \brief System arguments + * + * Sets the user app arguments (used by GUI mode) + * \param argc Number of arguments + * \param argv Array of arguments + */ +void gf_sys_set_args(s32 argc, const char **argv); + +/*! + * \brief Get number of args + * + * Gets the number of argument of the user application if any + * \return number of argument of the user application + */ +u32 gf_sys_get_argc(); + +/*! + * \brief Get number of args + * + * Gets the number of argument of the user application if any + * \param arg Index of argument to retrieve + * \return number of argument of the user application + */ +const char *gf_sys_get_arg(u32 arg); + /*! * \brief System clock query * @@ -725,6 +762,14 @@ GF_Err gf_rmdir(char *DirPathName); */ GF_Err gf_mkdir(char* DirPathName); +/*! + * \brief Check Directory Exists + * + * Create a directory within the full path. + * \param DirPathName the dir path name. + */ +Bool gf_dir_exists(char *DirPathName); + /*! * \brief Create Directory * @@ -889,6 +934,11 @@ GF_Err gf_global_resource_unlock(GF_GlobalLock * lock); */ char * gf_get_default_cache_directory(); +/** + * Gets the number of open file handles (gf_fopn/gf_fclose only). + * \return number of open file handles + */ +u32 gf_file_handles_count(); /** @@ -914,23 +964,25 @@ GF_Err gf_gz_decompress_payload(char *data, u32 data_len, char **uncompressed_da /*SHA1*/ typedef struct __sha1_context GF_SHA1Context; +#define GF_SHA1_DIGEST_SIZE 20 +#define GF_SHA1_DIGEST_SIZE_HEXA 41 /* * Core SHA-1 functions */ GF_SHA1Context *gf_sha1_starts(); void gf_sha1_update(GF_SHA1Context *ctx, u8 *input, u32 length); -void gf_sha1_finish(GF_SHA1Context *ctx, u8 digest[20] ); +void gf_sha1_finish(GF_SHA1Context *ctx, u8 digest[GF_SHA1_DIGEST_SIZE] ); /* * Output SHA-1(file contents), returns 0 if successful. */ -int gf_sha1_file(const char *filename, u8 digest[20]); +int gf_sha1_file(const char *filename, u8 digest[GF_SHA1_DIGEST_SIZE]); /* * Output SHA-1(buf) */ -void gf_sha1_csum(u8 *buf, u32 buflen, u8 digest[20]); -void gf_sha1_csum_hexa(u8 *buf, u32 buflen, u8 digest[41]); +void gf_sha1_csum(u8 *buf, u32 buflen, u8 digest[GF_SHA1_DIGEST_SIZE]); +void gf_sha1_csum_hexa(u8 *buf, u32 buflen, u8 digest[GF_SHA1_DIGEST_SIZE_HEXA]); #ifdef GPAC_ANDROID typedef void (*fm_callback_func)(void *cbk_obj, u32 type, u32 param, int *value); diff --git a/include/gpac/unicode.h b/include/gpac/unicode.h index b93959d..c4d23cc 100644 --- a/include/gpac/unicode.h +++ b/include/gpac/unicode.h @@ -31,8 +31,8 @@ extern "C" { #endif /*! - * \file <gpac/math.h> - * \brief math and trigo functions. + * \file <gpac/unicode.h> + * \brief Unicode conversion functions. */ #include <gpac/setup.h> diff --git a/include/gpac/user.h b/include/gpac/user.h index fc44065..ef998e8 100644 --- a/include/gpac/user.h +++ b/include/gpac/user.h @@ -32,7 +32,6 @@ extern "C" { #endif -//#include <gpac/math.h> #include <gpac/events.h> #include <gpac/module.h> @@ -65,16 +64,23 @@ enum /*disables frame-rate regulation (used when dumping content)*/ GF_TERM_NO_REGULATION = 1<<5, + + /*uses audio hardware clock rather than system clock. The clock is increased at the rate of audio sample consumption. This should only be used for extraction + purposes, as it may result in non-smooth visual playback (time is not continuously increasing)*/ + GF_TERM_USE_AUDIO_HW_CLOCK = 1<<6, + /*works without window thread*/ - GF_TERM_WINDOW_NO_THREAD = 1<<6, + GF_TERM_WINDOW_NO_THREAD = 1<<10, /*lets the main user handle window events (needed for browser plugins)*/ - GF_TERM_NO_WINDOWPROC_OVERRIDE = 1<<7, + GF_TERM_NO_WINDOWPROC_OVERRIDE = 1<<11, /*works without title bar*/ - GF_TERM_WINDOW_NO_DECORATION = 1<<8, + GF_TERM_WINDOW_NO_DECORATION = 1<<12, + + /*framebuffer works in 32 bit alpha mode - experimental, only supported on Win32*/ - GF_TERM_WINDOW_TRANSPARENT = 1<<9, + GF_TERM_WINDOW_TRANSPARENT = 1<<20, /*works in windowless mode - experimental, only supported on Win32*/ - GF_TERM_WINDOWLESS = 1<<10, + GF_TERM_WINDOWLESS = 1<<21, }; /*user object for all callbacks*/ diff --git a/include/gpac/version.h b/include/gpac/version.h index 3a8a8c2..548041e 100644 --- a/include/gpac/version.h +++ b/include/gpac/version.h @@ -35,14 +35,12 @@ * NO SPACE in GPAC_VERSION / GPAC_FULL_VERSION for proper install * SONAME versions must be digits (not strings) */ -#define GPAC_VERSION "0.5.1-DEV" -#define GPAC_VERSION_MAJOR 3 -#define GPAC_VERSION_MINOR 1 +#define GPAC_VERSION "0.5.2-DEV" +#define GPAC_VERSION_MAJOR 4 +#define GPAC_VERSION_MINOR 5 #define GPAC_VERSION_MICRO 0 #include <gpac/revision.h> -#define GPAC_FULL_VERSION GPAC_VERSION "-rev" GPAC_SVN_REVISION - +#define GPAC_FULL_VERSION GPAC_VERSION "-rev" GPAC_GIT_REVISION #endif //_GF_VERSION_H - diff --git a/include/gpac/webvtt.h b/include/gpac/webvtt.h index e36b2b1..2e1ef80 100644 --- a/include/gpac/webvtt.h +++ b/include/gpac/webvtt.h @@ -35,7 +35,8 @@ typedef enum { WEBVTT_ID, WEBVTT_SETTINGS, WEBVTT_PAYLOAD, - WEBVTT_TIME + WEBVTT_POSTCUE_TEXT, + WEBVTT_PRECUE_TEXT, } GF_WebVTTCuePropertyType; typedef struct _webvtt_timestamp { @@ -52,7 +53,8 @@ typedef struct _webvtt_cue char *id; char *settings; char *text; - char *time; + char *pre_text; + char *post_text; Bool split; /* original times before split, if applicable */ diff --git a/include/gpac/xml.h b/include/gpac/xml.h index ac1290c..fcef978 100644 --- a/include/gpac/xml.h +++ b/include/gpac/xml.h @@ -141,6 +141,10 @@ GF_Err gf_xml_dom_parse_string(GF_DOMParser *dom, char *string); const char *gf_xml_dom_get_error(GF_DOMParser *parser); u32 gf_xml_dom_get_line(GF_DOMParser *parser); +u32 gf_xml_dom_get_root_nodes_count(GF_DOMParser *parser); +GF_XMLNode *gf_xml_dom_get_root_idx(GF_DOMParser *parser, u32 idx); + + /* *\brief Serialize a node * @@ -216,6 +220,18 @@ GF_XMLAttribute *gf_xml_dom_get_attribute(GF_XMLNode *node, const char* name); */ GF_Err gf_xml_dom_append_child(GF_XMLNode *node, GF_XMLNode *child); +/* + *\brief Removes the node to the list of children of this node. + * + * Removes the node to the list of children of this node. + * Doesn't free the memory of the removed children. + * + *\param node the GF_XMLNode node + *\param child the GF_XMLNode child to remove + *\return GF_OK if removal occurs properly, otherwise a GF_Err + */ +GF_Err gf_xml_dom_rem_child(GF_XMLNode *node, GF_XMLNode *child); + /* *\brief Node constructor. * diff --git a/include/win32/inttypes.h b/include/win32/inttypes.h index f8139a2..e90a118 100644 --- a/include/win32/inttypes.h +++ b/include/win32/inttypes.h @@ -1,17 +1,21 @@ -/* 7.8 Format conversion of integer types <inttypes.h> */ - -#ifndef _INTTYPES_H_ -#define _INTTYPES_H_ - - -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -#endif /* ndef _INTTYPES_H */ +#ifndef _INTTYPES_H_ +#define _INTTYPES_H_ + +#if defined(_WIN32) && !defined(PRId64) +#define PRId64 "I64d" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#endif + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + +typedef int64_t ssize_t; + +#endif /*_INTTYPES_H_*/ diff --git a/mkdmg.sh b/mkdmg.sh index 6e3a22c..96241d1 100755 --- a/mkdmg.sh +++ b/mkdmg.sh @@ -20,6 +20,7 @@ if [ ! $basefile == 'libgpac.dylib' ] && [ ! -e lib/$basefile ]; then # echo copying $1 to bundle cp $1 lib/ + chmod +w lib/$basefile rewrite_deps lib/$basefile fi } @@ -31,16 +32,23 @@ then rm -fr tmpdmg fi mkdir -p tmpdmg/Osmo4.app -rsync -r --exclude=.svn $source_path/build/osxdmg/Osmo4.app/ ./tmpdmg/Osmo4.app/ +rsync -r --exclude=.git $source_path/build/osxdmg/Osmo4.app/ ./tmpdmg/Osmo4.app/ ln -s /Applications ./tmpdmg/Applications cp $source_path/README ./tmpdmg cp $source_path/COPYING ./tmpdmg +mkdir -p tmpdmg/Osmo4.app/Contents/MacOS/modules +mkdir -p tmpdmg/Osmo4.app/Contents/MacOS/lib + cp bin/gcc/gm* tmpdmg/Osmo4.app/Contents/MacOS/modules cp bin/gcc/libgpac.dylib tmpdmg/Osmo4.app/Contents/MacOS/lib cp bin/gcc/MP4Client tmpdmg/Osmo4.app/Contents/MacOS/Osmo4 cp bin/gcc/MP4Box tmpdmg/Osmo4.app/Contents/MacOS/MP4Box cp bin/gcc/MP42TS tmpdmg/Osmo4.app/Contents/MacOS/MP42TS +if [ -f bin/gcc/DashCast ] +then +cp bin/gcc/DashCast tmpdmg/Osmo4.app/Contents/MacOS/DashCast +fi cd tmpdmg/Osmo4.app/Contents/MacOS/ @@ -51,6 +59,11 @@ do rewrite_deps $dylib done +if [ -f DashCast ] +then + rewrite_deps DashCast +fi + echo rewriting APPS dependencies install_name_tool -change /usr/local/lib/libgpac.dylib @executable_path/lib/libgpac.dylib Osmo4 install_name_tool -change /usr/local/lib/libgpac.dylib @executable_path/lib/libgpac.dylib MP4Box @@ -59,26 +72,34 @@ install_name_tool -change ../bin/gcc/libgpac.dylib @executable_path/lib/libgpac. install_name_tool -change ../bin/gcc/libgpac.dylib @executable_path/lib/libgpac.dylib MP4Box install_name_tool -change ../bin/gcc/libgpac.dylib @executable_path/lib/libgpac.dylib MP42TS +if [ -f DashCast ] +then +install_name_tool -change /usr/local/lib/libgpac.dylib @executable_path/lib/libgpac.dylib DashCast +install_name_tool -change ../bin/gcc/libgpac.dylib @executable_path/lib/libgpac.dylib DashCast +fi cd ../../../.. echo Copying GUI -rsync -r --exclude=.svn $source_path/gui ./tmpdmg/Osmo4.app/Contents/MacOS/ +rsync -r --exclude=.git $source_path/gui ./tmpdmg/Osmo4.app/Contents/MacOS/ echo Building DMG version=`grep '#define GPAC_VERSION ' $source_path/include/gpac/version.h | cut -d '"' -f 2` cur_dir=`pwd` cd $source_path -rev=`LANG=en_US svn info | grep Revision | tr -d 'Revision: '` +TAG=$(git describe --tags --abbrev=0 2> /dev/null) +REVISION=$(echo `git describe --tags --long 2> /dev/null || echo "UNKNOWN"` | sed "s/^$TAG-//") +BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "UNKNOWN") +rev="$REVISION-$BRANCH" cd $cur_dir full_version=$version if [ "$rev" != "" ] then - full_version="$full_version-r$rev" + full_version="$full_version-rev$rev" else - #if no revision can be extracted from SVN, use date + #if no revision can be extracted, use date $rev = $(date +%Y%m%d) fi @@ -93,12 +114,17 @@ echo "Adding licence" hdiutil convert -format UDCO -o gpac_sla.dmg gpac.dmg rm gpac.dmg hdiutil unflatten gpac_sla.dmg -/Developer/Tools/Rez /Developer/Headers/FlatCarbon/*.r $source_path/build/osxdmg/SLA.r -a -o gpac_sla.dmg +Rez /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/*.r $source_path/build/osxdmg/SLA.r -a -o gpac_sla.dmg hdiutil flatten gpac_sla.dmg hdiutil internet-enable -yes gpac_sla.dmg -echo "GPAC-$full_version.dmg ready" +pck_name="gpac-$full_version.dmg" +if [ "$1" = "snow-leopard" ]; then +pck_name="gpac-$full_version-$1.dmg" +fi + +echo "$pck_name ready" chmod o+rx gpac_sla.dmg chmod g+rx gpac_sla.dmg -mv gpac_sla.dmg GPAC-$full_version.dmg +mv gpac_sla.dmg $pck_name diff --git a/modules/Makefile b/modules/Makefile index 8cd8fb2..67b9ffb 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -1,7 +1,7 @@ include ../config.mak #all OS and lib independent -PLUGDIRS=aac_in ac3_in audio_filter bifs_dec dummy_in soft_raster mp3_in isom_in odf_dec rtp_in timedtext img_in saf_in ismacryp raw_out +PLUGDIRS=aac_in ac3_in audio_filter bifs_dec dummy_in soft_raster mp3_in isom_in odf_dec rtp_in timedtext img_in saf_in ismacryp raw_out validator ifeq ($(DISABLE_DASH_CLIENT), no) PLUGDIRS+=mpd_in diff --git a/modules/aac_in/Makefile b/modules/aac_in/Makefile index 0681f36..143d6f1 100644 --- a/modules/aac_in/Makefile +++ b/modules/aac_in/Makefile @@ -32,7 +32,7 @@ endif EXTRALIBS+= -lfaad endif -LIB=gm_aac_in.$(DYN_LIB_SUFFIX) +LIB=gm_aac_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols aac_in.def endif @@ -44,7 +44,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(EXTRALIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_aac_in-static.$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_aac_in-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) endif clean: diff --git a/modules/aac_in/aac_in.c b/modules/aac_in/aac_in.c index 0c84d5c..1336f82 100644 --- a/modules/aac_in/aac_in.c +++ b/modules/aac_in/aac_in.c @@ -123,7 +123,7 @@ static GF_ESD *AAC_GetESD(AACReader *read) { GF_BitStream *dsi; GF_ESD *esd; - u32 i, sbr_sr_idx; + u32 i, sbr_sr_idx, sbr_oti; esd = gf_odf_desc_esd_new(0); if (!esd) @@ -142,16 +142,20 @@ static GF_ESD *AAC_GetESD(AACReader *read) gf_bs_write_int(dsi, read->nb_ch, 4); gf_bs_align(dsi); - /*always signal implicit S BR in case it's used*/ - sbr_sr_idx = read->sr_idx; - for (i=0; i<16; i++) { - if (GF_M4ASampleRates[i] == (u32) 2*read->sample_rate) { - sbr_sr_idx = i; - break; + sbr_sr_idx = 0; + sbr_oti = 0; + /*always signal implicit SBR for <=24000, in case it's used*/ + if (read->sample_rate<=24000) { + sbr_sr_idx = read->sr_idx; + for (i=0; i<16; i++) { + if (GF_M4ASampleRates[i] == (u32) 2*read->sample_rate) { + sbr_sr_idx = i; + break; + } } } gf_bs_write_int(dsi, 0x2b7, 11); - gf_bs_write_int(dsi, 5, 5); + gf_bs_write_int(dsi, sbr_oti, 5); gf_bs_write_int(dsi, 1, 1); gf_bs_write_int(dsi, sbr_sr_idx, 4); @@ -260,7 +264,7 @@ static Bool AAC_ConfigureFromFile(AACReader *read) read->duration = 0; - if (0 && !read->is_remote) { + if (!read->is_remote) { read->duration = 1024; gf_bs_skip_bytes(bs, hdr.frame_size); while (ADTS_SyncFrame(bs, !read->is_remote, &hdr)) { @@ -269,7 +273,7 @@ static Bool AAC_ConfigureFromFile(AACReader *read) } } gf_bs_del(bs); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); return 1; } @@ -491,7 +495,7 @@ void AAC_NetIO(void *cbk, GF_NETIO_Parameter *param) szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { - read->stream = gf_f64_open((char *) szCache, "rb"); + read->stream = gf_fopen((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { /*if full file at once (in cache) parse duration*/ @@ -504,7 +508,7 @@ void AAC_NetIO(void *cbk, GF_NETIO_Parameter *param) if (bytes_done>10*1024) { e = GF_CORRUPTED_DATA; } else { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; return; } @@ -571,7 +575,7 @@ static void AAC_Reader_del(AACReader * read) gf_free(read->icy_track_name); read->icy_name = read->icy_genre = read->icy_track_name = NULL; if (read->stream) - fclose(read->stream); + gf_fclose(read->stream); if (read->data) gf_free(read->data); read->data = NULL; @@ -625,11 +629,11 @@ static GF_Err AAC_ConnectService(GF_InputService *plug, GF_ClientService *serv, } reply = GF_OK; - read->stream = gf_f64_open(szURL, "rb"); + read->stream = gf_fopen(szURL, "rb"); if (!read->stream) { reply = GF_URL_ERROR; } else if (!AAC_ConfigureFromFile(read)) { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; reply = GF_NOT_SUPPORTED; } @@ -761,7 +765,7 @@ static GF_Err AAC_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) read->start_range = com->play.start_range; read->end_range = com->play.end_range; read->current_time = 0; - if (read->stream) gf_f64_seek(read->stream, 0, SEEK_SET); + if (read->stream) gf_fseek(read->stream, 0, SEEK_SET); if (read->ch == com->base.on_channel) { read->done = 0; @@ -822,7 +826,7 @@ static GF_Err AAC_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha *is_new_data = 1; fetch_next: - pos = gf_f64_tell(read->stream); + pos = gf_ftell(read->stream); sync = ADTS_SyncFrame(bs, !read->is_remote, &hdr); if (!sync) { gf_bs_del(bs); @@ -833,8 +837,8 @@ fetch_next: if ((read->input->query_proxy(read->input, ¶m)==GF_OK) && param.url_query.next_url ) { - fclose(read->stream); - read->stream = gf_f64_open(param.url_query.next_url, "rb"); + gf_fclose(read->stream); + read->stream = gf_fopen(param.url_query.next_url, "rb"); *out_reception_status = GF_OK; return GF_OK; } @@ -843,7 +847,7 @@ fetch_next: *out_reception_status = GF_EOS; read->done = 1; } else { - gf_f64_seek(read->stream, pos, SEEK_SET); + gf_fseek(read->stream, pos, SEEK_SET); *out_reception_status = GF_OK; } return GF_OK; @@ -986,6 +990,6 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( aac_in ) +GPAC_MODULE_STATIC_DECLARATION( aac_in ) #endif diff --git a/modules/aac_in/faad_dec.c b/modules/aac_in/faad_dec.c index 43241ee..84b1e17 100644 --- a/modules/aac_in/faad_dec.c +++ b/modules/aac_in/faad_dec.c @@ -306,7 +306,7 @@ static GF_Err FAAD_ProcessData(GF_MediaDecoder *ifcg, GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[FAAD] Decoding AU\n")); buffer = faacDecDecode(ctx->codec, &ctx->info, (unsigned char *) inBuffer, inBufferLength); if (ctx->info.error>0) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[FAAD] Error decoding AU %s\n", faacDecGetErrorMessage(ctx->info.error) )); + GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FAAD] Error decoding AU %s\n", faacDecGetErrorMessage(ctx->info.error) )); *outBufferLength = 0; //reinit if error FAAD_AttachStream((GF_BaseDecoder *)ifcg, ctx->esd); @@ -376,19 +376,19 @@ static GF_Err FAAD_ProcessData(GF_MediaDecoder *ifcg, *outBufferLength = ctx->out_size; if (sizeof(short) * ctx->info.samples > *outBufferLength) { - *outBufferLength = ctx->out_size = sizeof(short)*ctx->info.samples; + *outBufferLength = ctx->out_size = (u32) (sizeof(short)*ctx->info.samples); } return GF_BUFFER_TOO_SMALL; } if (sizeof(short) * ctx->info.samples > *outBufferLength) { - *outBufferLength = sizeof(short)*ctx->info.samples; + *outBufferLength = (u32) (sizeof(short)*ctx->info.samples); return GF_BUFFER_TOO_SMALL; } /*we assume left/right order*/ if (ctx->num_channels<=2) { memcpy(outBuffer, buffer, sizeof(short)* ctx->info.samples); - *outBufferLength = sizeof(short)*ctx->info.samples; + *outBufferLength = (u32) (sizeof(short)*ctx->info.samples); return GF_OK; } conv_in = (unsigned short *) buffer; @@ -398,7 +398,7 @@ static GF_Err FAAD_ProcessData(GF_MediaDecoder *ifcg, conv_out[i + j] = conv_in[i + ctx->ch_reorder[j]]; } } - *outBufferLength = sizeof(short)*ctx->info.samples; + *outBufferLength = (u32) (sizeof(short)*ctx->info.samples); return GF_OK; } diff --git a/modules/ac3_in/Makefile b/modules/ac3_in/Makefile index f426f7c..6d02663 100644 --- a/modules/ac3_in/Makefile +++ b/modules/ac3_in/Makefile @@ -32,7 +32,7 @@ endif EXTRALIBS+= -la52 endif -LIB=gm_ac3_in.$(DYN_LIB_SUFFIX) +LIB=gm_ac3_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ac3_in.def endif diff --git a/modules/ac3_in/ac3_in.c b/modules/ac3_in/ac3_in.c index 47ca89f..1510bfc 100644 --- a/modules/ac3_in/ac3_in.c +++ b/modules/ac3_in/ac3_in.c @@ -126,14 +126,15 @@ static Bool AC3_ConfigureFromFile(AC3Reader *read) Bool sync; GF_BitStream *bs; GF_AC3Header hdr; + memset(&hdr, 0, sizeof(GF_AC3Header)); if (!read->stream) return 0; bs = gf_bs_from_file(read->stream, GF_BITSTREAM_READ); - sync = gf_ac3_parser_bs(bs, &hdr, 1); + sync = gf_ac3_parser_bs(bs, &hdr, GF_TRUE); if (!sync) { gf_bs_del(bs); - return 0; + return GF_FALSE; } read->nb_ch = hdr.channels; read->sample_rate = hdr.sample_rate; @@ -142,13 +143,13 @@ static Bool AC3_ConfigureFromFile(AC3Reader *read) if (!read->is_remote) { read->duration = 1536; gf_bs_skip_bytes(bs, hdr.framesize); - while (gf_ac3_parser_bs(bs, &hdr, 0)) { + while (gf_ac3_parser_bs(bs, &hdr, GF_FALSE)) { read->duration += 1536; gf_bs_skip_bytes(bs, hdr.framesize); } } gf_bs_del(bs); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); return 1; } @@ -173,6 +174,8 @@ static void AC3_OnLiveData(AC3Reader *read, const char *data, u32 data_size) GF_BitStream *bs; GF_AC3Header hdr; + memset(&hdr, 0, sizeof(GF_AC3Header)); + read->data = gf_realloc(read->data, sizeof(char)*(read->data_size+data_size) ); memcpy(read->data + read->data_size, data, sizeof(char)*data_size); read->data_size += data_size; @@ -180,7 +183,7 @@ static void AC3_OnLiveData(AC3Reader *read, const char *data, u32 data_size) if (read->needs_connection) { read->needs_connection = 0; bs = gf_bs_new((char *) read->data, read->data_size, GF_BITSTREAM_READ); - sync = gf_ac3_parser_bs(bs, &hdr, 1); + sync = gf_ac3_parser_bs(bs, &hdr, GF_TRUE); gf_bs_del(bs); if (!sync) return; read->nb_ch = hdr.channels; @@ -198,7 +201,7 @@ static void AC3_OnLiveData(AC3Reader *read, const char *data, u32 data_size) bs = gf_bs_new((char *) read->data, read->data_size, GF_BITSTREAM_READ); hdr.framesize = 0; pos = 0; - while (gf_ac3_parser_bs(bs, &hdr, 0)) { + while (gf_ac3_parser_bs(bs, &hdr, GF_FALSE)) { pos = gf_bs_get_position(bs); read->sl_hdr.accessUnitStartFlag = 1; read->sl_hdr.accessUnitEndFlag = 1; @@ -292,7 +295,7 @@ void AC3_NetIO(void *cbk, GF_NETIO_Parameter *param) szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { - read->stream = gf_f64_open((char *) szCache, "rb"); + read->stream = gf_fopen((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { /*if full file at once (in cache) parse duration*/ @@ -305,7 +308,7 @@ void AC3_NetIO(void *cbk, GF_NETIO_Parameter *param) if (bytes_done>10*1024) { e = GF_CORRUPTED_DATA; } else { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; return; } @@ -362,11 +365,11 @@ static GF_Err AC3_ConnectService(GF_InputService *plug, GF_ClientService *serv, } reply = GF_OK; - read->stream = gf_f64_open(szURL, "rb"); + read->stream = gf_fopen(szURL, "rb"); if (!read->stream) { reply = GF_URL_ERROR; } else if (!AC3_ConfigureFromFile(read)) { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; reply = GF_NOT_SUPPORTED; } @@ -378,7 +381,7 @@ static GF_Err AC3_ConnectService(GF_InputService *plug, GF_ClientService *serv, static GF_Err AC3_CloseService(GF_InputService *plug) { AC3Reader *read = plug->priv; - if (read->stream) fclose(read->stream); + if (read->stream) gf_fclose(read->stream); read->stream = NULL; if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; @@ -493,7 +496,7 @@ static GF_Err AC3_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) read->start_range = com->play.start_range; read->end_range = com->play.end_range; read->current_time = 0; - if (read->stream) gf_f64_seek(read->stream, 0, SEEK_SET); + if (read->stream) gf_fseek(read->stream, 0, SEEK_SET); if (read->ch == com->base.on_channel) { read->done = 0; @@ -530,6 +533,7 @@ static GF_Err AC3_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha *out_reception_status = GF_OK; *sl_compressed = 0; *is_new_data = 0; + memset(&hdr, 0, sizeof(GF_AC3Header)); memset(&read->sl_hdr, 0, sizeof(GF_SLHeader)); read->sl_hdr.randomAccessPointFlag = 1; @@ -553,15 +557,15 @@ static GF_Err AC3_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha *is_new_data = 1; fetch_next: - pos = gf_f64_tell(read->stream); - sync = gf_ac3_parser_bs(bs, &hdr, 0); + pos = gf_ftell(read->stream); + sync = gf_ac3_parser_bs(bs, &hdr, GF_FALSE); if (!sync) { gf_bs_del(bs); if (!read->dnload) { *out_reception_status = GF_EOS; read->done = 1; } else { - gf_f64_seek(read->stream, pos, SEEK_SET); + gf_fseek(read->stream, pos, SEEK_SET); *out_reception_status = GF_OK; } return GF_OK; @@ -698,4 +702,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ac3 ) +GPAC_MODULE_STATIC_DECLARATION( ac3 ) diff --git a/modules/alsa/Makefile b/modules/alsa/Makefile index 944e720..921e3c1 100644 --- a/modules/alsa/Makefile +++ b/modules/alsa/Makefile @@ -20,7 +20,7 @@ OBJS= alsa.o SRCS := $(OBJS:.o=.c) -LIB=gm_alsa.$(DYN_LIB_SUFFIX) +LIB=gm_alsa$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/alsa/alsa.c b/modules/alsa/alsa.c index ff1748f..e8cc51e 100644 --- a/modules/alsa/alsa.c +++ b/modules/alsa/alsa.c @@ -376,4 +376,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) DeleteALSAOutput((GF_AudioOutput*)ifce); } -GPAC_MODULE_STATIC_DELARATION( alsa ) +GPAC_MODULE_STATIC_DECLARATION( alsa ) diff --git a/modules/amr_dec/Makefile b/modules/amr_dec/Makefile index 709bb51..0a67d56 100644 --- a/modules/amr_dec/Makefile +++ b/modules/amr_dec/Makefile @@ -45,7 +45,7 @@ OBJS=amr_in.o amr_dec.o \ SRCS := $(OBJS:.o=.c) -LIB=gm_amr_dec.$(DYN_LIB_SUFFIX) +LIB=gm_amr_dec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols amr_dec.def endif diff --git a/modules/amr_dec/amr_dec.c b/modules/amr_dec/amr_dec.c index ed7ade6..f047d0f 100644 --- a/modules/amr_dec/amr_dec.c +++ b/modules/amr_dec/amr_dec.c @@ -331,4 +331,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( amr_dec ) +GPAC_MODULE_STATIC_DECLARATION( amr_dec ) diff --git a/modules/amr_dec/amr_in.c b/modules/amr_dec/amr_in.c index 8581ae5..6fd1d9c 100644 --- a/modules/amr_dec/amr_in.c +++ b/modules/amr_dec/amr_in.c @@ -102,8 +102,8 @@ static GF_ESD *AMR_GetESD(AMR_Reader *read) gf_bs_get_content(dsi, & esd->decoderConfig->decoderSpecificInfo->data, & esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(dsi); } - else if (read->mtype==TYPE_EVRC) esd->decoderConfig->objectTypeIndication = 0xA0; - else if (read->mtype==TYPE_SMV) esd->decoderConfig->objectTypeIndication = 0xA1; + else if (read->mtype==TYPE_EVRC) esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_EVRC_VOICE; + else if (read->mtype==TYPE_SMV) esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_SMV_VOICE; return esd; } @@ -235,7 +235,7 @@ static void AMR_NetIO(void *cbk, GF_NETIO_Parameter *param) szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { - read->stream = fopen((char *) szCache, "rb"); + read->stream = gf_fopen((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { /*if full file at once (in cache) parse duration*/ @@ -248,7 +248,7 @@ static void AMR_NetIO(void *cbk, GF_NETIO_Parameter *param) if (bytes_done>10*1024) { e = GF_CORRUPTED_DATA; } else { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; return; } @@ -305,11 +305,11 @@ static GF_Err AMR_ConnectService(GF_InputService *plug, GF_ClientService *serv, } reply = GF_OK; - read->stream = fopen(szURL, "rb"); + read->stream = gf_fopen(szURL, "rb"); if (!read->stream) { reply = GF_URL_ERROR; } else if (!AMR_ConfigureFromFile(read)) { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; reply = GF_NOT_SUPPORTED; } @@ -321,7 +321,7 @@ static GF_Err AMR_ConnectService(GF_InputService *plug, GF_ClientService *serv, static GF_Err AMR_CloseService(GF_InputService *plug) { AMR_Reader *read = plug->priv; - if (read->stream) fclose(read->stream); + if (read->stream) gf_fclose(read->stream); read->stream = NULL; if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; @@ -600,7 +600,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( amr_in ) +GPAC_MODULE_STATIC_DECLARATION( amr_in ) #endif diff --git a/modules/amr_float_dec/Makefile b/modules/amr_float_dec/Makefile index 262abae..db35290 100644 --- a/modules/amr_float_dec/Makefile +++ b/modules/amr_float_dec/Makefile @@ -36,7 +36,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_amr_float_dec.$(DYN_LIB_SUFFIX) +LIB=gm_amr_float_dec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols amr_float_dec.def endif diff --git a/modules/amr_float_dec/amr_api.h b/modules/amr_float_dec/amr_api.h index a761c26..ab60cd1 100644 --- a/modules/amr_float_dec/amr_api.h +++ b/modules/amr_float_dec/amr_api.h @@ -1,35 +1,35 @@ -#ifndef _AMR_API_H -#define _AMR_API_H - -/*AMR*/ -void Decoder_Interface_Decode( void *st, -#ifndef ETSI - unsigned char *bits, -#else - short *bits, -#endif - short *synth, int bfi ); - -void *Decoder_Interface_init( void ); - - -void Decoder_Interface_exit( void *state ); - - - -/*AMR WB*/ - - -#define NB_SERIAL_MAX 61 /* max serial size */ -#define L_FRAME16k 320 /* Frame size at 16kHz */ - -#define _good_frame 0 -#define _bad_frame 1 -#define _lost_frame 2 -#define _no_frame 3 - -void D_IF_decode(void *st, unsigned char *bits, short *synth, long bfi); -void * D_IF_init(void); -void D_IF_exit(void *state); - +#ifndef _AMR_API_H +#define _AMR_API_H + +/*AMR*/ +void Decoder_Interface_Decode( void *st, +#ifndef ETSI + unsigned char *bits, +#else + short *bits, +#endif + short *synth, int bfi ); + +void *Decoder_Interface_init( void ); + + +void Decoder_Interface_exit( void *state ); + + + +/*AMR WB*/ + + +#define NB_SERIAL_MAX 61 /* max serial size */ +#define L_FRAME16k 320 /* Frame size at 16kHz */ + +#define _good_frame 0 +#define _bad_frame 1 +#define _lost_frame 2 +#define _no_frame 3 + +void D_IF_decode(void *st, unsigned char *bits, short *synth, long bfi); +void * D_IF_init(void); +void D_IF_exit(void *state); + #endif //_AMR_API_H \ No newline at end of file diff --git a/modules/amr_float_dec/amr_float_dec.c b/modules/amr_float_dec/amr_float_dec.c index 98dad50..3e8ab68 100644 --- a/modules/amr_float_dec/amr_float_dec.c +++ b/modules/amr_float_dec/amr_float_dec.c @@ -350,4 +350,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( amr_float ) +GPAC_MODULE_STATIC_DECLARATION( amr_float ) diff --git a/modules/audio_filter/Makefile b/modules/audio_filter/Makefile index eb7b96a..22b5fbd 100644 --- a/modules/audio_filter/Makefile +++ b/modules/audio_filter/Makefile @@ -19,7 +19,7 @@ OBJS= audio_filter.o SRCS := $(OBJS:.o=.c) -LIB=gm_audio_filter.$(DYN_LIB_SUFFIX) +LIB=gm_audio_filter$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/audio_filter/audio_filter.c b/modules/audio_filter/audio_filter.c index ee46e48..b62e54b 100644 --- a/modules/audio_filter/audio_filter.c +++ b/modules/audio_filter/audio_filter.c @@ -26,7 +26,7 @@ #include <gpac/modules/audio_out.h> -#include <gpac/math.h> +#include <gpac/maths.h> #ifndef PI #define PI GF_PI @@ -285,4 +285,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) DeleteAudioFilter((GF_AudioFilter*)ifce); } -GPAC_MODULE_STATIC_DELARATION( audio_filter ) +GPAC_MODULE_STATIC_DECLARATION( audio_filter ) diff --git a/modules/avcap/Makefile b/modules/avcap/Makefile index cdbb6ec..f1333ff 100644 --- a/modules/avcap/Makefile +++ b/modules/avcap/Makefile @@ -22,7 +22,7 @@ OBJS=avcap.o SRCS := $(OBJS:.o=.c) -LIB=gm_avcap.$(DYN_LIB_SUFFIX) +LIB=gm_avcap$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/avcap/avcap.cpp b/modules/avcap/avcap.cpp index 19cbe16..aa7e927 100644 --- a/modules/avcap/avcap.cpp +++ b/modules/avcap/avcap.cpp @@ -501,7 +501,7 @@ void ShutdownInterface(GF_BaseInterface *bi) } } -GPAC_MODULE_STATIC_DELARATION( avcap ) +GPAC_MODULE_STATIC_DECLARATION( avcap ) #ifdef __cplusplus } diff --git a/modules/bifs_dec/Makefile b/modules/bifs_dec/Makefile index 703d56f..49d8bb5 100644 --- a/modules/bifs_dec/Makefile +++ b/modules/bifs_dec/Makefile @@ -19,7 +19,7 @@ OBJS= bifs_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_bifs_dec.$(DYN_LIB_SUFFIX) +LIB=gm_bifs_dec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols bifs_dec.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_bifs_dec-static.$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_bifs_dec-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static endif diff --git a/modules/bifs_dec/bifs_dec.c b/modules/bifs_dec/bifs_dec.c index 6d11351..b8084f0 100644 --- a/modules/bifs_dec/bifs_dec.c +++ b/modules/bifs_dec/bifs_dec.c @@ -213,4 +213,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( bifs ) +GPAC_MODULE_STATIC_DECLARATION( bifs ) diff --git a/modules/ctx_load/Makefile b/modules/ctx_load/Makefile index 85d45e5..e67c10e 100644 --- a/modules/ctx_load/Makefile +++ b/modules/ctx_load/Makefile @@ -19,7 +19,7 @@ OBJS= ctx_load.o SRCS := $(OBJS:.o=.c) -LIB=gm_ctx_load.$(DYN_LIB_SUFFIX) +LIB=gm_ctx_load$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ctx_load.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_ctx_load-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_ctx_load-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/ctx_load/ctx_load.c b/modules/ctx_load/ctx_load.c index 9afe8ba..419f3fd 100644 --- a/modules/ctx_load/ctx_load.c +++ b/modules/ctx_load/ctx_load.c @@ -29,7 +29,7 @@ #include <gpac/network.h> #include <gpac/nodes_mpeg4.h> -#ifndef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH) typedef struct { @@ -74,7 +74,9 @@ static void ODS_SetupOD(GF_Scene *scene, GF_ObjectDescriptor *od) odm->OD = od; odm->term = scene->root_od->term; odm->parentscene = scene; + gf_mx_p(scene->mx_resources); gf_list_add(scene->resources, odm); + gf_mx_v(scene->mx_resources); /*locate service owner*/ gf_odm_setup_object(odm, scene->root_od->net_service); @@ -151,11 +153,11 @@ static Bool CTXLoad_CheckDownload(CTXLoadPriv *priv) if (!priv->file_size && (now - priv->last_check_time < 1000) ) return 0; - f = gf_f64_open(priv->file_name, "rt"); + f = gf_fopen(priv->file_name, "rt"); if (!f) return 0; - gf_f64_seek(f, 0, SEEK_END); - size = gf_f64_tell(f); - fclose(f); + gf_fseek(f, 0, SEEK_END); + size = gf_ftell(f); + gf_fclose(f); /*we MUST have a complete file for now ...*/ if (!priv->file_size) { @@ -344,7 +346,7 @@ static GF_Err CTXLoad_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u /*seek on root stream: destroy the context manager and reload it. We cannot seek on the main stream because commands may have changed node attributes/children and we d'ont track the initial value*/ if (priv->load_flags && (priv->base_stream_id == ES_ID)) { - if (priv->src) fclose(priv->src); + if (priv->src) gf_fclose(priv->src); priv->src = NULL; gf_sm_load_done(&priv->load); priv->file_pos = 0; @@ -375,21 +377,21 @@ static GF_Err CTXLoad_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u u32 entry_time; char file_buf[4096+1]; if (!priv->src) { - priv->src = gf_f64_open(priv->file_name, "rb"); + priv->src = gf_fopen(priv->file_name, "rb"); if (!priv->src) return GF_URL_ERROR; priv->file_pos = 0; } priv->load.type = GF_SM_LOAD_XMTA; e = GF_OK; entry_time = gf_sys_clock(); - gf_f64_seek(priv->src, priv->file_pos, SEEK_SET); + gf_fseek(priv->src, priv->file_pos, SEEK_SET); while (1) { u32 diff, nb_read; nb_read = (u32) fread(file_buf, 1, 4096, priv->src); file_buf[nb_read] = 0; if (!nb_read) { if (priv->file_pos==priv->file_size) { - fclose(priv->src); + gf_fclose(priv->src); priv->src = NULL; priv->load_flags = 2; gf_sm_load_done(&priv->load); @@ -587,6 +589,16 @@ static GF_Err CTXLoad_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u } continue; } + //solve url before import + if (mux->src_url) { + char *res_url = gf_url_concatenate(mux->src_url, mux->file_name); + if (res_url) { + gf_free(mux->file_name); + mux->file_name = res_url; + } + gf_free(mux->src_url); + mux->src_url = NULL; + } /*text import*/ if (mux->textNode) { #ifdef GPAC_DISABLE_MEDIA_IMPORT @@ -609,13 +621,13 @@ static GF_Err CTXLoad_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u /*soundstreams are a bit of a pain, they may be declared before any data gets written*/ if (mux->delete_file) { - FILE *t = gf_f64_open(mux->file_name, "rb"); + FILE *t = gf_fopen(mux->file_name, "rb"); if (!t) { keep_com = 1; gf_list_insert(odU->objectDescriptors, od, 0); break; } - fclose(t); + gf_fclose(t); } /*remap to remote URL - warning, the URL has already been resolved according to the parent path*/ remote = gf_malloc(sizeof(char) * (strlen("gpac://")+strlen(mux->file_name)+1) ); @@ -781,14 +793,14 @@ GF_BaseDecoder *NewContextLoader() return (GF_BaseDecoder*)tmp; } -#endif +#endif //defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH) GPAC_MODULE_EXPORT const u32 *QueryInterfaces() { static u32 si [] = { -#ifndef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH) GF_SCENE_DECODER_INTERFACE, #endif 0 @@ -800,7 +812,7 @@ GPAC_MODULE_EXPORT GF_BaseInterface *LoadInterface(u32 InterfaceType) { switch (InterfaceType) { -#ifndef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH) case GF_SCENE_DECODER_INTERFACE: return (GF_BaseInterface *)NewContextLoader(); #endif @@ -813,7 +825,7 @@ GPAC_MODULE_EXPORT void ShutdownInterface(GF_BaseInterface *ifce) { switch (ifce->InterfaceType) { -#ifndef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_SCENEGRAPH) case GF_SCENE_DECODER_INTERFACE: DeleteContextLoader((GF_BaseDecoder *)ifce); break; @@ -821,4 +833,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ctx_load ) +GPAC_MODULE_STATIC_DECLARATION( ctx_load ) diff --git a/modules/dektec_out/Makefile b/modules/dektec_out/Makefile new file mode 100644 index 0000000..f2ca92c --- /dev/null +++ b/modules/dektec_out/Makefile @@ -0,0 +1,58 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/modules/dektec_out + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" -DGPAC_HAVE_CONFIG_H -I../../ + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +ifeq ($(ENABLE_JOYSTICK), yes) +CFLAGS+=-DENABLE_JOYSTICK +endif + +ifeq ($(ENABLE_JOYSTICK_NO_CURSOR), yes) +CFLAGS+=-DENABLE_JOYSTICK_NO_CURSOR +endif + +#common obj +OBJS= dektec_video.o + +SRCS := $(OBJS:.o=.cpp) + +LIB=gm_dektec_out$(DYN_LIB_SUFFIX) +ifeq ($(CONFIG_WIN32),yes) +#LDFLAGS+=-export-symbols dektec_out.def +endif + + +all: $(LIB) + + +$(LIB): $(OBJS) + $(CXX) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac +ifeq ($(STATICBUILD),yes) + $(CXX) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_dektec_out-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static +endif + + +clean: + rm -f $(OBJS) ../../bin/gcc/$(LIB) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/modules/dektec_out/dektec_video.cpp b/modules/dektec_out/dektec_video.cpp new file mode 100644 index 0000000..241dc73 --- /dev/null +++ b/modules/dektec_out/dektec_video.cpp @@ -0,0 +1,361 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Romain Bouqueau + * Copyright (c) Romain Bouqueau @ GPAC Licensing + * All rights reserved + * + * This file is part of GPAC / Dektec SDI video render module + * + * 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. + * + */ + +#define _DTAPI_DISABLE_AUTO_LINK +#include <DTAPI.h> + +extern "C" { + +/*driver interfaces*/ +#include <gpac/modules/video_out.h> +#include <gpac/modules/audio_out.h> +#include <gpac/constants.h> +#include <gpac/setup.h> + + +//#define DEKTEC_DUMP_UYVY +#ifdef NDEBUG +#define tru 1 +#else +#define tru 0 +#endif + +//TODO: use gf_stretch_bits and get values from config file +#if 1 +#define DWIDTH 1280 +#define DHEIGHT 720 +#define DFORMAT DTAPI_IOCONFIG_720P59_94 +#define DNUMFIELDS 1 +#else +#define DWIDTH 1920 +#define DHEIGHT 1080 +#define DFORMAT DTAPI_IOCONFIG_1080I50 +#define DNUMFIELDS 2 +#endif + +typedef struct +{ + char *pixels; + unsigned char *pixels_UYVY; + u32 width, height, pixel_format, bpp; + + DtDevice *dvc; + DtFrameBuffer *dtf; + bool isSending; + s64 frameNum; +} DtContext; + + +void dx_copy_pixels(GF_VideoSurface *dst_s, const GF_VideoSurface *src_s, const GF_Window *src_wnd); //FIXME: referenced from dx +static GF_Err Dektec_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type) +{ + DtContext *dtc = (DtContext*)dr->opaque; + GF_VideoSurface temp_surf; + memset(&temp_surf, 0, sizeof(GF_VideoSurface)); + temp_surf.pixel_format = GF_PIXEL_UYVY; + temp_surf.video_buffer = (char*)dtc->pixels_UYVY; + temp_surf.pitch_y = dtc->width*2; + dx_copy_pixels(&temp_surf, video_src, src_wnd); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[Dektec Out] Blit\n")); + return GF_OK; +} + +static GF_Err Dektec_Flush(GF_VideoOutput *dr, GF_Window *dest) +{ + DtContext *dtc = (DtContext*)dr->opaque; + DtFrameBuffer *dtf = dtc->dtf; + DTAPI_RESULT res; + if (dest->w != DWIDTH || dest->h != DHEIGHT) { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Dektec Out] Discard data with wrong dimensions\n")); + if (tru) return GF_OK; + } + if (!dtc->isSending) { + // Start transmission + res = dtf->Start(); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_WARNING, GF_LOG_MODULE, ("[Dektec Out] Can't start transmission: %s.\n", DtapiResult2Str(res))); + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Dektec Out] Transmission started.\n")); + dtc->isSending = true; + } + } + s64 firstSafeFrame=-1, lastSafeFrame=-1; + res = dtf->WaitFrame(firstSafeFrame, lastSafeFrame); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't get the next frame: %s\n", DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + if (dtc->frameNum == -1) + dtc->frameNum = firstSafeFrame; + + int numLines=-1, numWritten=DWIDTH*DHEIGHT*2/DNUMFIELDS; + res = dtf->WriteVideo(dtc->frameNum, dtc->pixels_UYVY, numWritten, DTAPI_SDI_FIELD1, DTAPI_SDI_8B, 1, numLines); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't write frame "LLD": %s\n", dtc->frameNum, DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + if (DNUMFIELDS > 1) { + assert(DNUMFIELDS == 2); + numLines=-1, numWritten=DWIDTH*DHEIGHT*2/DNUMFIELDS; + res = dtf->WriteVideo(dtc->frameNum, dtc->pixels_UYVY+numWritten, numWritten, DTAPI_SDI_FIELD2, DTAPI_SDI_8B, 1, numLines); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't write frame "LLD": %s\n", dtc->frameNum, DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + } + + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[Dektec Out] Written frame "LLD" [(0x%X,0x%X,0x%X,0x%X)(0x%X,0x%X,0x%X,0x%X)(0x%X,0x%X,0x%X,0x%X)(0x%X,0x%X,0x%X,0x%X)]\n", dtc->frameNum, DWIDTH, DHEIGHT, + dtc->pixels_UYVY[0], dtc->pixels_UYVY[1], dtc->pixels_UYVY[2], dtc->pixels_UYVY[3], dtc->pixels_UYVY[4], dtc->pixels_UYVY[5], dtc->pixels_UYVY[6], dtc->pixels_UYVY[7], + dtc->pixels_UYVY[8], dtc->pixels_UYVY[9], dtc->pixels_UYVY[10], dtc->pixels_UYVY[11], dtc->pixels_UYVY[12], dtc->pixels_UYVY[13], dtc->pixels_UYVY[14], dtc->pixels_UYVY[15])); + + // commit HANC/VANC - mandatory to form a valid frame + res = dtf->AncCommit(dtc->frameNum); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't write VANC for frame "LLD": %s\n", dtc->frameNum, DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + dtc->frameNum++; + +#ifdef DEKTEC_DUMP_UYVY + char szName[1024]; + sprintf(szName, "test.uyvy"); + FILE *f = fopen(szName, "ab"); + fwrite(dtc->pixels_UYVY, dtc->width*dtc->height*2, 1, f); + fclose(f); +#endif + return GF_OK; +} + +static GF_Err Dektec_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *vi, Bool do_lock) +{ + DtContext *dtc = (DtContext*)dr->opaque; + + if (do_lock) { + if (!vi) return GF_BAD_PARAM; + memset(vi, 0, sizeof(GF_VideoSurface)); + vi->height = dtc->height; + vi->width = dtc->width; + vi->video_buffer = dtc->pixels; + vi->pitch_x = dtc->bpp; + vi->pitch_y = dtc->bpp * vi->width;/*the correct value here is dtc->pixel_format, but the soft raster only supports RGB*/ + vi->pixel_format = GF_PIXEL_RGB_24; + } + return GF_OK; +} + +static void Dektec_Shutdown(GF_VideoOutput *dr) +{ + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[Dektec Out] Dektec_Shutdown\n")); + DtContext *dtc = (DtContext*)dr->opaque; + DtFrameBuffer *dtf = dtc->dtf; + DTAPI_RESULT res = dtf->Start(false); + if (tru && res != DTAPI_OK) + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't stop transmission: %s\n", DtapiResult2Str(res))); + dtf->Detach(); + dtc->dvc->Detach(); + dtc->isSending = false; +} + +static GF_Err Dektec_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) +{ + DtFrameBuffer *dtf = (DtFrameBuffer*)(((DtContext*)dr->opaque)->dtf); + + if (evt) { + switch (evt->type) { + case GF_EVENT_VIDEO_SETUP: + //FIXME: we do not know how to resize - Dektec_Shutdown(dr); Dektec_attach_start(dr); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[Dektec Out] resize (%ux%u) received.\n", evt->size.width, evt->size.height)); + if (evt->size.width != DWIDTH || evt->size.height != DHEIGHT) { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Dektec Out] Bad resize (%ux%u) received. Expected %dx%d.\n", evt->size.width, evt->size.height, DWIDTH, DHEIGHT)); + if (evt->size.width*evt->size.height > DWIDTH*DHEIGHT) //FIXME + return GF_BAD_PARAM; + } + return GF_OK; + } + } + return GF_OK; +} + +static GF_Err Dektec_resize(GF_VideoOutput *dr, u32 w, u32 h) +{ + DtContext *dtc = (DtContext*)dr->opaque; + if (dtc->pixels) gf_free(dtc->pixels); + if (dtc->pixels_UYVY) gf_free(dtc->pixels_UYVY); + dtc->width = w; + dtc->height = h; + dtc->pixels = (char*)gf_malloc(dtc->bpp * w * h); + if (!dtc->pixels) return GF_OUT_OF_MEM; + memset(dtc->pixels, 0, dtc->bpp * w * h); + dtc->pixels_UYVY = (unsigned char*)gf_malloc(2 * w * h); + if (!dtc->pixels_UYVY) return GF_OUT_OF_MEM; + memset(dtc->pixels_UYVY, 0, 2 * w * h); + return GF_OK; +} + +GF_Err Dektec_Setup(GF_VideoOutput *dr, void *os_handle, void *os_display, u32 init_flags) +{ + GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[Dektec Out] Dektec_Setup\n")); + DtContext *dtc = (DtContext*)dr->opaque; + dtc->bpp = 3; //lock_buffer expects RGB + dtc->pixel_format = GF_PIXEL_YV12; + dtc->isSending = false; + Dektec_resize(dr, DWIDTH, DHEIGHT); + + int port = 1; + const char *opt; + opt = gf_modules_get_option((GF_BaseInterface *)dr, "DektecVideo", "SDIOutput"); + if (opt) { + port = atoi(opt); + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Dektec Out] Using port %d (%s)\n", port, opt)); + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Dektec Out] No port specified, using default port: %d\n", port)); + } + + DtDevice *dvc = dtc->dvc; + DtFrameBuffer *dtf = dtc->dtf; + DTAPI_RESULT res; + res = dvc->AttachToType(2154); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] No DTA-2154 in system: %s\n", DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + res = dvc->SetIoConfig(port, DTAPI_IOCONFIG_IODIR, DTAPI_IOCONFIG_OUTPUT, DTAPI_IOCONFIG_OUTPUT); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't set I/O config for the device: %s\n", DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + res = dtf->AttachToOutput(dvc, port, 0); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't attach to port %d: %s\n", port, DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + int IoStdValue=-1, IoStdSubValue=-1; + res = DtapiVidStd2IoStd(DFORMAT, IoStdValue, IoStdSubValue); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Unknown VidStd: %s\n", DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + res = dtf->SetIoConfig(DTAPI_IOCONFIG_IOSTD, IoStdValue, IoStdSubValue); + if (tru && res != DTAPI_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] Can't set I/O config: %s\n", DtapiResult2Str(res))); + return GF_BAD_PARAM; + } + + dtc->frameNum = -1; + + return GF_OK; +} + +GF_VideoOutput *NewDektecVideoOutput() +{ + GF_VideoOutput *driv = (GF_VideoOutput *) gf_malloc(sizeof(GF_VideoOutput)); + memset(driv, 0, sizeof(GF_VideoOutput)); + GF_REGISTER_MODULE_INTERFACE(driv, GF_VIDEO_OUTPUT_INTERFACE, "Dektec Video Output", "gpac distribution") + + DtDevice *dvc = new DtDevice; + DtFrameBuffer *dtf = new DtFrameBuffer; + if (!dtf || !dvc) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Dektec Out] DTA API couldn't be initialized.\n")); + delete dvc; + delete dtf; + gf_free(driv); + return NULL; + } + + DtContext *dtc = new DtContext; + memset(dtc, 0, sizeof(DtContext)); + dtc->dvc = dvc; + dtc->dtf = dtf; + driv->opaque = (void*)dtc; + + driv->Flush = Dektec_Flush; + driv->LockBackBuffer = Dektec_LockBackBuffer; + driv->Setup = Dektec_Setup; + driv->Shutdown = Dektec_Shutdown; + driv->ProcessEvent = Dektec_ProcessEvent; + driv->Blit = Dektec_Blit; + + driv->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY | GF_VIDEO_HW_HAS_YUV; + + return driv; +} + +void DeleteDektecVideoOutput(void *ifce) +{ + GF_VideoOutput *driv = (GF_VideoOutput *) ifce; + DtContext *dtc = (DtContext*)driv->opaque; + gf_free(dtc->pixels); + gf_free(dtc->pixels_UYVY); + delete(dtc->dtf); + delete(dtc->dvc); + delete(dtc); + gf_free(driv); +} + + +#ifndef GPAC_STANDALONE_RENDER_2D + +/*interface query*/ +GPAC_MODULE_EXPORT + const u32 *QueryInterfaces() +{ + static u32 si [] = { + GF_VIDEO_OUTPUT_INTERFACE, + 0 + }; + return si; +} + +/*interface create*/ +GPAC_MODULE_EXPORT + GF_BaseInterface *LoadInterface(u32 InterfaceType) +{ + if (InterfaceType == GF_VIDEO_OUTPUT_INTERFACE) return (GF_BaseInterface *) NewDektecVideoOutput(); + return NULL; +} + +/*interface destroy*/ +GPAC_MODULE_EXPORT + void ShutdownInterface(GF_BaseInterface *ifce) +{ + switch (ifce->InterfaceType) { + case GF_VIDEO_OUTPUT_INTERFACE: + DeleteDektecVideoOutput((GF_VideoOutput *)ifce); + break; + } +} + + +GPAC_MODULE_STATIC_DECLARATION( dektec_out ) + +#endif + +} /* extern "C" */ diff --git a/modules/demo_is/Makefile b/modules/demo_is/Makefile index 49793f0..0f0e6b8 100644 --- a/modules/demo_is/Makefile +++ b/modules/demo_is/Makefile @@ -19,7 +19,7 @@ OBJS= demo_is.o SRCS := $(OBJS:.o=.c) -LIB=gm_demo_is.$(DYN_LIB_SUFFIX) +LIB=gm_demo_is$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols demo_is.def endif diff --git a/modules/demo_is/demo_is.c b/modules/demo_is/demo_is.c index fcd5d84..fbfff14 100644 --- a/modules/demo_is/demo_is.c +++ b/modules/demo_is/demo_is.c @@ -101,4 +101,4 @@ void ShutdownInterface(GF_BaseInterface *bi) } } -GPAC_MODULE_STATIC_DELARATION( demo_is ) +GPAC_MODULE_STATIC_DECLARATION( demo_is ) diff --git a/modules/directfb_out/Makefile b/modules/directfb_out/Makefile index b708e65..67be028 100644 --- a/modules/directfb_out/Makefile +++ b/modules/directfb_out/Makefile @@ -24,7 +24,7 @@ OBJS=directfb_out.o directfb_wrapper.o SRCS := $(OBJS:.o=.c) -LIB=gm_directfb_out.$(DYN_LIB_SUFFIX) +LIB=gm_directfb_out$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/directfb_out/directfb_out.c b/modules/directfb_out/directfb_out.c index 8d03864..0cd58ca 100755 --- a/modules/directfb_out/directfb_out.c +++ b/modules/directfb_out/directfb_out.c @@ -397,4 +397,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( directfb_out ) +GPAC_MODULE_STATIC_DECLARATION( directfb_out ) diff --git a/modules/droid_audio/droidaudio.c b/modules/droid_audio/droidaudio.c index 15331cd..476592a 100644 --- a/modules/droid_audio/droidaudio.c +++ b/modules/droid_audio/droidaudio.c @@ -500,4 +500,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( droid_audio ) +GPAC_MODULE_STATIC_DECLARATION( droid_audio ) diff --git a/modules/droid_cam/droid_cam.c b/modules/droid_cam/droid_cam.c index a62a658..3e012db 100644 --- a/modules/droid_cam/droid_cam.c +++ b/modules/droid_cam/droid_cam.c @@ -744,4 +744,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( droid_cam ) +GPAC_MODULE_STATIC_DECLARATION( droid_cam ) diff --git a/modules/droid_mpegv/droid_mpegv.c b/modules/droid_mpegv/droid_mpegv.c index 0444a9f..a8cac8f 100644 --- a/modules/droid_mpegv/droid_mpegv.c +++ b/modules/droid_mpegv/droid_mpegv.c @@ -490,4 +490,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( droid_mpegv ) +GPAC_MODULE_STATIC_DECLARATION( droid_mpegv ) diff --git a/modules/droid_out/droid_vout-bitmap.c b/modules/droid_out/droid_vout-bitmap.c index 75f8302..a1cf493 100644 --- a/modules/droid_out/droid_vout-bitmap.c +++ b/modules/droid_out/droid_vout-bitmap.c @@ -216,4 +216,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( droid_vidbmp ) +GPAC_MODULE_STATIC_DECLARATION( droid_vidbmp ) diff --git a/modules/droid_out/droid_vout.c b/modules/droid_out/droid_vout.c index 53e0453..f174889 100644 --- a/modules/droid_out/droid_vout.c +++ b/modules/droid_out/droid_vout.c @@ -64,6 +64,8 @@ typedef struct u8 draw_texture; u8 non_power_two; + + Bool fullscreen; } AndroidContext; @@ -124,8 +126,6 @@ void initGL(AndroidContext *rc) /* Really Nice Perspective Calculations */ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - glDisable(GL_CULL_FACE | GL_NORMALIZE | GL_LIGHTING | GL_BLEND | GL_FOG | GL_COLOR_MATERIAL | GL_TEXTURE_2D); } void gluPerspective(GLfloat fovy, GLfloat aspect, @@ -197,7 +197,6 @@ void drawGLScene(AndroidContext *rc) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgba); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, rgba); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, rgba); - glDisable(GL_CULL_FACE | GL_NORMALIZE | GL_LIGHTING | GL_BLEND | GL_FOG | GL_COLOR_MATERIAL | GL_TEXTURE_2D); /* Clear The Screen And The Depth Buffer */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -441,6 +440,11 @@ static GF_Err droid_Resize(GF_VideoOutput *dr, u32 w, u32 h) rc->width = w; rc->height = h; + + if ((dr->max_screen_width < w) || (dr->max_screen_height < h)) { + dr->max_screen_width = w; + dr->max_screen_height = h; + } if ( rc->non_power_two ) { @@ -452,6 +456,7 @@ static GF_Err droid_Resize(GF_VideoOutput *dr, u32 w, u32 h) rc->tex_width = find_pow_2(rc->width); rc->tex_height = find_pow_2(rc->height); } + resizeWindow(rc); @@ -565,7 +570,24 @@ static GF_Err droid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) LOG( ANDROID_LOG_VERBOSE, TAG, "GF_EVENT_SIZE( %d x %d)", evt->setup.width, evt->setup.height); //if (evt->setup.opengl_mode) return GF_OK; - return droid_Resize(dr, evt->setup.width, evt->setup.height); + //in fullscreen mode: do not change viewport; just update perspective + if (rc->fullscreen) { + /* change to the projection matrix and set our viewing volume. */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + /* Set our perspective */ + glOrthox(0, INT2FIX(rc->width), 0, INT2FIX(rc->height), INT2FIX(-1), INT2FIX(1)); + + /* Make sure we're chaning the model view and not the projection */ + glMatrixMode(GL_MODELVIEW); + + /* Reset The View */ + glLoadIdentity(); + return GF_OK; + } else + return droid_Resize(dr, evt->setup.width, evt->setup.height); + case GF_EVENT_VIDEO_SETUP: LOG( ANDROID_LOG_DEBUG, TAG, "Android OpenGL mode: %d", evt->setup.opengl_mode); switch (evt->setup.opengl_mode) @@ -602,6 +624,16 @@ static GF_Err droid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) return GF_OK; } +static GF_Err droid_SetFullScreen(GF_VideoOutput *dr, Bool bOn, u32 *outWidth, u32 *outHeight) +{ + RAWCTX;; + + *outWidth = dr->max_screen_width; + *outHeight = dr->max_screen_height; + rc->fullscreen = bOn; + return droid_Resize(dr, dr->max_screen_width, dr->max_screen_height); +} + GF_VideoOutput *NewAndroidVideoOutput() { AndroidContext *pCtx; @@ -623,6 +655,7 @@ GF_VideoOutput *NewAndroidVideoOutput() driv->Setup = droid_Setup; driv->Shutdown = droid_Shutdown; driv->ProcessEvent = droid_ProcessEvent; + driv->SetFullScreen = droid_SetFullScreen; driv->max_screen_width = 1024; driv->max_screen_height = 1024; @@ -676,4 +709,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( droid_vidgl ) +GPAC_MODULE_STATIC_DECLARATION( droid_vidgl ) diff --git a/modules/dummy_in/Makefile b/modules/dummy_in/Makefile index 341600a..e69e26a 100644 --- a/modules/dummy_in/Makefile +++ b/modules/dummy_in/Makefile @@ -19,7 +19,7 @@ OBJS= dummy_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_dummy_in.$(DYN_LIB_SUFFIX) +LIB=gm_dummy_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols dummy_in.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_dummy_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_dummy_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/dummy_in/dummy_in.c b/modules/dummy_in/dummy_in.c index ee2e193..04a6779 100644 --- a/modules/dummy_in/dummy_in.c +++ b/modules/dummy_in/dummy_in.c @@ -295,12 +295,12 @@ GF_Err DC_ConnectService(GF_InputService *plug, GF_ClientService *serv, const ch return GF_OK; } - test = gf_f64_open(read->url, "rt"); + test = gf_fopen(read->url, "rt"); if (!test) { gf_service_connect_ack(serv, NULL, GF_URL_ERROR); return GF_OK; } - fclose(test); + gf_fclose(test); if (!read->is_service_connected) { gf_service_connect_ack(serv, NULL, GF_OK); read->is_service_connected = 1; @@ -348,10 +348,10 @@ static GF_Descriptor *DC_GetServiceDesc(GF_InputService *plug, u32 expect_type, uri = (char *) gf_dm_sess_get_cache_name(read->dnload); gf_dm_sess_get_stats(read->dnload, NULL, NULL, &size, NULL, NULL, NULL); } else { - FILE *f = gf_f64_open(read->url, "rt"); - gf_f64_seek(f, 0, SEEK_END); - size = (u32) gf_f64_tell(f); - fclose(f); + FILE *f = gf_fopen(read->url, "rt"); + gf_fseek(f, 0, SEEK_END); + size = (u32) gf_ftell(f); + gf_fclose(f); uri = read->url; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); @@ -516,4 +516,4 @@ void ShutdownInterface(GF_BaseInterface *bi) } } -GPAC_MODULE_STATIC_DELARATION( dummy_in ) +GPAC_MODULE_STATIC_DECLARATION( dummy_in ) diff --git a/modules/dx_hw/Makefile b/modules/dx_hw/Makefile index 9ba3858..8be42cd 100644 --- a/modules/dx_hw/Makefile +++ b/modules/dx_hw/Makefile @@ -29,7 +29,7 @@ OBJS=dx_audio.o dx_video.o dx_window.o dx_2d.o copy_pixels.o SRCS := $(OBJS:.o=.c) -LIB=gm_dx_hw.$(DYN_LIB_SUFFIX) +LIB=gm_dx_hw$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols dx_hw.def endif diff --git a/modules/dx_hw/copy_pixels.c b/modules/dx_hw/copy_pixels.c index aa3def9..d752bd7 100644 --- a/modules/dx_hw/copy_pixels.c +++ b/modules/dx_hw/copy_pixels.c @@ -23,7 +23,9 @@ * */ -#include "dx_hw.h" +#include <gpac/setup.h> +#include <gpac/constants.h> +#include <gpac/color.h> static u32 get_yuv_base(u32 in_pf) diff --git a/modules/dx_hw/dx_2d.c b/modules/dx_hw/dx_2d.c index 923b4fa..9cb9ee7 100644 --- a/modules/dx_hw/dx_2d.c +++ b/modules/dx_hw/dx_2d.c @@ -186,9 +186,6 @@ GF_Err CreateBackBuffer(GF_VideoOutput *dr, u32 Width, u32 Height, Bool use_syst if (!dd->fullscreen) { dd->width = Width; dd->height = Height; - } else { - dd->fs_store_width = Width; - dd->fs_store_height = Height; } DD_ClearBackBuffer(dr, 0xFF000000); @@ -233,7 +230,7 @@ GF_Err InitDirectDraw(GF_VideoOutput *dr, u32 Width, u32 Height) if( FAILED(hr)) return GF_IO_ERR; } dd->NeedRestore = 1; - cooplev = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN; +// cooplev = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN; } hr = dd->pDD->lpVtbl->SetCooperativeLevel(dd->pDD, dd->cur_hwnd, cooplev); diff --git a/modules/dx_hw/dx_audio.c b/modules/dx_hw/dx_audio.c index 0cfa57b..0c8d761 100644 --- a/modules/dx_hw/dx_audio.c +++ b/modules/dx_hw/dx_audio.c @@ -210,9 +210,9 @@ retry: hr = ctx->pDS->lpVtbl->CreateSoundBuffer(ctx->pDS, &dsbBufferDesc, &ctx->pOutput, NULL ); if (FAILED(hr)) { if (ctx->format.nChannels>2) { - GF_LOG(GF_LOG_ERROR, GF_LOG_AUDIO, ("[DirectSound] failed to configure output for %d channels (error %08x) - falling back to stereo\n", *NbChannels, hr)); - *NbChannels = 2; - return DS_ConfigureOutput(dr, SampleRate, NbChannels, nbBitsPerSample, 0); + GF_LOG(GF_LOG_ERROR, GF_LOG_AUDIO, ("[DirectSound] failed to configure output for %d channels (error %08x) - falling back to stereo\n", *NbChannels, hr)); + *NbChannels = 2; + return DS_ConfigureOutput(dr, SampleRate, NbChannels, nbBitsPerSample, 0); } return GF_IO_ERR; } diff --git a/modules/dx_hw/dx_hw.h b/modules/dx_hw/dx_hw.h index 5486846..854ff84 100644 --- a/modules/dx_hw/dx_hw.h +++ b/modules/dx_hw/dx_hw.h @@ -84,7 +84,7 @@ typedef HRESULT(WINAPI * DIRECTDRAWCREATEPROC) (GUID *, LPDIRECTDRAW *, IUnknown -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #include "GLES/egl.h" #endif @@ -130,7 +130,6 @@ typedef struct u32 width, height; u32 fs_width, fs_height; - u32 fs_store_width, fs_store_height; u32 store_width, store_height; LONG backup_styles; Bool alt_down, ctrl_down; @@ -155,11 +154,11 @@ typedef struct HCURSOR curs_normal, curs_hand, curs_collide; u32 cursor_type; Bool is_setup, disable_vsync; - + char *caption; /*gl*/ #ifndef GPAC_DISABLE_3D -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X NativeDisplayType gl_HDC; EGLDisplay egldpy; EGLSurface surface; diff --git a/modules/dx_hw/dx_video.c b/modules/dx_hw/dx_video.c index 5c07ae1..628c1a6 100644 --- a/modules/dx_hw/dx_video.c +++ b/modules/dx_hw/dx_video.c @@ -30,7 +30,7 @@ #ifdef _WIN32_WCE -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #endif #else #include <GL/gl.h> @@ -189,7 +189,7 @@ void DestroyObjectsEx(DDContext *dd, Bool only_3d) } /*delete openGL context*/ -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (dd->eglctx) eglDestroyContext(dd->egldpy, dd->eglctx); dd->eglctx = NULL; if (dd->surface) eglDestroySurface(dd->egldpy, dd->surface); @@ -246,7 +246,7 @@ GF_Err DD_SetupOpenGL(GF_VideoOutput *dr, u32 offscreen_width, u32 offscreen_hei Bool hw_reset = GF_FALSE; DDCONTEXT -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X EGLint major, minor; EGLint n; EGLConfig configs[1]; @@ -573,6 +573,21 @@ static void DD_Shutdown(GF_VideoOutput *dr) DD_ShutdownWindow(dr); } +void DD_ShowTaskbar(Bool show) +{ + HWND tbwnd = FindWindow("Shell_TrayWnd", NULL); + HWND swnd = FindWindow("Button", NULL); + + if (tbwnd != NULL) { + ShowWindow(tbwnd, show ? SW_SHOW : SW_HIDE); + UpdateWindow(tbwnd); + } + if (swnd != NULL) { + // Vista + ShowWindow(swnd, show ? SW_SHOW : SW_HIDE); + UpdateWindow(swnd); + } +} static GF_Err DD_SetFullScreen(GF_VideoOutput *dr, Bool bOn, u32 *outWidth, u32 *outHeight) { GF_Err e; @@ -617,60 +632,71 @@ static GF_Err DD_SetFullScreen(GF_VideoOutput *dr, Bool bOn, u32 *outWidth, u32 ShowWindow(dd->cur_hwnd, SW_SHOW); } -#ifndef GPAC_DISABLE_3D - if (dd->output_3d_type==1) { - e = GF_OK; - dd->on_secondary_screen = 0; - /*Setup FS*/ - if (dd->fullscreen) { - int X = 0; - int Y = 0; + + dd->on_secondary_screen = 0; + /*Setup FS*/ + if (dd->fullscreen) { + int X = 0; + int Y = 0; #if(WINVER >= 0x0500) - HMONITOR hMonitor; - MONITORINFOEX minfo; - /*get monitor our windows is on*/ - hMonitor = MonitorFromWindow(dd->os_hwnd, MONITOR_DEFAULTTONEAREST); - if (hMonitor) { - memset(&minfo, 0, sizeof(MONITORINFOEX)); - minfo.cbSize = sizeof(MONITORINFOEX); - /*get monitor top-left for fullscreen switch, and adjust width and height*/ - GetMonitorInfo(hMonitor, (LPMONITORINFO) &minfo); - dd->fs_width = minfo.rcWork.right - minfo.rcWork.left; - dd->fs_height = minfo.rcWork.bottom - minfo.rcWork.top; - X = minfo.rcWork.left; - Y = minfo.rcWork.top; - if (!(minfo.dwFlags & MONITORINFOF_PRIMARY)) dd->on_secondary_screen = 1; + HMONITOR hMonitor; + MONITORINFOEX minfo; + + DD_ShowTaskbar(GF_FALSE); + + /*get monitor our windows is on*/ + hMonitor = MonitorFromWindow(dd->os_hwnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + memset(&minfo, 0, sizeof(MONITORINFOEX)); + minfo.cbSize = sizeof(MONITORINFOEX); + /*get monitor top-left for fullscreen switch, and adjust width and height*/ + GetMonitorInfo(hMonitor, (LPMONITORINFO) &minfo); + dd->fs_width = minfo.rcWork.right - minfo.rcWork.left; + dd->fs_height = minfo.rcWork.bottom - minfo.rcWork.top; + X = minfo.rcWork.left; + Y = minfo.rcWork.top; + + if (dd->fs_height+100 > dr->max_screen_height) { + dd->fs_height = dr->max_screen_height; + Y = 0; } + if (!(minfo.dwFlags & MONITORINFOF_PRIMARY)) dd->on_secondary_screen = 1; + } #endif - /*change display mode*/ - if ((MaxWidth && (dd->fs_width >= MaxWidth)) || (MaxHeight && (dd->fs_height >= MaxHeight)) ) { - dd->fs_width = MaxWidth; - dd->fs_height = MaxHeight; - } - SetWindowPos(dd->cur_hwnd, NULL, X, Y, dd->fs_width, dd->fs_height, SWP_SHOWWINDOW | SWP_NOZORDER /*| SWP_ASYNCWINDOWPOS*/); - - dd->fs_store_width = dd->fs_width; - dd->fs_store_height = dd->fs_height; - } else if (dd->os_hwnd==dd->fs_hwnd) { - SetWindowPos(dd->os_hwnd, NULL, 0, 0, dd->store_width+dd->off_w, dd->store_height+dd->off_h, SWP_NOMOVE | SWP_NOZORDER /*| SWP_ASYNCWINDOWPOS*/); + /*change display mode*/ + if ((MaxWidth && (dd->fs_width >= MaxWidth)) || (MaxHeight && (dd->fs_height >= MaxHeight)) ) { + dd->fs_width = MaxWidth; + dd->fs_height = MaxHeight; } + SetWindowPos(dd->cur_hwnd, NULL, X, Y, dd->fs_width, dd->fs_height, SWP_SHOWWINDOW | SWP_NOZORDER /*| SWP_ASYNCWINDOWPOS*/); + } else if (dd->os_hwnd==dd->fs_hwnd) { + SetWindowPos(dd->os_hwnd, NULL, 0, 0, dd->store_width+dd->off_w, dd->store_height+dd->off_h, SWP_SHOWWINDOW | SWP_NOZORDER /*| SWP_ASYNCWINDOWPOS*/); + } + if (!dd->fullscreen || dd->on_secondary_screen) { + DD_ShowTaskbar(GF_TRUE); + } - if (!e) e = DD_SetupOpenGL(dr, 0, 0); +#ifndef GPAC_DISABLE_3D + if (dd->output_3d_type==1) { + e = DD_SetupOpenGL(dr, 0, 0); } else #endif { - if (!dd->fullscreen && (dd->os_hwnd==dd->fs_hwnd)) { - SetWindowPos(dd->os_hwnd, NULL, 0, 0, dd->store_width+dd->off_w, dd->store_height+dd->off_h, SWP_NOZORDER | SWP_NOMOVE | SWP_ASYNCWINDOWPOS); +// SetWindowPos(dd->os_hwnd, NULL, 0, 0, dd->store_width+dd->off_w, dd->store_height+dd->off_h, SWP_NOZORDER | SWP_NOMOVE | SWP_ASYNCWINDOWPOS); } /*first time FS, store*/ if (!dd->store_width) { dd->store_width = dd->width; dd->store_height = dd->height; } - e = InitDirectDraw(dr, dd->store_width, dd->store_height); + if (dd->fullscreen) { + e = InitDirectDraw(dr, dd->fs_width, dd->fs_height); + } else { + e = InitDirectDraw(dr, dd->store_width, dd->store_height); + } } if (bOn) { @@ -701,7 +727,7 @@ GF_Err DD_Flush(GF_VideoOutput *dr, GF_Window *dest) #ifndef GPAC_DISABLE_3D if (dd->output_3d_type==1) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (dd->surface) eglSwapBuffers(dd->egldpy, dd->surface); #else SwapBuffers(dd->gl_HDC); @@ -833,6 +859,10 @@ static void DeleteVideoOutput(void *ifce) GF_VideoOutput *driv = (GF_VideoOutput *) ifce; DDContext *dd = (DDContext *)driv->opaque; + if (dd->fullscreen) { + DD_ShowTaskbar(GF_TRUE); + } + if (dd->hDDrawLib) { FreeLibrary(dd->hDDrawLib); } @@ -874,4 +904,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( dx_out ) +GPAC_MODULE_STATIC_DECLARATION( dx_out ) diff --git a/modules/dx_hw/dx_window.c b/modules/dx_hw/dx_window.c index bcb20ef..0934697 100644 --- a/modules/dx_hw/dx_window.c +++ b/modules/dx_hw/dx_window.c @@ -475,14 +475,14 @@ LRESULT APIENTRY DD_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam case WM_SIZE: /*always notify GPAC since we're not sure the owner of the window is listening to these events*/ if (wParam==SIZE_MINIMIZED) { - evt.type = GF_EVENT_SHOWHIDE; + evt.type = GF_EVENT_SHOWHIDE_NOTIF; evt.show.show_type = 0; ctx->hidden = 1; vout->on_event(vout->evt_cbk_hdl, &evt); } else { if (ctx->hidden && wParam==SIZE_RESTORED) { ctx->hidden = 0; - evt.type = GF_EVENT_SHOWHIDE; + evt.type = GF_EVENT_SHOWHIDE_NOTIF; evt.show.show_type = 1; vout->on_event(vout->evt_cbk_hdl, &evt); } @@ -493,7 +493,7 @@ LRESULT APIENTRY DD_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam } break; case WM_MOVE: - evt.type = GF_EVENT_MOVE; + evt.type = GF_EVENT_MOVE_NOTIF; evt.move.x = LOWORD(lParam); evt.move.y = HIWORD(lParam); vout->on_event(vout->evt_cbk_hdl, &evt); @@ -533,7 +533,7 @@ LRESULT APIENTRY DD_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam && (ctx->output_3d_type!=2) #endif ) { - evt.type = GF_EVENT_SHOWHIDE; + evt.type = GF_EVENT_SHOWHIDE_NOTIF; vout->on_event(vout->evt_cbk_hdl, &evt); } /*fallthrough*/ @@ -783,14 +783,10 @@ LRESULT APIENTRY DD_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam case WM_UNICHAR: case WM_CHAR: - /*no reason to filter out things*/ -// if (wParam>=32) - { evt.type = GF_EVENT_TEXTINPUT; evt.character.unicode_char = (u32) wParam; ret = vout->on_event(vout->evt_cbk_hdl, &evt); - } - break; + break; /* case WM_CANCELMODE: case WM_CAPTURECHANGED: @@ -959,7 +955,7 @@ Bool DD_InitWindows(GF_VideoOutput *vout, DDContext *ctx) } ShowWindow(ctx->fs_hwnd, SW_HIDE); #ifdef _WIN64 - SetWindowLongPtr(ctx->fs_hwnd, GWLP_USERDATA, (LONG) vout); + SetWindowLongPtr(ctx->fs_hwnd, GWLP_USERDATA, (LONG_PTR) vout); #else SetWindowLong(ctx->fs_hwnd, GWL_USERDATA, (LONG) vout); #endif @@ -972,7 +968,7 @@ Bool DD_InitWindows(GF_VideoOutput *vout, DDContext *ctx) ctx->switch_res = 0; #ifdef _WIN64 - SetWindowLongPtr(ctx->os_hwnd, GWLP_USERDATA, (LONG) vout); + SetWindowLongPtr(ctx->os_hwnd, GWLP_USERDATA, (LONG_PTR) vout); #else SetWindowLong(ctx->os_hwnd, GWL_USERDATA, (LONG) vout); #endif @@ -1003,6 +999,13 @@ u32 DD_WindowThread(void *par) if (msg.message == WM_DESTROY) PostQuitMessage(0); //WM_DESTROY: exit TranslateMessage (&(msg)); DispatchMessage (&(msg)); + + if (ctx->caption) { + SetWindowText(ctx->os_hwnd, ctx->caption); + gf_free(ctx->caption); + ctx->caption = NULL; + } + } } ctx->th_state = 2; @@ -1019,10 +1022,10 @@ void DD_SetupWindow(GF_VideoOutput *dr, u32 flags) if (!(flags & GF_TERM_NO_WINDOWPROC_OVERRIDE) ) { #ifdef _WIN64 ctx->orig_wnd_proc = GetWindowLongPtr(ctx->os_hwnd, GWLP_WNDPROC); - SetWindowLongPtr(ctx->os_hwnd, GWLP_WNDPROC, (DWORD) DD_WindowProc); + SetWindowLongPtr(ctx->os_hwnd, GWLP_WNDPROC, (LONG_PTR) DD_WindowProc); #else ctx->orig_wnd_proc = GetWindowLong(ctx->os_hwnd, GWL_WNDPROC); - SetWindowLong(ctx->os_hwnd, GWL_WNDPROC, (DWORD) DD_WindowProc); + SetWindowLong(ctx->os_hwnd, GWL_WNDPROC, (LONG) DD_WindowProc); #endif } ctx->parent_wnd = GetParent(ctx->os_hwnd); @@ -1065,8 +1068,8 @@ void DD_ShutdownWindow(GF_VideoOutput *dr) if (ctx->fs_hwnd != ctx->os_hwnd) { dd_closewindow(ctx->fs_hwnd); #ifdef _WIN64 - SetWindowLongPtr(ctx->fs_hwnd, GWLP_USERDATA, (LONG) NULL); - SetWindowLongPtr(ctx->fs_hwnd, GWLP_WNDPROC, (DWORD) DefWindowProc); + SetWindowLongPtr(ctx->fs_hwnd, GWLP_USERDATA, (LONG_PTR) NULL); + SetWindowLongPtr(ctx->fs_hwnd, GWLP_WNDPROC, (LONG_PTR) DefWindowProc); #else SetWindowLong(ctx->fs_hwnd, GWL_USERDATA, (LONG) NULL); SetWindowLong(ctx->fs_hwnd, GWL_WNDPROC, (DWORD) DefWindowProc); @@ -1088,7 +1091,7 @@ void DD_ShutdownWindow(GF_VideoOutput *dr) /*special care for Firefox: the windows created by our NP plugin may still be called after the shutdown of the plugin !!*/ #ifdef _WIN64 - SetWindowLongPtr(ctx->os_hwnd, GWLP_USERDATA, (LONG) NULL); + SetWindowLongPtr(ctx->os_hwnd, GWLP_USERDATA, (LONG_PTR) NULL); #else SetWindowLong(ctx->os_hwnd, GWL_USERDATA, (LONG) NULL); #endif @@ -1165,6 +1168,13 @@ GF_Err DD_ProcessEvent(GF_VideoOutput*dr, GF_Event *evt) if (!evt) { if (!ctx->th) { MSG msg; + + if (ctx->caption) { + SetWindowText(ctx->os_hwnd, ctx->caption); + gf_free(ctx->caption); + ctx->caption = NULL; + } + while (PeekMessage (&(msg), NULL, 0, 0, PM_REMOVE)) { TranslateMessage (&(msg)); DispatchMessage (&(msg)); @@ -1179,7 +1189,7 @@ GF_Err DD_ProcessEvent(GF_VideoOutput*dr, GF_Event *evt) break; case GF_EVENT_SET_CAPTION: #ifndef _WIN32_WCE - if (evt->caption.caption) SetWindowText(ctx->os_hwnd, evt->caption.caption); + if (evt->caption.caption && !ctx->caption) ctx->caption = gf_strdup(evt->caption.caption); #endif break; case GF_EVENT_MOVE: diff --git a/modules/epoc_hw/epoc_vout.cpp b/modules/epoc_hw/epoc_vout.cpp index f958035..9904fcf 100644 --- a/modules/epoc_hw/epoc_vout.cpp +++ b/modules/epoc_hw/epoc_vout.cpp @@ -30,7 +30,7 @@ #include <w32std.h> -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #include <GLES/egl.h> #endif @@ -47,7 +47,7 @@ typedef struct char *locked_data; u32 output_3d_type; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X EGLDisplay egl_display; EGLSurface egl_surface; EGLContext egl_context; @@ -60,7 +60,7 @@ static void EVID_ResetSurface(GF_VideoOutput *dr, Bool gl_only) { EPOCVideo *ctx = (EPOCVideo *)dr->opaque; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (ctx->egl_display) { eglMakeCurrent(ctx->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (ctx->egl_context) eglDestroyContext(ctx->egl_display, ctx->egl_context); @@ -168,7 +168,7 @@ static GF_Err EVID_InitSurface(GF_VideoOutput *dr) ctx->width = s.iWidth; ctx->height = s.iHeight; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (ctx->output_3d_type==1) { if (!gl_buffer_size) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[EPOC Video] Display mode not supported by OpenGL\n")); @@ -237,7 +237,7 @@ static GF_Err EVID_InitSurface(GF_VideoOutput *dr) return GF_OK; } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X static GF_Err EVID_SetupOGL_ES_Offscreen(GF_VideoOutput *dr, u32 width, u32 height) { @@ -356,7 +356,7 @@ static GF_Err EVID_Setup(GF_VideoOutput *dr, void *os_handle, void *os_display, res = EVID_InitSurface(dr); /*setup opengl offscreen*/ -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[EPOC Video] Querying Offscreen OpenGL Capabilities\n")); dr->hw_caps |= GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA; GF_Err e = EVID_SetupOGL_ES_Offscreen(dr, 20, 20); @@ -419,7 +419,7 @@ static GF_Err EVID_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) case GF_EVENT_VIDEO_SETUP: ((EPOCVideo *)dr->opaque)->output_3d_type = evt->setup.opengl_mode; if (evt->setup.opengl_mode==2) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X return EVID_SetupOGL_ES_Offscreen(dr, evt->setup.width, evt->setup.height); #else return GF_NOT_SUPPORTED; @@ -473,7 +473,7 @@ static void *EPOC_vout_new() /*alpha and keying to do*/ driv->hw_caps = 0; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X /*no offscreen opengl with epoc at the moment*/ driv->hw_caps |= GF_VIDEO_HW_OPENGL; #endif @@ -547,7 +547,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( epoc_vout ) +GPAC_MODULE_STATIC_DECLARATION( epoc_vout ) #ifdef __cplusplus } diff --git a/modules/ffmpeg_in/Makefile b/modules/ffmpeg_in/Makefile index cdef530..e24908b 100644 --- a/modules/ffmpeg_in/Makefile +++ b/modules/ffmpeg_in/Makefile @@ -45,7 +45,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_ffmpeg_in.$(DYN_LIB_SUFFIX) +LIB=gm_ffmpeg_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ffmpeg_in.def endif diff --git a/modules/ffmpeg_in/ffmpeg_decode.c b/modules/ffmpeg_in/ffmpeg_decode.c index 16c4fbb..2eba865 100644 --- a/modules/ffmpeg_in/ffmpeg_decode.c +++ b/modules/ffmpeg_in/ffmpeg_decode.c @@ -28,7 +28,7 @@ #include <libavcodec/avcodec.h> -#if (LIBAVCODEC_VERSION_MAJOR >= 55) && (LIBAVCODEC_VERSION_MINOR >= 38) +#if ((LIBAVCODEC_VERSION_MAJOR == 55) && (LIBAVCODEC_VERSION_MINOR >= 38)) || (LIBAVCODEC_VERSION_MAJOR > 55) #define HAS_HEVC #include <libavutil/opt.h> @@ -327,7 +327,7 @@ static GF_Err FFDEC_AttachStream(GF_BaseDecoder *plug, GF_ESD *esd) } } } -#ifndef FF_API_AVFRAME_LAVC +#if !defined(FF_API_AVFRAME_LAVC) *frame = avcodec_alloc_frame(); #else *frame = av_frame_alloc(); @@ -398,7 +398,7 @@ static GF_Err FFDEC_AttachStream(GF_BaseDecoder *plug, GF_ESD *esd) #if defined(USE_AVCTX3) -#ifndef FF_API_AVFRAME_LAVC +#if !defined(FF_API_AVFRAME_LAVC) ffd->audio_frame = avcodec_alloc_frame(); #else ffd->audio_frame = av_frame_alloc(); @@ -415,11 +415,15 @@ static GF_Err FFDEC_AttachStream(GF_BaseDecoder *plug, GF_ESD *esd) case CODEC_ID_GIF: #endif case CODEC_ID_RAWVIDEO: - ffd->pix_fmt = GF_PIXEL_RGB_24; + if ((*ctx)->pix_fmt==PIX_FMT_YUV420P) { + ffd->pix_fmt = GF_PIXEL_YV12; + } else { + ffd->pix_fmt = GF_PIXEL_RGB_24; + } break; case CODEC_ID_DVD_SUBTITLE: -#ifndef FF_API_AVFRAME_LAVC +#if !defined(FF_API_AVFRAME_LAVC) *frame = avcodec_alloc_frame(); #else *frame = av_frame_alloc(); @@ -742,7 +746,11 @@ redecode: #if defined(USE_AVCTX3) len = avcodec_decode_audio4(ctx, ffd->audio_frame, &gotpic, &pkt); - if (gotpic) gotpic = ffd->audio_frame->nb_samples * 2 * ctx->channels; + if (gotpic) { + //int inputDataSize = av_samples_get_buffer_size(NULL, ctx->channels, ffd->audio_frame->nb_samples, ctx->sample_fmt, 1); + gotpic = ffd->audio_frame->nb_samples * 2 * ctx->channels; + + } #elif defined(USE_AVCODEC2) gotpic = 192000; len = avcodec_decode_audio3(ctx, (short *)ffd->audio_buf, &gotpic, &pkt); @@ -761,9 +769,11 @@ redecode: /*first config*/ if (!ffd->out_size) { - if (ctx->channels * ctx->frame_size* 2 < gotpic) ctx->frame_size = gotpic / (2 * ctx->channels); + u32 bpp = 2; - ffd->out_size = ctx->channels * ctx->frame_size * 2 /* 16 / 8 */; + if (ctx->channels * ctx->frame_size * bpp < gotpic) ctx->frame_size = gotpic / (bpp * ctx->channels); + + ffd->out_size = ctx->channels * ctx->frame_size * bpp; } if (ffd->out_size < (u32) gotpic) { /*looks like relying on frame_size is not a good idea for all codecs, so we use gotpic*/ @@ -792,8 +802,25 @@ redecode: output[i*ctx->channels + j] = (int16_t) (sample * GF_SHORT_MAX ); } } - } else { + } else if (ffd->audio_frame->format==AV_SAMPLE_FMT_U8) { + u32 i, size = ffd->audio_frame->nb_samples * ctx->channels; + s16 *output = (s16 *) outBuffer; + s8 *input = (s8 *) ffd->audio_frame->data; + for (i=0; i<size; i++) { + output [i] = input[i] * 128; + } + } else if (ffd->audio_frame->format==AV_SAMPLE_FMT_S32) { + u32 i, shift, size = ffd->audio_frame->nb_samples * ctx->channels; + s16 *output = (s16 *) outBuffer; + s32 *input = (s32*) ffd->audio_frame->data; + shift = 1<<31; + for (i=0; i<size; i++) { + output [i] = input[i] * shift; + } + } else if (ffd->audio_frame->format==AV_SAMPLE_FMT_S16) { memcpy(outBuffer, ffd->audio_frame->data, sizeof(char) * ffd->audio_frame->nb_samples * ctx->channels*2); + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[FFMPEG Decoder] Raw Audio format %d not supoorted\n", ffd->audio_frame->format )); } #else /*we're sure to have at least gotpic bytes available in output*/ @@ -803,6 +830,10 @@ redecode: (*outBufferLength) += gotpic; outBuffer += gotpic; +#if defined(USE_AVCTX3) + ffd->audio_frame->nb_samples = 0; +#endif + ffd->frame_start += len; if (inBufferLength <= ffd->frame_start) { ffd->frame_start = 0; @@ -823,7 +854,7 @@ redecode: } if (inBufferLength) { *outBufferLength = ffd->out_size; - assert(inBufferLength==ffd->out_size); +// assert(inBufferLength==ffd->out_size); if (ffd->raw_pix_fmt==PIX_FMT_BGR24) { s32 i, j; diff --git a/modules/ffmpeg_in/ffmpeg_demux.c b/modules/ffmpeg_in/ffmpeg_demux.c index e365910..ed945a4 100644 --- a/modules/ffmpeg_in/ffmpeg_demux.c +++ b/modules/ffmpeg_in/ffmpeg_demux.c @@ -54,11 +54,17 @@ #endif /* AVERROR_NOFMT */ -#if (LIBAVFORMAT_VERSION_MAJOR >= 54) && (LIBAVFORMAT_VERSION_MINOR >= 20) +#if ((LIBAVFORMAT_VERSION_MAJOR == 54) && (LIBAVFORMAT_VERSION_MINOR >= 20)) || (LIBAVFORMAT_VERSION_MAJOR > 54) #define av_find_stream_info(__c) avformat_find_stream_info(__c, NULL) -#ifndef FF_API_FORMAT_PARAMETERS -#define FF_API_FORMAT_PARAMETERS 1 +#define USE_AVFORMAT_OPEN_INPUT 1 +#endif + + +#if defined(GPAC_ANDROID) && (LIBAVFORMAT_VERSION_MAJOR <= 52) + +#ifndef FF_API_CLOSE_INPUT_FILE +#define FF_API_CLOSE_INPUT_FILE 1 #endif #endif @@ -85,7 +91,8 @@ static u32 FFDemux_Run(void *par) slh.compositionTimeStampFlag = slh.decodingTimeStampFlag = 1; while (ffd->is_running) { - if ((!ffd->video_ch && (ffd->video_st>=0)) || (!ffd->audio_ch && (ffd->audio_st>=0))) { + //nothing connected, wait + if (!ffd->video_ch && !ffd->audio_ch) { gf_sleep(100); continue; } @@ -107,27 +114,15 @@ static u32 FFDemux_Run(void *par) gf_mx_p(ffd->mx); /*blindly send audio as soon as video is init*/ if (ffd->audio_ch && (pkt.stream_index == ffd->audio_st) ) { -// u64 seek_audio = ffd->seek_time ? (u64) (s64) (ffd->seek_time*ffd->audio_tscale.den) : 0; slh.compositionTimeStamp *= ffd->audio_tscale.num; slh.decodingTimeStamp *= ffd->audio_tscale.num; -#if 0 - if (slh.compositionTimeStamp < seek_audio) { - slh.decodingTimeStamp = slh.compositionTimeStamp = seek_audio; - } -#endif gf_service_send_packet(ffd->service, ffd->audio_ch, (char *) pkt.data, pkt.size, &slh, GF_OK); } else if (ffd->video_ch && (pkt.stream_index == ffd->video_st)) { -// u64 seek_video = ffd->seek_time ? (u64) (s64) (ffd->seek_time*ffd->video_tscale.den) : 0; slh.compositionTimeStamp *= ffd->video_tscale.num; slh.decodingTimeStamp *= ffd->video_tscale.num; - -#if 0 - if (slh.compositionTimeStamp < seek_video) { - slh.decodingTimeStamp = slh.compositionTimeStamp = seek_video; - } -#endif + slh.randomAccessPointFlag = pkt.flags&AV_PKT_FLAG_KEY ? 1 : 0; gf_service_send_packet(ffd->service, ffd->video_ch, (char *) pkt.data, pkt.size, &slh, GF_OK); } gf_mx_v(ffd->mx); @@ -139,9 +134,10 @@ static u32 FFDemux_Run(void *par) gf_service_command(ffd->service, &com, GF_OK); if (com.buffer.occupancy < com.buffer.max) break; - gf_sleep(10); + gf_sleep(1); } + if (!ffd->audio_run && !ffd->video_run) break; } /*signal EOS*/ @@ -187,11 +183,39 @@ static u32 FFD_RegisterMimeTypes(const GF_InputService *plug) { return i/3; } -static int open_file(AVFormatContext ** ic_ptr, const char * filename, AVInputFormat * fmt) { +static int open_file(AVFormatContext ** ic_ptr, const char * filename, AVInputFormat * fmt, void *ops) { #ifdef USE_PRE_0_7 return av_open_input_file(ic_ptr, filename, fmt, 0, NULL); #else - return avformat_open_input(ic_ptr, filename, fmt, NULL); + return avformat_open_input(ic_ptr, filename, fmt, ops); +#endif +} + +void ffd_parse_options(FFDemux *ffd, const char *url) +{ +#ifdef USE_AVFORMAT_OPEN_INPUT + int res; + char *frag = (char*) strchr(url, '#'); + if (frag) frag = frag+1; + + if (ffd->options) return; + + while (frag) { + char *mid, *sep = strchr(frag, ':'); + if (sep) sep[0] = 0; + mid = strchr(frag, '='); + if (mid) { + mid[0] = 0; + res = av_dict_set(&ffd->options, frag, mid+1, 0); + if (res<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG Demuxer] Failed to set option %s:%s\n", frag, mid+1) ); + } + mid[0] = '='; + } + if (!sep) break; + sep[0] = ':'; + frag = sep+1; + } #endif } @@ -205,6 +229,7 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) Bool ret = 0; char *ext, szName[1000], szExt[20]; const char *szExtList; + FFDemux *ffd; if (!plug || !url) return 0; /*disable RTP/RTSP from ffmpeg*/ @@ -216,6 +241,8 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) if (!strnicmp(url, "tcp://", 6)) return 0; if (!strnicmp(url, "data:", 5)) return 0; + ffd = plug->priv; + strcpy(szName, url); ext = strrchr(szName, '#'); if (ext) ext[0] = 0; @@ -229,7 +256,7 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) strcpy(szExt, &ext[1]); strlwr(szExt); #ifndef FFMPEG_DEMUX_ENABLE_MPEG2TS - if (!strcmp(szExt, "ts")) return 0; + if (strstr("ts m2t mts dmb trp", szExt) ) return 0; #endif /*note we forbid ffmpeg to handle files we support*/ @@ -256,17 +283,21 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) } } + ffd_parse_options(ffd, url); + ctx = NULL; - if (open_file(&ctx, szName, NULL)<0) { + if (open_file(&ctx, szName, NULL, ffd->options ? &ffd->options : NULL)<0) { AVInputFormat *av_in = NULL;; /*some extensions not supported by ffmpeg*/ if (ext && !strcmp(szExt, "cmp")) av_in = av_find_input_format("m4v"); - if (open_file(&ctx, szName, av_in)<0) { + if (open_file(&ctx, szName, av_in, ffd->options ? &ffd->options : NULL)<0) { return 0; } } - if (!ctx || av_find_stream_info(ctx) <0) goto exit; + + if (!ctx) goto exit; + if (av_find_stream_info(ctx) <0) goto exit; /*figure out if we can use codecs or not*/ has_video = has_audio = 0; @@ -285,7 +316,7 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) } if (!has_audio && !has_video) goto exit; ret = 1; -#if LIBAVFORMAT_VERSION_MAJOR < 53 && LIBAVFORMAT_VERSION_MINOR < 45 +#if ((LIBAVFORMAT_VERSION_MAJOR == 52) && (LIBAVFORMAT_VERSION_MINOR <= 47)) || (LIBAVFORMAT_VERSION_MAJOR < 52) fmt_out = guess_stream_format(NULL, url, NULL); #else fmt_out = av_guess_format(NULL, url, NULL); @@ -314,7 +345,7 @@ static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url) } exit: -#ifndef FF_API_CLOSE_INPUT_FILE +#if FF_API_CLOSE_INPUT_FILE if (ctx) av_close_input_file(ctx); #else if (ctx) avformat_close_input(&ctx); @@ -426,7 +457,11 @@ opaque_video: } else { /*only send full AUs*/ esd->slConfig->useAccessUnitStartFlag = esd->slConfig->useAccessUnitEndFlag = 0; - esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1; + if (for_audio) { + esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1; + } else { + esd->slConfig->useRandomAccessPointFlag = 1; + } esd->slConfig->useTimestampsFlag = 1; } @@ -540,6 +575,8 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, ext[0] = 0; } + ffd_parse_options(ffd, url); + /*some extensions not supported by ffmpeg, overload input format*/ ext = strrchr(szName, '.'); strcpy(szExt, ext ? ext+1 : ""); @@ -559,7 +596,7 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, if (sOpt) ffd->buffer_size = atoi(sOpt); ffd->buffer = gf_malloc(sizeof(char)*ffd->buffer_size); #ifdef FFMPEG_DUMP_REMOTE - ffd->outdbg = gf_f64_open("ffdeb.raw", "wb"); + ffd->outdbg = gf_fopen("ffdeb.raw", "wb"); #endif #ifdef USE_PRE_0_7 init_put_byte(&ffd->io, ffd->buffer, ffd->buffer_size, 0, ffd, ff_url_read, NULL, NULL); @@ -582,7 +619,7 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, } if (e==GF_EOS) { const char *cache_file = gf_dm_sess_get_cache_name(ffd->dnload); - res = open_file(&ffd->ctx, cache_file, av_in); + res = open_file(&ffd->ctx, cache_file, av_in, ffd->options ? &ffd->options : NULL); } else { pd.filename = szName; pd.buf_size = ffd->buffer_used; @@ -594,14 +631,14 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, } /*setup downloader*/ av_in->flags |= AVFMT_NOFILE; -#if FF_API_FORMAT_PARAMETERS /*commit ffmpeg 603b8bc2a109978c8499b06d2556f1433306eca7*/ +#ifdef USE_AVFORMAT_OPEN_INPUT /*commit ffmpeg 603b8bc2a109978c8499b06d2556f1433306eca7*/ res = avformat_open_input(&ffd->ctx, szName, av_in, NULL); #else res = av_open_input_stream(&ffd->ctx, &ffd->io, szName, av_in, NULL); #endif } } else { - res = open_file(&ffd->ctx, szName, av_in); + res = open_file(&ffd->ctx, szName, av_in, ffd->options ? &ffd->options : NULL); } switch (res) { @@ -629,7 +666,12 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG] looking for streams in %s - %d streams - type %s\n", ffd->ctx->filename, ffd->ctx->nb_streams, ffd->ctx->iformat->name)); +#ifdef USE_AVFORMAT_OPEN_INPUT + res = avformat_find_stream_info(ffd->ctx, ffd->options ? &ffd->options : NULL); +#else res = av_find_stream_info(ffd->ctx); +#endif + if (res <0) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG] cannot locate streams - error %d\n", res)); e = GF_NOT_SUPPORTED; @@ -689,13 +731,13 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, ffd->seekable = (av_seek_frame(ffd->ctx, -1, 0, AVSEEK_FLAG_BACKWARD)<0) ? 0 : 1; if (!ffd->seekable) { -#ifndef FF_API_CLOSE_INPUT_FILE +#if FF_API_CLOSE_INPUT_FILE av_close_input_file(ffd->ctx); #else avformat_close_input(&ffd->ctx); #endif ffd->ctx = NULL; - open_file(&ffd->ctx, szName, av_in); + open_file(&ffd->ctx, szName, av_in, ffd->options ? &ffd->options : NULL); av_find_stream_info(ffd->ctx); } } @@ -708,7 +750,7 @@ static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, err_exit: GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG] Error opening file %s: %s\n", url, gf_error_to_string(e))); -#ifndef FF_API_CLOSE_INPUT_FILE +#if FF_API_CLOSE_INPUT_FILE if (ffd->ctx) av_close_input_file(ffd->ctx); #else if (ffd->ctx) avformat_close_input(&ffd->ctx); @@ -766,7 +808,7 @@ static GF_Err FFD_CloseService(GF_InputService *plug) ffd->is_running = 0; -#ifndef FF_API_CLOSE_INPUT_FILE +#if FF_API_CLOSE_INPUT_FILE if (ffd->ctx) av_close_input_file(ffd->ctx); #else if (ffd->ctx) avformat_close_input(&ffd->ctx); @@ -789,7 +831,7 @@ static GF_Err FFD_CloseService(GF_InputService *plug) gf_service_disconnect_ack(ffd->service, NULL, GF_OK); #ifdef FFMPEG_DUMP_REMOTE - if (ffd->outdbg) fclose(ffd->outdbg); + if (ffd->outdbg) gf_fclose(ffd->outdbg); #endif return GF_OK; } @@ -981,6 +1023,10 @@ void Delete_FFMPEG_Demux(void *ifce) ffd->thread = NULL; if (ffd->mx) gf_mx_del(ffd->mx); + +#ifndef USE_PRE_0_7 + if (ffd->options) av_dict_free(&ffd->options); +#endif ffd->mx = NULL; gf_free(ffd); ptr->priv = NULL; diff --git a/modules/ffmpeg_in/ffmpeg_in.h b/modules/ffmpeg_in/ffmpeg_in.h index a9aa0b7..02819ad 100644 --- a/modules/ffmpeg_in/ffmpeg_in.h +++ b/modules/ffmpeg_in/ffmpeg_in.h @@ -99,7 +99,7 @@ void gf_av_vlog(void* avcl, int level, const char *fmt, va_list vl); #ifndef FFMPEG_OLD_HEADERS -#if (LIBAVCODEC_VERSION_MAJOR <= 52) && (LIBAVCODEC_VERSION_MINOR <= 20) +#if ((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR <= 20)) || (LIBAVCODEC_VERSION_MAJOR < 52) #undef USE_AVCODEC2 #else #define USE_AVCODEC2 1 @@ -223,8 +223,10 @@ typedef struct #ifdef USE_PRE_0_7 ByteIOContext io; + void *options; #else AVIOContext io; + AVDictionary *options; #endif char *buffer; u32 buffer_size; diff --git a/modules/ffmpeg_in/ffmpeg_load.c b/modules/ffmpeg_in/ffmpeg_load.c index 0e82811..5eaacde 100644 --- a/modules/ffmpeg_in/ffmpeg_load.c +++ b/modules/ffmpeg_in/ffmpeg_load.c @@ -78,4 +78,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } -GPAC_MODULE_STATIC_DELARATION( ffmpeg ) +GPAC_MODULE_STATIC_DECLARATION( ffmpeg ) diff --git a/modules/freenect/Makefile b/modules/freenect/Makefile index 421794e..51dc4ce 100644 --- a/modules/freenect/Makefile +++ b/modules/freenect/Makefile @@ -30,7 +30,7 @@ OBJS=freenect.o SRCS := $(OBJS:.o=.c) -LIB=gm_freenect.$(DYN_LIB_SUFFIX) +LIB=gm_freenect$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/freenect/freenect.c b/modules/freenect/freenect.c index ca8925c..cc42192 100644 --- a/modules/freenect/freenect.c +++ b/modules/freenect/freenect.c @@ -589,5 +589,5 @@ void ShutdownInterface(GF_BaseInterface *bi) } } -GPAC_MODULE_STATIC_DELARATION( freenect ) +GPAC_MODULE_STATIC_DECLARATION( freenect ) diff --git a/modules/ft_font/Makefile b/modules/ft_font/Makefile index f66b200..2d47498 100644 --- a/modules/ft_font/Makefile +++ b/modules/ft_font/Makefile @@ -19,7 +19,7 @@ OBJS= ft_font.o SRCS := $(OBJS:.o=.c) -LIB=gm_ft_font.$(DYN_LIB_SUFFIX) +LIB=gm_ft_font$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ft_font.def endif @@ -38,7 +38,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKVAR) $(EXTRALIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_ft_font-static.$(DYN_LIB_SUFFIX) $(OBJS) $(LINKVAR) $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_ft_font-static$(DYN_LIB_SUFFIX) $(OBJS) $(LINKVAR) $(EXTRALIBS) endif diff --git a/modules/ft_font/ft_font.c b/modules/ft_font/ft_font.c index e88fa8a..da2a152 100644 --- a/modules/ft_font/ft_font.c +++ b/modules/ft_font/ft_font.c @@ -49,12 +49,13 @@ typedef struct { FT_Library library; FT_Face active_face; - char *font_dir; + + GF_List *font_dirs; GF_List *loaded_fonts; /*default fonts*/ - char *font_serif, *font_sans, *font_fixed; + char *font_serif, *font_sans, *font_fixed, *font_default; } FTBuilder; static const char * BEST_FIXED_FONTS[] = { @@ -127,7 +128,7 @@ static Bool ft_enum_fonts(void *cbck, char *file_name, char *file_path, GF_FileE if (FT_New_Face(ftpriv->library, file_path, 0, & face )) return 0; if (!face || !face->family_name) return 0; - num_faces = face->num_faces; + num_faces = (u32) face->num_faces; /*locate right font in collection if several*/ for (i=0; i<num_faces; i++) { @@ -139,14 +140,14 @@ static Bool ft_enum_fonts(void *cbck, char *file_name, char *file_path, GF_FileE strcpy(szfont, face->family_name); /*remember first font found which looks like a alphabetical one*/ - if (!ftpriv->font_dir) { + if (!ftpriv->font_default) { u32 gidx; FT_Select_Charmap(face, FT_ENCODING_UNICODE); gidx = FT_Get_Char_Index(face, (u32) 'a'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) 'z'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) '1'); if (gidx) gidx = FT_Get_Char_Index(face, (u32) '@'); - if (gidx) ftpriv->font_dir = gf_strdup(szfont); + if (gidx) ftpriv->font_default = gf_strdup(szfont); } bold = italic = 0; @@ -205,12 +206,11 @@ static Bool ft_enum_fonts_dir(void *cbck, char *file_name, char *file_path, GF_F static void ft_rescan_fonts(GF_FontReader *dr) { - char *font_dir, *font_default; u32 i, count; GF_Config *cfg = gf_modules_get_config((GF_BaseInterface *)dr); FTBuilder *ftpriv = (FTBuilder *)dr->udta; - GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Rescaning font directory %s\n", ftpriv->font_dir)); + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Rescaning %d font directories\n", gf_list_count(ftpriv->font_dirs) )); count = gf_cfg_get_key_count(cfg, "FontEngine"); for (i=0; i<count; i++) { @@ -226,19 +226,26 @@ static void ft_rescan_fonts(GF_FontReader *dr) } gf_modules_set_option((GF_BaseInterface *)dr, "FontEngine", "RescanFonts", "no"); - ftpriv->font_serif = NULL; - ftpriv->font_sans = NULL; - ftpriv->font_fixed = NULL; - - font_dir = ftpriv->font_dir; - ftpriv->font_dir = NULL; + if (ftpriv->font_fixed) gf_free(ftpriv->font_fixed); + ftpriv->font_fixed = NULL; + if (ftpriv->font_sans) gf_free(ftpriv->font_sans); + ftpriv->font_sans = NULL; + if (ftpriv->font_serif) gf_free(ftpriv->font_serif); + ftpriv->font_serif = NULL; - gf_enum_directory(font_dir, 0, ft_enum_fonts, dr, "ttf;ttc"); - gf_enum_directory(font_dir, 1, ft_enum_fonts_dir, dr, NULL); + if (ftpriv->font_default) gf_free(ftpriv->font_default); + ftpriv->font_default = NULL; + - font_default = ftpriv->font_dir; - ftpriv->font_dir = font_dir; + count = gf_list_count(ftpriv->font_dirs); + for (i=0; i<count; i++) { + char *font_dir = gf_list_get(ftpriv->font_dirs, i); + if (gf_dir_exists(font_dir)) { + gf_enum_directory(font_dir, 0, ft_enum_fonts, dr, "ttf;ttc"); + gf_enum_directory(font_dir, 1, ft_enum_fonts_dir, dr, NULL); + } + } if (ftpriv->font_fixed) gf_free(ftpriv->font_fixed); ftpriv->font_fixed = NULL; @@ -295,16 +302,15 @@ static void ft_rescan_fonts(GF_FontReader *dr) } } - if (!ftpriv->font_serif) ftpriv->font_serif = gf_strdup(font_default ? font_default : ""); - if (!ftpriv->font_sans) ftpriv->font_sans = gf_strdup(font_default ? font_default : ""); - if (!ftpriv->font_fixed) ftpriv->font_fixed = gf_strdup(font_default ? font_default : ""); - if (font_default) gf_free(font_default); + if (!ftpriv->font_serif) ftpriv->font_serif = gf_strdup(ftpriv->font_default ? ftpriv->font_default : ""); + if (!ftpriv->font_sans) ftpriv->font_sans = gf_strdup(ftpriv->font_default ? ftpriv->font_default : ""); + if (!ftpriv->font_fixed) ftpriv->font_fixed = gf_strdup(ftpriv->font_default ? ftpriv->font_default : ""); gf_modules_set_option((GF_BaseInterface *)dr, "FontEngine", "FontFixed", ftpriv->font_fixed); gf_modules_set_option((GF_BaseInterface *)dr, "FontEngine", "FontSerif", ftpriv->font_serif); gf_modules_set_option((GF_BaseInterface *)dr, "FontEngine", "FontSans", ftpriv->font_sans); - GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Font directory scanned\n", ftpriv->font_dir)); + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[FreeType] Font directories scanned\n")); } @@ -323,37 +329,48 @@ static GF_Err ft_init_font_engine(GF_FontReader *dr) return GF_IO_ERR; } - /*remove the final delimiter*/ - ftpriv->font_dir = gf_strdup(sOpt); - while ( (ftpriv->font_dir[strlen(ftpriv->font_dir)-1] == '\n') || (ftpriv->font_dir[strlen(ftpriv->font_dir)-1] == '\r') ) - ftpriv->font_dir[strlen(ftpriv->font_dir)-1] = 0; - - /*store font path*/ - if (ftpriv->font_dir[strlen(ftpriv->font_dir)-1] != GF_PATH_SEPARATOR) { - char ext[2], *temp; - ext[0] = GF_PATH_SEPARATOR; - ext[1] = 0; - temp = gf_malloc(sizeof(char) * (strlen(ftpriv->font_dir) + 2)); - strcpy(temp, ftpriv->font_dir); - strcat(temp, ext); - gf_free(ftpriv->font_dir); - ftpriv->font_dir = temp; + while (sOpt) { + char dir[GF_MAX_PATH]; + char *sep = (char *) strchr(sOpt, ','); + if (sep) sep[0] = 0; + + strcpy(dir, sOpt); + while ( (dir[strlen(dir)-1] == '\n') || (dir[strlen(dir)-1] == '\r') ) + dir[strlen(dir)-1] = 0; + + if (dir[strlen(dir)-1] != GF_PATH_SEPARATOR) { + char ext[2]; + ext[0] = GF_PATH_SEPARATOR; + ext[1] = 0; + strcat(dir, ext); + } + + gf_list_add(ftpriv->font_dirs, gf_strdup(dir) ); + + if (!sep) break; + sep[0] = ','; + sOpt = sep+1; } sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "RescanFonts"); if (!sOpt || !strcmp(sOpt, "yes") ) ft_rescan_fonts(dr); - sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "FontSerif"); - ftpriv->font_serif = gf_strdup(sOpt ? sOpt : ""); - - sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "FontSans"); - ftpriv->font_sans = gf_strdup(sOpt ? sOpt : ""); - - sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "FontFixed"); - ftpriv->font_fixed = gf_strdup(sOpt ? sOpt : ""); - - GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Init OK - font directory %s\n", ftpriv->font_dir)); + if (!ftpriv->font_serif) { + sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "FontSerif"); + ftpriv->font_serif = gf_strdup(sOpt ? sOpt : ""); + } + + if (!ftpriv->font_sans) { + sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "FontSans"); + ftpriv->font_sans = gf_strdup(sOpt ? sOpt : ""); + } + + if (!ftpriv->font_fixed) { + sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "FontEngine", "FontFixed"); + ftpriv->font_fixed = gf_strdup(sOpt ? sOpt : ""); + } + GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[FreeType] Init OK - %d font directory (first %s)\n", gf_list_count(ftpriv->font_dirs), gf_list_get(ftpriv->font_dirs, 0) )); return GF_OK; } @@ -556,16 +573,24 @@ typedef struct s32 last_x, last_y; } ft_outliner; +#if defined(GPAC_IPHONE) || defined(GPAC_ANDROID) +#define FTCST +#else +#define FTCST const +#endif + + -static int ft_move_to(const FT_Vector *to, void *user) +int ft_move_to(FTCST FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; gf_path_add_move_to(ftol->path, INT2FIX(to->x), INT2FIX(to->y) ); - ftol->last_x = to->x; - ftol->last_y = to->y; + ftol->last_x = (s32) to->x; + ftol->last_y = (s32) to->y; return 0; } -static int ft_line_to(const FT_Vector *to, void *user) + +int ft_line_to(FTCST FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; if ( (ftol->last_x == to->x) && (ftol->last_y == to->y)) { @@ -575,14 +600,16 @@ static int ft_line_to(const FT_Vector *to, void *user) } return 0; } -static int ft_conic_to(const FT_Vector * control, const FT_Vector *to, void *user) + +int ft_conic_to(FTCST FT_Vector * control, FTCST FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; gf_path_add_quadratic_to(ftol->path, INT2FIX(control->x), INT2FIX(control->y), INT2FIX(to->x), INT2FIX(to->y) ); if ( (ftol->last_x == to->x) && (ftol->last_y == to->y)) gf_path_close(ftol->path); return 0; } -static int ft_cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *to, void *user) + +int ft_cubic_to(FTCST FT_Vector *c1, FTCST FT_Vector *c2, FTCST FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; gf_path_add_cubic_to(ftol->path, INT2FIX(c1->x), INT2FIX(c1->y), INT2FIX(c2->x), INT2FIX(c2->y), INT2FIX(to->x), INT2FIX(to->y) ); @@ -643,14 +670,14 @@ static GF_Glyph *ft_load_glyph(GF_FontReader *dr, u32 glyph_name) glyph->ID = glyph_name; glyph->utf_name = glyph_name; - glyph->horiz_advance = ftpriv->active_face->glyph->metrics.horiAdvance; - glyph->vert_advance = ftpriv->active_face->glyph->metrics.vertAdvance; + glyph->horiz_advance = (s32) ftpriv->active_face->glyph->metrics.horiAdvance; + glyph->vert_advance = (s32) ftpriv->active_face->glyph->metrics.vertAdvance; /* glyph->x = bbox.xMin; glyph->y = bbox.yMax; */ - glyph->width = ftpriv->active_face->glyph->metrics.width; - glyph->height = ftpriv->active_face->glyph->metrics.height; + glyph->width = (u32) ftpriv->active_face->glyph->metrics.width; + glyph->height = (u32) ftpriv->active_face->glyph->metrics.height; FT_Done_Glyph((FT_Glyph) outline); return glyph; } @@ -667,6 +694,8 @@ GF_FontReader *ft_load() ftpriv = gf_malloc(sizeof(FTBuilder)); memset(ftpriv, 0, sizeof(FTBuilder)); + ftpriv->font_dirs = gf_list_new(); + ftpriv->loaded_fonts = gf_list_new(); dr->udta = ftpriv; @@ -687,8 +716,14 @@ void ft_delete(GF_BaseInterface *ifce) GF_FontReader *dr = (GF_FontReader *) ifce; FTBuilder *ftpriv = dr->udta; - - if (ftpriv->font_dir) gf_free(ftpriv->font_dir); + while (gf_list_count(ftpriv->font_dirs)) { + char *font = gf_list_pop_back(ftpriv->font_dirs); + if (font) + gf_free(font); + } + + gf_list_del(ftpriv->font_dirs); + if (ftpriv->font_serif) gf_free(ftpriv->font_serif); if (ftpriv->font_sans) gf_free(ftpriv->font_sans); if (ftpriv->font_fixed) gf_free(ftpriv->font_fixed); @@ -729,7 +764,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ftfont ) +GPAC_MODULE_STATIC_DECLARATION( ftfont ) #endif diff --git a/modules/gapi/gapi.cpp b/modules/gapi/gapi.cpp index b2f8a57..7d6a619 100644 --- a/modules/gapi/gapi.cpp +++ b/modules/gapi/gapi.cpp @@ -31,7 +31,7 @@ #include "gapi.h" -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__) @@ -552,7 +552,7 @@ void GAPI_WindowThread(void *par) void GAPI_SetupWindow(GF_VideoOutput *dr) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GF_Err e; #endif GAPIPriv *ctx = (GAPIPriv *)dr->opaque; @@ -579,7 +579,7 @@ void GAPI_SetupWindow(GF_VideoOutput *dr) } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X ctx->use_pbuffer = GF_TRUE; dr->hw_caps |= GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA; e = GAPI_SetupOGL_ES_Offscreen(dr, 20, 20); @@ -636,7 +636,7 @@ void GAPI_ShutdownWindow(GF_VideoOutput *dr) ctx->orig_wnd_proc = 0L; } ctx->hWnd = NULL; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X PostMessage(ctx->gl_hwnd, WM_DESTROY, 0, 0); ctx->gl_hwnd = NULL; UnregisterClass(_T("GPAC GAPI Offscreen"), GetModuleHandle(_T("gm_gapi.dll") )); @@ -698,7 +698,7 @@ static void createPixmap(GAPIPriv *ctx, u32 pix_type) ctx->hdc = GetDC(NULL/*ctx->hWnd*/); if (pix_type==2) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X ctx->gl_bitmap = CreateDIBSection(ctx->hdc, bmi, DIB_RGB_COLORS, (void **) &ctx->gl_bits, NULL, 0); #endif } else if (pix_type==1) { @@ -720,7 +720,7 @@ static void createPixmap(GAPIPriv *ctx, u32 pix_type) } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X void GAPI_ReleaseOGL_ES(GAPIPriv *ctx, Bool offscreen_only) { @@ -926,7 +926,7 @@ void GAPI_ReleaseObjects(GAPIPriv *ctx) { ctx->raw_ptr = NULL; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (ctx->output_3d_type) GAPI_ReleaseOGL_ES(ctx, GF_FALSE); else #endif @@ -1019,7 +1019,7 @@ static GF_Err GAPI_SetFullScreen(GF_VideoOutput *dr, Bool bOn, u32 *outWidth, u3 if (is_wide_scene) bOn = GF_TRUE; if (bOn == gctx->fullscreen) return GF_OK; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (gctx->output_3d_type==1) { gctx->fullscreen = bOn; return GAPI_SetupOGL_ES(dr); @@ -1161,7 +1161,7 @@ static GF_Err GAPI_Flush(GF_VideoOutput *dr, GF_Window *dest) gf_mx_p(gctx->mx); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X if (gctx->output_3d_type==1) { #ifndef GLES_NO_PIXMAP if (gctx->fullscreen && gctx->surface && gctx->egldpy) { @@ -1239,11 +1239,11 @@ static GF_Err GAPI_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) case GF_EVENT_VIDEO_SETUP: switch (evt->setup.opengl_mode) { case 0: -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X gctx->output_3d_type = 0; #endif return GAPI_InitBackBuffer(dr, evt->setup.width, evt->setup.height); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X case 1: gctx->output_3d_type = 1; return GAPI_SetupOGL_ES(the_video_driver); @@ -1606,7 +1606,7 @@ static void *NewGAPIVideoOutput() priv->mx = gf_mx_new("GAPI"); driv->opaque = priv; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X driv->hw_caps = GF_VIDEO_HW_OPENGL | GF_VIDEO_HW_OPENGL_OFFSCREEN | GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA; #endif /*rgb, yuv to do*/ @@ -1667,7 +1667,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( gapi ) +GPAC_MODULE_STATIC_DECLARATION( gapi ) #ifdef __cplusplus } diff --git a/modules/gapi/gapi.h b/modules/gapi/gapi.h index 2934a20..6c77f8b 100644 --- a/modules/gapi/gapi.h +++ b/modules/gapi/gapi.h @@ -32,7 +32,7 @@ /*driver interface*/ #include <gpac/modules/video_out.h> -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #include "GLES/egl.h" #endif @@ -83,7 +83,7 @@ typedef struct HDC hdcBitmap, hdc; BITMAPINFO* bmi; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X u32 output_3d_type; EGLDisplay egldpy; EGLSurface surface; diff --git a/modules/gdip_raster/gdip_font.cpp b/modules/gdip_raster/gdip_font.cpp index 7437342..d680424 100644 --- a/modules/gdip_raster/gdip_font.cpp +++ b/modules/gdip_raster/gdip_font.cpp @@ -400,7 +400,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( gdiplus ) +GPAC_MODULE_STATIC_DECLARATION( gdiplus ) #ifdef __cplusplus } diff --git a/modules/gpac_js/Makefile b/modules/gpac_js/Makefile index 9bc7733..277feb9 100644 --- a/modules/gpac_js/Makefile +++ b/modules/gpac_js/Makefile @@ -36,7 +36,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_gpac_js.$(DYN_LIB_SUFFIX) +LIB=gm_gpac_js$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols gpac_js.def endif diff --git a/modules/gpac_js/gpac_js.c b/modules/gpac_js/gpac_js.c index 0d1ded3..f64ed5f 100644 --- a/modules/gpac_js/gpac_js.c +++ b/modules/gpac_js/gpac_js.c @@ -61,6 +61,7 @@ #include <gpac/modules/js_usr.h> #include <gpac/internal/terminal_dev.h> #include <gpac/internal/compositor_dev.h> +#include <gpac/term_info.h> #define GPAC_JS_RTI_REFRESH_RATE 200 @@ -71,8 +72,11 @@ typedef struct GF_JSClass gpacClass; GF_JSClass gpacEvtClass; + GF_JSClass odmClass; GF_JSClass anyClass; + GF_JSClass storageClass; + jsval evt_fun; GF_TermEventFilter evt_filter; GF_Event *evt; @@ -83,6 +87,10 @@ typedef struct u32 rti_refresh_rate; GF_SystemRTInfo rti; + + //list of config files for storage + GF_List *storages; + } GF_GPACJSExt; @@ -94,211 +102,300 @@ static GF_Terminal *gpac_get_term(JSContext *c, JSObject *obj) static SMJS_FUNC_PROP_GET( gpac_getProperty) - const char *res; - char *prop_name; - GF_Terminal *term = gpac_get_term(c, obj); - if (!term) return JS_FALSE; +const char *res; +s32 prop_id; +GF_Terminal *term = gpac_get_term(c, obj); +if (!term) return JS_FALSE; - if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; - prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); - if (!prop_name) return JS_FALSE; - - if (!strcmp(prop_name, "last_working_directory")) { - res = gf_cfg_get_key(term->user->config, "General", "LastWorkingDir"); - if (!res) res = gf_cfg_get_key(term->user->config, "General", "ModulesDirectory"); - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, res)); - } - else if (!strcmp(prop_name, "scale_x")) { - *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->scale_x)) ); - } - else if (!strcmp(prop_name, "scale_y")) { - *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->scale_y)) ); - } - else if (!strcmp(prop_name, "translation_x")) { - *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->trans_x)) ); - } - else if (!strcmp(prop_name, "translation_y")) { - *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->trans_y)) ); - } - else if (!strcmp(prop_name, "rectangular_textures")) { - Bool any_size = GF_FALSE; - #ifndef GPAC_DISABLE_3D - if (term->compositor->gl_caps.npot_texture || term->compositor->gl_caps.rect_texture) - any_size = GF_TRUE; - #endif - *vp = BOOLEAN_TO_JSVAL( any_size ? JS_TRUE : JS_FALSE ); - } - else if (!strcmp(prop_name, "batteryOn")) { - Bool on_battery = GF_FALSE; - gf_sys_get_battery_state(&on_battery, NULL, NULL, NULL, NULL); - *vp = BOOLEAN_TO_JSVAL( on_battery ? JS_TRUE : JS_FALSE ); - } - else if (!strcmp(prop_name, "batteryCharging")) { - u32 on_charge = 0; - gf_sys_get_battery_state(NULL, &on_charge, NULL, NULL, NULL); - *vp = BOOLEAN_TO_JSVAL( on_charge ? JS_TRUE : JS_FALSE ); - } - else if (!strcmp(prop_name, "batteryPercent")) { - u32 level = 0; - gf_sys_get_battery_state(NULL, NULL, &level, NULL, NULL); - *vp = INT_TO_JSVAL( level ); - } - else if (!strcmp(prop_name, "batteryLifeTime")) { - u32 level = 0; - gf_sys_get_battery_state(NULL, NULL, NULL, &level, NULL); - *vp = INT_TO_JSVAL( level ); - } - else if (!strcmp(prop_name, "batteryFullLifeTime")) { - u32 level = 0; - gf_sys_get_battery_state(NULL, NULL, NULL, NULL, &level); - *vp = INT_TO_JSVAL( level ); - } - else if (!strcmp(prop_name, "hostname")) { - char hostname[100]; - gf_sk_get_host_name((char*)hostname); - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, hostname)); - } - else if (!strcmp(prop_name, "fullscreen")) { - *vp = BOOLEAN_TO_JSVAL( term->compositor->fullscreen ? JS_TRUE : JS_FALSE); - } - else if (!strcmp(prop_name, "current_path")) { - char *url = gf_url_concatenate(term->root_scene->root_od->net_service->url, ""); - if (!url) url = gf_strdup(""); - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, url)); - gf_free(url); - } - else if (!strcmp(prop_name, "volume")) { - *vp = INT_TO_JSVAL( gf_term_get_option(term, GF_OPT_AUDIO_VOLUME)); - } - else if (!strcmp(prop_name, "navigation")) { - *vp = INT_TO_JSVAL( gf_term_get_option(term, GF_OPT_NAVIGATION)); - } - else if (!strcmp(prop_name, "navigation_type")) { - *vp = INT_TO_JSVAL( gf_term_get_option(term, GF_OPT_NAVIGATION_TYPE) ); - } - else if (!strcmp(prop_name, "hardware_yuv")) { - *vp = INT_TO_JSVAL( (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_YUV) ? 1 : 0 ); - } - else if (!strcmp(prop_name, "hardware_rgb")) { - *vp = INT_TO_JSVAL( (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGB) ? 1 : 0 ); - } - else if (!strcmp(prop_name, "hardware_rgba")) { - u32 has_rgba = (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGBA) ? 1 : 0; - #ifndef GPAC_DISABLE_3D - if (term->compositor->hybrid_opengl || term->compositor->is_opengl) has_rgba = 1; - #endif - *vp = INT_TO_JSVAL( has_rgba ); - } - else if (!strcmp(prop_name, "hardware_stretch")) { - *vp = INT_TO_JSVAL( (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_STRETCH) ? 1 : 0 ); - } - else if (!strcmp(prop_name, "screen_width")) { - *vp = INT_TO_JSVAL( term->compositor->video_out->max_screen_width); - } - else if (!strcmp(prop_name, "screen_height")) { - *vp = INT_TO_JSVAL( term->compositor->video_out->max_screen_height); - } - else if (!strcmp(prop_name, "http_bitrate")) { - *vp = INT_TO_JSVAL( gf_dm_get_data_rate(term->downloader)*8/1024); - } - else if (!strcmp(prop_name, "fps")) { - Double fps = gf_sc_get_fps(term->compositor, 0); - *vp = DOUBLE_TO_JSVAL(JS_NewDouble(c, fps) ); - } - else if (!strcmp(prop_name, "cpu_load")) { - GF_GPACJSExt *ext = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); - gf_sys_get_rti(ext->rti_refresh_rate, &ext->rti, 0); - *vp = INT_TO_JSVAL(ext->rti.process_cpu_usage); - } - else if (!strcmp(prop_name, "memory")) { - GF_GPACJSExt *ext = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); - gf_sys_get_rti(ext->rti_refresh_rate, &ext->rti, 0); - *vp = INT_TO_JSVAL(ext->rti.process_memory); - } +if (!SMJS_ID_IS_INT(id)) return JS_TRUE; +prop_id = SMJS_ID_TO_INT(id); +switch (prop_id) { +case -1: //"last_working_directory" + res = gf_cfg_get_key(term->user->config, "General", "LastWorkingDir"); + if (!res) res = gf_cfg_get_key(term->user->config, "General", "ModulesDirectory"); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, res)); + break; - SMJS_FREE(c, prop_name); - return JS_TRUE; +case -2: //"scale_x")) + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->scale_x)) ); + break; + +case -3: //"scale_y" + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->scale_y)) ); + break; + +case -4: //"translation_x" + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->trans_x)) ); + break; + +case -5: //"translation_y" + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(term->compositor->trans_y)) ); + break; + +case -6: //"rectangular_textures" +{ + Bool any_size = GF_FALSE; +#ifndef GPAC_DISABLE_3D + if (term->compositor->gl_caps.npot_texture || term->compositor->gl_caps.rect_texture) + any_size = GF_TRUE; +#endif + *vp = BOOLEAN_TO_JSVAL( any_size ? JS_TRUE : JS_FALSE ); +} +break; + +case -7: //"batteryOn" +{ + Bool on_battery = GF_FALSE; + gf_sys_get_battery_state(&on_battery, NULL, NULL, NULL, NULL); + *vp = BOOLEAN_TO_JSVAL( on_battery ? JS_TRUE : JS_FALSE ); +} +break; + +case -8: // "batteryCharging" +{ + u32 on_charge = 0; + gf_sys_get_battery_state(NULL, &on_charge, NULL, NULL, NULL); + *vp = BOOLEAN_TO_JSVAL( on_charge ? JS_TRUE : JS_FALSE ); +} +break; + +case -9: // "batteryPercent" +{ + u32 level = 0; + gf_sys_get_battery_state(NULL, NULL, &level, NULL, NULL); + *vp = INT_TO_JSVAL( level ); +} +break; + +case -10: //"batteryLifeTime" +{ + u32 level = 0; + gf_sys_get_battery_state(NULL, NULL, NULL, &level, NULL); + *vp = INT_TO_JSVAL( level ); +} +break; + +case -11: //"batteryFullLifeTime" +{ + u32 level = 0; + gf_sys_get_battery_state(NULL, NULL, NULL, NULL, &level); + *vp = INT_TO_JSVAL( level ); +} +break; + +case -12: //"hostname" +{ + char hostname[100]; + gf_sk_get_host_name((char*)hostname); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, hostname)); +} +break; + +case -13: //"fullscreen" + *vp = BOOLEAN_TO_JSVAL( term->compositor->fullscreen ? JS_TRUE : JS_FALSE); + break; + +case -14: //"current_path" +{ + char *url = gf_url_concatenate(term->root_scene->root_od->net_service->url, ""); + if (!url) url = gf_strdup(""); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, url)); + gf_free(url); +} +break; + +case -15: //"volume" + *vp = INT_TO_JSVAL( gf_term_get_option(term, GF_OPT_AUDIO_VOLUME)); + break; + +case -16: //"navigation" + *vp = INT_TO_JSVAL( gf_term_get_option(term, GF_OPT_NAVIGATION)); + break; + +case -17: //"navigation_type" + *vp = INT_TO_JSVAL( gf_term_get_option(term, GF_OPT_NAVIGATION_TYPE) ); + break; + +case -18: //"hardware_yuv" + *vp = INT_TO_JSVAL( (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_YUV) ? 1 : 0 ); + break; + +case -19: //"hardware_rgb" + *vp = INT_TO_JSVAL( (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGB) ? 1 : 0 ); + break; + +case -20: //"hardware_rgba" +{ + u32 has_rgba = (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGBA) ? 1 : 0; +#ifndef GPAC_DISABLE_3D + if (term->compositor->hybrid_opengl || term->compositor->is_opengl) has_rgba = 1; +#endif + *vp = INT_TO_JSVAL( has_rgba ); +} +break; + +case -21: //"hardware_stretch" + *vp = INT_TO_JSVAL( (term->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_STRETCH) ? 1 : 0 ); + break; + +case -22: //"screen_width" + *vp = INT_TO_JSVAL( term->compositor->video_out->max_screen_width); + break; + +case -23: //"screen_height" + *vp = INT_TO_JSVAL( term->compositor->video_out->max_screen_height); + break; + +case -24: //"http_max_bitrate" + *vp = INT_TO_JSVAL( gf_dm_get_data_rate(term->downloader)); + break; + +case -25: //"http_bitrate" + *vp = INT_TO_JSVAL( gf_dm_get_global_rate(term->downloader) / 1000); + break; + +case -26: //"fps" + *vp = DOUBLE_TO_JSVAL(JS_NewDouble(c, gf_term_get_framerate(term, 0) ) ); + break; + +case -27: //"cpu_load" || "cpu" +{ + GF_GPACJSExt *ext = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); + gf_sys_get_rti(ext->rti_refresh_rate, &ext->rti, 0); + *vp = INT_TO_JSVAL(ext->rti.process_cpu_usage); +} +break; + +case -28: //"nb_cores" +{ + GF_GPACJSExt *ext = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); + gf_sys_get_rti(ext->rti_refresh_rate, &ext->rti, 0); + *vp = INT_TO_JSVAL(ext->rti.nb_cores); +} +break; + +case -29: //"system_memory" +{ + GF_GPACJSExt *ext = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); + gf_sys_get_rti(ext->rti_refresh_rate, &ext->rti, 0); + *vp = DOUBLE_TO_JSVAL(JS_NewDouble(c, (Double) ext->rti.physical_memory ) ); +} +break; + +case -30: //"memory" +{ + GF_GPACJSExt *ext = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); + gf_sys_get_rti(ext->rti_refresh_rate, &ext->rti, 0); + *vp = INT_TO_JSVAL(ext->rti.process_memory); +} +break; + +case -31: //"argc" + *vp = INT_TO_JSVAL(gf_sys_get_argc() ); + break; + +case -36://"dpi_x" + *vp = INT_TO_JSVAL(term->compositor->video_out->dpi_x); + break; + +case -37://"dpi_y" + *vp = INT_TO_JSVAL(term->compositor->video_out->dpi_y); + break; +} + +return JS_TRUE; } static SMJS_FUNC_PROP_SET( gpac_setProperty) - char *prop_name, *prop_val; - GF_Terminal *term = gpac_get_term(c, obj); - if (!term) return JS_FALSE; +s32 prop_id; +char *prop_val; +GF_Terminal *term = gpac_get_term(c, obj); +if (!term) return JS_FALSE; - if (!SMJS_ID_IS_STRING(id)) return JS_TRUE; - prop_name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); +if (!SMJS_ID_IS_INT(id)) return JS_TRUE; +prop_id = SMJS_ID_TO_INT(id); - if (!strcmp(prop_name, "last_working_directory")) { - if (!JSVAL_IS_STRING(*vp)) { - SMJS_FREE(c, prop_name); - return JS_FALSE; - } - prop_val = SMJS_CHARS(c, *vp); - gf_cfg_set_key(term->user->config, "General", "LastWorkingDir", prop_val); - SMJS_FREE(c, prop_val); - } - else if (!strcmp(prop_name, "caption")) { - GF_Event evt; - if (!JSVAL_IS_STRING(*vp)) { - SMJS_FREE(c, prop_name); - return JS_FALSE; - } - evt.type = GF_EVENT_SET_CAPTION; - evt.caption.caption = SMJS_CHARS(c, *vp); - gf_term_user_event(term, &evt); - SMJS_FREE(c, (char*)evt.caption.caption); - } - else if (!strcmp(prop_name, "fullscreen")) { - /*no fullscreen for iOS (always on)*/ - #ifndef GPAC_IPHONE - Bool res = (JSVAL_TO_BOOLEAN(*vp)==JS_TRUE) ? 1 : 0; - if (term->compositor->fullscreen != res) { - gf_term_set_option(term, GF_OPT_FULLSCREEN, res); - } - #endif - } - else if (!strcmp(prop_name, "volume")) { - if (JSVAL_IS_NUMBER(*vp)) { - jsdouble d; - JS_ValueToNumber(c, *vp, &d); - gf_term_set_option(term, GF_OPT_AUDIO_VOLUME, (u32) d); - } else if (JSVAL_IS_INT(*vp)) { - gf_term_set_option(term, GF_OPT_AUDIO_VOLUME, JSVAL_TO_INT(*vp)); - } +switch (prop_id) { +case -1: //"last_working_directory" + if (!JSVAL_IS_STRING(*vp)) { + return JS_FALSE; } - else if (!strcmp(prop_name, "navigation")) { - gf_term_set_option(term, GF_OPT_NAVIGATION, JSVAL_TO_INT(*vp) ); + prop_val = SMJS_CHARS(c, *vp); + gf_cfg_set_key(term->user->config, "General", "LastWorkingDir", prop_val); + SMJS_FREE(c, prop_val); + break; +case -32://"caption" +{ + GF_Event evt; + if (!JSVAL_IS_STRING(*vp)) { + return JS_FALSE; } - else if (!strcmp(prop_name, "navigation_type")) { - gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 0); + evt.type = GF_EVENT_SET_CAPTION; + evt.caption.caption = SMJS_CHARS(c, *vp); + gf_term_user_event(term, &evt); + SMJS_FREE(c, (char*)evt.caption.caption); +} +break; +case -13://"fullscreen" +{ + /*no fullscreen for iOS (always on)*/ +#ifndef GPAC_IPHONE + Bool res = (JSVAL_TO_BOOLEAN(*vp)==JS_TRUE) ? 1 : 0; + if (term->compositor->fullscreen != res) { + gf_term_set_option(term, GF_OPT_FULLSCREEN, res); } - else if (!strcmp(prop_name, "disable_hardware_blit")) { - term->compositor->disable_hardware_blit = JSVAL_TO_INT(*vp) ? 1 : 0; +#endif +} +break; +case -15: //"volume" + if (JSVAL_IS_NUMBER(*vp)) { + jsdouble d; + SMJS_GET_NUMBER(*vp, d); + gf_term_set_option(term, GF_OPT_AUDIO_VOLUME, (u32) d); + } else if (JSVAL_IS_INT(*vp)) { + gf_term_set_option(term, GF_OPT_AUDIO_VOLUME, JSVAL_TO_INT(*vp)); + } + break; + +case -16: //"navigation" + gf_term_set_option(term, GF_OPT_NAVIGATION, JSVAL_TO_INT(*vp) ); + break; +case -17: //"navigation_type" + gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 0); + break; +case -33: //"disable_hardware_blit" + term->compositor->disable_hardware_blit = JSVAL_TO_INT(*vp) ? 1 : 0; + gf_sc_set_option(term->compositor, GF_OPT_REFRESH, 0); + break; +case -34: //"disable_composite_blit" +{ + Bool new_val = JSVAL_TO_INT(*vp) ? 1 : 0; + if (new_val != term->compositor->disable_composite_blit) { + term->compositor->disable_composite_blit = new_val; + term->compositor->rebuild_offscreen_textures = 1; gf_sc_set_option(term->compositor, GF_OPT_REFRESH, 0); } - else if (!strcmp(prop_name, "disable_composite_blit")) { - Bool new_val = JSVAL_TO_INT(*vp) ? 1 : 0; - if (new_val != term->compositor->disable_composite_blit) { - term->compositor->disable_composite_blit = new_val; - term->compositor->rebuild_offscreen_textures = 1; - gf_sc_set_option(term->compositor, GF_OPT_REFRESH, 0); - } - } - else if (!strcmp(prop_name, "http_bitrate")) { - u32 new_rate = JSVAL_TO_INT(*vp); - gf_dm_set_data_rate(term->downloader, new_rate); - } - - SMJS_FREE(c, prop_name); - return JS_TRUE; +} +break; +case -24: //"http_max_bitrate" +{ + u32 new_rate = JSVAL_TO_INT(*vp); + gf_dm_set_data_rate(term->downloader, new_rate); +} +break; +case -35: //"focus_highlight" + term->compositor->disable_focus_highlight = JSVAL_TO_BOOLEAN(*vp) ? 0 : 1; + break; +} +return JS_TRUE; } -static JSBool SMJS_FUNCTION(gpac_getOption) +static JSBool SMJS_FUNCTION(gpac_get_option) { - const char *opt; + const char *opt = NULL; char *sec_name, *key_name; s32 idx = -1; JSString *s; @@ -332,7 +429,9 @@ static JSBool SMJS_FUNCTION(gpac_getOption) opt = gf_cfg_get_key(term->user->config, sec_name, key_name); } else if (idx>=0) { opt = gf_cfg_get_key_name(term->user->config, sec_name, idx); - } + } else { + opt = NULL; + } if (key_name) { SMJS_FREE(c, key_name); } @@ -347,7 +446,7 @@ static JSBool SMJS_FUNCTION(gpac_getOption) return JS_TRUE; } -static JSBool SMJS_FUNCTION(gpac_setOption) +static JSBool SMJS_FUNCTION(gpac_set_option) { char *sec_name, *key_name, *key_val; SMJS_OBJ @@ -358,11 +457,12 @@ static JSBool SMJS_FUNCTION(gpac_setOption) if (!JSVAL_IS_STRING(argv[0])) return JS_FALSE; if (!JSVAL_IS_STRING(argv[1])) return JS_FALSE; - if (!JSVAL_IS_STRING(argv[2])) return JS_FALSE; sec_name = SMJS_CHARS(c, argv[0]); key_name = SMJS_CHARS(c, argv[1]); - key_val = SMJS_CHARS(c, argv[2]); + key_val = NULL; + if (JSVAL_IS_STRING(argv[2])) + key_val = SMJS_CHARS(c, argv[2]); if (!stricmp(sec_name, "audiofilters")) { if (term->compositor->audio_renderer->filter_chain.enable_filters @@ -377,7 +477,55 @@ static JSBool SMJS_FUNCTION(gpac_setOption) } SMJS_FREE(c, sec_name); SMJS_FREE(c, key_name); - SMJS_FREE(c, key_val); + if (key_val) { + SMJS_FREE(c, key_val); + } + return JS_TRUE; +} + + +static JSBool SMJS_FUNCTION(gpac_get_arg) +{ + SMJS_OBJ + SMJS_ARGS + GF_Terminal *term = gpac_get_term(c, obj); + if (!term) return JS_FALSE; + + if (argc < 1) return JS_FALSE; + + if (JSVAL_IS_INT(argv[0])) { + u32 idx = JSVAL_TO_INT(argv[0]); + const char *arg = gf_sys_get_arg(idx); + if (arg) { + SMJS_SET_RVAL( STRING_TO_JSVAL(JS_NewStringCopyZ(c, arg)) ); + } else { + SMJS_SET_RVAL( JSVAL_NULL ); + } + return JS_TRUE; + } else { + return JS_FALSE; + } + return JS_TRUE; +} + + + +static JSBool SMJS_FUNCTION(gpac_switch_quality) +{ + SMJS_OBJ + SMJS_ARGS + GF_Terminal *term = gpac_get_term(c, obj); + if (!term) return JS_FALSE; + + if (argc < 1) return JS_FALSE; + + if (JSVAL_IS_BOOLEAN(argv[0])) { + Bool up = (JSVAL_TO_BOOLEAN(argv[0])==JS_TRUE) ? GF_TRUE : GF_FALSE; + gf_term_switch_quality(term, up); + return JS_TRUE; + } else { + return JS_FALSE; + } return JS_TRUE; } @@ -534,11 +682,11 @@ static JSBool SMJS_FUNCTION(gpac_set_size) w = h = 0; if ((argc >= 1) && JSVAL_IS_NUMBER(argv[0])) { - JS_ValueToNumber(c, argv[0], &d); + SMJS_GET_NUMBER(argv[0], d); w = (u32) d; } if ((argc >= 2) && JSVAL_IS_NUMBER(argv[1])) { - JS_ValueToNumber(c, argv[1], &d); + SMJS_GET_NUMBER(argv[1], d); h = (u32) d; } if ((argc >= 3) && JSVAL_IS_BOOLEAN(argv[2]) && (JSVAL_TO_BOOLEAN(argv[2])==JS_TRUE) ) @@ -550,6 +698,7 @@ static JSBool SMJS_FUNCTION(gpac_set_size) term->compositor->scene_width = w; term->compositor->scene_height = h; term->compositor->has_size_info = 1; + return JS_TRUE; } if (term->user->os_window_handler) { evt.type = GF_EVENT_SCENE_SIZE; @@ -567,37 +716,6 @@ static JSBool SMJS_FUNCTION(gpac_set_size) return JS_TRUE; } -static JSBool SMJS_FUNCTION(gpac_get_horizontal_dpi) -{ - SMJS_OBJ - GF_Terminal *term = gpac_get_term(c, obj); - if (term) SMJS_SET_RVAL( INT_TO_JSVAL(term->compositor->video_out->dpi_x) ); - return JS_TRUE; -} - -static JSBool SMJS_FUNCTION(gpac_get_vertical_dpi) -{ - SMJS_OBJ - GF_Terminal *term = gpac_get_term(c, obj); - if (term) SMJS_SET_RVAL( INT_TO_JSVAL(term->compositor->video_out->dpi_y) ); - return JS_TRUE; -} - -static JSBool SMJS_FUNCTION(gpac_get_screen_width) -{ - SMJS_OBJ - GF_Terminal *term = gpac_get_term(c, obj); - SMJS_SET_RVAL( INT_TO_JSVAL(term->compositor->video_out->max_screen_width)); - return JS_TRUE; -} - -static JSBool SMJS_FUNCTION(gpac_get_screen_height) -{ - SMJS_OBJ - GF_Terminal *term = gpac_get_term(c, obj); - SMJS_SET_RVAL( INT_TO_JSVAL(term->compositor->video_out->max_screen_height)); - return JS_TRUE; -} static JSBool SMJS_FUNCTION(gpac_exit) { @@ -677,7 +795,6 @@ static JSBool SMJS_FUNCTION(gpac_get_scene_time) static JSBool SMJS_FUNCTION(gpac_trigger_gc) { SMJS_OBJ - SMJS_ARGS GF_SceneGraph *sg = NULL; GF_Terminal *term = gpac_get_term(c, obj); @@ -686,6 +803,7 @@ static JSBool SMJS_FUNCTION(gpac_trigger_gc) return JS_TRUE; } + static JSBool SMJS_FUNCTION(gpac_migrate_url) { char *url; @@ -719,78 +837,737 @@ static JSBool SMJS_FUNCTION(gpac_migrate_url) return JS_TRUE; } -static SMJS_FUNC_PROP_GET( gpacevt_getProperty) +static SMJS_FUNC_PROP_GET( odm_getProperty) - GF_GPACJSExt *gjs = SMJS_GET_PRIVATE(c, obj); - GF_Event *evt = gjs->evt; - if (!evt) return 0; + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + GF_MediaInfo odi; + s32 prop_id; + char *str; + if (!SMJS_ID_IS_INT(id)) return JS_TRUE; - if (SMJS_ID_IS_INT(id)) { - switch (SMJS_ID_TO_INT(id)) { - case -1: -#ifndef GPAC_DISABLE_SVG - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, gf_dom_get_key_name(evt->key.key_code) )); -#endif - break; - case -2: - *vp = INT_TO_JSVAL(evt->mouse.x); - break; - case -3: - *vp = INT_TO_JSVAL(evt->mouse.y); - break; - case -4: - if (gjs->term->compositor->hit_appear) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); - else if (gf_list_count(gjs->term->compositor->previous_sensors) ) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); - else if (gjs->term->compositor->text_selection) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); - else *vp = BOOLEAN_TO_JSVAL(JS_FALSE); - break; - case -5: - *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(evt->mouse.wheel_pos)) ); - break; - case -6: - *vp = INT_TO_JSVAL( evt->mouse.button); + gf_term_get_object_info(odm->term, odm, &odi); + + prop_id = SMJS_ID_TO_INT(id); + switch (prop_id) { + case -1: + *vp = INT_TO_JSVAL(odi.od->objectDescriptorID); + break; + case -2: + *vp = INT_TO_JSVAL(odm->subscene ? gf_list_count(odm->subscene->resources) : 0); + break; + case -3: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, odi.service_url)); + break; + case -4: + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, odi.duration) ); + break; + case -5: + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, odi.current_time) ); + break; + case -6: + *vp = INT_TO_JSVAL( odi.clock_drift); + break; + case -7: + if (odi.status==0) str = "Stopped"; + else if (odi.status==1) str = "Playing"; + else if (odi.status==2) str = "Paused"; + else if (odi.status==3) str = "Not Setup"; + else str = "Setup Failed"; + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, str)); + break; + case -8: + *vp = INT_TO_JSVAL( odi.buffer); + break; + case -9: + *vp = INT_TO_JSVAL( odi.db_unit_count); + break; + case -10: + *vp = INT_TO_JSVAL( odi.cb_unit_count); + break; + case -11: + *vp = INT_TO_JSVAL( odi.cb_max_count); + break; + case -12: + if (odi.od_type==GF_STREAM_SCENE) str = "Scene"; + else if (odi.od_type==GF_STREAM_OD) str = "Object Descriptor"; + else if (odi.od_type==GF_STREAM_VISUAL) str = "Video"; + else if (odi.od_type==GF_STREAM_AUDIO) str = "Audio"; + else if (odi.od_type==GF_STREAM_TEXT) str = "Text"; + else if (odm->subscene) str = "Subscene"; + else str = "Unknow"; + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, str)); + break; + case -13: + *vp = INT_TO_JSVAL( odi.sample_rate); + break; + case -14: + *vp = INT_TO_JSVAL( odi.num_channels); + break; + case -15: + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, gf_4cc_to_str(odi.lang) ) ); + break; + case -16: + *vp = INT_TO_JSVAL( odi.width); + break; + case -17: + *vp = INT_TO_JSVAL( odi.height); + break; + case -18: + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, gf_4cc_to_str(odi.pixelFormat) ) ); + break; + case -19: + if (odi.par) { + char szPar[50]; + sprintf(szPar, "%d:%d", (odi.par>>16)&0xFF, (odi.par)&0xFF ); + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, szPar ) ); + } else { + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, "1:1" ) ); + } + break; + case -20: + *vp = INT_TO_JSVAL(odi.nb_dec_frames); + break; + case -21: + *vp = INT_TO_JSVAL(odi.nb_dropped); + break; + case -22: + *vp = INT_TO_JSVAL(odi.max_dec_time); + break; + case -23: + *vp = INT_TO_JSVAL(odi.total_dec_time); + break; + case -24: + *vp = INT_TO_JSVAL(odi.avg_bitrate); + break; + case -25: + *vp = INT_TO_JSVAL(odi.max_bitrate); + break; + case -26: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, odi.service_handler)); + break; + case -27: + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, odi.codec_name)); + break; + case -28: + { + //first check network + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_QUALITY_QUERY; + com.base.on_channel = gf_list_get(odm->channels, 0); + + gf_term_service_command(odm->net_service, &com); + if (com.quality_query.index) { + *vp = INT_TO_JSVAL(com.quality_query.index); break; - case -7: - *vp = INT_TO_JSVAL(evt->type); + } +#if 0 + //use input channels + if (odm->codec->type==GF_STREAM_VISUAL) { + u32 count = gf_list_count(odm->codec->inChannels); + if (count>1) { + *vp = INT_TO_JSVAL(count); + break; + } + } + //use number of scalable addons + if (odm->upper_layer_odm) { + u32 count = 0; + while (odm) { + odm = odm->upper_layer_odm; + count++; + } + *vp = INT_TO_JSVAL(count); break; - case -8: -#ifndef GPAC_DISABLE_SVG - *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, gf_dom_event_get_name(evt->type) )); + } #endif + *vp = INT_TO_JSVAL(1); + break; + } + case -29: + *vp = INT_TO_JSVAL(odi.max_buffer); + break; + case -30: + *vp = INT_TO_JSVAL(odi.min_buffer); + break; + case -31: + *vp = INT_TO_JSVAL(odi.au_duration); + break; + case -32: + *vp = INT_TO_JSVAL(odi.nb_iraps); + break; + case -33: + *vp = INT_TO_JSVAL(odi.irap_total_dec_time); + break; + case -34: + *vp = INT_TO_JSVAL(odi.irap_max_dec_time); + break; + case -35: + *vp = INT_TO_JSVAL(odi.od ? odi.od->ServiceID : 0); + break; + case -36: + *vp = INT_TO_JSVAL( (!odm->addon && odm->subscene) ? odm->subscene->selected_service_id : odm->parentscene->selected_service_id); + break; + case -37: + { + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_GET_STATS; + com.base.on_channel = gf_list_get(odm->channels, 0); + gf_term_service_command(odm->net_service, &com); + *vp = INT_TO_JSVAL(com.net_stats.bw_down/1000); + } + break; + case -38: + *vp = INT_TO_JSVAL(gf_list_count(odm->net_service->dnloads) ); + break; + case -39: + if ((s32) odm->timeshift_depth > 0) { + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, ((Double) odm->timeshift_depth) / 1000.0 ) ); + } else { + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, 0.0) ); + } + break; + case -40: + { + GF_NetworkCommand com; + GF_Scene *scene; + Double res = 0.0; + + if (!odm->timeshift_depth) { + *vp = INT_TO_JSVAL(0); break; } - } else if (SMJS_ID_IS_STRING(id)) { - char *name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); - if (!strcmp(name, "target_url")) { - *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, evt->navigate.to_url) ); + + scene = odm->subscene ? odm->subscene : odm->parentscene; + + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_GET_TIMESHIFT; + + //we may need to check the main addon for timeshifting + if (scene->main_addon_selected) { + u32 i, count = gf_list_count(scene->resources); + for (i=0; i < count; i++) { + GF_ObjectManager *an_odm = gf_list_get(scene->resources, i); + if (an_odm && an_odm->addon && (an_odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + odm = an_odm; + } + } } - else if (!strcmp(name, "files")) { - u32 i, idx; - jsval v; - JSObject *files_array = JS_NewArrayObject(c, 0, NULL); - for (i=0; i<evt->open_file.nb_files; i++) { - if (evt->open_file.files[i]) { - JS_GetArrayLength(c, files_array, &idx); - v = STRING_TO_JSVAL( JS_NewStringCopyZ(c, evt->open_file.files[i]) ); - JS_SetElement(c, files_array, idx, &v); + + if (odm->timeshift_depth) { + //can be NULL + com.base.on_channel = gf_list_get(odm->channels, 0); + gf_term_service_command(odm->net_service, &com); + res = com.timeshift.time; + } else if (scene->main_addon_selected) { + GF_Clock *ck; + ck = scene->dyn_ck; + if (scene->scene_codec) ck = scene->scene_codec->ck; + if (ck) { + u32 now = gf_clock_time(scene->dyn_ck) ; + u32 live = scene->obj_clock_at_main_activation + gf_sys_clock() - scene->sys_clock_at_main_activation; + res = ((Double) live) / 1000.0; + res -= ((Double) now) / 1000.0; + + if (res<0) { + GF_Event evt; + memset(&evt, 0, sizeof(evt)); + evt.type = GF_EVENT_TIMESHIFT_UNDERRUN; + gf_term_send_event(odm->term, &evt); + res=0; + } else if (res && res*1000 > scene->timeshift_depth) { + GF_Event evt; + memset(&evt, 0, sizeof(evt)); + evt.type = GF_EVENT_TIMESHIFT_OVERFLOW; + gf_term_send_event(odm->term, &evt); + res=scene->timeshift_depth; + res/=1000; } } - *vp = OBJECT_TO_JSVAL(files_array); } - SMJS_FREE(c, name); + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, res) ); + } + break; + case -41: + *vp = BOOLEAN_TO_JSVAL( (odm->addon || (!odm->subscene && odm->parentscene->root_od->addon)) ? JS_TRUE : JS_FALSE); + break; + case -42: + { + GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene; + *vp = BOOLEAN_TO_JSVAL( scene->main_addon_selected ? JS_TRUE : JS_FALSE); + } + break; + case -43: + { + GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene; + *vp = BOOLEAN_TO_JSVAL( gf_sc_is_over(odm->term->compositor, scene->graph) ? JS_TRUE : JS_FALSE); + } + break; + case -44: + { + GF_Channel *ch = gf_list_get(odm->channels, 0); + *vp = BOOLEAN_TO_JSVAL((ch && ch->is_pulling) ? JS_TRUE : JS_FALSE); + } + break; + case -45: + *vp = BOOLEAN_TO_JSVAL(odm->subscene && odm->subscene->is_dynamic_scene ? JS_TRUE : JS_FALSE); + break; + case -46: + { + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_INFO; + com.info.service_id = odi.od->ServiceID; + gf_term_service_command(odm->net_service, &com); + if (com.info.name) { + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, com.info.name ) ); + } else { + *vp = JSVAL_NULL; + } } + break; + case -47: + *vp = INT_TO_JSVAL( odi.ntp_diff); + break; + + case -48: + { + GF_Scene *scene = odm->subscene ? odm->subscene : odm->parentscene; + u32 i, count = gf_list_count(scene->resources); + *vp = JSVAL_NULL; + for (i=0; i < count; i++) { + GF_ObjectManager *an_odm = gf_list_get(scene->resources, i); + if (an_odm && an_odm->addon && (an_odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + if (!strstr(an_odm->addon->url, "://")) { + char szURL[GF_MAX_PATH]; + sprintf(szURL, "gpac://%s", an_odm->addon->url); + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, szURL) ); + } else { + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, an_odm->addon->url) ); + } + } + } + } + break; + case -49: + { + u32 i, count; + GF_Err e; + GF_NetworkCommand com; + GF_Scene *scene; + scene = odm->subscene ? odm->subscene : odm->parentscene; + + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_CAN_REVERSE_PLAYBACK; + + //we may need to check the main addon for timeshifting + count = gf_list_count(scene->resources); + for (i=0; i < count; i++) { + GF_ObjectManager *an_odm = gf_list_get(scene->resources, i); + if (an_odm && an_odm->addon && (an_odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + odm = an_odm; + } + } + + //can be NULL + com.base.on_channel = gf_list_get(odm->channels, 0); + e = gf_term_service_command(odm->net_service, &com); + *vp = BOOLEAN_TO_JSVAL((e==GF_OK) ? GF_TRUE : GF_FALSE ); + } + break; + case -50: + *vp = BOOLEAN_TO_JSVAL(odm && (odm->lower_layer_odm || odm->scalable_addon) ? JS_TRUE : JS_FALSE); + break; + } + + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_get_quality) +{ + GF_NetworkCommand com; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (!odm) return JS_TRUE; + if (argc<1) return JS_TRUE; + if (! JSVAL_IS_INT(argv[0]) ) return JS_TRUE; + + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_QUALITY_QUERY; + com.quality_query.index = 1 + JSVAL_TO_INT(argv[0]); + com.base.on_channel = gf_list_get(odm->channels, 0); + + if (gf_term_service_command(odm->net_service, &com) == GF_OK) { + JSObject *a = JS_NewObject(c, NULL, NULL, NULL); + + JS_DefineProperty(c, a, "ID", STRING_TO_JSVAL(JS_NewStringCopyZ(c, com.quality_query.ID ? com.quality_query.ID : "")) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "mime", STRING_TO_JSVAL(JS_NewStringCopyZ(c, com.quality_query.mime ? com.quality_query.mime : "")) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "codec", STRING_TO_JSVAL(JS_NewStringCopyZ(c, com.quality_query.codec ? com.quality_query.codec : "")) , 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "width", INT_TO_JSVAL(com.quality_query.width), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "height", INT_TO_JSVAL(com.quality_query.height), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "bandwidth", INT_TO_JSVAL(com.quality_query.bandwidth), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "interlaced", BOOLEAN_TO_JSVAL(com.quality_query.interlaced), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "fps", DOUBLE_TO_JSVAL( JS_NewDouble(c, com.quality_query.fps) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "samplerate", INT_TO_JSVAL(com.quality_query.sample_rate), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "channels", INT_TO_JSVAL(com.quality_query.nb_channels), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "par_num", INT_TO_JSVAL(com.quality_query.par_num), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "par_den", INT_TO_JSVAL(com.quality_query.par_den), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "disabled", BOOLEAN_TO_JSVAL(com.quality_query.disabled), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "is_selected", BOOLEAN_TO_JSVAL(com.quality_query.is_selected), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineProperty(c, a, "automatic", BOOLEAN_TO_JSVAL(com.quality_query.automatic), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); + + SMJS_SET_RVAL( OBJECT_TO_JSVAL(a) ); + } else { + SMJS_SET_RVAL(JSVAL_NULL); + } + + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_select_quality) +{ + GF_NetworkCommand com; + char *ID = NULL; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (!odm) return JS_TRUE; + + if ((argc==1) && JSVAL_IS_STRING(argv[0])) { + ID = SMJS_CHARS(c, argv[0]); + } + if (!ID) { + return JS_TRUE; + } + + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_QUALITY_SWITCH; + com.base.on_channel = gf_list_get(odm->channels, 0); + if (!strcmp(ID, "auto")) { + com.switch_quality.set_auto = 1; + } else { + com.switch_quality.ID = ID; + } + + gf_term_service_command(odm->net_service, &com); + + SMJS_FREE(c, ID); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_disable_main_addon) +{ + SMJS_OBJ + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (!odm || !odm->subscene || !odm->subscene->main_addon_selected) return JS_TRUE; + + gf_scene_resume_live(odm->subscene); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_select_service) +{ + u32 sid; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (!odm) return JS_TRUE; + if (argc<1) return JS_TRUE; + if (! JSVAL_IS_INT(argv[0]) ) return JS_TRUE; + sid = JSVAL_TO_INT(argv[0]); + + gf_term_select_service(odm->term, odm->subscene ? odm : odm->parentscene->root_od, sid); + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_get_resource) +{ + GF_ObjectManager *an_odm = NULL; + u32 idx; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (!odm) return JS_TRUE; + if (argc<1) return JS_TRUE; + if (! JSVAL_IS_INT(argv[0]) ) return JS_TRUE; + idx = JSVAL_TO_INT(argv[0]); + + if (odm->subscene) { + an_odm = gf_list_get(odm->subscene->resources, idx); + } + if (an_odm && an_odm->net_service) { + JSObject *anobj; + JSClass *_class = JS_GET_CLASS(c, obj); + anobj = JS_NewObject(c, _class, 0, 0); + SMJS_SET_PRIVATE(c, anobj, an_odm); + SMJS_SET_RVAL( OBJECT_TO_JSVAL(anobj) ); + } else { + SMJS_SET_RVAL(JSVAL_NULL); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_addon_layout) +{ + u32 pos, size; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (argc<2) return JS_TRUE; + if (! JSVAL_IS_INT(argv[0]) ) return JS_TRUE; + if (! JSVAL_IS_INT(argv[1]) ) return JS_TRUE; + pos = JSVAL_TO_INT(argv[0]); + size = JSVAL_TO_INT(argv[1]); + + gf_scene_set_addon_layout_info(odm->subscene, pos, size); + return JS_TRUE; +} + +static void do_enable_addon(GF_ObjectManager *odm, char *addon_url, Bool enable_if_defined ) +{ + GF_AssociatedContentLocation addon_info; + memset(&addon_info, 0, sizeof(GF_AssociatedContentLocation)); + addon_info.external_URL = addon_url; + addon_info.timeline_id = -100; + addon_info.enable_if_defined = enable_if_defined; + gf_scene_register_associated_media(odm->subscene ? odm->subscene : odm->parentscene, &addon_info); +} + +static JSBool SMJS_FUNCTION(gjs_odm_enable_addon) +{ + char *addon_url = NULL; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (! JSVAL_IS_STRING(argv[0]) ) return JS_TRUE; + + addon_url = SMJS_CHARS(c, argv[0]); + if (addon_url) { + do_enable_addon(odm, addon_url, GF_TRUE); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_odm_declare_addon) +{ + char *addon_url = NULL; + SMJS_OBJ + SMJS_ARGS + GF_ObjectManager *odm = (GF_ObjectManager *)SMJS_GET_PRIVATE(c, obj); + + if (! JSVAL_IS_STRING(argv[0]) ) return JS_TRUE; + + addon_url = SMJS_CHARS(c, argv[0]); + if (addon_url) { + do_enable_addon(odm, addon_url, GF_FALSE); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gpac_get_object_manager) +{ + JSObject *anobj; + u32 i, count; + GF_ObjectManager *odm = NULL; + char *service_url = NULL; + SMJS_OBJ + SMJS_ARGS + GF_GPACJSExt *gjs = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); + GF_Terminal *term = gpac_get_term(c, obj); + GF_Scene *scene = term->root_scene; + + if (JSVAL_IS_STRING(argv[0]) ) { + char *url; + url = service_url = SMJS_CHARS(c, argv[0]); + if (!service_url) { + SMJS_SET_RVAL(JSVAL_NULL); + return JS_TRUE; + } + if (!strncmp(service_url, "gpac://", 7)) url = service_url + 7; + count = gf_list_count(scene->resources); + for (i=0; i<count; i++) { + odm = gf_list_get(scene->resources, i); + if (odm->net_service && !strcmp(odm->net_service->url, url)) break; + odm = NULL; + } + } + + SMJS_FREE(c, service_url); + + if (!odm) { + SMJS_SET_RVAL(JSVAL_NULL); + return JS_TRUE; + } + + anobj = JS_NewObject(c, &gjs->odmClass._class, 0, 0); + SMJS_SET_PRIVATE(c, anobj, odm); + + SMJS_SET_RVAL( OBJECT_TO_JSVAL(anobj) ); + return JS_TRUE; +} + + +static JSBool SMJS_FUNCTION(gpac_new_storage) +{ + char szFile[GF_MAX_PATH]; + JSObject *anobj; + GF_Config *storage = NULL; + char *storage_url = NULL; + u8 hash[20]; + char temp[3]; + SMJS_OBJ + SMJS_ARGS + GF_GPACJSExt *gjs = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); + + if (JSVAL_IS_STRING(argv[0]) ) { + u32 i, count; + storage_url = SMJS_CHARS(c, argv[0]); + if (!storage_url) { + SMJS_SET_RVAL(JSVAL_NULL); + return JS_TRUE; + } + + szFile[0]=0; + gf_sha1_csum((u8 *)storage_url, (u32) strlen(storage_url), hash); + for (i=0; i<20; i++) { + sprintf(temp, "%02X", hash[i]); + strcat(szFile, temp); + } + strcat(szFile, ".cfg"); + + count = gf_list_count(gjs->storages); + for (i=0; i<count; i++) { + GF_Config *a_cfg = gf_list_get(gjs->storages, i); + char *cfg_name = gf_cfg_get_filename(a_cfg); + + if (!strstr(cfg_name, szFile)) { + storage = a_cfg; + gf_free(cfg_name); + break; + } + gf_free(cfg_name); + } + + if (!storage) { + const char *storage_dir = gf_cfg_get_key(gjs->term->user->config, "General", "StorageDirectory"); + + storage = gf_cfg_force_new(storage_dir, szFile); + if (storage) { + gf_cfg_set_key(storage, "GPAC", "StorageURL", storage_url); + gf_list_add(gjs->storages, storage); + } + } + + SMJS_FREE(c, storage_url); + } + + if (!storage) { + SMJS_SET_RVAL(JSVAL_NULL); + return JS_TRUE; + } + anobj = JS_NewObject(c, &gjs->storageClass._class, 0, 0); + SMJS_SET_PRIVATE(c, anobj, storage); + + + SMJS_SET_RVAL( OBJECT_TO_JSVAL(anobj) ); return JS_TRUE; } +static SMJS_FUNC_PROP_GET( gpacevt_getProperty) + +GF_GPACJSExt *gjs = SMJS_GET_PRIVATE(c, obj); +GF_Event *evt = gjs->evt; +if (!evt) return 0; + +if (SMJS_ID_IS_INT(id)) { + switch (SMJS_ID_TO_INT(id)) { + case -1: +#ifndef GPAC_DISABLE_SVG + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, gf_dom_get_key_name(evt->key.key_code) )); +#endif + break; + case -2: + *vp = INT_TO_JSVAL(evt->mouse.x); + break; + case -3: + *vp = INT_TO_JSVAL(evt->mouse.y); + break; + case -4: + if (gjs->term->compositor->hit_appear) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); + else if (gf_list_count(gjs->term->compositor->previous_sensors) ) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); + else if (gjs->term->compositor->text_selection) *vp = BOOLEAN_TO_JSVAL(JS_TRUE); + else *vp = BOOLEAN_TO_JSVAL(JS_FALSE); + break; + case -5: + *vp = DOUBLE_TO_JSVAL( JS_NewDouble(c, FIX2FLT(evt->mouse.wheel_pos)) ); + break; + case -6: + *vp = INT_TO_JSVAL( evt->mouse.button); + break; + case -7: + *vp = INT_TO_JSVAL(evt->type); + break; + case -8: +#ifndef GPAC_DISABLE_SVG + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(c, gf_dom_event_get_name(evt->type) )); +#endif + break; + } +} else if (SMJS_ID_IS_STRING(id)) { + char *name = SMJS_CHARS_FROM_STRING(c, SMJS_ID_TO_STRING(id)); + if (!strcmp(name, "target_url")) { + *vp = STRING_TO_JSVAL( JS_NewStringCopyZ(c, evt->navigate.to_url) ); + } + else if (!strcmp(name, "files")) { + u32 i, idx; + jsval v; + JSObject *files_array = JS_NewArrayObject(c, 0, NULL); + for (i=0; i<evt->open_file.nb_files; i++) { + if (evt->open_file.files[i]) { + JS_GetArrayLength(c, files_array, &idx); + v = STRING_TO_JSVAL( JS_NewStringCopyZ(c, evt->open_file.files[i]) ); + JS_SetElement(c, files_array, idx, &v); + } + } + *vp = OBJECT_TO_JSVAL(files_array); + } + SMJS_FREE(c, name); +} + +return JS_TRUE; +} + static Bool gjs_event_filter(void *udta, GF_Event *evt, Bool consumed_by_compositor) { + u32 retry; Bool res; jsval argv[1], rval; GF_GPACJSExt *gjs = (GF_GPACJSExt *)udta; if (consumed_by_compositor) return 0; if (gjs->evt != NULL) return 0; + + /*fixme - events should all be handled by the compositor */ + res = 0; + retry=100; + while (retry && gjs->nb_loaded) { + res = gf_mx_try_lock(gjs->term->compositor->mx); + if (res) break; + retry --; + gf_sleep(0); + } + if (!res) return 0; + res = 0; while (gjs->nb_loaded) { res = gf_sg_try_lock_javascript(gjs->c); @@ -802,14 +1579,15 @@ static Bool gjs_event_filter(void *udta, GF_Event *evt, Bool consumed_by_composi gjs->evt = evt; SMJS_SET_PRIVATE(gjs->c, gjs->evt_obj, gjs); argv[0] = OBJECT_TO_JSVAL(gjs->evt_obj); - rval = JSVAL_VOID; + rval = BOOLEAN_TO_JSVAL(JS_TRUE); JS_CallFunctionValue(gjs->c, gjs->evt_filter_obj, gjs->evt_fun, 1, argv, &rval); SMJS_SET_PRIVATE(gjs->c, gjs->evt_obj, NULL); gjs->evt = NULL; + gf_mx_v(gjs->term->compositor->mx); res = 0; if (JSVAL_IS_BOOLEAN(rval) ) { - res = (JSVAL_TO_BOOLEAN(rval)==JS_TRUE) ? 1 : 0; + res = (JSVAL_TO_BOOLEAN(rval)==JS_TRUE) ? GF_TRUE : GF_FALSE; } else if (JSVAL_IS_INT(rval) ) { res = (JSVAL_TO_INT(rval)) ? 1 : 0; } @@ -873,8 +1651,11 @@ static JSBool SMJS_FUNCTION(gpac_get_scene) GF_Node *elt; u32 w, h; JSObject *scene_obj; +#ifndef GPAC_DISABLE_SCENEGRAPH GF_SceneGraph *sg; +#endif GF_Scene *scene=NULL; + SMJS_OBJ SMJS_ARGS GF_GPACJSExt *gjs = (GF_GPACJSExt *)SMJS_GET_PRIVATE(c, obj); @@ -883,12 +1664,18 @@ static JSBool SMJS_FUNCTION(gpac_get_scene) elt = gf_sg_js_get_node(c, JSVAL_TO_OBJECT(argv[0])); if (!elt) return JS_TRUE; switch (elt->sgprivate->tag) { +#ifndef GPAC_DISABLE_VRML case TAG_MPEG4_Inline: + scene = (GF_Scene *)gf_node_get_private(elt); + break; +#endif + #ifndef GPAC_DISABLE_X3D case TAG_X3D_Inline: -#endif scene = (GF_Scene *)gf_node_get_private(elt); break; +#endif + #ifndef GPAC_DISABLE_SVG case TAG_SVG_animation: sg = gf_sc_animation_get_scenegraph(elt); @@ -928,6 +1715,91 @@ static JSBool SMJS_FUNCTION(gpac_show_keyboard) return JS_TRUE; } + +static JSBool SMJS_FUNCTION(gjs_storage_get_option) +{ + const char *opt = NULL; + char *sec_name, *key_name; + s32 idx = -1; + JSString *s; + SMJS_OBJ + SMJS_ARGS + GF_Config *config = (GF_Config *)SMJS_GET_PRIVATE(c, obj); + if (!config) return JS_FALSE; + + if (argc < 2) return JS_FALSE; + + if (!JSVAL_IS_STRING(argv[0])) return JS_FALSE; + if (!JSVAL_IS_STRING(argv[1]) && !JSVAL_IS_INT(argv[1])) return JS_FALSE; + + sec_name = SMJS_CHARS(c, argv[0]); + key_name = NULL; + if (JSVAL_IS_INT(argv[1])) { + idx = JSVAL_TO_INT(argv[1]); + } else if (JSVAL_IS_STRING(argv[1]) ) { + key_name = SMJS_CHARS(c, argv[1]); + } + + if (key_name) { + opt = gf_cfg_get_key(config, sec_name, key_name); + } else if (idx>=0) { + opt = gf_cfg_get_key_name(config, sec_name, idx); + } else { + opt = NULL; + } + if (key_name) { + SMJS_FREE(c, key_name); + } + SMJS_FREE(c, sec_name); + + if (opt) { + s = JS_NewStringCopyZ(c, opt); + SMJS_SET_RVAL( STRING_TO_JSVAL(s) ); + } else { + SMJS_SET_RVAL( JSVAL_NULL ); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_storage_set_option) +{ + char *sec_name, *key_name, *key_val; + SMJS_OBJ + SMJS_ARGS + GF_Config *config = (GF_Config *)SMJS_GET_PRIVATE(c, obj); + if (!config) return JS_FALSE; + + if (argc < 3) return JS_FALSE; + + if (!JSVAL_IS_STRING(argv[0])) return JS_FALSE; + if (!JSVAL_IS_STRING(argv[1])) return JS_FALSE; + + sec_name = SMJS_CHARS(c, argv[0]); + key_name = SMJS_CHARS(c, argv[1]); + key_val = NULL; + if (JSVAL_IS_STRING(argv[2])) + key_val = SMJS_CHARS(c, argv[2]); + + gf_cfg_set_key(config, sec_name, key_name, key_val); + + SMJS_FREE(c, sec_name); + SMJS_FREE(c, key_name); + if (key_val) { + SMJS_FREE(c, key_val); + } + return JS_TRUE; +} + +static JSBool SMJS_FUNCTION(gjs_storage_save) +{ + SMJS_OBJ + GF_Config *config = (GF_Config *)SMJS_GET_PRIVATE(c, obj); + if (!config) return JS_FALSE; + + gf_cfg_save(config); + return JS_TRUE; +} + static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext *c, JSObject *global, Bool unload) { GF_GPACJSExt *gjs; @@ -949,19 +1821,54 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext }; JSPropertySpec gpacClassProps[] = { + + SMJS_PROPERTY_SPEC("last_working_directory", -1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED , 0, 0), + SMJS_PROPERTY_SPEC("scale_x", -2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("scale_y", -3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("translation_x", -4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("translation_y", -5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("rectangular_textures", -6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("batteryOn", -7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("batteryCharging", -8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("batteryPercent", -9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("batteryLifeTime", -10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("batteryFullLifeTime", -11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("hostname", -12, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("fullscreen", -13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0), + SMJS_PROPERTY_SPEC("current_path", -14, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("volume", -15, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED , 0, 0), + SMJS_PROPERTY_SPEC("navigation", -16, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED , 0, 0), + SMJS_PROPERTY_SPEC("navigation_type", -17, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED , 0, 0), + SMJS_PROPERTY_SPEC("hardware_yuv", -18, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("hardware_rgb", -19, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("hardware_rgba", -20, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("hardware_stretch", -21, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("screen_width", -22, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("screen_height", -23, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("http_max_bitrate", -24, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED , 0, 0), + SMJS_PROPERTY_SPEC("http_bitrate", -25, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("fps", -26, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("cpu_load", -27, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("cpu", -27, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("nb_cores", -28, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("system_memory", -29, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("memory", -30, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("argc", -31, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("caption", -32, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0), + SMJS_PROPERTY_SPEC("disable_hardware_blit", -33, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0), + SMJS_PROPERTY_SPEC("disable_composite_blit", -34, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0), + SMJS_PROPERTY_SPEC("focus_highlight", -35, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0), + SMJS_PROPERTY_SPEC("dpi_x", -36, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("dpi_y", -37, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0) }; JSFunctionSpec gpacClassFuncs[] = { - SMJS_FUNCTION_SPEC("getOption", gpac_getOption, 3), - SMJS_FUNCTION_SPEC("setOption", gpac_setOption, 4), - SMJS_FUNCTION_SPEC("get_option", gpac_getOption, 3), - SMJS_FUNCTION_SPEC("set_option", gpac_setOption, 4), + SMJS_FUNCTION_SPEC("get_option", gpac_get_option, 3), + SMJS_FUNCTION_SPEC("set_option", gpac_set_option, 4), + SMJS_FUNCTION_SPEC("get_arg", gpac_get_arg, 1), SMJS_FUNCTION_SPEC("enum_directory", gpac_enum_directory, 1), SMJS_FUNCTION_SPEC("set_size", gpac_set_size, 1), - SMJS_FUNCTION_SPEC("get_horizontal_dpi", gpac_get_horizontal_dpi, 0), - SMJS_FUNCTION_SPEC("get_vertical_dpi", gpac_get_vertical_dpi, 0), - SMJS_FUNCTION_SPEC("get_screen_width", gpac_get_screen_width, 0), - SMJS_FUNCTION_SPEC("get_screen_height", gpac_get_screen_height, 0), SMJS_FUNCTION_SPEC("exit", gpac_exit, 0), SMJS_FUNCTION_SPEC("set_3d", gpac_set_3d, 1), SMJS_FUNCTION_SPEC("move_window", gpac_move_window, 2), @@ -973,11 +1880,95 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext SMJS_FUNCTION_SPEC("error_string", gpac_error_string, 1), SMJS_FUNCTION_SPEC("show_keyboard", gpac_show_keyboard, 1), SMJS_FUNCTION_SPEC("trigger_gc", gpac_trigger_gc, 1), + SMJS_FUNCTION_SPEC("get_object_manager", gpac_get_object_manager, 1), + SMJS_FUNCTION_SPEC("new_storage", gpac_new_storage, 1), + SMJS_FUNCTION_SPEC("switch_quality", gpac_switch_quality, 1), + + SMJS_FUNCTION_SPEC(0, 0, 0) + }; + JSPropertySpec odmClassProps[] = { + SMJS_PROPERTY_SPEC("ID", -1, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("nb_resources", -2, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("service_url", -3, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("duration", -4, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("clock_time", -5, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("clock_drift", -6, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("status", -7, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("buffer", -8, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("db_unit_count", -9, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("cb_unit_count", -10, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("cb_capacity", -11, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("type", -12, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("samplerate", -13, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("channels", -14, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("lang", -15, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("width", -16, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("height", -17, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("pixelformt", -18, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("par", -19, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("dec_frames", -20, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("drop_frames", -21, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("max_dec_time", -22, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("total_dec_time", -23, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("avg_bitrate", -24, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("max_bitrate", -25, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("service_handler", -26, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("codec", -27, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("nb_qualities", -28, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("max_buffer", -29, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("min_buffer", -30, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("frame_duration", -31, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("irap_frames", -32, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("irap_dec_time", -33, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("irap_max_time", -34, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("service_id", -35, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("selected_service", -36, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("bandwidth_down", -37, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("nb_http", -38, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("timeshift_depth", -39, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("timeshift_time", -40, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("is_addon", -41, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("main_addon_on", -42, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("is_over", -43, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("is_pulling", -44, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("dynamic_scene", -45, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("service_name", -46, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("ntp_diff", -47, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("main_addon_url", -48, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("reverse_playback_supported", -49, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("scalable_enhancement", -50, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + + + + SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0) + }; + JSFunctionSpec odmClassFuncs[] = { + SMJS_FUNCTION_SPEC("declare_addon", gjs_odm_declare_addon, 1), + SMJS_FUNCTION_SPEC("enable_addon", gjs_odm_enable_addon, 1), + SMJS_FUNCTION_SPEC("addon_layout", gjs_odm_addon_layout, 1), + SMJS_FUNCTION_SPEC("get_resource", gjs_odm_get_resource, 1), + SMJS_FUNCTION_SPEC("get_quality", gjs_odm_get_quality, 1), + SMJS_FUNCTION_SPEC("select_service", gjs_odm_select_service, 1), + SMJS_FUNCTION_SPEC("select_quality", gjs_odm_select_quality, 1), + SMJS_FUNCTION_SPEC("disable_main_addon", gjs_odm_disable_main_addon, 1), + + SMJS_FUNCTION_SPEC(0, 0, 0) + }; + + + JSPropertySpec storageClassProps[] = { + SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0) + }; + JSFunctionSpec storageClassFuncs[] = { + SMJS_FUNCTION_SPEC("get_option", gjs_storage_get_option, 2), + SMJS_FUNCTION_SPEC("set_option", gjs_storage_set_option, 3), + SMJS_FUNCTION_SPEC("save", gjs_storage_save, 0), SMJS_FUNCTION_SPEC(0, 0, 0) }; + gjs = jsext->udta; /*nothing to do on unload*/ if (unload) { @@ -1006,6 +1997,13 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext } } SMJS_SET_PRIVATE(c, gjs->gpac_obj, gjs); + + JS_SETUP_CLASS(gjs->odmClass, "ODM", JSCLASS_HAS_PRIVATE, odm_getProperty, JS_PropertyStub_forSetter, JS_FinalizeStub); + GF_JS_InitClass(c, global, 0, &gjs->odmClass, 0, 0, odmClassProps, odmClassFuncs, 0, 0); + + + JS_SETUP_CLASS(gjs->storageClass, "Storage", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub_forSetter, JS_FinalizeStub); + GF_JS_InitClass(c, global, 0, &gjs->storageClass, 0, 0, storageClassProps, storageClassFuncs, 0, 0); } else { JS_DefineProperty(c, global, "gpac", OBJECT_TO_JSVAL(gjs->gpac_obj), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); } @@ -1023,6 +2021,7 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext DECLARE_GPAC_CONST(GF_EVENT_MOUSEDOWN); DECLARE_GPAC_CONST(GF_EVENT_MOUSEMOVE); DECLARE_GPAC_CONST(GF_EVENT_MOUSEWHEEL); + DECLARE_GPAC_CONST(GF_EVENT_DBLCLICK); DECLARE_GPAC_CONST(GF_EVENT_KEYUP); DECLARE_GPAC_CONST(GF_EVENT_KEYDOWN); DECLARE_GPAC_CONST(GF_EVENT_TEXTINPUT); @@ -1030,7 +2029,16 @@ static void gjs_load(GF_JSUserExtension *jsext, GF_SceneGraph *scene, JSContext DECLARE_GPAC_CONST(GF_EVENT_NAVIGATE_INFO); DECLARE_GPAC_CONST(GF_EVENT_NAVIGATE); DECLARE_GPAC_CONST(GF_EVENT_DROPFILE); - + DECLARE_GPAC_CONST(GF_EVENT_ADDON_DETECTED); + DECLARE_GPAC_CONST(GF_EVENT_QUALITY_SWITCHED); + DECLARE_GPAC_CONST(GF_EVENT_TIMESHIFT_DEPTH); + DECLARE_GPAC_CONST(GF_EVENT_TIMESHIFT_UPDATE); + DECLARE_GPAC_CONST(GF_EVENT_TIMESHIFT_OVERFLOW); + DECLARE_GPAC_CONST(GF_EVENT_TIMESHIFT_UNDERRUN); + DECLARE_GPAC_CONST(GF_EVENT_QUIT); + DECLARE_GPAC_CONST(GF_EVENT_MAIN_ADDON_STATE); + DECLARE_GPAC_CONST(GF_EVENT_SCENE_SIZE); + DECLARE_GPAC_CONST(GF_NAVIGATE_NONE); DECLARE_GPAC_CONST(GF_NAVIGATE_WALK); DECLARE_GPAC_CONST(GF_NAVIGATE_FLY); @@ -1067,6 +2075,7 @@ GF_JSUserExtension *gjs_new() GF_SAFEALLOC(gjs, GF_GPACJSExt); gjs->rti_refresh_rate = GPAC_JS_RTI_REFRESH_RATE; gjs->evt_fun = JSVAL_NULL; + gjs->storages = gf_list_new(); dr->load = gjs_load; dr->udta = gjs; return dr; @@ -1077,6 +2086,14 @@ void gjs_delete(GF_BaseInterface *ifce) { GF_JSUserExtension *dr = (GF_JSUserExtension *) ifce; GF_GPACJSExt *gjs = dr->udta; + + while (gf_list_count(gjs->storages)) { + GF_Config *cfg = (GF_Config *) gf_list_pop_back(gjs->storages); + gf_cfg_discard_changes(cfg); + gf_cfg_del(cfg); + } + gf_list_del(gjs->storages); + gf_free(gjs); gf_free(dr); } @@ -1117,4 +2134,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( gpac_js ) +GPAC_MODULE_STATIC_DECLARATION( gpac_js ) diff --git a/modules/hyb_in/Makefile b/modules/hyb_in/Makefile index abb2716..72f979d 100644 --- a/modules/hyb_in/Makefile +++ b/modules/hyb_in/Makefile @@ -19,7 +19,7 @@ OBJS=hyb_in.o fm_fake_pull.o fm_fake_push.o SRCS := $(OBJS:.o=.c) -LIB=gm_hyb_in.$(DYN_LIB_SUFFIX) +LIB=gm_hyb_in$(DYN_LIB_SUFFIX) all: $(LIB) @@ -28,7 +28,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_hyb_in-static.$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_hyb_in-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/hyb_in/hyb_in.c b/modules/hyb_in/hyb_in.c index 8b1d70a..8db7996 100644 --- a/modules/hyb_in/hyb_in.c +++ b/modules/hyb_in/hyb_in.c @@ -309,4 +309,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( hyb_in ) +GPAC_MODULE_STATIC_DECLARATION( hyb_in ) diff --git a/modules/img_in/Makefile b/modules/img_in/Makefile index a11b1c7..300291b 100644 --- a/modules/img_in/Makefile +++ b/modules/img_in/Makefile @@ -48,7 +48,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_img_in.$(DYN_LIB_SUFFIX) +LIB=gm_img_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) LINKLIBS+=-lwinmm #LDFLAGS+=-export-symbols img_in.def @@ -60,7 +60,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L$(LOCAL_LIB) $(LINKLIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_img_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L$(LOCAL_LIB) $(LINKLIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_img_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L$(LOCAL_LIB) $(LINKLIBS) endif clean: diff --git a/modules/img_in/img_dec.c b/modules/img_in/img_dec.c index dd08701..1ed3748 100644 --- a/modules/img_in/img_dec.c +++ b/modules/img_in/img_dec.c @@ -156,4 +156,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( img_in ) +GPAC_MODULE_STATIC_DECLARATION( img_in ) diff --git a/modules/img_in/img_in.c b/modules/img_in/img_in.c index 8514202..5c0afab 100644 --- a/modules/img_in/img_in.c +++ b/modules/img_in/img_in.c @@ -179,13 +179,13 @@ void IMG_NetIO(void *cbk, GF_NETIO_Parameter *param) szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { - read->stream = gf_f64_open((char *) szCache, "rb"); + read->stream = gf_fopen((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { e = GF_OK; - gf_f64_seek(read->stream, 0, SEEK_END); - read->data_size = (u32) gf_f64_tell(read->stream); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_END); + read->data_size = (u32) gf_ftell(read->stream); + gf_fseek(read->stream, 0, SEEK_SET); } } } @@ -233,11 +233,11 @@ static GF_Err IMG_ConnectService(GF_InputService *plug, GF_ClientService *serv, return GF_OK; } - read->stream = fopen(url, "rb"); + read->stream = gf_fopen(url, "rb"); if (read->stream) { - gf_f64_seek(read->stream, 0, SEEK_END); - read->data_size = (u32) gf_f64_tell(read->stream); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_END); + read->data_size = (u32) gf_ftell(read->stream); + gf_fseek(read->stream, 0, SEEK_SET); } gf_service_connect_ack(serv, NULL, read->stream ? GF_OK : GF_URL_ERROR); if (read->stream && read->is_inline) IMG_SetupObject(read); @@ -252,7 +252,7 @@ static GF_Err IMG_CloseService(GF_InputService *plug) read = (IMGLoader *)plug->priv; if (!read) return GF_BAD_PARAM; - if (read->stream) fclose(read->stream); + if (read->stream) gf_fclose(read->stream); read->stream = NULL; if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; @@ -379,10 +379,10 @@ static GF_Err IMG_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha return GF_OK; } *is_new_data = 1; - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); read->data = (char*) gf_malloc(sizeof(char) * (read->data_size + read->pad_bytes)); read->data_size = (u32) fread(read->data, sizeof(char), read->data_size, read->stream); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); if (read->pad_bytes) memset(read->data + read->data_size, 0, sizeof(char) * read->pad_bytes); } diff --git a/modules/ios_cam/ios_cam.c b/modules/ios_cam/ios_cam.c index 08b5ef9..df253b9 100644 --- a/modules/ios_cam/ios_cam.c +++ b/modules/ios_cam/ios_cam.c @@ -370,6 +370,8 @@ GF_Err CAM_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) com->get_dsi.dsi_len = buf_size; return GF_OK; } + default: + return GF_NOT_SUPPORTED; } return GF_NOT_SUPPORTED; } @@ -430,4 +432,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ios_cam ) +GPAC_MODULE_STATIC_DECLARATION( ios_cam ) diff --git a/modules/ios_mpegv/ios_mpegv.c b/modules/ios_mpegv/ios_mpegv.c index a64c35e..f39ee55 100644 --- a/modules/ios_mpegv/ios_mpegv.c +++ b/modules/ios_mpegv/ios_mpegv.c @@ -303,4 +303,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ios_mpegv ) +GPAC_MODULE_STATIC_DECLARATION( ios_mpegv ) diff --git a/modules/ismacryp/Makefile b/modules/ismacryp/Makefile index 48ffd78..203c819 100644 --- a/modules/ismacryp/Makefile +++ b/modules/ismacryp/Makefile @@ -19,7 +19,7 @@ OBJS=isma_ea.o SRCS := $(OBJS:.o=.c) -LIB=gm_ismacryp.$(DYN_LIB_SUFFIX) +LIB=gm_ismacryp$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ismacryp.def endif @@ -30,7 +30,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_ismacryp-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_ismacryp-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/ismacryp/isma_ea.c b/modules/ismacryp/isma_ea.c index 5eb282e..c1988ee 100644 --- a/modules/ismacryp/isma_ea.c +++ b/modules/ismacryp/isma_ea.c @@ -76,9 +76,9 @@ static GF_Err ISMA_GetGPAC_KMS(ISMAEAPriv *priv, GF_Channel *ch, const char *kms e = GF_OK; /*try local*/ - t = (strstr(kms_url, "://") == NULL) ? gf_f64_open(kms_url, "r") : NULL; + t = (strstr(kms_url, "://") == NULL) ? gf_fopen(kms_url, "r") : NULL; if (t) { - fclose(t); + gf_fclose(t); return gf_ismacryp_gpac_get_info(ch->esd->ESID, (char *)kms_url, priv->key, priv->salt); } /*note that gpac doesn't have TLS support -> not really usefull. As a general remark, ISMACryp @@ -494,43 +494,6 @@ static GF_Err CENC_ProcessData(ISMAEAPriv *priv, GF_IPMPEvent *evt) gf_crypt_decrypt(priv->crypt, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); gf_bs_write_data(pleintext_bs, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); - /*update IV for next subsample*/ - if (priv->is_cenc) { - BSO += sai->subsamples[subsample_count].bytes_encrypted_data; - if (gf_bs_available(cyphertext_bs)) { - char next_IV[17]; - u64 prev_block_count, salt_portion, block_count_portion; - u32 remain; - GF_BitStream *bs, *tmp; - - prev_block_count = BSO / 16; - remain = BSO % 16; - tmp = gf_bs_new((const char *)sai->IV, 16, GF_BITSTREAM_READ); - bs = gf_bs_new(next_IV, 17, GF_BITSTREAM_WRITE); - gf_bs_write_u8(bs, 0); /*begin of counter*/ - - salt_portion = gf_bs_read_u64(tmp); - block_count_portion = gf_bs_read_u64(tmp); - /*reset the block counter to zero without affecting the other 64 bits of the IV*/ - if (prev_block_count > 0xFFFFFFFFFFFFFFFFULL - block_count_portion) - block_count_portion = prev_block_count - (0xFFFFFFFFFFFFFFFFULL - block_count_portion) - 1; - else - block_count_portion += prev_block_count; - gf_bs_write_u64(bs, salt_portion); - gf_bs_write_u64(bs, block_count_portion); - - gf_crypt_set_state(priv->crypt, next_IV, 17); - /*decrypt remain bytes*/ - if (remain) { - char dummy[20]; - gf_crypt_decrypt(priv->crypt, dummy, remain); - } - - gf_bs_del(bs); - gf_bs_del(tmp); - } - } - subsample_count++; } if (buffer) gf_free(buffer); @@ -659,5 +622,5 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( isma_ea ) +GPAC_MODULE_STATIC_DECLARATION( isma_ea ) diff --git a/modules/isom_in/Makefile b/modules/isom_in/Makefile index 1362410..5d0149f 100644 --- a/modules/isom_in/Makefile +++ b/modules/isom_in/Makefile @@ -19,7 +19,7 @@ OBJS= load.o read.o read_ch.o isom_cache.o SRCS := $(OBJS:.o=.c) -LIB=gm_isom_in.$(DYN_LIB_SUFFIX) +LIB=gm_isom_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols isom_in.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(EXTRALIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_isom_in-static.$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_isom_in-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) endif clean: diff --git a/modules/isom_in/isom_cache.c b/modules/isom_in/isom_cache.c index 447e924..880ec72 100644 --- a/modules/isom_in/isom_cache.c +++ b/modules/isom_in/isom_cache.c @@ -39,15 +39,15 @@ static GF_Err ISOW_Open(GF_StreamingCache *mc, GF_ClientService *serv, const cha strcpy(szPath, szRoot); strcat(szPath, ".mp4"); if (keep_existing_files) { - FILE *f = gf_f64_open(szPath, "rb"); + FILE *f = gf_fopen(szPath, "rb"); if (f) { u32 i=0; - fclose(f); + gf_fclose(f); while (1) { sprintf(szPath, "%s_%04d.mp4", szRoot, i); - f = gf_f64_open(szPath, "rb"); + f = gf_fopen(szPath, "rb"); if (!f) break; - fclose(f); + gf_fclose(f); i++; } } diff --git a/modules/isom_in/isom_in.h b/modules/isom_in/isom_in.h index 470999b..44f138c 100644 --- a/modules/isom_in/isom_in.h +++ b/modules/isom_in/isom_in.h @@ -53,16 +53,17 @@ typedef struct /*input file*/ GF_ISOFile *mov; u32 time_scale; + u32 nb_playing; /*remote file handling*/ GF_DownloadSession * dnload; u64 missing_bytes, last_size; Bool no_service_desc; - u32 base_track_id; + u32 play_only_track_id; /*0: not fragmented - 1 fragmented - 2 fragmented and last fragment received*/ u32 frag_type; - Bool waiting_for_data; + Bool waiting_for_data, reset_frag_state; GF_Mutex *segment_mutex; Bool use_memory; @@ -70,10 +71,15 @@ typedef struct u32 seg_opened; Bool drop_next_segment; Bool in_data_flush; - s32 has_pending_segments; + u32 has_pending_segments, nb_force_flush; Bool clock_discontinuity; Bool disconnected; + Bool no_order_check; + + u64 last_sender_ntp, cts_for_last_sender_ntp; + Double remain_at_buffering_start; + Bool buffering; } ISOMReader; @@ -120,7 +126,10 @@ typedef struct Bool disable_seek; u32 nalu_extract_mode; + + u32 last_sample_desc_index; } ISOMChannel; + void isor_reset_reader(ISOMChannel *ch); void isor_reader_get_sample(ISOMChannel *ch); void isor_reader_release_sample(ISOMChannel *ch); diff --git a/modules/isom_in/load.c b/modules/isom_in/load.c index 303c80c..0006549 100644 --- a/modules/isom_in/load.c +++ b/modules/isom_in/load.c @@ -94,7 +94,8 @@ void isor_declare_objects(ISOMReader *read) /*TODO check for alternate tracks*/ count = gf_isom_get_track_count(read->mov); for (i=0; i<count; i++) { - if (!gf_isom_is_track_enabled(read->mov, i+1)) continue; + if (!gf_isom_is_track_enabled(read->mov, i+1)) + continue; switch (gf_isom_get_media_type(read->mov, i+1)) { case GF_ISOM_MEDIA_AUDIO: @@ -117,6 +118,8 @@ void isor_declare_objects(ISOMReader *read) /*we declare only the highest video track (i.e the track we play)*/ highest_stream = GF_TRUE; track_id = gf_isom_get_track_id(read->mov, i+1); + if (read->play_only_track_id && (read->play_only_track_id != track_id)) continue; + for (j = 0; j < count; j++) { if (gf_isom_has_track_reference(read->mov, j+1, GF_ISOM_REF_SCAL, track_id) > 0) { highest_stream = GF_FALSE; @@ -160,7 +163,7 @@ void isor_declare_objects(ISOMReader *read) sprintf(szName, "%s%s_cover.%s", cdir, sep, (tlen & 0x80000000) ? "png" : "jpg"); } - t = gf_f64_open(szName, "wb"); + t = gf_fopen(szName, "wb"); if (t) { Bool isom_contains_video = GF_FALSE; @@ -168,7 +171,7 @@ void isor_declare_objects(ISOMReader *read) /*write cover data*/ assert(!(tlen & 0x80000000)); gf_fwrite(tag, tlen & 0x7FFFFFFF, 1, t); - fclose(t); + gf_fclose(t); /*don't display cover art when video is present*/ for (i=0; i<gf_isom_get_track_count(read->mov); i++) { @@ -250,4 +253,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( isom ) +GPAC_MODULE_STATIC_DECLARATION( isom ) diff --git a/modules/isom_in/read.c b/modules/isom_in/read.c index 3e8b411..ccd2dbc 100644 --- a/modules/isom_in/read.c +++ b/modules/isom_in/read.c @@ -67,11 +67,13 @@ static const char * ISOR_MIME_TYPES[] = { "application/x-isomedia", "*", "IsoMedia Files", "video/mp4", "mp4 mpg4", "MPEG-4 Movies", "audio/mp4", "m4a mp4 mpg4", "MPEG-4 Music", - "application/mp4", "mp4 mpg4", "MPEG-4 Applications", + "application/mp4", "m4i mp4 mpg4", "MPEG-4 Applications", "video/3gpp", "3gp 3gpp", "3GPP/MMS Movies", "audio/3gpp", "3gp 3gpp", "3GPP/MMS Music", "video/3gpp2", "3g2 3gp2", "3GPP2/MMS Movies", "audio/3gpp2", "3g2 3gp2", "3GPP2/MMS Music", + "video/iso.segment", "iso", "ISOBMF Fragments", + "audio/iso.segment", "iso", "ISOBMF Fragments", NULL }; @@ -128,8 +130,15 @@ void isor_check_buffer_level(ISOMReader *read) gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total, &done, &Bps, &status); if (!Bps) return; + + gf_mx_p(read->segment_mutex); + dld_time_remaining = total-done; dld_time_remaining /= Bps; + + //we add 30 seconds to smooth out bitrate variations ..; + dld_time_remaining += 30; + mov_rate = total; dur = gf_isom_get_duration(read->mov); if (dur) { @@ -171,12 +180,15 @@ void isor_check_buffer_level(ISOMReader *read) gf_isom_sample_del(&samp); time_remain_ch /= ch->time_scale; - //we add 2 seconds safety - if (time_remain_ch && (time_remain_ch < dld_time_remaining + 2)) { + if (time_remain_ch && (time_remain_ch < dld_time_remaining)) { do_buffer = GF_TRUE; - buffer_level = (u32) (ch->buffer_max * time_remain_ch / dld_time_remaining); + if (!read->remain_at_buffering_start || (read->remain_at_buffering_start < dld_time_remaining)) { + buffer_level = 0; + read->remain_at_buffering_start = dld_time_remaining; + } else { + buffer_level = (u32) (100 * (read->remain_at_buffering_start - dld_time_remaining) / (read->remain_at_buffering_start - time_remain_ch) ); + } } else { - buffer_level = (u32) (1000 * (data_offset - done)/mov_rate); do_buffer = GF_FALSE; } } @@ -187,8 +199,11 @@ void isor_check_buffer_level(ISOMReader *read) memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = do_buffer ? GF_NET_CHAN_PAUSE : GF_NET_CHAN_RESUME; com.buffer.on_channel = ch->channel; + com.buffer.min = ch->buffer_min; + com.buffer.max = ch->buffer_max; gf_service_command(read->service, &com, GF_OK); ch->buffering = do_buffer; + read->buffering = do_buffer; } else if (ch->buffering) { memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_CHAN_BUFFER; @@ -199,6 +214,7 @@ void isor_check_buffer_level(ISOMReader *read) gf_service_command(read->service, &com, GF_OK); } } + gf_mx_v(read->segment_mutex); } void isor_net_io(void *cbk, GF_NETIO_Parameter *param) @@ -209,7 +225,8 @@ void isor_net_io(void *cbk, GF_NETIO_Parameter *param) ISOMReader *read = (ISOMReader *) cbk; /*handle service message*/ - gf_service_download_update_stats(read->dnload); + if (!read->buffering) + gf_service_download_update_stats(read->dnload); if (param->msg_type==GF_NETIO_DATA_TRANSFERED) { e = GF_EOS; @@ -250,6 +267,7 @@ void isor_net_io(void *cbk, GF_NETIO_Parameter *param) read->mov = gf_isom_open(local_name, GF_ISOM_OPEN_READ, NULL); if (!read->mov) e = gf_isom_last_error(NULL); else read->time_scale = gf_isom_get_timescale(read->mov); + read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0; if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, GF_OK, NULL, NULL); } else { @@ -350,7 +368,6 @@ GF_Err ISOR_ConnectService(GF_InputService *plug, GF_ClientService *serv, const if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; - read->base_track_id = 0; if (!url) return GF_URL_ERROR; strcpy(szURL, url); @@ -359,9 +376,9 @@ GF_Err ISOR_ConnectService(GF_InputService *plug, GF_ClientService *serv, const tmp = strchr(tmp, '#'); if (tmp) { if (!strnicmp(tmp, "#trackID=", 9)) { - read->base_track_id = atoi(tmp+9); + read->play_only_track_id = atoi(tmp+9); } else { - read->base_track_id = atoi(tmp+1); + read->play_only_track_id = atoi(tmp+1); } tmp[0] = 0; } @@ -418,8 +435,6 @@ GF_Err ISOR_CloseService(GF_InputService *plug) reply = GF_OK; read->disconnected = GF_TRUE; - if (read->mov) gf_isom_close(read->mov); - read->mov = NULL; while (gf_list_count(read->channels)) { ISOMChannel *ch = (ISOMChannel *)gf_list_get(read->channels, 0); @@ -430,6 +445,9 @@ GF_Err ISOR_CloseService(GF_InputService *plug) if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; + if (read->mov) gf_isom_close(read->mov); + read->mov = NULL; + if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_TRUE, GF_FALSE, reply, NULL, NULL); } else { @@ -531,8 +549,8 @@ static GF_Descriptor *ISOR_GetServiceDesc(GF_InputService *plug, u32 expect_type trackID = 0; if (!sub_url) { - trackID = read->base_track_id; - read->base_track_id = 0; + trackID = read->play_only_track_id; + read->play_only_track_id = 0; } else { char *ext = (char *)strrchr(sub_url, '#'); if (!ext) { @@ -845,6 +863,7 @@ GF_Err ISOR_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel) read = (ISOMReader *) plug->priv; if (!read->mov) return GF_SERVICE_ERROR; + gf_mx_p(read->segment_mutex); e = GF_OK; ch = isor_get_channel(read, channel); assert(ch); @@ -862,6 +881,7 @@ exit: } else { gf_service_disconnect_ack(read->service, channel, e); } + gf_mx_v(read->segment_mutex); return e; } @@ -1040,10 +1060,12 @@ GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) return GF_OK; } if (com->command_type == GF_NET_SERVICE_FLUSH_DATA) { - if (plug->query_proxy) + if (read->nb_playing && plug->query_proxy) isor_flush_data(read, 0, 0); return GF_OK; } + if (com->command_type == GF_NET_SERVICE_CAN_REVERSE_PLAYBACK) + return GF_OK; if (!com->base.on_channel) return GF_NOT_SUPPORTED; @@ -1097,8 +1119,14 @@ GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) return GF_OK; case GF_NET_CHAN_PLAY: + gf_mx_p(read->segment_mutex); isor_reset_reader(ch); ch->speed = com->play.speed; + read->reset_frag_state = 1; + if (read->frag_type) + read->frag_type = 1; + gf_mx_v(read->segment_mutex); + ch->start = ch->end = 0; if (com->play.speed>0) { if (com->play.start_range>=0) { @@ -1122,11 +1150,18 @@ GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) //and check buffer level on play request isor_check_buffer_level(read); + read->nb_playing++; return GF_OK; case GF_NET_CHAN_STOP: + if (read->nb_playing) read->nb_playing--; isor_reset_reader(ch); return GF_OK; + case GF_NET_CHAN_SET_SPEED: + gf_mx_p(read->segment_mutex); + ch->speed = com->play.speed; + gf_mx_v(read->segment_mutex); + return GF_OK; /*nothing to do on MP4 for channel config*/ case GF_NET_CHAN_CONFIG: return GF_OK; diff --git a/modules/isom_in/read_ch.c b/modules/isom_in/read_ch.c index 5e948c8..9b55f7a 100644 --- a/modules/isom_in/read_ch.c +++ b/modules/isom_in/read_ch.c @@ -45,13 +45,40 @@ void isor_reset_reader(ISOMChannel *ch) memset(&ch->current_slh, 0, sizeof(GF_SLHeader)); } +void isor_check_producer_ref_time(ISOMReader *read) +{ + u32 trackID; + u64 ntp; + u64 timestamp; + + if (gf_isom_get_last_producer_time_box(read->mov, &trackID, &ntp, ×tamp, GF_TRUE)) { +#if !defined(_WIN32_WCE) && !defined(GPAC_DISABLE_LOG) + + if (gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_DEBUG)) { + time_t secs; + struct tm t; + + s32 diff = gf_net_get_ntp_diff_ms(ntp); + + secs = (ntp>>32) - GF_NTP_SEC_1900_TO_1970; + t = *gmtime(&secs); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] TrackID %d: Timestamp %d matches sender NTP time %d-%02d-%02dT%02d:%02d:%02dZ - NTP clock diff (local - remote): %d ms\n", trackID, (u32) timestamp, 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, diff)); + } +#endif + + read->last_sender_ntp = ntp; + read->cts_for_last_sender_ntp = timestamp; + } +} + /* refresh type: 0: not progressive 1: progressive 2: not progressive and don't check current download */ -void isor_segment_switch_or_refresh(ISOMReader *read, u32 refresh_type) +void isor_segment_switch_or_refresh(ISOMReader *read, Bool do_refresh) { GF_NetworkCommand param; u32 i, count; @@ -68,18 +95,17 @@ void isor_segment_switch_or_refresh(ISOMReader *read, u32 refresh_type) memset(¶m, 0, sizeof(GF_NetworkCommand)); param.command_type = GF_NET_SERVICE_QUERY_NEXT; - param.url_query.current_download = (refresh_type==2) ? 0 : 1; - if (refresh_type==2) - refresh_type = 0; + //always check current download - this might be ignored by the dash client depending on lowLatency settings + param.url_query.current_download = 1; count = gf_list_count(read->channels); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Refresh seg: refresh_type %d - seg opened %d\n", refresh_type , read->seg_opened)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Refresh seg: do_refresh %d - seg opened %d\n", do_refresh, read->seg_opened)); - if (refresh_type && !read->seg_opened) - refresh_type = 0; + if (do_refresh && !read->seg_opened) + do_refresh = 0; - if ((read->seg_opened==1) && !refresh_type) { + if ((read->seg_opened==1) && !do_refresh) { gf_mx_v(read->segment_mutex); return; } @@ -90,7 +116,7 @@ void isor_segment_switch_or_refresh(ISOMReader *read, u32 refresh_type) } //if first time trying to fetch next segment, check if we have to discard it - if (!refresh_type && (read->seg_opened==2)) { + if (!do_refresh && (read->seg_opened==2)) { #ifdef DASH_USE_PULL for (i=0; i<count; i++) { ISOMChannel *ch = gf_list_get(read->channels, i); @@ -115,29 +141,40 @@ next_segment: /*update current fragment if any*/ e = read->input->query_proxy(read->input, ¶m); if (e == GF_OK) { - u64 timestamp, ntp; u32 trackID = 0; if (param.url_query.next_url) { + u32 flags; //previously loaded file has been aborted, reload segment ! - if (refresh_type && param.url_query.discontinuity_type) { + if (do_refresh && param.url_query.discontinuity_type) { gf_isom_release_segment(read->mov, 1); gf_isom_reset_fragment_info(read->mov, 1); - refresh_type = 0; + do_refresh = 0; + } + + if (read->reset_frag_state) { + read->reset_frag_state = 0; + gf_isom_reset_fragment_info(read->mov, 0); } //refresh file - if (refresh_type) { + if (do_refresh) { //the url is the current download or we just finished downloaded it, refresh the parsing. if ((param.url_query.current_download || (read->seg_opened==1)) && param.url_query.has_new_data) { u64 bytesMissing=0; e = gf_isom_refresh_fragmented(read->mov, &bytesMissing, read->use_memory ? param.url_query.next_url : NULL); GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[IsoMedia] LowLatency mode: Reparsing segment %s boxes at UTC "LLU" - "LLU" bytes still missing\n", param.url_query.next_url, gf_net_get_utc(), bytesMissing )); - for (i=0; i<count; i++) { - ISOMChannel *ch = gf_list_get(read->channels, i); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[IsoMedia] refresh track %d fragment - cur sample %d - new sample count %d\n", ch->track, ch->sample_num, gf_isom_get_sample_count(ch->owner->mov, ch->track) )); + +#ifndef GPAC_DISABLE_LOG + if (gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_DEBUG)) { + for (i=0; i<count; i++) { + ISOMChannel *ch = gf_list_get(read->channels, i); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] refresh track %d fragment - cur sample %d - new sample count %d\n", ch->track, ch->sample_num, gf_isom_get_sample_count(ch->owner->mov, ch->track) )); + } } +#endif + isor_check_producer_ref_time(read); } //we did the last refresh and the segment is downloaded, move to fully parsed mode if (! param.url_query.current_download) { @@ -153,28 +190,35 @@ next_segment: gf_isom_reset_fragment_info(read->mov, 0); read->clock_discontinuity = 1; } - + e = GF_OK; if (param.url_query.next_url_init_or_switch_segment) { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Switching between files - opening new init segment %s\n", param.url_query.next_url_init_or_switch_segment)); if (read->mov) gf_isom_close(read->mov); e = gf_isom_open_progressive(param.url_query.next_url_init_or_switch_segment, param.url_query.switch_start_range, param.url_query.switch_end_range, &read->mov, &read->missing_bytes); + if (e<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[IsoMedia] Error opening init segment %s at UTC "LLU": %s\n", param.url_query.next_url_init_or_switch_segment, gf_net_get_utc(), gf_error_to_string(e) )); + } } - - e = gf_isom_open_segment(read->mov, param.url_query.next_url, param.url_query.start_range, param.url_query.end_range, scalable_segment); - - if (param.url_query.current_download && (e==GF_ISOM_INCOMPLETE_FILE)) { - e = GF_OK; - } + if (!e) { + flags = 0; + if (read->no_order_check) flags |= GF_ISOM_SEGMENT_NO_ORDER_FLAG; + if (scalable_segment) flags |= GF_ISOM_SEGMENT_SCALABLE_FLAG; + e = gf_isom_open_segment(read->mov, param.url_query.next_url, param.url_query.start_range, param.url_query.end_range, flags); + + if (param.url_query.current_download && (e==GF_ISOM_INCOMPLETE_FILE)) { + e = GF_OK; + } #ifndef GPAC_DISABLE_LOG - if (e<0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[IsoMedia] Error opening new segment %s at UTC "LLU": %s\n", param.url_query.next_url, gf_net_get_utc(), gf_error_to_string(e) )); - } else if (param.url_query.end_range) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Playing new range in %s: "LLU"-"LLU"\n", param.url_query.next_url, param.url_query.start_range, param.url_query.end_range )); - } else { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] playing new segment %s\n", param.url_query.next_url)); - } + if (e<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[IsoMedia] Error opening new segment %s at UTC "LLU": %s\n", param.url_query.next_url, gf_net_get_utc(), gf_error_to_string(e) )); + } else if (param.url_query.end_range) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Playing new range in %s: "LLU"-"LLU"\n", param.url_query.next_url, param.url_query.start_range, param.url_query.end_range )); + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] playing new segment %s\n", param.url_query.next_url)); + } #endif + } if (e<0) { gf_isom_release_segment(read->mov, 1); @@ -202,30 +246,7 @@ next_segment: GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Opening current segment in non-progressive mode (completely downloaded)\n")); } -#ifndef _WIN32_WCE - if (gf_isom_get_last_producer_time_box(read->mov, &trackID, &ntp, ×tamp, 1)) { - u32 remote_s, remote_f, local_s, local_f; - s64 diff_s, diff_f; - time_t secs; - struct tm t; - remote_s = (ntp>>32); - remote_f = (u32) (ntp & 0xFFFFFFFFULL); - gf_net_get_ntp(&local_s, &local_f); - diff_s = local_s; - diff_s -= remote_s; - diff_s *= 1000; - diff_f = local_f; - diff_f -= remote_f; - diff_f *= 1000; - diff_f /= 0xFFFFFFFFULL; - diff_s += diff_f; - - secs = remote_s - GF_NTP_SEC_1900_TO_1970; - t = *gmtime(&secs); - - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] TrackID %d: Timestamp %d matches sender NTP time %d-%02d-%02dT%02d:%02d:%02dZ - NTP clock diff (local - remote): %d ms\n", trackID, (u32) timestamp, 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, diff_s )); - } -#endif + isor_check_producer_ref_time(read); trackID = 0; for (i=0; i<count; i++) { @@ -294,12 +315,8 @@ next_segment: read->frag_type = 2; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] No more segments - done playing file\n")); } else if (e==GF_BUFFER_TOO_SMALL) { - if (refresh_type==0) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Next segment is not yet available\n")); - read->waiting_for_data = GF_TRUE; - } else { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[IsoMedia] Corrupted state in low latency mode !!\n")); - } + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Next segment is not yet available\n")); + read->waiting_for_data = GF_TRUE; } else { /*consider we are done*/ read->frag_type = 2; @@ -310,7 +327,7 @@ next_segment: static void init_reader(ISOMChannel *ch) { - u32 ivar; + u32 sample_desc_index; if (ch->is_pulling && ch->wait_for_segment_switch) { isor_segment_switch_or_refresh(ch->owner, 0); if (ch->wait_for_segment_switch) @@ -330,7 +347,7 @@ static void init_reader(ISOMChannel *ch) if (ch->streamType==GF_STREAM_OCR) { assert(!ch->sample); ch->sample = gf_isom_sample_new(); - ch->sample->IsRAP = 1; + ch->sample->IsRAP = RAP; ch->sample->DTS = ch->start; ch->last_state=GF_OK; } else { @@ -339,9 +356,9 @@ static void init_reader(ISOMChannel *ch) /*take care of seeking out of the track range*/ if (!ch->owner->frag_type && (ch->duration<ch->start)) { - ch->last_state = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->duration, &ivar, mode, &ch->sample, &ch->sample_num); + ch->last_state = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->duration, &sample_desc_index, mode, &ch->sample, &ch->sample_num); } else { - ch->last_state = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->start, &ivar, mode, &ch->sample, &ch->sample_num); + ch->last_state = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->start, &sample_desc_index, mode, &ch->sample, &ch->sample_num); } ch->last_state = GF_OK; @@ -366,11 +383,22 @@ static void init_reader(ISOMChannel *ch) ch->to_init = 0; } return; - } + } - ch->sample_time = ch->sample->DTS; + if (ch->has_edit_list) { + ch->sample_time = ch->sample->DTS; + } else { + //store movie time in media timescale in the sample time, eg no edit list is used but we may have a shift (dts_offset) between + //movie and media timelines + + if ((ch->dts_offset<0) && (ch->sample->DTS < (u64) -ch->dts_offset)) //should not happen + ch->sample_time = 0; + else + ch->sample_time = ch->sample->DTS + ch->dts_offset; + } ch->to_init = 0; + ch->current_slh.seekFlag = 0; if (ch->disable_seek) { ch->current_slh.decodingTimeStamp = ch->sample->DTS; ch->current_slh.compositionTimeStamp = ch->sample->DTS + ch->sample->CTS_Offset; @@ -378,8 +406,13 @@ static void init_reader(ISOMChannel *ch) } else { ch->current_slh.decodingTimeStamp = ch->start; ch->current_slh.compositionTimeStamp = ch->start; + if (ch->current_slh.compositionTimeStamp != ch->sample->DTS + ch->sample->CTS_Offset) { + ch->current_slh.seekFlag = 1; + } } ch->current_slh.randomAccessPointFlag = ch->sample ? ch->sample->IsRAP : 0; + ch->last_sample_desc_index = sample_desc_index; + ch->owner->no_order_check = ch->speed < 0 ? GF_TRUE : GF_FALSE; } @@ -387,7 +420,7 @@ static void init_reader(ISOMChannel *ch) void isor_reader_get_sample(ISOMChannel *ch) { GF_Err e; - u32 ivar; + u32 sample_desc_index; if (ch->sample) return; if (ch->next_track) { @@ -401,13 +434,38 @@ void isor_reader_get_sample(ISOMChannel *ch) if (ch->to_init) { init_reader(ch); + sample_desc_index = ch->last_sample_desc_index; } else if (ch->speed < 0) { - gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time - 1, &ivar, GF_ISOM_SEARCH_SYNC_BACKWARD, &ch->sample, &ch->sample_num); - if (ch->sample) ch->sample_time = ch->sample->DTS; + if (!ch->sample_time) { + ch->last_state = GF_EOS; + return; + } else { + e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time - 1, &sample_desc_index, GF_ISOM_SEARCH_SYNC_BACKWARD, &ch->sample, &ch->sample_num); + if (e) { + if ((e==GF_EOS) && !ch->owner->frag_type) { + ch->last_state = GF_EOS; + } + return; + } + } + if (ch->sample->DTS + ch->dts_offset == ch->sample_time) { + if (!ch->owner->frag_type) { + ch->last_state = GF_EOS; + } else { + if (ch->sample) + gf_isom_sample_del(&ch->sample); + } + } + if (ch->sample) { + if ((ch->dts_offset<0) && (ch->sample->DTS < (u64) -ch->dts_offset)) //should not happen + ch->sample_time = 0; + else + ch->sample_time = ch->sample->DTS + ch->dts_offset; + } } else if (ch->has_edit_list) { u32 prev_sample = ch->sample_num; - e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + 1, &ivar, GF_ISOM_SEARCH_FORWARD, &ch->sample, &ch->sample_num); + e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + 1, &sample_desc_index, GF_ISOM_SEARCH_FORWARD, &ch->sample, &ch->sample_num); if (e == GF_OK) { @@ -416,7 +474,7 @@ void isor_reader_get_sample(ISOMChannel *ch) ch->edit_sync_frame++; if (ch->edit_sync_frame < ch->sample_num) { gf_isom_sample_del(&ch->sample); - ch->sample = gf_isom_get_sample(ch->owner->mov, ch->track, ch->edit_sync_frame, &ivar); + ch->sample = gf_isom_get_sample(ch->owner->mov, ch->track, ch->edit_sync_frame, &sample_desc_index); ch->sample->DTS = ch->sample_time; ch->sample->CTS_Offset = 0; } else { @@ -440,7 +498,7 @@ void isor_reader_get_sample(ISOMChannel *ch) if (s2 && s1) { assert(s2->DTS >= s1->DTS); time_diff = (u32) (s2->DTS - s1->DTS); - e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + time_diff, &ivar, GF_ISOM_SEARCH_FORWARD, &ch->sample, &ch->sample_num); + e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + time_diff, &sample_desc_index, GF_ISOM_SEARCH_FORWARD, &ch->sample, &ch->sample_num); } else if (s1 && !s2) { e = GF_EOS; } @@ -456,7 +514,7 @@ void isor_reader_get_sample(ISOMChannel *ch) GF_ISOSample *found = ch->sample; u32 samp_num = ch->sample_num; ch->sample = NULL; - e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + 1, &ivar, GF_ISOM_SEARCH_SYNC_BACKWARD, &ch->sample, &ch->sample_num); + e = gf_isom_get_sample_for_movie_time(ch->owner->mov, ch->track, ch->sample_time + 1, &sample_desc_index, GF_ISOM_SEARCH_SYNC_BACKWARD, &ch->sample, &ch->sample_num); assert (e == GF_OK); /*if no sync point in the past, use the first non-sync for the given time*/ if (!ch->sample || !ch->sample->data) { @@ -478,14 +536,14 @@ void isor_reader_get_sample(ISOMChannel *ch) } else { ch->sample_num++; - ch->sample = gf_isom_get_sample(ch->owner->mov, ch->track, ch->sample_num, &ivar); + ch->sample = gf_isom_get_sample(ch->owner->mov, ch->track, ch->sample_num, &sample_desc_index); /*if sync shadow / carousel RAP skip*/ - if (ch->sample && (ch->sample->IsRAP==2)) { + if (ch->sample && (ch->sample->IsRAP==RAP_REDUNDANT)) { gf_isom_sample_del(&ch->sample); ch->sample_num++; isor_reader_get_sample(ch); return; - } + } } //check scalable track change @@ -520,7 +578,12 @@ void isor_reader_get_sample(ISOMChannel *ch) else if (ch->owner->input->query_proxy) { ch->last_state = GF_OK; } - } else if (!ch->sample_num || (ch->sample_num >= gf_isom_get_sample_count(ch->owner->mov, ch->track))) { + } + else if (!ch->sample_num + || ((ch->speed >= 0) && (ch->sample_num >= gf_isom_get_sample_count(ch->owner->mov, ch->track))) + || ((ch->speed < 0) && (ch->sample_time == gf_isom_get_current_tfdt(ch->owner->mov, ch->track) + ch->dts_offset)) + ) { + if (ch->owner->frag_type==1) { //if segment is fully opened and no more data, this track is done, wait for next segment if (!ch->wait_for_segment_switch && ch->owner->input->query_proxy && (ch->owner->seg_opened==2) ) { @@ -530,7 +593,7 @@ void isor_reader_get_sample(ISOMChannel *ch) /*if sample cannot be found and file is fragmented, rewind sample*/ if (ch->sample_num) ch->sample_num--; ch->last_state = GF_OK; - } else if (!ch->owner->frag_type) { + } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Track #%d end of stream reached\n", ch->track)); ch->last_state = GF_EOS; } @@ -546,6 +609,39 @@ void isor_reader_get_sample(ISOMChannel *ch) } return; } + + if (sample_desc_index != ch->last_sample_desc_index) { + u32 mtype = gf_isom_get_media_type(ch->owner->mov, ch->track); + switch (mtype) { + case GF_ISOM_MEDIA_VISUAL: + //code is here as a reminder, but by default we use inband param set extraction so no need for it +#if 0 + if ( ! (ch->nalu_extract_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ) { + u32 extract_mode = ch->nalu_extract_mode | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG; + + gf_isom_sample_del(&ch->sample); + ch->sample = NULL; + gf_isom_set_nalu_extract_mode(ch->owner->mov, ch->track, extract_mode); + ch->sample = gf_isom_get_sample(ch->owner->mov, ch->track, ch->sample_num, &ch->last_sample_desc_index); + + gf_isom_set_nalu_extract_mode(ch->owner->mov, ch->track, ch->nalu_extract_mode); + } +#endif + break; + case GF_ISOM_MEDIA_TEXT: + case GF_ISOM_MEDIA_SUBPIC: + case GF_ISOM_MEDIA_MPEG_SUBT: + break; + default: + //TODO: do we want to support codec changes ? + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[IsoMedia] Change of sample description (%d->%d) for media type %s not supported\n", ch->last_sample_desc_index, sample_desc_index, gf_4cc_to_str(mtype) )); + gf_isom_sample_del(&ch->sample); + ch->sample = NULL; + ch->last_state = GF_NOT_SUPPORTED; + return; + } + } + ch->last_state = GF_OK; ch->current_slh.accessUnitEndFlag = ch->current_slh.accessUnitStartFlag = 1; ch->current_slh.accessUnitLength = ch->sample->dataLength; @@ -558,8 +654,10 @@ void isor_reader_get_sample(ISOMChannel *ch) if ((ch->speed < 0) || (ch->start <= ch->sample->DTS + ch->sample->CTS_Offset)) { ch->current_slh.decodingTimeStamp = ch->sample->DTS; ch->current_slh.compositionTimeStamp = ch->sample->DTS + ch->sample->CTS_Offset; + ch->current_slh.seekFlag = 0; } else { ch->current_slh.compositionTimeStamp = ch->start; + ch->current_slh.seekFlag = 1; if (ch->streamType==GF_STREAM_SCENE) ch->current_slh.decodingTimeStamp = ch->sample->DTS; else @@ -573,6 +671,12 @@ void isor_reader_get_sample(ISOMChannel *ch) GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] End of Channel "LLD" (CTS "LLD")\n", ch->end, ch->sample->DTS + ch->sample->CTS_Offset)); ch->last_state = GF_EOS; } + if (ch->owner->last_sender_ntp && ch->current_slh.compositionTimeStamp==ch->owner->cts_for_last_sender_ntp) { + ch->current_slh.sender_ntp = ch->owner->last_sender_ntp; + } else { + ch->current_slh.sender_ntp = 0; + } + if (ch->is_encrypted) { GF_ISMASample *ismasamp = gf_isom_get_ismacryp_sample(ch->owner->mov, ch->track, ch->sample, 1); @@ -601,15 +705,16 @@ void isor_reader_get_sample(ISOMChannel *ch) sai = NULL; gf_isom_cenc_get_sample_aux_info(ch->owner->mov, ch->track, ch->sample_num, &sai, NULL); if (sai) { + u32 i; GF_BitStream *bs; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); /*write sample auxiliary information*/ gf_bs_write_data(bs, (char *)KID, 16); gf_bs_write_data(bs, (char *)sai->IV, IV_size); gf_bs_write_u16(bs, sai->subsample_count); - for (ivar = 0; ivar < sai->subsample_count; ivar++) { - gf_bs_write_u16(bs, sai->subsamples[ivar].bytes_clear_data); - gf_bs_write_u32(bs, sai->subsamples[ivar].bytes_encrypted_data); + for (i = 0; i < sai->subsample_count; i++) { + gf_bs_write_u16(bs, sai->subsamples[i].bytes_clear_data); + gf_bs_write_u32(bs, sai->subsamples[i].bytes_encrypted_data); } gf_bs_get_content(bs, &ch->current_slh.sai, &ch->current_slh.saiz); gf_bs_del(bs); @@ -641,7 +746,7 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl { u32 i, count; GF_Err e = GF_OK; - Bool in_progressive_mode; + Bool do_refresh; GF_NetworkCommand com; ISOMChannel *ch; @@ -658,9 +763,9 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl read->in_data_flush = 1; count = gf_list_count(read->channels); - in_progressive_mode = (read->seg_opened==1) ? 1 : 0; + do_refresh = (read->seg_opened==1) ? 1 : 0; - if (in_progressive_mode) { + if (do_refresh) { //query from terminal - do nothing if we are not done downloading the segment - otherwise we could access media data while it is reallocated by the downloader if (!check_buffer_level) { read->in_data_flush = 0; @@ -670,7 +775,7 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl //otherwise this is new chunk or end of chunk, process } //this is a new file, check buffer level - else if (!is_chunk_flush && check_buffer_level) { + else if (/*!is_chunk_flush && */ check_buffer_level) { Bool buffer_full = 1; for (i=0; i<count; i++) { ch = (ISOMChannel *)gf_list_get(read->channels, i); @@ -694,21 +799,20 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl return; } } -#if 1 //flush request from terminal: only process if nothing is opened and we have pending segments - if (!check_buffer_level && !read->seg_opened && !read->has_pending_segments && !read->drop_next_segment) { + //we have to keep the polling event when no segments are pending, in order to detect period switch - we therefore tolerate a couble of requests even though no segments are pending + if (!check_buffer_level && !read->seg_opened && !read->has_pending_segments && (read->nb_force_flush > 2) && !read->drop_next_segment) { read->in_data_flush = 0; gf_mx_v(read->segment_mutex); return; } -#endif - //if this is a request from terminal to flush pending segments, do not attempt to open the current download one, only open the first available in the cache - if (!check_buffer_level && !in_progressive_mode) - in_progressive_mode = 2; + //if this is a request from terminal to flush pending segments, try to refresh + if (!check_buffer_level && !do_refresh) + do_refresh = 1; //update data - isor_segment_switch_or_refresh(read, in_progressive_mode); + isor_segment_switch_or_refresh(read, do_refresh); //for all channels, fetch and send ... count = gf_list_count(read->channels); @@ -718,7 +822,8 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl while (!ch->sample) { isor_reader_get_sample(ch); if (!ch->sample) break; - gf_service_send_packet(read->service, ch->channel, ch->sample->data, ch->sample->dataLength, &ch->current_slh, GF_OK); + if (ch->is_playing) + gf_service_send_packet(read->service, ch->channel, ch->sample->data, ch->sample->dataLength, &ch->current_slh, GF_OK); isor_reader_release_sample(ch); } if (!ch->sample && (ch->last_state==GF_EOS)) { @@ -736,7 +841,7 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl param.url_query.drop_first_segment = 1; e = read->input->query_proxy(read->input, ¶m); - + read->nb_force_flush = 0; if (read->has_pending_segments) { read->has_pending_segments--; } @@ -750,7 +855,7 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl //not enough data else if (param.url_query.in_end_of_period) { //act as if we have a pending segment to process at next call until we get to the next period - if (!read->has_pending_segments) + if (!read->has_pending_segments) read->has_pending_segments++; } @@ -760,6 +865,10 @@ void isor_flush_data(ISOMReader *read, Bool check_buffer_level, Bool is_chunk_fl GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[IsoMedia] Done playing segment \n")); } read->in_data_flush = 0; + + if (!read->has_pending_segments) { + read->nb_force_flush ++; + } gf_mx_v(read->segment_mutex); } diff --git a/modules/jack/Makefile b/modules/jack/Makefile index 495cd98..7f5bc33 100644 --- a/modules/jack/Makefile +++ b/modules/jack/Makefile @@ -20,7 +20,7 @@ OBJS= jack.o SRCS := $(OBJS:.o=.c) -LIB=gm_jack.$(DYN_LIB_SUFFIX) +LIB=gm_jack$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/jack/jack.c b/modules/jack/jack.c index 5fb2774..78ef71a 100644 --- a/modules/jack/jack.c +++ b/modules/jack/jack.c @@ -569,4 +569,4 @@ void ShutdownInterface (GF_BaseInterface * ifce) DeleteJackOutput ((GF_AudioOutput *) ifce); } -GPAC_MODULE_STATIC_DELARATION( jack ) +GPAC_MODULE_STATIC_DECLARATION( jack ) diff --git a/modules/laser_dec/Makefile b/modules/laser_dec/Makefile index 8685745..1412d02 100644 --- a/modules/laser_dec/Makefile +++ b/modules/laser_dec/Makefile @@ -19,7 +19,7 @@ OBJS=laser_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_laser_dec.$(DYN_LIB_SUFFIX) +LIB=gm_laser_dec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols laser_dec.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_laser_dec-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_laser_dec-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif diff --git a/modules/laser_dec/laser_dec.c b/modules/laser_dec/laser_dec.c index 9df3408..a0684e7 100644 --- a/modules/laser_dec/laser_dec.c +++ b/modules/laser_dec/laser_dec.c @@ -195,4 +195,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } -GPAC_MODULE_STATIC_DELARATION( laser ) +GPAC_MODULE_STATIC_DECLARATION( laser ) diff --git a/modules/libplayer/Makefile b/modules/libplayer/Makefile index 3218dcc..8c31731 100644 --- a/modules/libplayer/Makefile +++ b/modules/libplayer/Makefile @@ -19,7 +19,7 @@ OBJS= libplayer.o SRCS := $(OBJS:.o=.c) -LIB=gm_libplayer.$(DYN_LIB_SUFFIX) +LIB=gm_libplayer$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/libplayer/libplayer.c b/modules/libplayer/libplayer.c index 5738900..d25670f 100644 --- a/modules/libplayer/libplayer.c +++ b/modules/libplayer/libplayer.c @@ -661,4 +661,4 @@ void ShutdownInterface(GF_BaseInterface *bi) } } -GPAC_MODULE_STATIC_DELARATION( libplayer ) +GPAC_MODULE_STATIC_DECLARATION( libplayer ) diff --git a/modules/mp3_in/Makefile b/modules/mp3_in/Makefile index 6f2108c..5228e8c 100644 --- a/modules/mp3_in/Makefile +++ b/modules/mp3_in/Makefile @@ -34,7 +34,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_mp3_in.$(DYN_LIB_SUFFIX) +LIB=gm_mp3_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols mp3_in.def endif @@ -46,7 +46,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(EXTRALIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mp3_in-static.$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mp3_in-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) endif diff --git a/modules/mp3_in/mad_dec.c b/modules/mp3_in/mad_dec.c index b86bfb0..0894348 100644 --- a/modules/mp3_in/mad_dec.c +++ b/modules/mp3_in/mad_dec.c @@ -221,7 +221,6 @@ static GF_Err MAD_ProcessData(GF_MediaDecoder *ifcg, /*if late or seeking don't decode*/ switch (mmlevel) { case GF_CODEC_LEVEL_SEEK: - case GF_CODEC_LEVEL_DROP: *outBufferLength = 0; return GF_OK; default: diff --git a/modules/mp3_in/mp3_in.c b/modules/mp3_in/mp3_in.c index a79ba7b..9e0d006 100644 --- a/modules/mp3_in/mp3_in.c +++ b/modules/mp3_in/mp3_in.c @@ -159,12 +159,12 @@ static Bool MP3_ConfigureFromFile(MP3Reader *read, u32 *minSizeToRead) *minSizeToRead = sz; } } - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); hdr = gf_mp3_get_next_header(read->stream); if (!hdr) return 0; read->sample_rate = gf_mp3_sampling_rate(hdr); read->oti = gf_mp3_object_type_indication(hdr); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); if (!read->oti) return 0; /*we don't have the full file...*/ @@ -172,17 +172,17 @@ static Bool MP3_ConfigureFromFile(MP3Reader *read, u32 *minSizeToRead) // return 1; - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); read->duration = 0; while (1) { hdr = gf_mp3_get_next_header(read->stream); if (!hdr) break; read->duration += gf_mp3_window_size(hdr); size = gf_mp3_frame_size(hdr); - pos = gf_f64_tell(read->stream); - gf_f64_seek(read->stream, pos + size - 4, SEEK_SET); + pos = gf_ftell(read->stream); + gf_fseek(read->stream, pos + size - 4, SEEK_SET); } - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); return 1; } @@ -337,7 +337,7 @@ void MP3_NetIO(void *cbk, GF_NETIO_Parameter *param) szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { - read->stream = gf_f64_open((char *) szCache, "rb"); + read->stream = gf_fopen((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { u32 minSizeToRead = 0; @@ -351,7 +351,7 @@ void MP3_NetIO(void *cbk, GF_NETIO_Parameter *param) if (bytes_done>(100*1024 + minSizeToRead)) { e = GF_CORRUPTED_DATA; } else { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; return; } @@ -410,11 +410,11 @@ static GF_Err MP3_ConnectService(GF_InputService *plug, GF_ClientService *serv, } reply = GF_OK; - read->stream = gf_f64_open(szURL, "rb"); + read->stream = gf_fopen(szURL, "rb"); if (!read->stream) { reply = GF_URL_ERROR; } else if (!MP3_ConfigureFromFile(read, &minSizeToRead)) { - fclose(read->stream); + gf_fclose(read->stream); read->stream = NULL; reply = GF_NOT_SUPPORTED; } @@ -426,7 +426,7 @@ static GF_Err MP3_ConnectService(GF_InputService *plug, GF_ClientService *serv, static GF_Err MP3_CloseService(GF_InputService *plug) { MP3Reader *read = plug->priv; - if (read->stream) fclose(read->stream); + if (read->stream) gf_fclose(read->stream); read->stream = NULL; if (read->dnload) gf_service_download_del(read->dnload); @@ -550,7 +550,7 @@ static GF_Err MP3_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) read->start_range = com->play.start_range; read->end_range = com->play.end_range; read->current_time = 0; - if (read->stream) gf_f64_seek(read->stream, 0, SEEK_SET); + if (read->stream) gf_fseek(read->stream, 0, SEEK_SET); if (read->ch == com->base.on_channel) { read->done = 0; @@ -607,14 +607,14 @@ static GF_Err MP3_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha } *is_new_data = 1; - pos = gf_f64_tell(read->stream); + pos = gf_ftell(read->stream); hdr = gf_mp3_get_next_header(read->stream); if (!hdr) { if (!read->dnload) { *out_reception_status = GF_EOS; read->done = 1; } else { - gf_f64_seek(read->stream, pos, SEEK_SET); + gf_fseek(read->stream, pos, SEEK_SET); *out_reception_status = GF_OK; } return GF_OK; @@ -631,7 +631,7 @@ static GF_Err MP3_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha if (read->start_range && read->duration) { read->current_time = 0; start_from = (u32) (read->start_range * read->sample_rate); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); while (read->current_time<start_from) { hdr = gf_mp3_get_next_header(read->stream); if (!hdr) { @@ -641,14 +641,14 @@ static GF_Err MP3_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha } read->current_time += gf_mp3_window_size(hdr); read->data_size = gf_mp3_frame_size(hdr); - gf_f64_seek(read->stream, read->data_size-4, SEEK_CUR); + gf_fseek(read->stream, read->data_size-4, SEEK_CUR); } read->start_range = 0; - GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[MP3Demux] Seeking to frame size %d - TS %d - file pos %d\n", read->data_size, read->current_time, gf_f64_tell(read->stream))); + GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[MP3Demux] Seeking to frame size %d - TS %d - file pos %d\n", read->data_size, read->current_time, gf_ftell(read->stream))); } read->sl_hdr.compositionTimeStamp = read->current_time; - GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[MP3Demux] Found new frame size %d - TS %d - file pos %d\n", read->data_size, read->current_time, gf_f64_tell(read->stream))); + GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[MP3Demux] Found new frame size %d - TS %d - file pos %d\n", read->data_size, read->current_time, gf_ftell(read->stream))); read->current_time += gf_mp3_window_size(hdr); @@ -662,7 +662,7 @@ static GF_Err MP3_ChannelGetSLP(GF_InputService *plug, LPNETCHANNEL channel, cha gf_free(read->data); read->data = NULL; if (read->is_remote) { - gf_f64_seek(read->stream, pos, SEEK_SET); + gf_fseek(read->stream, pos, SEEK_SET); *out_reception_status = GF_OK; } else { *out_reception_status = GF_EOS; @@ -778,4 +778,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( mp3_in ) +GPAC_MODULE_STATIC_DECLARATION( mp3_in ) diff --git a/modules/mpd_in/Makefile b/modules/mpd_in/Makefile index 15b77c4..e24a83d 100644 --- a/modules/mpd_in/Makefile +++ b/modules/mpd_in/Makefile @@ -20,7 +20,7 @@ OBJS=mpd_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_mpd_in.$(DYN_LIB_SUFFIX) +LIB=gm_mpd_in$(DYN_LIB_SUFFIX) all: $(LIB) @@ -28,7 +28,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mpegts_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mpegts_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/mpd_in/mpd_in.c b/modules/mpd_in/mpd_in.c index 09c48cf..d4f4e69 100644 --- a/modules/mpd_in/mpd_in.c +++ b/modules/mpd_in/mpd_in.c @@ -49,16 +49,17 @@ typedef struct __mpd_module GF_DASHFileIO dash_io; Bool connection_ack_sent; - Bool in_seek; Bool memory_storage; Bool use_max_res, immediate_switch, allow_http_abort; u32 use_low_latency; MpdInBuffer buffer_mode; - Double previous_start_range; + u32 nb_playing; + /*max width & height in all active representations*/ u32 width, height; - + Double seek_request; + Double media_start_range; //we store here all callbacks to the parent services we need to intercept, and we will override our own ones void (*fn_connect_ack) (GF_ClientService *service, LPNETCHANNEL ns, GF_Err response); void (*fn_data_packet) (GF_ClientService *service, LPNETCHANNEL ns, char *data, u32 data_size, GF_SLHeader *hdr, GF_Err reception_status); @@ -74,7 +75,11 @@ typedef struct Bool has_new_data; u32 idx; GF_DownloadSession *sess; - Bool in_seek, is_timestamp_based; + Bool is_timestamp_based, pto_setup; + u32 timescale; + s64 pto; + s64 max_cts_in_period; + bin128 key_IV; } GF_MPDGroup; const char * MPD_MPD_DESC = "MPEG-DASH Streaming"; @@ -85,10 +90,10 @@ const char * MPD_M3U8_EXT = "m3u8 m3u"; static u32 MPD_RegisterMimeTypes(const GF_InputService *plug) { u32 i, c; - for (i = 0 ; GF_DASH_MPD_MIME_TYPES[i]; i++) + for (i=0; GF_DASH_MPD_MIME_TYPES[i]; i++) gf_service_register_mime (plug, GF_DASH_MPD_MIME_TYPES[i], MPD_MPD_EXT, MPD_MPD_DESC); c = i; - for (i = 0 ; GF_DASH_M3U8_MIME_TYPES[i]; i++) + for (i=0; GF_DASH_M3U8_MIME_TYPES[i]; i++) gf_service_register_mime(plug, GF_DASH_M3U8_MIME_TYPES[i], MPD_M3U8_EXT, MPD_M3U8_DESC); return c+i; } @@ -98,22 +103,37 @@ Bool MPD_CanHandleURL(GF_InputService *plug, const char *url) u32 i; char *sExt; if (!plug || !url) - return 0; + return GF_FALSE; sExt = strrchr(url, '.'); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Can Handle URL request from terminal for %s\n", url)); - for (i = 0 ; GF_DASH_MPD_MIME_TYPES[i]; i++) { + for (i=0; GF_DASH_MPD_MIME_TYPES[i]; i++) { if (gf_service_check_mime_register(plug, GF_DASH_MPD_MIME_TYPES[i], MPD_MPD_EXT, MPD_MPD_DESC, sExt)) - return 1; + return GF_TRUE; } - for (i = 0 ; GF_DASH_M3U8_MIME_TYPES[i]; i++) { + for (i=0; GF_DASH_M3U8_MIME_TYPES[i]; i++) { if (gf_service_check_mime_register(plug, GF_DASH_M3U8_MIME_TYPES[i], MPD_M3U8_EXT, MPD_M3U8_DESC, sExt)) - return 1; + return GF_TRUE; } return gf_dash_check_mpd_root_type(url); } +static s32 gf_dash_get_group_idx_from_service(GF_MPD_In *mpdin, GF_InputService *ifce) +{ + s32 i; + + for (i=0; (u32) i < gf_dash_get_group_count(mpdin->dash); i++) { + GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); + if (!group) continue; + if (group->segment_ifce == ifce) { + return i; + } + } + return -1; +} + + static void mpdin_connect_ack(GF_ClientService *service, LPNETCHANNEL ns, GF_Err response) { GF_MPD_In *mpdin = (GF_MPD_In*) service->ifce->priv; @@ -124,11 +144,11 @@ static void mpdin_connect_ack(GF_ClientService *service, LPNETCHANNEL ns, GF_Err void mpdin_data_packet(GF_ClientService *service, LPNETCHANNEL ns, char *data, u32 data_size, GF_SLHeader *hdr, GF_Err reception_status) { - u32 i; - GF_InputService *ifce; + s32 i; GF_MPD_In *mpdin = (GF_MPD_In*) service->ifce->priv; GF_Channel *ch; - + GF_MPDGroup *group; + Bool do_map_time = GF_FALSE; if (!ns || !hdr) { mpdin->fn_data_packet(service, ns, data, data_size, hdr, reception_status); return; @@ -136,33 +156,114 @@ void mpdin_data_packet(GF_ClientService *service, LPNETCHANNEL ns, char *data, u ch = (GF_Channel *) ns; assert(ch->odm && ch->odm->OD); - ifce = (GF_InputService *) ch->odm->OD->service_ifce; - for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { - GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); - if (!group) continue; - if (group->segment_ifce == ifce) { - //if sync is based on timestamps do not adjust the timestamps back - if (! group->is_timestamp_based) { - u32 timescale; - u64 pto=0; - gf_dash_group_get_presentation_time_offset(mpdin->dash, i, &pto, ×cale); - if (timescale && (timescale != ch->esd->slConfig->timestampResolution)) { - pto *= ch->esd->slConfig->timestampResolution; - pto /= timescale; - } - if (hdr->decodingTimeStamp > pto) hdr->decodingTimeStamp -= pto; - else hdr->decodingTimeStamp = 0; - if (hdr->compositionTimeStamp> pto) hdr->compositionTimeStamp -= pto; - else hdr->compositionTimeStamp = 0; + i = gf_dash_get_group_idx_from_service(mpdin, (GF_InputService *) ch->odm->OD->service_ifce); + if (i<0) { + mpdin->fn_data_packet(service, ns, data, data_size, hdr, reception_status); + return; + } + + group = gf_dash_get_group_udta(mpdin->dash, i); + + if (gf_dash_is_m3u8(mpdin->dash)) { + mpdin->fn_data_packet(service, ns, data, data_size, hdr, reception_status); + if (!group->pto_setup) { + GF_NetworkCommand com; + memset(&com, 0, sizeof(com)); + com.command_type = GF_NET_CHAN_SET_MEDIA_TIME; + com.map_time.media_time = mpdin->media_start_range; + com.map_time.timestamp = hdr->compositionTimeStamp; + com.base.on_channel = ns; + gf_service_command(service, &com, GF_OK); + group->pto_setup = GF_TRUE; + } + return; + } + + //if sync is based on timestamps do not adjust the timestamps back + if (! group->is_timestamp_based) { + if (!group->pto_setup) { + Double scale; + s64 start, dur; + u64 pto; + gf_dash_group_get_presentation_time_offset(mpdin->dash, i, &pto, &group->timescale); + group->pto = (s64) pto; + group->pto_setup = 1; + + if (group->timescale && (group->timescale != ch->esd->slConfig->timestampResolution)) { + group->pto *= ch->esd->slConfig->timestampResolution; + group->pto /= group->timescale; } + scale = ch->esd->slConfig->timestampResolution; + scale /= 1000; - mpdin->fn_data_packet(service, ns, data, data_size, hdr, reception_status); - return; + dur = (u64) (scale * gf_dash_get_period_duration(mpdin->dash)); + if (dur) { + group->max_cts_in_period = group->pto + dur; + } else { + group->max_cts_in_period = 0; + } + + start = (u64) (scale * gf_dash_get_period_start(mpdin->dash)); + group->pto -= start; } + + //filter any packet outside the current period + if (group->max_cts_in_period && (s64) hdr->compositionTimeStamp > group->max_cts_in_period) { +// GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Packet timestamp "LLU" larger than max CTS in period "LLU" - skipping\n", hdr->compositionTimeStamp, group->max_cts_in_period)); +// return; + } + + //remap timestamps to our timeline + if (hdr->decodingTimeStampFlag) { + if ((s64) hdr->decodingTimeStamp >= group->pto) + hdr->decodingTimeStamp -= group->pto; + else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Packet DTS "LLU" less than PTO "LLU" - forcing DTS to 0\n", hdr->compositionTimeStamp, group->pto)); + hdr->decodingTimeStamp = 0; + hdr->seekFlag = 1; + } + } + if (hdr->compositionTimeStampFlag) { + if ((s64) hdr->compositionTimeStamp >= group->pto) + hdr->compositionTimeStamp -= group->pto; + else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Packet CTS "LLU" less than PTO "LLU" - forcing CTS to 0\n", hdr->compositionTimeStamp, group->pto)); + hdr->compositionTimeStamp = 0; + hdr->seekFlag = 1; + } + } + + if (hdr->OCRflag) { + u32 scale = hdr->m2ts_pcr ? 300 : 1; + u64 pto = scale*group->pto; + if (hdr->objectClockReference >= pto) + hdr->objectClockReference -= pto; + else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Packet OCR/PCR "LLU" less than PTO "LLU" - discarding PCR\n", hdr->objectClockReference/scale, group->pto)); + return; + } + } + + } else if (!group->pto_setup) { + do_map_time = 1; + group->pto_setup = 1; + } + + mpdin->fn_data_packet(service, ns, data, data_size, hdr, reception_status); + + if (do_map_time) { + GF_NetworkCommand com; + memset(&com, 0, sizeof(com)); + com.command_type = GF_NET_CHAN_SET_MEDIA_TIME; + com.map_time.media_time = mpdin->media_start_range; + com.map_time.timestamp = hdr->compositionTimeStamp; + com.base.on_channel = ns; + gf_service_command(service, &com, GF_OK); } } + static void MPD_NotifyData(GF_MPDGroup *group, Bool chunk_flush) { GF_NetworkCommand com; @@ -186,8 +287,6 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) param->url_query.start_range = 0; param->url_query.end_range = 0; - mpdin->in_seek = 0; - for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { GF_MPDGroup *group; if (!gf_dash_is_group_selectable(mpdin->dash, i)) continue; @@ -195,6 +294,11 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) if (group->segment_ifce == ifce) { gf_dash_group_get_segment_init_url(mpdin->dash, i, ¶m->url_query.start_range, ¶m->url_query.end_range); param->url_query.current_download = 0; + + param->url_query.key_url = gf_dash_group_get_segment_init_keys(mpdin->dash, i, &group->key_IV); + if (param->url_query.key_url) { + param->url_query.key_IV = &group->key_IV; + } return GF_OK; } } @@ -231,12 +335,6 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) return GF_SERVICE_ERROR; } - if (group->in_seek) { - group->in_seek = 0; - param->url_query.discontinuity_type = 2; - discard_first_cache_entry = 0; - } - //update group idx if (group->idx != group_idx) { group->idx = group_idx; @@ -248,14 +346,14 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) gf_dash_group_discard_segment(mpdin->dash, group_idx); } - while (gf_dash_is_running(mpdin->dash) ) { + while (gf_dash_is_running(mpdin->dash)) { group_done=0; nb_segments_cached = gf_dash_group_get_num_segments_ready(mpdin->dash, group_idx, &group_done); if (nb_segments_cached>=1) break; if (group_done) { - if (!gf_dash_get_period_switch_status(mpdin->dash) && !gf_dash_in_last_period(mpdin->dash) ) { + if (!gf_dash_get_period_switch_status(mpdin->dash) && !gf_dash_in_last_period(mpdin->dash)) { GF_NetworkCommand com; param->url_query.in_end_of_period = 1; memset(&com, 0, sizeof(GF_NetworkCommand)); @@ -304,17 +402,19 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) e = gf_dash_group_get_next_segment_location(mpdin->dash, group_idx, param->url_query.dependent_representation_index, ¶m->url_query.next_url, ¶m->url_query.start_range, ¶m->url_query.end_range, NULL, ¶m->url_query.next_url_init_or_switch_segment, ¶m->url_query.switch_start_range , ¶m->url_query.switch_end_range, - &src_url, ¶m->url_query.has_next); + &src_url, ¶m->url_query.has_next, ¶m->url_query.key_url, &group->key_IV); if (e) return e; + param->url_query.key_IV = &group->key_IV; + if (gf_dash_group_loop_detected(mpdin->dash, group_idx)) param->url_query.discontinuity_type = 2; #ifndef GPAC_DISABLE_LOG { - u32 timer2 = gf_sys_clock() - timer ; + u32 timer2 = gf_sys_clock() - timer; if (timer2 > 1000) { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Waiting for download to end took a long time : %u ms\n", timer2)); } @@ -323,7 +423,7 @@ static GF_Err MPD_ClientQuery(GF_InputService *ifce, GF_NetworkCommand *param) } else { GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[MPD_IN] Next Segment is %s\n", src_url)); } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Waited %d ms - Elements in cache: %u/%u\n\tCache file name %s\n\tsegment start time %g sec\n", timer2, gf_dash_group_get_num_segments_ready(mpdin->dash, group_idx, &group_done), gf_dash_group_get_max_segments_in_cache(mpdin->dash, group_idx), param->url_query.next_url, gf_dash_group_current_segment_start_time(mpdin->dash, group_idx) )); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Waited %d ms - Elements in cache: %u/%u\n\tCache file name %s\n\tsegment start time %g sec\n", timer2, gf_dash_group_get_num_segments_ready(mpdin->dash, group_idx, &group_done), gf_dash_group_get_max_segments_in_cache(mpdin->dash, group_idx), param->url_query.next_url, gf_dash_group_current_segment_start_time(mpdin->dash, group_idx))); } #endif } @@ -442,7 +542,7 @@ static void mpdin_dash_segment_netio(void *cbk, GF_NETIO_Parameter *param) if (param->msg_type == GF_NETIO_PARSE_HEADER) { if (!strcmp(param->name, "Dash-Newest-Segment")) { - gf_dash_resync_to_segment(group->mpdin->dash, param->value, gf_dm_sess_get_header(param->sess, "Dash-Oldest-Segment") ); + gf_dash_resync_to_segment(group->mpdin->dash, param->value, gf_dm_sess_get_header(param->sess, "Dash-Oldest-Segment")); } } @@ -497,7 +597,7 @@ GF_DASHFileIOSession mpdin_dash_io_create(GF_DASHFileIO *dashio, Bool persistent } else { sess = gf_service_download_new(mpdin->service, url, flags, NULL, NULL); } - return (GF_DASHFileIOSession ) sess; + return (GF_DASHFileIOSession) sess; } void mpdin_dash_io_del(GF_DASHFileIO *dashio, GF_DASHFileIOSession session) { @@ -595,6 +695,7 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_ } if (dash_evt==GF_DASH_EVENT_SELECT_GROUPS) { + const char *opt; //configure buffer in dynamic mode without low latency: we indicate how much the player will buffer if (gf_dash_is_dynamic_mpd(mpdin->dash) && !mpdin->use_low_latency) { u32 buffer_ms = 0; @@ -613,12 +714,17 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_ } } //let the player decide which group to play: we declare everything + + //however select the default languague + opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Systems", "LanguageName"); + if (opt) + gf_dash_groups_set_language(mpdin->dash, opt); + return GF_OK; } /*for all selected groups, create input service and connect to init/first segment*/ if (dash_evt==GF_DASH_EVENT_CREATE_PLAYBACK) { - /*select input services if possible*/ for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { const char *mime, *init_segment; @@ -656,6 +762,17 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_ mpdin->fn_connect_ack(mpdin->service, NULL, GF_OK); mpdin->connection_ack_sent=1; } + + //we had a seek outside of the period we were setting up, during period setup ! + //request the seek again from the player + if (mpdin->seek_request>=0) { + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.command_type = GF_NET_SERVICE_SEEK; + com.play.start_range = mpdin->seek_request; + mpdin->seek_request = 0; + gf_service_command(mpdin->service, &com, GF_OK); + } return GF_OK; } @@ -685,7 +802,7 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_ if (dash_evt==GF_DASH_EVENT_BUFFERING) { u32 tot, done; - gf_dash_get_buffer_info_buffering(mpdin->dash, &tot, &done); + gf_dash_get_buffer_info(mpdin->dash, &tot, &done); fprintf(stderr, "DASH: Buffering %g%% out of %d ms\n", (100.0*done)/tot, tot); return GF_OK; } @@ -694,10 +811,59 @@ GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_ GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx); if (group) MPD_NotifyData(group, 0); } + return GF_OK; + } + if (dash_evt==GF_DASH_EVENT_QUALITY_SWITCH) { + if (group_idx>=0) { + GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx); + if (group) { + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + + com.command_type = GF_NET_SERVICE_EVENT; + com.send_event.evt.type = GF_EVENT_QUALITY_SWITCHED; + gf_service_command(mpdin->service, &com, GF_OK); + } + } + return GF_OK; } + if (dash_evt==GF_DASH_EVENT_TIMESHIFT_OVERFLOW) { + GF_NetworkCommand com; + com.command_type = GF_NET_SERVICE_EVENT; + com.send_event.evt.type = (group_idx>=0) ? GF_EVENT_TIMESHIFT_OVERFLOW : GF_EVENT_TIMESHIFT_UNDERRUN; + gf_service_command(mpdin->service, &com, GF_OK); + } + if (dash_evt==GF_DASH_EVENT_TIMESHIFT_UPDATE) { + GF_NetworkCommand com; + com.command_type = GF_NET_SERVICE_EVENT; + com.send_event.evt.type = GF_EVENT_TIMESHIFT_UPDATE; + gf_service_command(mpdin->service, &com, GF_OK); + } + return GF_OK; } +/*check in all groups if the service can support reverse playback (speed<0); return GF_OK only if service is supported in all groups*/ +static GF_Err mpdin_dash_can_reverse_playback(GF_MPD_In *mpdin) +{ + u32 i; + GF_Err e = GF_NOT_SUPPORTED; + for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { + if (gf_dash_is_group_selectable(mpdin->dash, i)) { + GF_MPDGroup *mudta = gf_dash_get_group_udta(mpdin->dash, i); + if (mudta && mudta->segment_ifce) { + GF_NetworkCommand com; + com.command_type = GF_NET_SERVICE_CAN_REVERSE_PLAYBACK; + e = mudta->segment_ifce->ServiceCommand(mudta->segment_ifce, &com); + if (GF_OK != e) + return e; + } + } + } + + return e; +} + GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url) { @@ -716,6 +882,7 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c return GF_BAD_PARAM; mpdin->service = serv; + mpdin->seek_request = -1; mpdin->dash_io.udta = mpdin; mpdin->dash_io.delete_cache_file = mpdin_dash_io_delete_cache_file; @@ -791,12 +958,11 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c else if (opt && !strcmp(opt, "none")) mpdin->buffer_mode = MPDIN_BUFFER_NONE; else mpdin->buffer_mode = MPDIN_BUFFER_MIN; - opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "LowLatency"); if (!opt) gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "LowLatency", "no"); - if (opt && !strcmp(opt, "chunk") ) mpdin->use_low_latency = 1; - else if (opt && !strcmp(opt, "always") ) mpdin->use_low_latency = 2; + if (opt && !strcmp(opt, "chunk")) mpdin->use_low_latency = 1; + else if (opt && !strcmp(opt, "always")) mpdin->use_low_latency = 2; else mpdin->use_low_latency = 0; opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "AllowAbort"); @@ -811,8 +977,7 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c if (!opt) gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "UseServerUTC", "yes"); use_server_utc = (opt && !strcmp(opt, "yes")) ? 1 : 0; - mpdin->in_seek = 0; - mpdin->previous_start_range = -1; + mpdin->nb_playing = 0; init_timeshift = 0; opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "InitialTimeshift"); @@ -860,6 +1025,13 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c gf_dash_set_segment_expiration_threshold(mpdin->dash, atoi(opt)); } + opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "SwitchProbeCount"); + if (opt) { + gf_dash_set_switching_probe_count(mpdin->dash, atoi(opt)); + } else { + gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "SwitchProbeCount", "1"); + } + opt = gf_modules_get_option((GF_BaseInterface *)plug, "DASH", "DebugAdaptationSet"); if (!opt) gf_modules_set_option((GF_BaseInterface *)plug, "DASH", "DebugAdaptationSet", "-1"); @@ -870,7 +1042,7 @@ GF_Err MPD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const c /*dash thread starts at the end of gf_dash_open */ e = gf_dash_open(mpdin->dash, url); if (e) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[MPD_IN] Error - cannot initialize DASH Client for %s: %s\n", url, gf_error_to_string(e) )); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[MPD_IN] Error - cannot initialize DASH Client for %s: %s\n", url, gf_error_to_string(e))); mpdin->fn_connect_ack(mpdin->service, NULL, e); return GF_OK; } @@ -895,7 +1067,7 @@ static GF_Descriptor *MPD_GetServiceDesc(GF_InputService *plug, u32 expect_type, desc = mudta->segment_ifce->GetServiceDescriptor(mudta->segment_ifce, expect_type, sub_url); if (desc) mudta->service_descriptor_fetched = 1; - return desc; + gf_odf_desc_del(desc); } return NULL; } @@ -904,7 +1076,7 @@ static GF_Descriptor *MPD_GetServiceDesc(GF_InputService *plug, u32 expect_type, GF_Err MPD_CloseService(GF_InputService *plug) { GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv; - assert( mpdin ); + assert(mpdin); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Close Service (%p) request from terminal\n", mpdin->service)); mpdin->closed = 1; @@ -924,13 +1096,14 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv; GF_InputService *segment_ifce = NULL; - if (!plug || !plug->priv || !com ) return GF_SERVICE_ERROR; + if (!plug || !plug->priv || !com) return GF_SERVICE_ERROR; segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel); switch (com->command_type) { case GF_NET_SERVICE_INFO: { + s32 idx; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Info command from terminal on Service (%p)\n", mpdin->service)); e = GF_OK; @@ -942,6 +1115,19 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) if (e!= GF_OK || !com->info.name || 2 > strlen(com->info.name)) { gf_dash_get_info(mpdin->dash, &com->info.name, &com->info.comment); } + idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel); + if (idx>=0) { + //gather role and co + if (!com->info.role) { + gf_dash_group_enum_descriptor(mpdin->dash, idx, GF_MPD_DESC_ROLE, 0, NULL, NULL, &com->info.role); + } + if (!com->info.accessibility) { + gf_dash_group_enum_descriptor(mpdin->dash, idx, GF_MPD_DESC_ACCESSIBILITY, 0, NULL, NULL, &com->info.accessibility); + } + if (!com->info.rating) { + gf_dash_group_enum_descriptor(mpdin->dash, idx, GF_MPD_DESC_RATING, 0, NULL, NULL, &com->info.rating); + } + } return GF_OK; } /*we could get it from MPD*/ @@ -959,9 +1145,27 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) return GF_OK; case GF_NET_SERVICE_QUALITY_SWITCH: - gf_dash_switch_quality(mpdin->dash, com->switch_quality.up, mpdin->immediate_switch); + if (com->switch_quality.set_auto) { + gf_dash_set_automatic_switching(mpdin->dash, 1); + } else if (com->base.on_channel) { + segment_ifce = MPD_GetInputServiceForChannel(mpdin, com->base.on_channel); + if (!segment_ifce) return GF_NOT_SUPPORTED; + idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel); + if (idx < 0) return GF_BAD_PARAM; + + gf_dash_set_automatic_switching(mpdin->dash, 0); + gf_dash_group_select_quality(mpdin->dash, idx, com->switch_quality.ID); + } else { + gf_dash_switch_quality(mpdin->dash, com->switch_quality.up, mpdin->immediate_switch); + } return GF_OK; + case GF_NET_GET_TIMESHIFT: + com->timeshift.time = gf_dash_get_timeshift_buffer_pos(mpdin->dash); + return GF_OK; + case GF_NET_SERVICE_CAN_REVERSE_PLAYBACK: + return mpdin_dash_can_reverse_playback(mpdin); + default: break; } @@ -973,12 +1177,60 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) switch (com->command_type) { case GF_NET_CHAN_INTERACTIVE: - /* we are interactive (that's the whole point of MPD) */ + /* TODO - we are interactive if not live without timeshift */ return GF_OK; + case GF_NET_GET_STATS: + { + idx = MPD_GetGroupIndexForChannel(mpdin, com->base.on_channel); + if (idx < 0) return GF_BAD_PARAM; + com->net_stats.bw_down = 8 * gf_dash_group_get_download_rate(mpdin->dash, idx); + } + return GF_OK; + + case GF_NET_SERVICE_QUALITY_QUERY: + { + GF_DASHQualityInfo qinfo; + GF_Err e; + u32 count; + idx = MPD_GetGroupIndexForChannel(mpdin, com->quality_query.on_channel); + if (idx < 0) return GF_BAD_PARAM; + count = gf_dash_group_get_num_qualities(mpdin->dash, idx); + if (!com->quality_query.index) { + com->quality_query.index = count; + return GF_OK; + } + if (com->quality_query.index>count) return GF_BAD_PARAM; + + e = gf_dash_group_get_quality_info(mpdin->dash, idx, com->quality_query.index-1, &qinfo); + if (e) return e; + + com->quality_query.bandwidth = qinfo.bandwidth; + com->quality_query.ID = qinfo.ID; + com->quality_query.mime = qinfo.mime; + com->quality_query.codec = qinfo.codec; + com->quality_query.width = qinfo.width; + com->quality_query.height = qinfo.height; + com->quality_query.interlaced = qinfo.interlaced; + if (qinfo.fps_den) { + com->quality_query.fps = qinfo.fps_num; + com->quality_query.fps /= qinfo.fps_den; + } + com->quality_query.par_num = qinfo.par_num; + com->quality_query.par_den = qinfo.par_den; + com->quality_query.sample_rate = qinfo.sample_rate; + com->quality_query.nb_channels = qinfo.nb_channels; + com->quality_query.disabled = qinfo.disabled; + com->quality_query.is_selected = qinfo.is_selected; + com->quality_query.automatic = gf_dash_get_automatic_switching(mpdin->dash); + return GF_OK; + } + + break; + case GF_NET_CHAN_BUFFER: /*get it from MPD minBufferTime - if not in low latency mode, indicate the value given in MPD (not possible to fetch segments earlier) - to be more precise we should get the min segment duration for this group*/ - if (!mpdin->use_low_latency && (mpdin->buffer_mode>=MPDIN_BUFFER_MIN) ) { + if (/* !mpdin->use_low_latency && */ (mpdin->buffer_mode>=MPDIN_BUFFER_MIN)) { u32 max = gf_dash_get_min_buffer_time(mpdin->dash); if (max>com->buffer.max) com->buffer.max = max; @@ -990,77 +1242,94 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) return GF_OK; case GF_NET_CHAN_DURATION: - /* Ignore the duration given by the input service and use the one given in the MPD - Note: the duration of the initial segment will be 0 anyway (in MP4).*/ com->duration.duration = gf_dash_get_duration(mpdin->dash); + idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel); + if (idx >= 0) { + com->duration.time_shift_buffer = gf_dash_group_get_time_shift_buffer_depth(mpdin->dash, idx); + } return GF_OK; case GF_NET_CHAN_PLAY: - /*don't seek if this command is the first PLAY request of objects declared by the subservice - not long ago*/ - if (!com->play.initial_broadcast_play || (com->play.start_range>2.0) ) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Play command from terminal on channel %p on Service (%p)\n", com->base.on_channel, mpdin->service)); - idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel); + idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel); + if (idx < 0) return GF_BAD_PARAM; + + //adjust play range from media timestamps to MPD time + if (com->play.timestamp_based) { + u32 timescale; + u64 pto; + Double offset; + GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, idx); + + if (com->play.timestamp_based==1) { + gf_dash_group_get_presentation_time_offset(mpdin->dash, idx, &pto, ×cale); + offset = (Double) pto; + offset /= timescale; + com->play.start_range -= offset; + if (com->play.start_range < 0) com->play.start_range = 0; + } - if (!gf_dash_in_period_setup(mpdin->dash) && !com->play.dash_segment_switch && ! mpdin->in_seek) { - //Bool skip_seek; + group->is_timestamp_based = 1; + group->pto_setup = 0; + mpdin->media_start_range = com->play.start_range; + } else { + GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, idx); + group->is_timestamp_based = 0; + group->pto_setup = 0; + if (com->play.start_range<0) com->play.start_range = 0; + //in m3u8, we need also media start time for mapping time + if (gf_dash_is_m3u8(mpdin->dash)) + mpdin->media_start_range = com->play.start_range; + } - mpdin->in_seek = 1; + //we cannot handle seek request outside of a period being setup, this messes up our internal service setup + //we postpone the seek and will request it later on ... + if (gf_dash_in_period_setup(mpdin->dash)) { + u64 p_end = gf_dash_get_period_duration(mpdin->dash); + if (p_end) { + p_end += gf_dash_get_period_start(mpdin->dash); + if (p_end<1000*com->play.start_range) { + mpdin->seek_request = com->play.start_range; + return GF_OK; + } + } + } - /*if start range request is the same as previous one, don't process it - - this happens at period switch when new objects are declared*/ - //skip_seek = (mpdin->previous_start_range==com->play.start_range) ? 1 : 0; - mpdin->previous_start_range = com->play.start_range; - gf_dash_seek(mpdin->dash, com->play.start_range); - } - /*For MPEG-2 TS or formats not using Init Seg: since objects are declared and started once the first - segment is playing, we will stay in playback_start_range!=-1 until next segment (because we won't have a query_next), - which will prevent seeking until then ... we force a reset of playback_start_range to allow seeking asap*/ - else if (mpdin->in_seek && (com->play.start_range==0)) { -// mpdin->in_seek = 0; - } - else if (gf_dash_in_period_setup(mpdin->dash)) { - if (idx>=0) { - GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, idx); - group->is_timestamp_based = com->play.is_timestamp_based; - - if (com->play.is_timestamp_based) { - u32 timescale; - u64 pto; - Double offset; - gf_dash_group_get_presentation_time_offset(mpdin->dash, idx, &pto, ×cale); - offset = (Double) pto; - offset /= timescale; - com->play.start_range -= offset; - if (com->play.start_range < 0) com->play.start_range = 0; - } - } - gf_dash_seek(mpdin->dash, com->play.start_range); + gf_dash_set_speed(mpdin->dash, com->play.speed); - com->play.start_range = gf_dash_get_playback_start_range(mpdin->dash); - } + /*don't seek if this command is the first PLAY request of objects declared by the subservice, unless start range is not default one (0) */ + if (!mpdin->nb_playing && (!com->play.initial_broadcast_play || (com->play.start_range>1.0) )) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Play command from terminal on channel %p on Service (%p)\n", com->base.on_channel, mpdin->service)); - if (idx>=0) { - if (mpdin->in_seek) { - GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, idx); - group->in_seek = 1; - } - gf_dash_group_select(mpdin->dash, idx, GF_TRUE); - gf_dash_set_group_done(mpdin->dash, idx, 0); - com->play.dash_segment_switch = gf_dash_group_segment_switch_forced(mpdin->dash, idx); + if (com->play.end_range<=0) { + u32 ms = (u32) ( 1000 * (-com->play.end_range) ); + if (ms<1000) ms = 0; + gf_dash_set_timeshift(mpdin->dash, ms); } + gf_dash_seek(mpdin->dash, com->play.start_range); - /*don't forward commands, we are killing the service anyway ...*/ - if (gf_dash_get_period_switch_status(mpdin->dash) ) return GF_OK; - } else { - idx = MPD_GetGroupIndexForChannel(mpdin, com->play.on_channel); - if (idx>=0) - gf_dash_group_select(mpdin->dash, idx, GF_TRUE); + //to remove once we manage to keep the service alive + /*don't forward commands if a switch of period is to be scheduled, we are killing the service anyway ...*/ + if (gf_dash_get_period_switch_status(mpdin->dash)) return GF_OK; + } + + //check if current segment playback should be aborted + com->play.dash_segment_switch = gf_dash_group_segment_switch_forced(mpdin->dash, idx); + + gf_dash_group_select(mpdin->dash, idx, GF_TRUE); + gf_dash_set_group_done(mpdin->dash, (u32) idx, 0); + + //adjust start range from MPD time to media time + { + u64 pto; + u32 timescale; com->play.start_range = gf_dash_group_get_start_range(mpdin->dash, idx); + gf_dash_group_get_presentation_time_offset(mpdin->dash, idx, &pto, ×cale); + com->play.start_range += ((Double)pto) / timescale; } + mpdin->nb_playing++; return segment_ifce->ServiceCommand(segment_ifce, com); case GF_NET_CHAN_STOP: @@ -1069,6 +1338,8 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) if (idx>=0) { gf_dash_set_group_done(mpdin->dash, (u32) idx, 1); } + if (mpdin->nb_playing) + mpdin->nb_playing--; } return segment_ifce->ServiceCommand(segment_ifce, com); @@ -1078,6 +1349,7 @@ GF_Err MPD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) return segment_ifce->ServiceCommand(segment_ifce, com); case GF_NET_CHAN_SET_SPEED: + gf_dash_set_speed(mpdin->dash, com->play.speed); return segment_ifce->ServiceCommand(segment_ifce, com); default: @@ -1108,7 +1380,7 @@ Bool MPD_CanHandleURLInService(GF_InputService *plug, const char *url) */ GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Can Handle URL In Service (%p) request from terminal for %s\n", mpdin->service, url)); - if (!plug || !plug->priv) return GF_FALSE; + if (!plug || !plug->priv || !mpdin->dash) return GF_FALSE; if (gf_dash_get_url(mpdin->dash) && !strcmp(gf_dash_get_url(mpdin->dash) , url)) { return 1; } else { @@ -1170,7 +1442,7 @@ void ShutdownInterface(GF_BaseInterface *bi) if (bi->InterfaceType!=GF_NET_CLIENT_INTERFACE) return; mpdin = (GF_MPD_In*) ((GF_InputService*)bi)->priv; - assert( mpdin ); + assert(mpdin); if (mpdin->dash) gf_dash_del(mpdin->dash); @@ -1180,6 +1452,6 @@ void ShutdownInterface(GF_BaseInterface *bi) } -GPAC_MODULE_STATIC_DELARATION( mpd_in ) +GPAC_MODULE_STATIC_DECLARATION( mpd_in ) #endif //GPAC_DISABLE_DASH_CLIENT diff --git a/modules/mpegts_in/Makefile b/modules/mpegts_in/Makefile index c07a392..b4dc984 100644 --- a/modules/mpegts_in/Makefile +++ b/modules/mpegts_in/Makefile @@ -20,7 +20,7 @@ OBJS=mpegts_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_mpegts_in.$(DYN_LIB_SUFFIX) +LIB=gm_mpegts_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols mpegts_in.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mpegts_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mpegts_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif diff --git a/modules/mpegts_in/mpegts_in.c b/modules/mpegts_in/mpegts_in.c index 6966932..df731c3 100644 --- a/modules/mpegts_in/mpegts_in.c +++ b/modules/mpegts_in/mpegts_in.c @@ -33,6 +33,7 @@ #ifndef GPAC_DISABLE_MPEG2TS static const char * MIMES[] = { "video/mpeg-2", "video/mp2t", "video/mpeg", NULL}; +static const char * M2TS_EXTENSIONS = "ts m2t mts dmb trp"; //when regulating data rate from file using PCR, this is the maximum sleep we tolerate #define M2TS_MAX_SLEEP 200 @@ -81,6 +82,16 @@ typedef struct Bool flush_sdt; + u64 pcr_last; + u32 stb_at_last_pcr; + + u32 nb_paused; + Bool file_regulate; + u32 nb_playing; + u32 nb_prog_to_setup; + + u32 map_media_time_on_prog_id; + Double media_start_range; } M2TSIn; @@ -105,7 +116,7 @@ static Bool M2TS_CanHandleURL(GF_InputService *plug, const char *url) { int i=0; for (i = 0 ; NULL != MIMES[i]; i++) - if (gf_service_check_mime_register(plug, MIMES[i], "ts m2t dmb trp", "MPEG-2 TS", sExt)) + if (gf_service_check_mime_register(plug, MIMES[i], M2TS_EXTENSIONS, "MPEG-2 TS", sExt)) return 1; } return 0; @@ -224,9 +235,10 @@ static GF_ESD *MP2TS_GetESD(M2TSIn *m2ts, GF_M2TS_PES *stream, char *dsi, u32 ds NB: we removed "no file regulation" since we may get broken files where PMT declares an AAC stream but no AAC PID is in the MUX (filtered out). In this case, "no regulation" will make the entire TS to be read as fast as possible */ - if (m2ts->ts->file) - m2ts->ts->file_regulate = 2; - + if (m2ts->ts->file) { + m2ts->file_regulate = 2; + gf_m2ts_pause_demux(m2ts->ts, 0); + } gf_m2ts_set_pes_framing(stream, GF_M2TS_PES_FRAMING_DEFAULT); gf_odf_desc_del((GF_Descriptor *)esd); return NULL; @@ -339,8 +351,10 @@ static void MP2TS_SetupProgram(M2TSIn *m2ts, GF_M2TS_Program *prog, Bool regener #endif /*TS is a file, start regulation regardless of how the TS is access (with or without fragment URI)*/ - if (m2ts->ts->file || m2ts->ts->dnload) - m2ts->ts->file_regulate = 1; + if (m2ts->ts->file || m2ts->ts->dnload) { + m2ts->file_regulate = 1; + if (!m2ts->nb_playing) gf_m2ts_pause_demux(m2ts->ts, 1); + } for (i=0; i<count; i++) { GF_M2TS_ES *es = gf_list_get(prog->streams, i); @@ -362,7 +376,10 @@ static void MP2TS_SetupProgram(M2TSIn *m2ts, GF_M2TS_Program *prog, Bool regener gf_m2ts_set_pes_framing((GF_M2TS_PES *)es, GF_M2TS_PES_FRAMING_SKIP); if (!prog->pmt_iod && !no_declare) { - MP2TS_DeclareStream(m2ts, (GF_M2TS_PES *)es, NULL, 0); + if (! (es->flags & GF_M2TS_ES_ALREADY_DECLARED)) { + MP2TS_DeclareStream(m2ts, (GF_M2TS_PES *)es, NULL, 0); + es->flags |= GF_M2TS_ES_ALREADY_DECLARED; + } } /*if IOD, streams not declared through OD framework are refered to by pid:// scheme, and will be declared upon request by the terminal through GetServiceDesc*/ @@ -371,6 +388,11 @@ static void MP2TS_SetupProgram(M2TSIn *m2ts, GF_M2TS_Program *prog, Bool regener /*force scene regeneration*/ if (!prog->pmt_iod && regenerate_scene) gf_service_declare_media(m2ts->service, NULL, 0); + + + if (m2ts->nb_prog_to_setup) { + m2ts->nb_prog_to_setup--; + } } static void MP2TS_SendPacket(M2TSIn *m2ts, GF_M2TS_PES_PCK *pck) @@ -384,13 +406,6 @@ static void MP2TS_SendPacket(M2TSIn *m2ts, GF_M2TS_PES_PCK *pck) memset(&slh, 0, sizeof(GF_SLHeader)); slh.accessUnitStartFlag = (pck->flags & GF_M2TS_PES_PCK_AU_START) ? 1 : 0; if (slh.accessUnitStartFlag) { -#if 0 - slh.OCRflag = 1; - slh.m2ts_pcr = 1; - slh.objectClockReference = pck->stream->program->last_pcr_value; -#else - slh.OCRflag = 0; -#endif slh.compositionTimeStampFlag = 1; slh.compositionTimeStamp = pck->PTS; if (pck->DTS != pck->PTS) { @@ -400,6 +415,7 @@ static void MP2TS_SendPacket(M2TSIn *m2ts, GF_M2TS_PES_PCK *pck) slh.randomAccessPointFlag = (pck->flags & GF_M2TS_PES_PCK_RAP) ? 1 : 0; } gf_service_send_packet(m2ts->service, pck->stream->user, pck->data, pck->data_len, &slh, GF_OK); + } static GFINLINE void MP2TS_SendSLPacket(M2TSIn *m2ts, GF_M2TS_SL_PCK *pck) @@ -454,7 +470,8 @@ static void M2TS_FlushRequested(M2TSIn *m2ts) GF_M2TS_Program *ts_prog = gf_list_get(m2ts->ts->programs, j); //PMT not yet received, do not allow playback regulation if (!ts_prog->pcr_pid) { - m2ts->ts->file_regulate = 0; + m2ts->file_regulate = 0; + gf_m2ts_pause_demux(m2ts->ts, 0); gf_mx_v(m2ts->mx); return; } @@ -550,14 +567,14 @@ static void forward_m2ts_event(M2TSIn *m2ts, u32 evt_type, void *param) static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) { M2TSIn *m2ts = (M2TSIn *) ts->user; - + switch (evt_type) { case GF_M2TS_EVT_PAT_UPDATE: /* example code showing how to forward an event from MPEG-2 TS input service to GPAC user*/ #if 0 send_m2ts_event(m2ts, evt_type, param); #endif - break; + break; case GF_M2TS_EVT_AIT_FOUND: forward_m2ts_event(m2ts, evt_type, param); break; @@ -569,6 +586,9 @@ static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) } /* Send the TS to the a user if needed. Useful to check the number of received programs*/ forward_m2ts_event(m2ts, evt_type, param); + + m2ts->nb_prog_to_setup = gf_list_count(m2ts->ts->programs) ; + break; case GF_M2TS_EVT_DSMCC_FOUND: forward_m2ts_event(m2ts, evt_type, param); @@ -585,9 +605,12 @@ static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) forward_m2ts_event(m2ts, evt_type, param); break; case GF_M2TS_EVT_PMT_REPEAT: -// case GF_M2TS_EVT_PMT_UPDATE: M2TS_FlushRequested(m2ts); break; + case GF_M2TS_EVT_PMT_UPDATE: + MP2TS_SetupProgram(m2ts, param, GF_TRUE, GF_FALSE); + break; + case GF_M2TS_EVT_SDT_FOUND: case GF_M2TS_EVT_SDT_UPDATE: m2ts->flush_sdt = 1; @@ -622,8 +645,11 @@ static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) if (!pck->stream->first_dts) { gf_m2ts_set_pes_framing(pck->stream, GF_M2TS_PES_FRAMING_SKIP_NO_RESET); MP2TS_DeclareStream(m2ts, pck->stream, pck->data, pck->data_len); - if (ts->file || ts->dnload) - ts->file_regulate = 1; + if (ts->file || ts->dnload) { + m2ts->file_regulate = 1; + if (!m2ts->nb_playing) gf_m2ts_pause_demux(m2ts->ts, 1); + + } pck->stream->first_dts=1; /*force scene regeneration*/ gf_service_declare_media(m2ts->service, NULL, 0); @@ -631,31 +657,61 @@ static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) } break; case GF_M2TS_EVT_PES_PCR: + { + Bool discontinuity = ( ((GF_M2TS_PES_PCK *) param)->flags & GF_M2TS_PES_PCK_DISCONTINUITY) ? 1 : 0; /*send pcr*/ if (((GF_M2TS_PES_PCK *) param)->stream && ((GF_M2TS_PES_PCK *) param)->stream->user) { GF_SLHeader slh; memset(&slh, 0, sizeof(GF_SLHeader) ); slh.OCRflag = 1; - slh.m2ts_pcr = ( ((GF_M2TS_PES_PCK *) param)->flags & GF_M2TS_PES_PCK_DISCONTINUITY) ? 2 : 1; + slh.m2ts_pcr = discontinuity ? 2 : 1; slh.objectClockReference = ((GF_M2TS_PES_PCK *) param)->PTS; + + //check if our buffer level is low enough otherwise we would send the OCR_disc way too early + //we have to do this because the terminal doesn't "queue" clock discontinuities + if (m2ts->file_regulate && discontinuity) { + /*query buffer level, don't sleep if too low*/ + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.command_type = GF_NET_BUFFER_QUERY; + com.base.on_channel = NULL; + while (ts->run_state) { + gf_service_command(m2ts->service, &com, GF_OK); + if (!com.buffer.occupancy) { + break; + } + gf_sleep(1); + } + } + gf_service_send_packet(m2ts->service, ((GF_M2TS_PES_PCK *) param)->stream->user, NULL, 0, &slh, GF_OK); + + if ( m2ts->map_media_time_on_prog_id && !ts->start_range && (m2ts->map_media_time_on_prog_id==((GF_M2TS_PES_PCK *) param)->stream->program->number)) { + GF_NetworkCommand com; + memset(&com, 0, sizeof(com)); + com.command_type = GF_NET_CHAN_SET_MEDIA_TIME; + com.map_time.media_time = m2ts->media_start_range; + com.map_time.timestamp = slh.objectClockReference / 300; + com.base.on_channel = ((GF_M2TS_PES_PCK *) param)->stream->user; + gf_service_command(m2ts->service, &com, GF_OK); + m2ts->map_media_time_on_prog_id = 0; + m2ts->pcr_last = 0; + } } ((GF_M2TS_PES_PCK *) param)->stream->program->first_dts = 1; - if ( ((GF_M2TS_PES_PCK *) param)->flags & GF_M2TS_PES_PCK_DISCONTINUITY) { -#if 0 - if (ts->pcr_last) { - ts->pcr_last = ((GF_M2TS_PES_PCK *) param)->PTS; - ts->stb_at_last_pcr = gf_sys_clock(); + if (discontinuity) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] PCR discontinuity - switching from old STB "LLD" to new one "LLD"\n", m2ts->pcr_last, ((GF_M2TS_PES_PCK *) param)->PTS)); + if (m2ts->pcr_last) { + m2ts->pcr_last = ((GF_M2TS_PES_PCK *) param)->PTS; + m2ts->stb_at_last_pcr = gf_sys_clock(); } -#endif - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TS In] PCR discontinuity - switching from old STB "LLD" to new one "LLD"\n", ts->pcr_last, ((GF_M2TS_PES_PCK *) param)->PTS)); /*FIXME - we need to find a way to treat PCR discontinuities correctly while ignoring broken PCR discontinuities seen in many HLS solutions*/ return; } - if (ts->file_regulate) { + if (m2ts->file_regulate) { u64 pcr = ((GF_M2TS_PES_PCK *) param)->PTS; u32 stb = gf_sys_clock(); @@ -668,25 +724,25 @@ static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) } - if (ts->pcr_last) { + if (m2ts->pcr_last) { s32 diff; - if (pcr < ts->pcr_last) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TS In] PCR "LLU" less than previous PCR "LLU"\n", ((GF_M2TS_PES_PCK *) param)->PTS, ts->pcr_last)); - ts->pcr_last = pcr; - ts->stb_at_last_pcr = gf_sys_clock(); + if (pcr < m2ts->pcr_last) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] PCR "LLU" less than previous PCR "LLU"\n", ((GF_M2TS_PES_PCK *) param)->PTS, m2ts->pcr_last)); + m2ts->pcr_last = pcr; + m2ts->stb_at_last_pcr = gf_sys_clock(); diff = 0; } else { - u64 pcr_diff = (pcr - ts->pcr_last); + u64 pcr_diff = (pcr - m2ts->pcr_last); pcr_diff /= 27000; if (pcr_diff>1000) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] PCR diff too big: "LLU" ms - PCR "LLU" - previous PCR "LLU" - error in TS ?\n", pcr_diff, ((GF_M2TS_PES_PCK *) param)->PTS, ts->pcr_last)); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] PCR diff too big: "LLU" ms - PCR "LLU" - previous PCR "LLU" - error in TS ?\n", pcr_diff, ((GF_M2TS_PES_PCK *) param)->PTS, m2ts->pcr_last)); diff = 100; } else { - diff = (u32) pcr_diff - (stb - ts->stb_at_last_pcr); + diff = (u32) pcr_diff - (stb - m2ts->stb_at_last_pcr); } } if (diff<-400) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] Demux not going fast enough according to PCR (drift %d, pcr: "LLU", last pcr: "LLU")\n", diff, pcr, ts->pcr_last)); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] Demux not going fast enough according to PCR (drift %d, pcr: "LLU", last pcr: "LLU")\n", diff, pcr, m2ts->pcr_last)); } else if (diff>0) { u32 sleep_for=1; #ifndef GPAC_DISABLE_LOG @@ -719,17 +775,18 @@ static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param) GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TS In] Demux resume after %d ms - current buffer occupancy %d ms\n", sleep_for*nb_sleep, com.buffer.occupancy)); } #endif - ts->pcr_last = pcr; - ts->stb_at_last_pcr = gf_sys_clock(); + m2ts->pcr_last = pcr; + m2ts->stb_at_last_pcr = gf_sys_clock(); } else { - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TS In] Demux drift according to PCR (drift %d, pcr: "LLD", last pcr: "LLD")\n", diff, pcr, ts->pcr_last)); + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TS In] Demux drift according to PCR (drift %d, pcr: "LLD", last pcr: "LLD")\n", diff, pcr, m2ts->pcr_last)); } } else { - ts->pcr_last = pcr; - ts->stb_at_last_pcr = gf_sys_clock(); + m2ts->pcr_last = pcr; + m2ts->stb_at_last_pcr = gf_sys_clock(); } } - break; + } + break; case GF_M2TS_EVT_TDT: if (m2ts->hybrid_on) { u32 i, count; @@ -844,8 +901,8 @@ void m2ts_net_io(void *cbk, GF_NETIO_Parameter *param) } /*if asked to regulate, wait until we get a play request*/ - if (m2ts->ts->run_state && !m2ts->ts->nb_playing && (m2ts->ts->file_regulate==1)) { - while (m2ts->ts->run_state && !m2ts->ts->nb_playing && (m2ts->ts->file_regulate==1) ) { + if (m2ts->ts->paused) { + while (m2ts->ts->run_state && m2ts->ts->paused ) { gf_sleep(50); continue; } @@ -887,7 +944,13 @@ void m2ts_net_io(void *cbk, GF_NETIO_Parameter *param) 2: query next segment except currently downloading one 3: drop next segment */ -static GF_Err M2TS_QueryNextFile(void *udta, u32 query_type, const char **out_url, u64 *out_start_range, u64 *out_end_range, u32 *refresh_type) +typedef enum { + INIT_RANGE = 0, + NEXT_SEGMENT, + NEXT_SEGMENT_EXCEPT_DL, + DROP_NEXT_SEGMENT, +} DASHQueryType; +static GF_Err M2TS_QueryNextFile(void *udta, DASHQueryType query_type, const char **out_url, u64 *out_start_range, u64 *out_end_range, u32 *refresh_type) { GF_NetworkCommand param; GF_Err query_ret; @@ -900,9 +963,9 @@ static GF_Err M2TS_QueryNextFile(void *udta, u32 query_type, const char **out_ur if (out_end_range) *out_end_range = 0; memset(¶m, 0, sizeof(GF_NetworkCommand)); - param.command_type = (query_type==0) ? GF_NET_SERVICE_QUERY_INIT_RANGE : GF_NET_SERVICE_QUERY_NEXT; - param.url_query.drop_first_segment = (query_type==3) ? 1 : 0; - param.url_query.current_download = (query_type==2) ? 0 : 1; + param.command_type = (query_type == INIT_RANGE) ? GF_NET_SERVICE_QUERY_INIT_RANGE : GF_NET_SERVICE_QUERY_NEXT; + param.url_query.drop_first_segment = (query_type == DROP_NEXT_SEGMENT) ? 1 : 0; + param.url_query.current_download = (query_type == NEXT_SEGMENT_EXCEPT_DL) ? 0 : 1; //we are downloading the segment we play, don't delete it if (m2ts->in_segment_download) @@ -965,7 +1028,11 @@ void m2ts_flush_data(M2TSIn *m2ts, u32 flush_type) m2ts->has_pending_segments++; return; } - gf_mx_p(m2ts->mx); + if (! gf_mx_try_lock(m2ts->mx)) { + if (flush_type==GF_M2TS_PUSH_SEGMENT) + m2ts->has_pending_segments++; + return; + } m2ts->in_data_flush = 1; //check buffer level when start of new segment @@ -993,9 +1060,12 @@ void m2ts_flush_data(M2TSIn *m2ts, u32 flush_type) } } - e = M2TS_QueryNextFile(m2ts, (flush_type==GF_M2TS_FLUSH_DATA) ? 2 : 1, &url, &start_byterange, &end_byterange, &refresh_type); + e = M2TS_QueryNextFile(m2ts, (flush_type==GF_M2TS_FLUSH_DATA) ? NEXT_SEGMENT_EXCEPT_DL : NEXT_SEGMENT, &url, &start_byterange, &end_byterange, &refresh_type); if (e) { m2ts->in_data_flush = 0; + if (e==GF_EOS) { + gf_m2ts_demux_file(m2ts->ts, NULL, 0, 0, 0, 1); + } gf_mx_v(m2ts->mx); return; } @@ -1003,7 +1073,7 @@ void m2ts_flush_data(M2TSIn *m2ts, u32 flush_type) //done, drop segment if (!m2ts->in_segment_download) { - e = M2TS_QueryNextFile(m2ts, 3, &url, &start_byterange, &end_byterange, &refresh_type); + e = M2TS_QueryNextFile(m2ts, DROP_NEXT_SEGMENT, &url, &start_byterange, &end_byterange, &refresh_type); if (m2ts->has_pending_segments) m2ts->has_pending_segments--; @@ -1057,9 +1127,9 @@ static GF_Err M2TS_ConnectService(GF_InputService *plug, GF_ClientService *serv, u64 start_byterange, end_byterange; gf_mx_p(m2ts->mx); m2ts->in_data_flush = 1; - M2TS_QueryNextFile(m2ts, 0, NULL, &start_byterange, &end_byterange, NULL); + M2TS_QueryNextFile(m2ts, INIT_RANGE, NULL, &start_byterange, &end_byterange, NULL); e = gf_m2ts_demux_file(m2ts->ts, url, start_byterange, end_byterange, 0, 0); - M2TS_QueryNextFile(m2ts, 3, NULL, NULL, NULL, NULL); + M2TS_QueryNextFile(m2ts, DROP_NEXT_SEGMENT, NULL, NULL, NULL, NULL); m2ts->in_data_flush = 0; gf_mx_v(m2ts->mx); } else { @@ -1176,7 +1246,7 @@ static GF_Descriptor *M2TS_GetServiceDesc(GF_InputService *plug, u32 expect_type /* restart the thread if the same service is reused and if the previous thread terminated */ if (!plug->query_proxy) { if (m2ts->ts->run_state == 2) { - m2ts->ts->file_regulate = 0; + m2ts->file_regulate = 0; gf_m2ts_demuxer_play(m2ts->ts); } } @@ -1224,20 +1294,28 @@ static GF_Err M2TS_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, c } /* No IOD */ - if (ES_ID == 18) { + if ((ES_ID == 18) && (!m2ts->ts->ess[18] || !(m2ts->ts->ess[18]->flags & GF_M2TS_ES_IS_PES)) ) { e = GF_OK; /* 18 is the PID of EIT packets */ m2ts->eit_channel = channel; - } else if ((ES_ID<GF_M2TS_MAX_STREAMS) && m2ts->ts->ess[ES_ID]) { - GF_M2TS_PES *pes = (GF_M2TS_PES *)m2ts->ts->ess[ES_ID]; - if (pes->user) { - e = GF_SERVICE_ERROR; - } else { - pes->user = channel; - e = GF_OK; + } else if (ES_ID<GF_M2TS_MAX_STREAMS) { + u32 i, j, count, count2; + e = GF_SERVICE_ERROR; + count = gf_list_count(m2ts->ts->programs); + for (i=0; i<count; i++) { + GF_M2TS_Program *prog = gf_list_get(m2ts->ts->programs, i); + count2 = gf_list_count(prog->streams); + for (j=0; j<count2; j++) { + GF_M2TS_PES *pes = (GF_M2TS_PES *)gf_list_get(prog->streams, j); + if ((pes->pid == ES_ID) && !pes->user) { + pes->user = channel; + /*we try to play the highest layer*/ + if (pes->program->pid_playing < pes->pid) + pes->program->pid_playing = pes->pid; + e = GF_OK; + break; + } + } } - /*we try to play the highest layer*/ - if (pes->program->pid_playing < pes->pid) - pes->program->pid_playing = pes->pid; } } gf_service_connect_ack(m2ts->service, channel, e); @@ -1246,11 +1324,15 @@ static GF_Err M2TS_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, c static GF_M2TS_PES *M2TS_GetChannel(M2TSIn *m2ts, LPNETCHANNEL channel) { - u32 i; - for (i=0; i<GF_M2TS_MAX_STREAMS; i++) { - GF_M2TS_PES *pes = (GF_M2TS_PES *)m2ts->ts->ess[i]; - if (!pes || (pes->pid==pes->program->pmt_pid)) continue; - if (pes->user == channel) return pes; + u32 i, j, count, count2; + count = gf_list_count(m2ts->ts->programs); + for (i=0; i<count; i++) { + GF_M2TS_Program *prog = gf_list_get(m2ts->ts->programs, i); + count2 = gf_list_count(prog->streams); + for (j=0; j<count2; j++) { + GF_M2TS_PES *pes = (GF_M2TS_PES *)gf_list_get(prog->streams, j); + if (pes->user == channel) return pes; + } } return NULL; } @@ -1351,9 +1433,13 @@ static GF_Err M2TS_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) } //get info on the first running program if (com->command_type==GF_NET_SERVICE_INFO) { - pes = M2TS_GetFirstRunningChannel(m2ts); - if (pes) { - GF_M2TS_SDT *sdt = gf_m2ts_get_sdt_info(ts, pes->program->number); + u32 id = com->info.service_id; + if (!id) { + pes = M2TS_GetFirstRunningChannel(m2ts); + if (pes) id = pes->program->number; + } + if (id) { + GF_M2TS_SDT *sdt = gf_m2ts_get_sdt_info(ts, id); if (sdt) { com->info.name = sdt->service; com->info.provider = sdt->provider; @@ -1396,14 +1482,20 @@ static GF_Err M2TS_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_DEFAULT); GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSIn] Setting default reframing for PID %d\n", pes->pid)); /*this is a multplex, only trigger the play command for the first stream activated*/ - if (!ts->nb_playing) { + if (!m2ts->nb_playing) { if (ts->file) { ts->start_range = (u32) (com->play.start_range*1000); ts->end_range = (com->play.end_range>0) ? (u32) (com->play.end_range*1000) : 0; + m2ts->media_start_range = com->play.start_range; } + if (!m2ts->map_media_time_on_prog_id) + m2ts->map_media_time_on_prog_id = pes->program->number; - if (plug->query_proxy && ts->file) - ts->segment_switch = 1; + if (com->play.dash_segment_switch) { + /*this is used in case of HLS stream while we need update media start time for mapping*/ + m2ts->media_start_range = com->play.start_range; + gf_m2ts_abort_parsing(ts, GF_TRUE); + } /*start demuxer*/ if (!plug->query_proxy) { @@ -1412,7 +1504,15 @@ static GF_Err M2TS_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) } } } - ts->nb_playing++; + //remap media time for this program + else if (!m2ts->map_media_time_on_prog_id) { + m2ts->media_start_range = com->play.start_range; + m2ts->map_media_time_on_prog_id = pes->program->number; + } + if (!m2ts->nb_playing) { + gf_m2ts_pause_demux(ts, 0); + } + m2ts->nb_playing++; return GF_OK; case GF_NET_CHAN_STOP: pes = M2TS_GetChannel(m2ts, com->base.on_channel); @@ -1423,15 +1523,15 @@ static GF_Err M2TS_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) return GF_STREAM_NOT_FOUND; } /* In case of EOS, we may receive a stop command after no one is playing */ - if (ts->nb_playing) - ts->nb_playing--; + if (m2ts->nb_playing) + m2ts->nb_playing--; /*stop demuxer*/ if (!plug->query_proxy) { - if (!ts->nb_playing && (ts->run_state==1)) { + if (!m2ts->nb_playing && (ts->run_state==1) && !m2ts->nb_prog_to_setup) { ts->run_state=0; while (ts->run_state!=2) gf_sleep(2); if (gf_list_count(m2ts->ts->requested_progs)) { - ts->file_regulate = 0; + m2ts->file_regulate = 0; gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP); return gf_m2ts_demuxer_play(ts); } @@ -1450,6 +1550,23 @@ static GF_Err M2TS_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) pes->flags |= GF_M2TS_ES_SEND_REPEATED_SECTIONS; } return GF_OK; + case GF_NET_CHAN_PAUSE: + if (!m2ts->nb_paused) { + gf_m2ts_pause_demux(m2ts->ts, 1); + } + m2ts->nb_paused++; + return GF_OK; + case GF_NET_CHAN_RESUME: + if (m2ts->nb_paused) { + m2ts->nb_paused--; + if (!m2ts->nb_paused) { + m2ts->pcr_last = 0; + gf_m2ts_pause_demux(m2ts->ts, 0); + + } + } + return GF_OK; + default: return GF_OK; } @@ -1460,7 +1577,7 @@ static u32 M2TS_RegisterMimeTypes(const GF_InputService * service) { if (service == NULL) return 0; for (i = 0 ; MIMES[i]; i++) - gf_service_register_mime( service, MIMES[i], "ts m2t dmb", "MPEG-2 TS"); + gf_service_register_mime( service, MIMES[i], M2TS_EXTENSIONS, "MPEG-2 TS"); return i; } @@ -1476,7 +1593,7 @@ static void M2TS_GetNetworkType(GF_InputService *plug,M2TSIn *reader) } mcast_ifce = gf_modules_get_option((GF_BaseInterface*)plug, "Network", "DefaultMCastInterface"); - if(mcast_ifce) reader->ts->network_type = gf_strdup(mcast_ifce); + if(mcast_ifce) reader->ts->network_type = mcast_ifce; } GF_InputService *NewM2TSReader() @@ -1541,15 +1658,12 @@ void DeleteM2TSReader(void *ifce) } if (m2ts->network_buffer) gf_free(m2ts->network_buffer); + m2ts->network_buffer = NULL; - m2ts->network_buffer_size = 0; - m2ts->request_all_pids = 0; gf_m2ts_demux_del(m2ts->ts); - m2ts->ts = NULL; gf_mx_del(m2ts->mx); - m2ts->mx = NULL; gf_free(m2ts); - plug->priv = NULL; + gf_free(plug); } @@ -1593,4 +1707,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( mpegts_in ) +GPAC_MODULE_STATIC_DECLARATION( mpegts_in ) diff --git a/modules/mse_in/Makefile b/modules/mse_in/Makefile index dbf6249..afcbc58 100644 --- a/modules/mse_in/Makefile +++ b/modules/mse_in/Makefile @@ -34,14 +34,14 @@ OBJS=mse_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_mse_in.$(DYN_LIB_SUFFIX) +LIB=gm_mse_in$(DYN_LIB_SUFFIX) all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mse_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_mse_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/mse_in/mse_in.c b/modules/mse_in/mse_in.c index c60f644..ec2b9f2 100644 --- a/modules/mse_in/mse_in.c +++ b/modules/mse_in/mse_in.c @@ -27,6 +27,8 @@ #include <gpac/internal/terminal_dev.h> #include <gpac/html5_mse.h> +#ifndef GPAC_DISABLE_MSE + typedef struct __mse_module { GF_HTML_MediaSource *mediasource; @@ -315,11 +317,15 @@ static Bool MSE_CanHandleURLInService(GF_InputService *plug, const char *url) } } +#endif //GPAC_DISABLE_MSE + GPAC_MODULE_EXPORT const u32 *QueryInterfaces() { static u32 si [] = { +#ifndef GPAC_DISABLE_MSE GF_NET_CLIENT_INTERFACE, +#endif 0 }; return si; @@ -328,6 +334,9 @@ const u32 *QueryInterfaces() GPAC_MODULE_EXPORT GF_BaseInterface *LoadInterface(u32 InterfaceType) { +#ifdef GPAC_DISABLE_MSE + return NULL; +#else GF_MSE_In *msein; GF_InputService *plug; if (InterfaceType != GF_NET_CLIENT_INTERFACE) return NULL; @@ -349,10 +358,13 @@ GF_BaseInterface *LoadInterface(u32 InterfaceType) plug->priv = msein; msein->plug = plug; return (GF_BaseInterface *)plug; +#endif } + GPAC_MODULE_EXPORT void ShutdownInterface(GF_BaseInterface *bi) { +#ifndef GPAC_DISABLE_MSE GF_MSE_In *msein; if (bi->InterfaceType!=GF_NET_CLIENT_INTERFACE) return; @@ -361,6 +373,7 @@ void ShutdownInterface(GF_BaseInterface *bi) assert(msein); gf_free(msein); gf_free(bi); +#endif } -GPAC_MODULE_STATIC_DELARATION( mse_in ) +GPAC_MODULE_STATIC_DECLARATION( mse_in ) diff --git a/modules/odf_dec/Makefile b/modules/odf_dec/Makefile index 7746ada..7bba72f 100644 --- a/modules/odf_dec/Makefile +++ b/modules/odf_dec/Makefile @@ -19,7 +19,7 @@ OBJS= odf_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_odf_dec.$(DYN_LIB_SUFFIX) +LIB=gm_odf_dec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols odf_dec.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_odf_dec-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_odf_dec-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/odf_dec/odf_dec.c b/modules/odf_dec/odf_dec.c index 9558807..e682341 100644 --- a/modules/odf_dec/odf_dec.c +++ b/modules/odf_dec/odf_dec.c @@ -61,7 +61,9 @@ static void ODS_SetupOD(GF_Scene *scene, GF_ObjectDescriptor *od) odm->OD = od; odm->term = scene->root_od->term; odm->parentscene = scene; + gf_mx_p(scene->mx_resources); gf_list_add(scene->resources, odm); + gf_mx_v(scene->mx_resources); /*locate service owner*/ gf_odm_setup_object(odm, scene->root_od->net_service); @@ -318,4 +320,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } -GPAC_MODULE_STATIC_DELARATION( odf_dec ) +GPAC_MODULE_STATIC_DECLARATION( odf_dec ) diff --git a/modules/ogg/Makefile b/modules/ogg/Makefile index 8dc5272..67b37dc 100644 --- a/modules/ogg/Makefile +++ b/modules/ogg/Makefile @@ -56,7 +56,7 @@ LOCAL_LIB+=-L../../extra_lib/lib/gcc endif -LIB=gm_ogg_xiph.$(DYN_LIB_SUFFIX) +LIB=gm_ogg_xiph$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ogg.def endif diff --git a/modules/ogg/ogg_in.c b/modules/ogg/ogg_in.c index 50383b6..642260f 100644 --- a/modules/ogg/ogg_in.c +++ b/modules/ogg/ogg_in.c @@ -126,7 +126,7 @@ static Bool OGG_ReadPage(OGGReader *read, ogg_page *oggpage) else if (!read->is_live && !read->ogfile) { const char *szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) return 0; - read->ogfile = gf_f64_open((char *) szCache, "rb"); + read->ogfile = gf_fopen((char *) szCache, "rb"); if (!read->ogfile) return 0; } } @@ -567,10 +567,10 @@ static u32 OggDemux(void *par) u32 seek_to = 0; read->resync_stream = NULL; if (read->dur) seek_to = (u32) (read->file_size * (read->start_range/read->dur) * 0.6f); - if ((s32) seek_to > gf_f64_tell(read->ogfile) ) { - gf_f64_seek(read->ogfile, seek_to, SEEK_SET); + if ((s32) seek_to > gf_ftell(read->ogfile) ) { + gf_fseek(read->ogfile, seek_to, SEEK_SET); } else { - gf_f64_seek(read->ogfile, 0, SEEK_SET); + gf_fseek(read->ogfile, 0, SEEK_SET); } } } @@ -610,7 +610,7 @@ Bool OGG_CheckFile(OGGReader *read) ogg_stream_state os, the_os; u64 max_gran; Bool has_stream = 0; - gf_f64_seek(read->ogfile, 0, SEEK_SET); + gf_fseek(read->ogfile, 0, SEEK_SET); ogg_sync_init(&read->oy); memset(&the_info, 0, sizeof(OGGInfo)); @@ -644,8 +644,8 @@ Bool OGG_CheckFile(OGGReader *read) } } ogg_sync_clear(&read->oy); - read->file_size = gf_f64_tell(read->ogfile); - gf_f64_seek(read->ogfile, 0, SEEK_SET); + read->file_size = gf_ftell(read->ogfile); + gf_fseek(read->ogfile, 0, SEEK_SET); read->dur = 0; if (has_stream) { ogg_stream_clear(&the_os); @@ -768,14 +768,14 @@ static GF_Err OGG_ConnectService(GF_InputService *plug, GF_ClientService *serv, OGG_DownloadFile(plug, szURL); return GF_OK; } else { - read->ogfile = gf_f64_open(szURL, "rb"); + read->ogfile = gf_fopen(szURL, "rb"); if (!read->ogfile) { reply = GF_URL_ERROR; } else { reply = GF_OK; /*init ogg file in local mode*/ if (!OGG_CheckFile(read)) { - fclose(read->ogfile); + gf_fclose(read->ogfile); reply = GF_NON_COMPLIANT_BITSTREAM; } else { read->needs_connection = 1; @@ -799,7 +799,7 @@ static GF_Err OGG_CloseService(GF_InputService *plug) while (read->kill_demux!=2) gf_sleep(2); } - if (read->ogfile) fclose(read->ogfile); + if (read->ogfile) gf_fclose(read->ogfile); read->ogfile = NULL; if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; diff --git a/modules/ogg/ogg_load.c b/modules/ogg/ogg_load.c index 78bac81..0236825 100644 --- a/modules/ogg/ogg_load.c +++ b/modules/ogg/ogg_load.c @@ -159,4 +159,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ogg_in ) +GPAC_MODULE_STATIC_DECLARATION( ogg_in ) diff --git a/modules/opencv_is/Makefile b/modules/opencv_is/Makefile index 98b1340..e1cfb45 100644 --- a/modules/opencv_is/Makefile +++ b/modules/opencv_is/Makefile @@ -21,7 +21,7 @@ SRCS := $(OBJS:.o=.c) EXTRALIBS+=-lcv -lcvaux -lhighgui -lcxcore -LIB=gm_opencv.$(DYN_LIB_SUFFIX) +LIB=gm_opencv$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols opencv.def endif diff --git a/modules/opencv_is/opencv_is.c b/modules/opencv_is/opencv_is.c index 30b2e7d..34f2ff9 100644 --- a/modules/opencv_is/opencv_is.c +++ b/modules/opencv_is/opencv_is.c @@ -218,4 +218,4 @@ void ShutdownInterface(GF_BaseInterface *bi) } } -GPAC_MODULE_STATIC_DELARATION( opencv_is ) +GPAC_MODULE_STATIC_DECLARATION( opencv_is ) diff --git a/modules/openhevc_dec/Makefile b/modules/openhevc_dec/Makefile index 7cc1708..f76513f 100644 --- a/modules/openhevc_dec/Makefile +++ b/modules/openhevc_dec/Makefile @@ -25,7 +25,7 @@ OBJS= openhevc_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_openhevc_dec.$(DYN_LIB_SUFFIX) +LIB=gm_openhevc_dec$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/openhevc_dec/openhevc_dec.c b/modules/openhevc_dec/openhevc_dec.c index ea223cb..1dcef7c 100644 --- a/modules/openhevc_dec/openhevc_dec.c +++ b/modules/openhevc_dec/openhevc_dec.c @@ -68,6 +68,10 @@ typedef struct u32 frame_idx; Bool pack_mode; + u32 dec_frames; + + + FILE *raw_out; } HEVCDec; static GF_Err HEVC_ConfigurationScalableStream(HEVCDec *ctx, GF_ESD *esd) @@ -98,6 +102,9 @@ static GF_Err HEVC_ConfigurationScalableStream(HEVCDec *ctx, GF_ESD *esd) gf_bs_get_content(bs, &data, &data_len); gf_bs_del(bs); libOpenHevcDecode(ctx->openHevcHandle, (u8 *)data, data_len, 0); + + if (ctx->raw_out) fwrite((u8 *)data, 1, data_len, ctx->raw_out); + gf_free(data); libOpenHevcSetActiveDecoders(ctx->openHevcHandle, 2); @@ -164,7 +171,7 @@ static GF_Err HEVC_ConfigureStream(HEVCDec *ctx, GF_ESD *esd) if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { - libOpenHevcSetActiveDecoders(ctx->openHevcHandle, ctx->nb_layers); + libOpenHevcSetActiveDecoders(ctx->openHevcHandle, 1/*ctx->nb_layers*/); libOpenHevcSetViewLayers(ctx->openHevcHandle, ctx->nb_layers-1); libOpenHevcCopyExtraData(ctx->openHevcHandle, (u8 *) esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); @@ -187,7 +194,7 @@ static GF_Err HEVC_ConfigureStream(HEVCDec *ctx, GF_ESD *esd) ctx->conv_to_8bit = 1; ctx->pack_mode = 0; } - + ctx->dec_frames = 0; return GF_OK; } @@ -236,6 +243,11 @@ static GF_Err HEVC_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd) if (sOpt && !strcmp(sOpt, "yes") ) ctx->pack_mode = 1; else if (!sOpt) gf_modules_set_option((GF_BaseInterface *)ifcg, "OpenHEVC", "PackHFR", "no"); + if (!ctx->raw_out) { + sOpt = gf_modules_get_option((GF_BaseInterface *)ifcg, "OpenHEVC", "InputRipFile"); + if (sOpt) ctx->raw_out = fopen(sOpt, "wb"); + } + /*RTP case: configure enhancement now*/ if (esd->dependsOnESID) { @@ -252,10 +264,11 @@ static GF_Err HEVC_DetachStream(GF_BaseDecoder *ifcg, u16 ES_ID) { HEVCDec *ctx = (HEVCDec*) ifcg->privateStack; - if (ctx->is_init) { + if (ctx->openHevcHandle) { libOpenHevcClose(ctx->openHevcHandle); - ctx->is_init = GF_FALSE; + ctx->openHevcHandle = NULL; } + ctx->is_init = 0; ctx->width = ctx->height = ctx->out_size = 0; if (ctx->conv_buffer) gf_free(ctx->conv_buffer); ctx->conv_buffer = NULL; @@ -269,7 +282,7 @@ static GF_Err HEVC_GetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability *cap switch (capability->CapCode) { case GF_CODEC_RESILIENT: - capability->cap.valueInt = 2; + capability->cap.valueInt = 1; break; case GF_CODEC_WIDTH: capability->cap.valueInt = ctx->width; @@ -339,8 +352,14 @@ static GF_Err HEVC_SetCapabilities(GF_BaseDecoder *ifcg, GF_CodecCapability capa ctx->display_bpp = capability.cap.valueInt; return GF_OK; case GF_CODEC_WAIT_RAP: - if (ctx->openHevcHandle) - libOpenHevcFlush(ctx->openHevcHandle); + if (ctx->dec_frames) { + //quick hack, we have an issue with openHEVC resuming after being flushed ... + ctx->had_pic = 0; + libOpenHevcClose(ctx->openHevcHandle); + ctx->openHevcHandle = NULL; + ctx->is_init = GF_FALSE; + HEVC_ConfigureStream(ctx, ctx->esd); + } return GF_OK; case GF_CODEC_MEDIA_SWITCH_QUALITY: /*switch up*/ @@ -371,9 +390,9 @@ static GF_Err HEVC_flush_picture(HEVCDec *ctx, char *outBuffer, u32 *outBufferLe OpenHevc_Frame_cpy openHevcFrame; if (ctx->direct_output) - libOpenHevcGetPictureInfo(ctx->openHevcHandle, &openHevcFrame.frameInfo); - else - libOpenHevcGetPictureInfoCpy(ctx->openHevcHandle, &openHevcFrame.frameInfo); + libOpenHevcGetPictureInfo(ctx->openHevcHandle, &openHevcFrame.frameInfo); + else + libOpenHevcGetPictureInfoCpy(ctx->openHevcHandle, &openHevcFrame.frameInfo); a_w = openHevcFrame.frameInfo.nWidth; a_h = openHevcFrame.frameInfo.nHeight; @@ -414,7 +433,7 @@ static GF_Err HEVC_flush_picture(HEVCDec *ctx, char *outBuffer, u32 *outBufferLe *outBufferLength = ctx->out_size; ctx->has_pic = GF_TRUE; return GF_OK; - } + } if (ctx->conv_to_8bit) { OpenHevc_Frame openHevcFramePtr; @@ -435,7 +454,7 @@ static GF_Err HEVC_flush_picture(HEVCDec *ctx, char *outBuffer, u32 *outBufferLe } return GF_OK; } - + if (ctx->pack_mode) { OpenHevc_Frame openHFrame; u8 *pY, *pU, *pV; @@ -477,10 +496,10 @@ static GF_Err HEVC_flush_picture(HEVCDec *ctx, char *outBuffer, u32 *outBufferLe if (ctx->frame_idx==4) { *outBufferLength = 4 * ctx->out_size; ctx->frame_idx = 0; - } + } } return GF_OK; - } + } openHevcFrame.pvY = (void*) outBuffer; @@ -534,7 +553,11 @@ static GF_Err HEVC_ProcessData(GF_MediaDecoder *ifcg, ctx->had_pic = 0; return HEVC_flush_picture(ctx, outBuffer, outBufferLength, CTS); } + ctx->dec_frames++; got_pic = libOpenHevcDecode(ctx->openHevcHandle, (u8 *) inBuffer, inBufferLength, *CTS); + + if (ctx->raw_out) fwrite((u8 *) inBuffer, 1, inBufferLength, ctx->raw_out); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[HEVC Decoder] Decode CTS %d - size %d - got pic %d\n", *CTS, inBufferLength, got_pic)); if (got_pic>0) { e = HEVC_flush_picture(ctx, outBuffer, outBufferLength, CTS); @@ -620,6 +643,8 @@ GF_BaseDecoder *NewHEVCDec() void DeleteHEVCDec(GF_BaseDecoder *ifcg) { HEVCDec *ctx = (HEVCDec*) ifcg->privateStack; + if (ctx->raw_out) fclose(ctx->raw_out); + gf_free(ctx); gf_free(ifcg); } @@ -657,4 +682,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( openhevc ) +GPAC_MODULE_STATIC_DECLARATION( openhevc ) diff --git a/modules/opensvc_dec/Makefile b/modules/opensvc_dec/Makefile index 9451e5a..c7b16db 100644 --- a/modules/opensvc_dec/Makefile +++ b/modules/opensvc_dec/Makefile @@ -21,7 +21,7 @@ OBJS= opensvc_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_opensvc_dec.$(DYN_LIB_SUFFIX) +LIB=gm_opensvc_dec$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/opensvc_dec/opensvc_dec.c b/modules/opensvc_dec/opensvc_dec.c index 95e545c..302c2a6 100644 --- a/modules/opensvc_dec/opensvc_dec.c +++ b/modules/opensvc_dec/opensvc_dec.c @@ -251,10 +251,10 @@ static GF_Err OSVC_ProcessData(GF_MediaDecoder *ifcg, got_pic = 0; nalu_size = 0; ptr = (u8 *) inBuffer; + sc_size = 0; if (!ctx->nalu_size_length) { u32 size; - sc_size = 0; size = gf_media_nalu_next_start_code((u8 *) inBuffer, inBufferLength, &sc_size); if (sc_size) { ptr += size+sc_size; @@ -274,7 +274,6 @@ static GF_Err OSVC_ProcessData(GF_MediaDecoder *ifcg, } ptr += ctx->nalu_size_length; } else { - u32 sc_size; nalu_size = gf_media_nalu_next_start_code(ptr, inBufferLength, &sc_size); } #ifndef GPAC_DISABLE_LOG @@ -455,5 +454,5 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( opensvc ) +GPAC_MODULE_STATIC_DECLARATION( opensvc ) diff --git a/modules/osd/Makefile b/modules/osd/Makefile index a832691..ee60bc4 100644 --- a/modules/osd/Makefile +++ b/modules/osd/Makefile @@ -22,7 +22,7 @@ OBJS=osd.o SRCS := $(OBJS:.o=.c) -LIB=gm_osd.$(DYN_LIB_SUFFIX) +LIB=gm_osd$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/osd/osd.c b/modules/osd/osd.c index 619b620..7c4ffc1 100644 --- a/modules/osd/osd.c +++ b/modules/osd/osd.c @@ -46,6 +46,7 @@ typedef struct GF_SystemRTInfo rti; } GF_OSD; +#if 0 static GFINLINE GF_Node *create_node(GF_OSD *osd, u32 tag, GF_Node *par) { GF_Node *n = gf_node_new(osd->odm->subscene->graph, tag); @@ -58,6 +59,8 @@ static GFINLINE GF_Node *create_node(GF_OSD *osd, u32 tag, GF_Node *par) } return n; } +#endif + const char *osd_scene_graph = "\ EXTERNPROTO Untransform [\ exposedField MFNode children []\ @@ -210,7 +213,7 @@ static Bool osd_process(GF_TermExt *termext, u32 action, void *param) case GF_TERM_EXT_START: osd->term = (GF_Terminal *) param; opt = gf_modules_get_option((GF_BaseInterface*)termext, "OSD", "Enabled"); - if (opt && strcmp(opt, "yes")) return 0; + if (!opt || strcmp(opt, "yes")) return 0; /*load scene*/ if (! osd_load_scene(osd)) return 0; @@ -228,7 +231,7 @@ static Bool osd_process(GF_TermExt *termext, u32 action, void *param) return 1; case GF_TERM_EXT_STOP: - osd->text->string.vals[0] = NULL; + osd->text->string.vals[0] = NULL; /*remove scene to compositor*/ gf_sc_register_extra_graph(osd->term->compositor, osd->odm->subscene->graph, 1); gf_odm_disconnect(osd->odm, 1); @@ -300,4 +303,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( osd ) +GPAC_MODULE_STATIC_DECLARATION( osd ) diff --git a/modules/oss_audio/Makefile b/modules/oss_audio/Makefile index 567dc75..036e35a 100644 --- a/modules/oss_audio/Makefile +++ b/modules/oss_audio/Makefile @@ -29,7 +29,7 @@ OBJS= oss.o SRCS := $(OBJS:.o=.c) -LIB=gm_oss_audio.$(DYN_LIB_SUFFIX) +LIB=gm_oss_audio$(DYN_LIB_SUFFIX) all: $(LIB) @@ -37,7 +37,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac $(OSS_LDFLAGS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_oss_audio-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static $(OSS_LDFLAGS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_oss_audio-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static $(OSS_LDFLAGS) endif clean: diff --git a/modules/oss_audio/oss.c b/modules/oss_audio/oss.c index 2f68b62..d2307be 100644 --- a/modules/oss_audio/oss.c +++ b/modules/oss_audio/oss.c @@ -283,4 +283,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) DeleteOSSRender((GF_AudioOutput*)ifce); } -GPAC_MODULE_STATIC_DELARATION( oss ) +GPAC_MODULE_STATIC_DECLARATION( oss ) diff --git a/modules/platinum/GPACFileMediaServer.cpp b/modules/platinum/GPACFileMediaServer.cpp index 5b81ba9..3d2e611 100644 --- a/modules/platinum/GPACFileMediaServer.cpp +++ b/modules/platinum/GPACFileMediaServer.cpp @@ -112,7 +112,7 @@ GPAC_FileMediaServer::OnBrowseDirectChildren(PLT_ActionReference& actio } NPT_Result -GPAC_FileMediaServer::ServeFile(NPT_HttpRequest& request, +GPAC_FileMediaServer::ServeFile(const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, const NPT_String& _file_path) @@ -221,7 +221,8 @@ PLT_MediaObject* GPAC_FileMediaServer::BuildFromFilePath(const NPT_String& filepath, const PLT_HttpRequestContext &context, bool with_count, - bool keep_extension_in_title) + bool keep_extension_in_title, + bool allip) { return BuildFromFilePathAndHost(filepath, &context, with_count, keep_extension_in_title, NULL); @@ -406,9 +407,9 @@ NPT_String GPAC_FileMediaServer::GetResourceURI(const char *url, const char *for GPAC_MediaDirectory *dir; m_Directories.Get(i, dir); abs_url = gf_url_concatenate(dir->m_Path, url); - FILE *f = gf_f64_open(abs_url, "rt"); + FILE *f = gf_fopen(abs_url, "rt"); if (f) { - fclose(f); + gf_fclose(f); break; } gf_free((void*)abs_url); diff --git a/modules/platinum/GPACFileMediaServer.h b/modules/platinum/GPACFileMediaServer.h index 2ececfb..07a9f5e 100644 --- a/modules/platinum/GPACFileMediaServer.h +++ b/modules/platinum/GPACFileMediaServer.h @@ -108,7 +108,7 @@ protected: virtual NPT_Result GetFilePath(const char* object_id, NPT_String& filepath); - virtual NPT_Result ServeFile(NPT_HttpRequest& request, + virtual NPT_Result ServeFile(const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, const NPT_String& file_path); @@ -116,7 +116,8 @@ protected: virtual PLT_MediaObject* BuildFromFilePath(const NPT_String& filepath, const PLT_HttpRequestContext& context, bool with_count = true, - bool keep_extension_in_title = false); + bool keep_extension_in_title = false, + bool allip = false); PLT_MediaObject* BuildFromFilePathAndHost(const NPT_String& filepath, const PLT_HttpRequestContext *context = NULL, diff --git a/modules/platinum/GPACMediaRenderer.h b/modules/platinum/GPACMediaRenderer.h index b60c26b..1c14f98 100644 --- a/modules/platinum/GPACMediaRenderer.h +++ b/modules/platinum/GPACMediaRenderer.h @@ -93,8 +93,8 @@ private: GF_List *m_mediaHistoryList; u32 m_track_pos; - u32 m_volume; - Bool m_muted, m_l_muted, m_r_muted; +// u32 m_volume; +// Bool m_muted, m_l_muted, m_r_muted; NPT_String m_ip_src; Double m_Duration, m_Time; }; diff --git a/modules/platinum/GPACPlatinum.cpp b/modules/platinum/GPACPlatinum.cpp index 4f3c297..88ddea1 100644 --- a/modules/platinum/GPACPlatinum.cpp +++ b/modules/platinum/GPACPlatinum.cpp @@ -66,7 +66,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( platinum ) +GPAC_MODULE_STATIC_DECLARATION( platinum ) #ifdef __cplusplus } @@ -1617,7 +1617,7 @@ Bool GF_UPnP::LoadJS(GF_TermExtJS *param) if (!sep[1]) continue; strcpy(szFriendlyName, sep+1); - FILE *f = gf_f64_open(szFile, "rt"); + FILE *f = gf_fopen(szFile, "rt"); if (!f) continue; @@ -1625,9 +1625,9 @@ Bool GF_UPnP::LoadJS(GF_TermExtJS *param) device->js_source = szFile; jsval aval; - gf_f64_seek(f, 0, SEEK_END); - u32 size = (u32) gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + u32 size = (u32) gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); char *buf = (char*)gf_malloc(sizeof(char)*(size+1)); size = (u32) fread(buf, 1, size, f); buf[size]=0; @@ -1638,7 +1638,7 @@ Bool GF_UPnP::LoadJS(GF_TermExtJS *param) gf_list_del_item(m_Devices, device); delete device; } - fclose(f); + gf_fclose(f); gf_free(buf); } return GF_TRUE; @@ -1655,15 +1655,9 @@ static Bool upnp_process(GF_TermExt *termext, u32 action, void *param) case GF_TERM_EXT_START: opt = gf_modules_get_option((GF_BaseInterface*)termext, "UPnP", "Enabled"); if (!opt) { -#ifdef GPAC_CONFIG_DARWIN - opt = "no"; - GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[UPnP] Disabling UPnP - to enable it, modify section [UPnP] key \"Enabled\" in /Users/yourname/.gpacrc")); -#else -// opt = "yes"; //UPnP is disabkled by default on all platforms until we have a more stable state on load and exit opt = "no"; - GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[UPnP] Disabling UPnP - to enable it, modify section [UPnP] key \"Enabled\" in /Users/yourname/.gpacrc")); -#endif + GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[UPnP] Disabling UPnP - to enable it, modify section [UPnP] key \"Enabled\" in GPAC config file\n")); gf_modules_set_option((GF_BaseInterface*)termext, "UPnP", "Enabled", opt); } if (!strcmp(opt, "yes")) { diff --git a/modules/platinum/Makefile b/modules/platinum/Makefile index 087059c..6954bf1 100644 --- a/modules/platinum/Makefile +++ b/modules/platinum/Makefile @@ -32,7 +32,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_platinum.$(DYN_LIB_SUFFIX) +LIB=gm_platinum$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols platinum.def endif diff --git a/modules/pulseaudio/Makefile b/modules/pulseaudio/Makefile index bac49a3..d2a476e 100644 --- a/modules/pulseaudio/Makefile +++ b/modules/pulseaudio/Makefile @@ -20,7 +20,7 @@ OBJS= pulseaudio.o SRCS := $(OBJS:.o=.c) -LIB=gm_pulseaudio.$(DYN_LIB_SUFFIX) +LIB=gm_pulseaudio$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/pulseaudio/pulseaudio.c b/modules/pulseaudio/pulseaudio.c index d40ba40..0952d0b 100644 --- a/modules/pulseaudio/pulseaudio.c +++ b/modules/pulseaudio/pulseaudio.c @@ -343,4 +343,4 @@ void ShutdownInterface (GF_BaseInterface * ifce) DeletePulseAudioOutput ((GF_AudioOutput *) ifce); } -GPAC_MODULE_STATIC_DELARATION( pulseaudio ) +GPAC_MODULE_STATIC_DECLARATION( pulseaudio ) diff --git a/modules/raw_out/Makefile b/modules/raw_out/Makefile index f5256fd..e7b1a95 100644 --- a/modules/raw_out/Makefile +++ b/modules/raw_out/Makefile @@ -27,7 +27,7 @@ OBJS= raw_video.o SRCS := $(OBJS:.o=.c) -LIB=gm_raw_out.$(DYN_LIB_SUFFIX) +LIB=gm_raw_out$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols raw_out.def endif @@ -39,7 +39,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_raw_out-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_raw_out-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif diff --git a/modules/raw_out/raw_video.c b/modules/raw_out/raw_video.c index 896fdb5..79e2780 100644 --- a/modules/raw_out/raw_video.c +++ b/modules/raw_out/raw_video.c @@ -288,6 +288,6 @@ void ShutdownInterface(GF_BaseInterface *ifce) } -GPAC_MODULE_STATIC_DELARATION( raw_out ) +GPAC_MODULE_STATIC_DECLARATION( raw_out ) #endif diff --git a/modules/redirect_av/Makefile b/modules/redirect_av/Makefile index 0b52426..0867598 100644 --- a/modules/redirect_av/Makefile +++ b/modules/redirect_av/Makefile @@ -29,7 +29,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_redirect_av.$(DYN_LIB_SUFFIX) +LIB=gm_redirect_av$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/redirect_av/ffmpeg_ts_muxer.c b/modules/redirect_av/ffmpeg_ts_muxer.c index d265f5b..6cc6e4b 100644 --- a/modules/redirect_av/ffmpeg_ts_muxer.c +++ b/modules/redirect_av/ffmpeg_ts_muxer.c @@ -164,11 +164,11 @@ exit: } -#if LIBAVFORMAT_VERSION_MAJOR < 53 && LIBAVFORMAT_VERSION_MINOR < 45 +#if ((LIBAVFORMAT_VERSION_MAJOR == 52) && (LIBAVFORMAT_VERSION_MINOR <= 47)) || (LIBAVFORMAT_VERSION_MAJOR < 52) #define GUESS_FORMAT guess_stream_format #else #define GUESS_FORMAT av_guess_format -#endif /* LIBAVFORMAT_VERSION_MAJOR < 53 && LIBAVFORMAT_VERSION_MINOR < 45 */ +#endif GF_AbstractTSMuxer * ts_amux_new(GF_AVRedirect * avr, u32 videoBitrateInBitsPerSec, u32 width, u32 height, u32 audioBitRateInBitsPerSec) { GF_AbstractTSMuxer * ts = gf_malloc( sizeof(GF_AbstractTSMuxer)); diff --git a/modules/redirect_av/redirect_av.c b/modules/redirect_av/redirect_av.c index 3fb5874..452ac22 100644 --- a/modules/redirect_av/redirect_av.c +++ b/modules/redirect_av/redirect_av.c @@ -133,7 +133,7 @@ static u32 audio_encoding_thread_run(void *param) outBuff = gf_malloc(outBuffSize* sizeof(u8)); inBuff = NULL; #ifdef DUMP_MP3 - FILE * mp3 = fopen("/tmp/dump.mp3", "w"); + FILE * mp3 = gf_fopen("/tmp/dump.mp3", "w"); #endif /* DUMP_MP3 */ sendPts = 1; gf_sc_add_audio_listener ( avr->term->compositor, &avr->audio_listen ); @@ -212,7 +212,7 @@ exit: gf_free( outBuff ); #ifdef DUMP_MP3 if (mp3) - fclose(mp3); + gf_fclose(mp3); #endif /* DUMP_MP3 */ if (avr->term) gf_sc_remove_audio_listener ( avr->term->compositor, &avr->audio_listen ); @@ -848,4 +848,4 @@ void ShutdownInterface ( GF_BaseInterface *ifce ) } -GPAC_MODULE_STATIC_DELARATION( redirect_av ) +GPAC_MODULE_STATIC_DECLARATION( redirect_av ) diff --git a/modules/redirect_av/ts_muxer.h b/modules/redirect_av/ts_muxer.h index 4430e54..b8eff3e 100644 --- a/modules/redirect_av/ts_muxer.h +++ b/modules/redirect_av/ts_muxer.h @@ -32,7 +32,7 @@ #include <gpac/tools.h> #include <libavcodec/avcodec.h> -#if (LIBAVCODEC_VERSION_MAJOR <= 52) && (LIBAVCODEC_VERSION_MINOR <= 20) +#if ((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR <= 20)) || (LIBAVCODEC_VERSION_MAJOR < 52) #undef USE_AVCODEC2 #else #define USE_AVCODEC2 1 diff --git a/modules/rtp_in/Makefile b/modules/rtp_in/Makefile index c13d4e7..da865da 100644 --- a/modules/rtp_in/Makefile +++ b/modules/rtp_in/Makefile @@ -20,7 +20,7 @@ OBJS= rtp_in.o rtp_session.o rtp_signaling.o rtp_stream.o sdp_fetch.o sdp_load.o SRCS := $(OBJS:.o=.c) -LIB=gm_rtp_in.$(DYN_LIB_SUFFIX) +LIB=gm_rtp_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols rtp_in.def endif @@ -32,7 +32,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(EXTRALIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_rtp_in-static.$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_rtp_in-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static $(EXTRALIBS) endif diff --git a/modules/rtp_in/rtp_in.c b/modules/rtp_in/rtp_in.c index a93c55b..1c24d5c 100644 --- a/modules/rtp_in/rtp_in.c +++ b/modules/rtp_in/rtp_in.c @@ -232,9 +232,9 @@ GF_Err RP_ConnectServiceEx(GF_InputService *plug, GF_ClientService *serv, const if (!skip_migration) { session_cache = (char *) gf_modules_get_option((GF_BaseInterface *) plug, "Streaming", "SessionMigrationFile"); if (session_cache && session_cache[0]) { - FILE *f = gf_f64_open(session_cache, "rb"); + FILE *f = gf_fopen(session_cache, "rb"); if (f) { - fclose(f); + gf_fclose(f); GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTP] Restarting RTSP session from %s\n", session_cache)); RP_FetchSDP(priv, (char *) session_cache, NULL, (char *) url); return GF_OK; @@ -917,4 +917,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( rtp_in ) +GPAC_MODULE_STATIC_DECLARATION( rtp_in ) diff --git a/modules/rtp_in/rtp_in.h b/modules/rtp_in/rtp_in.h index 6e05923..52ff4ab 100644 --- a/modules/rtp_in/rtp_in.h +++ b/modules/rtp_in/rtp_in.h @@ -204,6 +204,8 @@ enum RTP_SET_TIME_RTP_SEEK, }; +#define RTCP_DEFAULT_TIMEOUT_MS 5000 + /*rtp channel*/ typedef struct { @@ -257,6 +259,8 @@ typedef struct u32 next_stream; u32 base_stream; + u32 rtcp_check_start; + u64 ts_offset; } RTPStream; diff --git a/modules/rtp_in/rtp_stream.c b/modules/rtp_in/rtp_stream.c index f9fca87..9745b10 100644 --- a/modules/rtp_in/rtp_stream.c +++ b/modules/rtp_in/rtp_stream.c @@ -117,11 +117,32 @@ static void rtp_sl_packet_cbk(void *udta, char *payload, u32 size, GF_SLHeader * u64 cts, dts; RTPStream *ch = (RTPStream *)udta; - if (!ch->rtcp_init) return; + if (!ch->rtcp_init) { + if (!ch->rtcp_check_start) { + ch->rtcp_check_start = gf_sys_clock(); + return; + } + else if (gf_sys_clock() - ch->rtcp_check_start <= RTCP_DEFAULT_TIMEOUT_MS) { + return; + } + GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] Timeout for RTCP: no SR recevied after %d ms - forcing playback, sync may be broken\n", RTCP_DEFAULT_TIMEOUT_MS)); + ch->rtcp_init = 1; + } + cts = hdr->compositionTimeStamp; dts = hdr->decodingTimeStamp; - hdr->compositionTimeStamp -= ch->ts_offset; - hdr->decodingTimeStamp -= ch->ts_offset; + + if (hdr->compositionTimeStamp < ch->ts_offset) { + hdr->compositionTimeStamp = hdr->decodingTimeStamp = 0; + hdr->seekFlag = 1; + } else { + hdr->seekFlag = 0; + hdr->compositionTimeStamp -= ch->ts_offset; + + if (hdr->decodingTimeStamp) { + hdr->decodingTimeStamp -= ch->ts_offset; + } + } if (ch->rtp_ch->packet_loss) e = GF_REMOTE_SERVICE_ERROR; @@ -472,22 +493,6 @@ void RP_ProcessRTCP(RTPStream *ch, char *pck, u32 size) ch->ts_offset = ch->rtp_ch->last_SR_rtp_time; ch->ts_offset -= (s64) (ntp_clock * ch->rtp_ch->TimeScale); -#if 0 - GF_NetworkCommand com; - memset(&com, 0, sizeof(com)); - com.command_type = GF_NET_CHAN_MAP_TIME; - com.base.on_channel = ch->channel; - com.map_time.media_time = ntp; - - if (com.map_time.media_time >= ch->owner->last_ntp) { - com.map_time.media_time -= ch->owner->last_ntp; - } else { - com.map_time.media_time = 0; - } - com.map_time.timestamp = ch->rtp_ch->last_SR_rtp_time; - com.map_time.reset_buffers = 1; - gf_service_command(ch->owner->service, &com, GF_OK); -#endif GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTCP] At %d Using Sender Report to map RTP TS %d to NTP clock %g - new TS offset "LLD" \n", gf_sys_clock(), ch->rtp_ch->last_SR_rtp_time, ntp_clock, ch->ts_offset diff --git a/modules/rtp_in/sdp_fetch.c b/modules/rtp_in/sdp_fetch.c index 062e4e8..5df6228 100644 --- a/modules/rtp_in/sdp_fetch.c +++ b/modules/rtp_in/sdp_fetch.c @@ -58,21 +58,21 @@ void RP_SDPFromFile(RTPClient *rtp, char *file_name, RTPStream *stream) sdp_buf = NULL; if (file_name && strstr(file_name, "file://")) file_name += strlen("file://"); - if (!file_name || !(_sdp = gf_f64_open(file_name, "rt")) ) { + if (!file_name || !(_sdp = gf_fopen(file_name, "rt")) ) { gf_service_connect_ack(rtp->service, NULL, GF_URL_ERROR); return; } - gf_f64_seek(_sdp, 0, SEEK_END); - sdp_size = (u32) gf_f64_tell(_sdp); - gf_f64_seek(_sdp, 0, SEEK_SET); + gf_fseek(_sdp, 0, SEEK_END); + sdp_size = (u32) gf_ftell(_sdp); + gf_fseek(_sdp, 0, SEEK_SET); sdp_buf = (char*)gf_malloc(sdp_size); if (1 > fread(sdp_buf, 1, sdp_size, _sdp)) { gf_service_connect_ack(rtp->service, NULL, GF_URL_ERROR); } else { RP_LoadSDP(rtp, sdp_buf, sdp_size, stream); } - fclose(_sdp); + gf_fclose(_sdp); gf_free(sdp_buf); } diff --git a/modules/rtp_in/sdp_load.c b/modules/rtp_in/sdp_load.c index 46b2482..c95eb8a 100644 --- a/modules/rtp_in/sdp_load.c +++ b/modules/rtp_in/sdp_load.c @@ -552,11 +552,11 @@ void RP_SaveSessionState(RTPClient *rtp) gf_service_download_del(rtp->dnload); rtp->dnload = NULL; } else { - FILE *f = gf_f64_open(opt, "wt"); + FILE *f = gf_fopen(opt, "wt"); if (f) { sdp_buf = rtp->session_state_data + strlen("data:application/sdp,"); gf_fwrite(sdp_buf, 1, strlen(sdp_buf), f); - fclose(f); + gf_fclose(f); } else { e = GF_IO_ERR; } diff --git a/modules/rvc_dec/Makefile b/modules/rvc_dec/Makefile index 586db43..5e3ad1e 100644 --- a/modules/rvc_dec/Makefile +++ b/modules/rvc_dec/Makefile @@ -21,7 +21,7 @@ OBJS= rvc_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_rvc_dec.$(DYN_LIB_SUFFIX) +LIB=gm_rvc_dec$(DYN_LIB_SUFFIX) all: $(LIB) diff --git a/modules/rvc_dec/rvc_dec.c b/modules/rvc_dec/rvc_dec.c index bbbcd70..e25cb4d 100644 --- a/modules/rvc_dec/rvc_dec.c +++ b/modules/rvc_dec/rvc_dec.c @@ -100,18 +100,18 @@ static GF_Err RVCD_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd) sprintf(opt, "Predefined_%d", esd->decoderConfig->predefined_rvc_config); path = (char *) gf_modules_get_option((GF_BaseInterface *)ifcg, "RVCDecoder", (const char *)opt); if (!opt) return GF_NOT_SUPPORTED; - f = fopen(path, "rt"); + f = gf_fopen(path, "rt"); if (!f) return GF_NOT_SUPPORTED; fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); XDF_doc = gf_malloc(sizeof(char)*(size+1)); if (!XDF_doc) { - fclose(f); + gf_fclose(f); return GF_OUT_OF_MEM; } fread(XDF_doc, 1, size, f); - fclose(f); + gf_fclose(f); XDF_doc[size]=0; } else { if (!esd->decoderConfig->rvc_config) @@ -496,4 +496,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } -GPAC_MODULE_STATIC_DELARATION( rev_dec ) +GPAC_MODULE_STATIC_DECLARATION( rev_dec ) diff --git a/modules/saf_in/Makefile b/modules/saf_in/Makefile index 383dd1b..69c7726 100644 --- a/modules/saf_in/Makefile +++ b/modules/saf_in/Makefile @@ -20,7 +20,7 @@ OBJS=saf_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_saf_in.$(DYN_LIB_SUFFIX) +LIB=gm_saf_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols saf_in.def endif @@ -32,7 +32,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_dummy_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_dummy_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif diff --git a/modules/saf_in/saf_in.c b/modules/saf_in/saf_in.c index ad0e5db..29d0d30 100644 --- a/modules/saf_in/saf_in.c +++ b/modules/saf_in/saf_in.c @@ -312,7 +312,7 @@ u32 SAF_Run(void *_p) par.msg_type = GF_NETIO_DATA_EXCHANGE; par.data = data; - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); read->saf_size=0; read->run_state = 1; while (read->run_state && !feof(read->stream) ) { @@ -350,7 +350,7 @@ static void SAF_CheckFile(SAFIn *read) u32 nb_streams, i, cts, au_size, au_type, stream_id, ts_res; GF_BitStream *bs; StreamInfo si[1024]; - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); bs = gf_bs_from_file(read->stream, GF_BITSTREAM_READ); nb_streams=0; @@ -384,7 +384,7 @@ static void SAF_CheckFile(SAFIn *read) gf_bs_skip_bytes(bs, au_size); } gf_bs_del(bs); - gf_f64_seek(read->stream, 0, SEEK_SET); + gf_fseek(read->stream, 0, SEEK_SET); } static GF_Err SAF_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url) @@ -412,7 +412,7 @@ static GF_Err SAF_ConnectService(GF_InputService *plug, GF_ClientService *serv, return GF_OK; } - read->stream = gf_f64_open(szURL, "rb"); + read->stream = gf_fopen(szURL, "rb"); if (!read->stream) { gf_service_connect_ack(serv, NULL, GF_URL_ERROR); return GF_OK; @@ -437,7 +437,7 @@ static GF_Err SAF_CloseService(GF_InputService *plug) read->th = NULL; } - if (read->stream) fclose(read->stream); + if (read->stream) gf_fclose(read->stream); read->stream = NULL; if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; @@ -622,4 +622,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( saf_in ) +GPAC_MODULE_STATIC_DECLARATION( saf_in ) diff --git a/modules/sdl_out/Makefile b/modules/sdl_out/Makefile index f6a5e1a..fd1b166 100644 --- a/modules/sdl_out/Makefile +++ b/modules/sdl_out/Makefile @@ -21,7 +21,7 @@ OBJS=sdl_out.o audio.o video.o SRCS := $(OBJS:.o=.c) -LIB=gm_sdl_out.$(DYN_LIB_SUFFIX) +LIB=gm_sdl_out$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols sdl_out.def endif diff --git a/modules/sdl_out/sdl_out.c b/modules/sdl_out/sdl_out.c index 4a518b5..69f4a33 100644 --- a/modules/sdl_out/sdl_out.c +++ b/modules/sdl_out/sdl_out.c @@ -93,4 +93,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( sdl_out ) +GPAC_MODULE_STATIC_DECLARATION( sdl_out ) diff --git a/modules/sdl_out/sdl_out.h b/modules/sdl_out/sdl_out.h index 744446c..cd8a64d 100644 --- a/modules/sdl_out/sdl_out.h +++ b/modules/sdl_out/sdl_out.h @@ -68,14 +68,21 @@ typedef struct #if SDL_VERSION_ATLEAST(2,0,0) - SDL_GLContext gl_context; + char szCaption[100]; + Bool enable_defer_mode; + Bool needs_clear; + Bool needs_bb_flush; + Bool needs_bb_grab; + + SDL_GLContext gl_context; SDL_Renderer *renderer; SDL_Window *screen; - SDL_Surface *back_buffer; - SDL_Surface *pool_rgb, *pool_rgba; - SDL_Texture *yuv_texture; - char szCaption[100]; + SDL_Texture *tx_back_buffer; + char *back_buffer_pixels; + + SDL_Texture *pool_rgb, *pool_rgba, *pool_yuv; + #else SDL_Surface *screen; SDL_Surface *back_buffer; diff --git a/modules/sdl_out/video.c b/modules/sdl_out/video.c index e6cde15..e307f31 100644 --- a/modules/sdl_out/video.c +++ b/modules/sdl_out/video.c @@ -26,8 +26,6 @@ #include "sdl_out.h" #include <gpac/user.h> -//#include "unicode.h" - #ifdef WIN32 #include <windows.h> #endif @@ -596,14 +594,19 @@ void SDLVid_SetHack(void *os_handle, Bool set_on) static void SDLVid_DestroyObjects(SDLVidCtx *ctx) { #if SDL_VERSION_ATLEAST(2,0,0) - if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer); - ctx->back_buffer = NULL; - if (ctx->pool_rgb) SDL_FreeSurface(ctx->pool_rgb); - ctx->pool_rgb = NULL; - if (ctx->pool_rgba) SDL_FreeSurface(ctx->pool_rgba); + + if (ctx->pool_rgb) SDL_DestroyTexture(ctx->pool_rgb); + ctx->pool_rgb = NULL; + if (ctx->pool_rgba) SDL_DestroyTexture(ctx->pool_rgba); ctx->pool_rgba = NULL; - SDL_DestroyTexture(ctx->yuv_texture); - ctx->yuv_texture = NULL; + if (ctx->pool_yuv) SDL_DestroyTexture(ctx->pool_yuv); + ctx->pool_yuv = NULL; + + if (ctx->tx_back_buffer) SDL_DestroyTexture(ctx->tx_back_buffer); + ctx->tx_back_buffer = NULL; + if (ctx->back_buffer_pixels) gf_free(ctx->back_buffer_pixels); + ctx->back_buffer_pixels = NULL; + #else if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer); ctx->back_buffer = NULL; @@ -688,8 +691,9 @@ GF_Err SDLVid_ResizeWindow(GF_VideoOutput *dr, u32 width, u32 height) assert(width); assert(height); #if SDL_VERSION_ATLEAST(2,0,0) + if (!ctx->screen) { - if (!(ctx->screen = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags))) { + if (!(ctx->screen = SDL_CreateWindow("", 0, 0, width, height, flags))) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError())); gf_mx_v(ctx->evt_mx); return GF_IO_ERR; @@ -731,21 +735,37 @@ GF_Err SDLVid_ResizeWindow(GF_VideoOutput *dr, u32 width, u32 height) flags = SDL_FULLSCREEN_FLAGS; //SDL readme says it would make us faster SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 1); #else - flags = SDL_WINDOW_FLAGS; + flags = SDL_WINDOW_FLAGS | SDL_WINDOW_RESIZABLE; + + if (ctx->os_handle) flags &= ~SDL_WINDOW_RESIZABLE; + #endif if (ctx->os_handle) flags &= ~SDL_WINDOW_RESIZABLE; #if SDL_VERSION_ATLEAST(2,0,0) + +#ifdef GPAC_IPHONE + //still some issues with render to tager and landscape orientation, we need to reset everything ... + if (ctx->enable_defer_mode) { + if (ctx->renderer) SDL_DestroyRenderer(ctx->renderer); + ctx->renderer=NULL; + if (ctx->screen) SDL_DestroyWindow(ctx->screen); + ctx->screen=NULL; + } +#endif + if (!ctx->screen) { - if (!(ctx->screen = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags))) { + ctx->screen = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); + + if (!ctx->screen) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Cannot create window: %s\n", SDL_GetError())); gf_mx_v(ctx->evt_mx); return GF_IO_ERR; } GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL] Window created\n")); - } + SDL_RaiseWindow(ctx->screen); + } if ( !ctx->renderer ) { u32 flags = SDL_RENDERER_ACCELERATED; const char *opt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "DisableVSync"); @@ -759,7 +779,12 @@ GF_Err SDLVid_ResizeWindow(GF_VideoOutput *dr, u32 width, u32 height) return GF_IO_ERR; } } - SDL_SetWindowSize(ctx->screen, width, height); +#ifndef GPAC_IPHONE + SDL_SetWindowSize(ctx->screen, width, height); +#endif + SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255); + SDL_RenderClear(ctx->renderer); + #else ctx->screen = SDL_SetVideoMode(width, height, 0, flags); #endif @@ -940,8 +965,10 @@ Bool SDLVid_ProcessMessageQueue(SDLVidCtx *ctx, GF_VideoOutput *dr) u32 ucs4_len; assert( len < 5 ); ucs4_len = utf8_to_ucs4 (&(gpac_evt.character.unicode_char), len, (unsigned char*)(sdl_evt.text.text)); - gpac_evt.type = GF_EVENT_TEXTINPUT; - dr->on_event(dr->evt_cbk_hdl, &gpac_evt); + if (ucs4_len) { + gpac_evt.type = GF_EVENT_TEXTINPUT; + dr->on_event(dr->evt_cbk_hdl, &gpac_evt); + } break; } #endif /* SDL_TEXTINPUTEVENT_TEXT_SIZE */ @@ -1206,13 +1233,14 @@ GF_Err SDLVid_SetFullScreen(GF_VideoOutput *dr, Bool bFullScreenOn, u32 *screen_ #endif if (ctx->fullscreen) { - u32 flags; +#if ! ( SDL_VERSION_ATLEAST(2,0,0) ) + u32 flags = (ctx->output_3d_type==1) ? SDL_GL_FULLSCREEN_FLAGS : SDL_FULLSCREEN_FLAGS; +#endif Bool switch_res = GF_FALSE; const char *sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "Video", "SwitchResolution"); if (sOpt && !stricmp(sOpt, "yes")) switch_res = 1; if (!dr->max_screen_width || !dr->max_screen_height) switch_res = 1; - flags = (ctx->output_3d_type==1) ? SDL_GL_FULLSCREEN_FLAGS : SDL_FULLSCREEN_FLAGS; ctx->store_width = *screen_width; ctx->store_height = *screen_height; if (switch_res) { @@ -1253,7 +1281,7 @@ GF_Err SDLVid_SetFullScreen(GF_VideoOutput *dr, Bool bFullScreenOn, u32 *screen_ } #if SDL_VERSION_ATLEAST(2,0,0) SDL_SetWindowDisplayMode(ctx->screen, &goodMode); - SDL_SetWindowFullscreen(ctx->screen, SDL_TRUE); + SDL_SetWindowFullscreen(ctx->screen, SDL_WINDOW_FULLSCREEN_DESKTOP); #else ctx->screen = SDL_SetVideoMode(ctx->fs_width, ctx->fs_height, pref_bpp, flags); #endif @@ -1271,12 +1299,12 @@ GF_Err SDLVid_SetFullScreen(GF_VideoOutput *dr, Bool bFullScreenOn, u32 *screen_ } } else { #if SDL_VERSION_ATLEAST(2,0,0) - SDL_SetWindowFullscreen(ctx->screen, SDL_FALSE); + SDL_SetWindowFullscreen(ctx->screen, 0); #endif SDLVid_ResizeWindow(dr, ctx->store_width, ctx->store_height); *screen_width = ctx->store_width; *screen_height = ctx->store_height; - } + } gf_mx_v(ctx->evt_mx); if (!ctx->screen) return GF_IO_ERR; return GF_OK; @@ -1287,9 +1315,7 @@ GF_Err SDLVid_SetBackbufferSize(GF_VideoOutput *dr, u32 newWidth, u32 newHeight, const char *opt; SDLVID(); #if SDL_VERSION_ATLEAST(2,0,0) - SDL_DisplayMode disp; - s32 bpp; - u32 Rmask, Gmask, Bmask, Amask; + #else u32 col; #endif @@ -1307,29 +1333,35 @@ GF_Err SDLVid_SetBackbufferSize(GF_VideoOutput *dr, u32 newWidth, u32 newHeight, /*clear screen*/ #if SDL_VERSION_ATLEAST(2,0,0) - SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255); - SDL_RenderClear(ctx->renderer); - SDL_RenderPresent(ctx->renderer); + + + if (ctx->tx_back_buffer) SDL_DestroyTexture(ctx->tx_back_buffer); + if (ctx->back_buffer_pixels) gf_free(ctx->back_buffer_pixels); + + ctx->tx_back_buffer = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, newWidth, newHeight); + ctx->back_buffer_pixels = gf_malloc(sizeof(char)*3*newWidth*newHeight); + + + SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 255); + SDL_RenderClear(ctx->renderer); + SDL_RenderPresent(ctx->renderer); + #else col = SDL_MapRGB(ctx->screen->format, 0, 0, 0); SDL_FillRect(ctx->screen, NULL, col); SDL_Flip(ctx->screen); -#endif - if (ctx->back_buffer && ((u32) ctx->back_buffer->w==newWidth) && ((u32) ctx->back_buffer->h==newHeight)) { - return GF_OK; - } - if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer); -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_GetWindowDisplayMode(ctx->screen, &disp); - SDL_PixelFormatEnumToMasks(disp.format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); - ctx->back_buffer = SDL_CreateRGBSurface(0, newWidth, newHeight, bpp, Rmask, Gmask, Bmask, 0); -#else - ctx->back_buffer = SDL_CreateRGBSurface(ctx->use_systems_memory ? SDL_SWSURFACE : SDL_HWSURFACE, newWidth, newHeight, ctx->screen->format->BitsPerPixel, ctx->screen->format->Rmask, ctx->screen->format->Gmask, ctx->screen->format->Bmask, 0); + if (ctx->back_buffer && ((u32) ctx->back_buffer->w==newWidth) && ((u32) ctx->back_buffer->h==newHeight)) { + return GF_OK; + } + if (ctx->back_buffer) SDL_FreeSurface(ctx->back_buffer); + + ctx->back_buffer = SDL_CreateRGBSurface(ctx->use_systems_memory ? SDL_SWSURFACE : SDL_HWSURFACE, newWidth, newHeight, ctx->screen->format->BitsPerPixel, ctx->screen->format->Rmask, ctx->screen->format->Gmask, ctx->screen->format->Bmask, 0); + + if (!ctx->back_buffer) return GF_IO_ERR; #endif ctx->width = newWidth; ctx->height = newHeight; - if (!ctx->back_buffer) return GF_IO_ERR; return GF_OK; } @@ -1356,9 +1388,36 @@ u32 SDLVid_MapPixelFormat(SDL_PixelFormat *format, Bool force_alpha) } } +#if SDL_VERSION_ATLEAST(2,0,0) +static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_info, Bool do_lock) +{ + SDLVID(); + + if (do_lock) { + memset(video_info, 0, sizeof(GF_VideoSurface)); + video_info->width = ctx->width; + video_info->height = ctx->height; + video_info->pitch_x = 0; + video_info->pitch_y = ctx->width*3; + video_info->video_buffer = ctx->back_buffer_pixels; + video_info->pixel_format = GF_PIXEL_RGB_24; + video_info->is_hardware_memory = 0; + if (ctx->needs_bb_grab) { + SDL_RenderReadPixels(ctx->renderer, NULL, SDL_PIXELFORMAT_RGB24, video_info->video_buffer, video_info->pitch_y); + ctx->needs_bb_grab = 0; + } + } else { + SDL_UpdateTexture(ctx->tx_back_buffer, NULL, video_info->video_buffer, video_info->pitch_y); + SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); + } + return GF_OK; +} + +#else static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_info, Bool do_lock) { SDLVID(); + if (!ctx->back_buffer) return GF_BAD_PARAM; if (do_lock) { if (!video_info) return GF_BAD_PARAM; @@ -1374,8 +1433,47 @@ static GF_Err SDLVid_LockBackBuffer(GF_VideoOutput *dr, GF_VideoSurface *video_i } else { SDL_UnlockSurface(ctx->back_buffer); } - return GF_OK; + return GF_OK; } +#endif + + +#if SDL_VERSION_ATLEAST(2,0,0) + +static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) +{ + SDLVID(); + /*if resizing don't process otherwise we may deadlock*/ + if (!ctx->screen) return GF_OK; + + //GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Flush\n")); + + if (ctx->output_3d_type==1) { + SDL_GL_SwapWindow(ctx->screen); + return GF_OK; + } + + if (ctx->enable_defer_mode) { + if (ctx->needs_bb_flush) { + SDL_UpdateTexture(ctx->tx_back_buffer, NULL, ctx->back_buffer_pixels, 3*ctx->width); + SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); + } + SDL_RenderReadPixels(ctx->renderer, NULL, SDL_PIXELFORMAT_RGB24, ctx->back_buffer_pixels, 3*ctx->width); + ctx->needs_bb_grab = 0; + ctx->needs_bb_flush = 0; + SDL_RenderPresent(ctx->renderer); + //push back texture after SDL flip + SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); + } else { + ctx->needs_clear = 1; + SDL_RenderPresent(ctx->renderer); + } + + + return GF_OK; +} + +#else static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) { @@ -1387,20 +1485,13 @@ static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) //GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Flush\n")); if (ctx->output_3d_type==1) { -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_GL_SwapWindow(ctx->screen); -#else SDL_GL_SwapBuffers(); -#endif return GF_OK; } if (!ctx->back_buffer) return GF_BAD_PARAM; - + if ((dest->w != (u32) ctx->back_buffer->w) || (dest->h != (u32) ctx->back_buffer->h)) { GF_VideoSurface src, dst; -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_Surface* wndSurface; -#endif SDL_LockSurface(ctx->back_buffer); memset(&src, 0, sizeof(GF_VideoSurface)); @@ -1411,17 +1502,6 @@ static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) src.pixel_format = SDLVid_MapPixelFormat(ctx->back_buffer->format, ctx->force_alpha); src.video_buffer = (char*)ctx->back_buffer->pixels; -#if SDL_VERSION_ATLEAST(2,0,0) - wndSurface = SDL_GetWindowSurface(ctx->screen); - SDL_LockSurface(wndSurface); - memset(&dst, 0, sizeof(GF_VideoSurface)); - dst.height = wndSurface->h; - dst.width = wndSurface->w; - dst.pitch_x = 0; - dst.pitch_y = wndSurface->pitch; - dst.pixel_format = SDLVid_MapPixelFormat(wndSurface->format, GF_FALSE); - dst.video_buffer = (char*)wndSurface->pixels; -#else SDL_LockSurface(ctx->screen); dst.height = ctx->screen->h; dst.width = ctx->screen->w; @@ -1429,47 +1509,27 @@ static GF_Err SDLVid_Flush(GF_VideoOutput *dr, GF_Window *dest) dst.pitch_y = ctx->screen->pitch; dst.pixel_format = SDLVid_MapPixelFormat(ctx->screen->format, 0); dst.video_buffer = ctx->screen->pixels; -#endif gf_stretch_bits(&dst, &src, dest, NULL, 0xFF, 0, NULL, NULL); -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_UnlockSurface(wndSurface); -#else SDL_UnlockSurface(ctx->screen); -#endif SDL_UnlockSurface(ctx->back_buffer); } else { -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_Texture* tx; -#endif rc.x = dest->x; rc.y = dest->y; rc.w = dest->w; rc.h = dest->h; -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_ClearError(); - if (!(tx = SDL_CreateTextureFromSurface(ctx->renderer, ctx->back_buffer))) { - GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("SDL_GetWindowSurface failed: %s\n", SDL_GetError())); - SDL_ClearError(); - } - SDL_RenderCopy(ctx->renderer, tx, NULL, &rc); - SDL_DestroyTexture(tx); -#else SDL_BlitSurface(ctx->back_buffer, NULL, ctx->screen, &rc); -#endif } -#if SDL_VERSION_ATLEAST(2,0,0) - SDL_RenderPresent(ctx->renderer); -#else SDL_Flip(ctx->screen); -#endif return GF_OK; } +#endif static void SDLVid_SetCursor(GF_VideoOutput *dr, u32 cursor_type) { - SDLVID(); +#ifndef GPAC_IPHONE + SDLVID(); switch (cursor_type) { case GF_CURSOR_ANCHOR: case GF_CURSOR_TOUCH: @@ -1485,6 +1545,7 @@ static void SDLVid_SetCursor(GF_VideoOutput *dr, u32 cursor_type) SDL_SetCursor(ctx->curs_def); break; } +#endif } @@ -1523,8 +1584,10 @@ static GF_Err SDLVid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) } switch (evt->type) { case GF_EVENT_SET_CURSOR: - SDLVid_SetCursor(dr, evt->cursor.cursor_type); - break; +#ifndef GPAC_IPHONE + SDLVid_SetCursor(dr, evt->cursor.cursor_type); +#endif + break; case GF_EVENT_SET_CAPTION: #ifdef SDL_WINDOW_THREAD { @@ -1550,21 +1613,42 @@ static GF_Err SDLVid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) case GF_EVENT_SIZE: { SDLVID(); - if (ctx->fullscreen) { - ctx->store_width = evt->size.width; - ctx->store_height = evt->size.height; - } else { #ifdef GPAC_IPHONE -// SDLVid_ResizeWindow(dr, dr->max_screen_width, dr->max_screen_height); - SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height); + if (ctx->fullscreen) { + } else { + SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height); + } #else + if (ctx->fullscreen) { + //ctx->store_width = evt->size.width; + //ctx->store_height = evt->size.height; + } else { SDLVid_ResizeWindow(dr, evt->size.width, evt->size.height); -#endif } +#endif } break; case GF_EVENT_MOVE: - break; + +#if !defined(GPAC_IPHONE) && SDL_VERSION_ATLEAST(2,0,0) + { + SDLVID(); + + if (ctx->fullscreen) return GF_OK; + + if (evt->move.relative == 2) { + } + else if (evt->move.relative) { + s32 x, y; + x = y = 0; + SDL_GetWindowPosition(ctx->screen, &x, &y); + SDL_SetWindowPosition(ctx->screen, x + evt->move.x, y + evt->move.y); + } else { + SDL_SetWindowPosition(ctx->screen, evt->move.x, evt->move.y); + } + } +#endif + break; case GF_EVENT_VIDEO_SETUP: { SDLVID(); @@ -1642,7 +1726,21 @@ static GF_Err SDLVid_ProcessEvent(GF_VideoOutput *dr, GF_Event *evt) #else return GF_NOT_SUPPORTED; #endif - } + + case GF_EVENT_TEXT_EDITING_START: + case GF_EVENT_TEXT_EDITING_END: +#if defined(GPAC_IPHONE) && SDL_VERSION_ATLEAST(2,0,0) + if (evt->type==GF_EVENT_TEXT_EDITING_START) { + SDL_StartTextInput(); + } else { + SDL_StopTextInput(); + } + return GF_OK; +#else + return GF_NOT_SUPPORTED; +#endif + + } return GF_OK; } @@ -1759,72 +1857,162 @@ static void copy_yuv(u8 *pYD, u8 *pVD, u8 *pUD, u32 pixel_format, u32 pitch_y, u } } +#if SDL_VERSION_ATLEAST(2,0,0) +static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type) +{ + SDLVID(); + Bool need_copy=0; + u32 format; + s32 acc, w, h; + int res; + Bool set_blend=0; + SDL_Rect dstrc; + SDL_Texture **pool; + SDL_Rect srcrc, *src_ptr=NULL; + + GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] Bliting surface (overlay type %d)\n", overlay_type)); + + if (ctx->needs_bb_flush) { + SDL_UpdateTexture(ctx->tx_back_buffer, NULL, ctx->back_buffer_pixels, 3*ctx->width); + SDL_RenderCopy(ctx->renderer, ctx->tx_back_buffer, NULL, NULL); + ctx->needs_bb_grab = 1; + } + + ctx->needs_bb_grab = 1; + if (ctx->needs_clear) { + SDL_RenderClear(ctx->renderer); + ctx->needs_clear = 0; + } + + dstrc.w = dst_wnd->w; + dstrc.h = dst_wnd->h; + dstrc.x = dst_wnd->x; + dstrc.y = dst_wnd->y; + + if (src_wnd) { + srcrc.x = src_wnd->x; + srcrc.y = src_wnd->y; + srcrc.w = src_wnd->w; + srcrc.h = src_wnd->h; + src_ptr = &srcrc; + } + + //this is a clear (not very elegant ...) + if ((video_src->width<=2) && (video_src->height<=2)) { + u8 *pix =(u8 *) video_src->video_buffer; + if (video_src->pixel_format == GF_PIXEL_RGB_24) { + SDL_SetRenderDrawColor(ctx->renderer, pix[0], pix[1], pix[2], 0xFF); + } else { + SDL_SetRenderDrawColor(ctx->renderer, pix[0], pix[1], pix[2], pix[3]); + } + res = SDL_RenderFillRect(ctx->renderer, &dstrc); + if (res<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Clear error: %s\n", SDL_GetError())); + return GF_IO_ERR; + } + return GF_OK; + } + + switch (video_src->pixel_format) { + case GF_PIXEL_RGB_24: + pool = &ctx->pool_rgb; + format=SDL_PIXELFORMAT_RGB24; + break; + case GF_PIXEL_RGBA: + pool = &ctx->pool_rgba; + format=SDL_PIXELFORMAT_ABGR8888; + set_blend=1; + break; + case GF_PIXEL_YV12: + pool = &ctx->pool_yuv; + format=SDL_PIXELFORMAT_YV12; + format=SDL_PIXELFORMAT_IYUV; + break; + case GF_PIXEL_YV12_10: + need_copy=1; + pool = &ctx->pool_yuv; + format=SDL_PIXELFORMAT_YV12; + break; + default: + return GF_NOT_SUPPORTED; + } + + + if (*pool ) { + SDL_QueryTexture(*pool, &format, &acc, &w, &h); + if ((w != video_src->width) || (h != video_src->height) ) { + SDL_DestroyTexture(*pool); + *pool = NULL; + } + } + if (!(*pool)) { + (*pool) = SDL_CreateTexture(ctx->renderer, format, SDL_TEXTUREACCESS_STREAMING, video_src->width, video_src->height); + if (!(*pool)) return GF_NOT_SUPPORTED; + } + + SDL_QueryTexture((*pool), &format, &acc, &w, &h); + + if (need_copy) { + u8* pixels; + int pitch; + u8 *pY, *pU, *pV; + /*copy pixels*/ + if (SDL_LockTexture(*pool, NULL, (void**)&pixels, &pitch) < 0) { + return GF_NOT_SUPPORTED; + } + + pY = pixels; + pU = pixels + h*pitch; + pV = pixels + 5*h*pitch/4; + copy_yuv(pY, pU, pV, GF_PIXEL_YV12, pitch, (unsigned char *) video_src->video_buffer, (unsigned char *) video_src->u_ptr, (unsigned char *) video_src->v_ptr, video_src->pitch_y, video_src->pixel_format, video_src->width, video_src->height, src_wnd); + + SDL_UnlockTexture(*pool); + } else { + SDL_UpdateTexture(*pool, NULL, video_src->video_buffer, video_src->pitch_y); + } + + if (set_blend || (video_src->global_alpha!=0xFF)) { + res = SDL_SetTextureBlendMode(*pool, SDL_BLENDMODE_BLEND); + if (res<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change texture blend mode: %s\n", SDL_GetError())); + return GF_IO_ERR; + } + res = SDL_SetTextureAlphaMod(*pool, video_src->global_alpha); + if (res<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change global alpha of texture: %s\n", SDL_GetError())); + return GF_IO_ERR; + } + } else { + res = SDL_SetTextureBlendMode(*pool, SDL_BLENDMODE_NONE); + if (res<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Cannot change texture blend mode: %s\n", SDL_GetError())); + return GF_IO_ERR; + } + } + + res = SDL_RenderCopy(ctx->renderer, *pool, src_ptr, &dstrc); + if (res<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL2] Blit error: %s\n", SDL_GetError())); + return GF_IO_ERR; + } + return GF_OK; +} + +#else static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type) { SDLVID(); u32 amask = 0; u32 bpp; -#if SDL_VERSION_ATLEAST(2,0,0) -#else + GF_Err e = GF_OK; u32 i; u8 *dst, *src; -#endif SDL_Rect dstrc; SDL_Surface **pool; GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[SDL] Bliting surface (overlay type %d)\n", overlay_type)); - + if (overlay_type) { -#if SDL_VERSION_ATLEAST(2,0,0) - u8* pixels; - int pitch; - u32 format; - s32 acc, w, h; - u8 *pY, *pU, *pV; - if (!video_src) { - if (ctx->yuv_texture) { - SDL_DestroyTexture(ctx->yuv_texture); - ctx->yuv_texture=NULL; - } - return GF_OK; - } - if (ctx->yuv_texture ) { - SDL_QueryTexture(ctx->yuv_texture, &format, &acc, &w, &h); - if ((w != src_wnd->w) || (h != src_wnd->h) ) { - SDL_DestroyTexture(ctx->yuv_texture); - ctx->yuv_texture = NULL; - } - } - if (! ctx->yuv_texture ) { - ctx->yuv_texture = SDL_CreateTexture(ctx->renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, src_wnd->w, src_wnd->h); - if (!ctx->yuv_texture) return GF_NOT_SUPPORTED; - } - - SDL_QueryTexture(ctx->yuv_texture, &format, &acc, &w, &h); - - /*copy pixels*/ - if (SDL_LockTexture(ctx->yuv_texture, NULL, (void**)&pixels, &pitch) < 0) { - return GF_NOT_SUPPORTED; - } - - pY = pixels; - pU = pixels + h*pitch; - pV = pixels + 5*h*pitch/4; - copy_yuv(pY, pU, pV, GF_PIXEL_YV12, pitch, (unsigned char *) video_src->video_buffer, (unsigned char *) video_src->u_ptr, (unsigned char *) video_src->v_ptr, video_src->pitch_y, video_src->pixel_format, video_src->width, video_src->height, src_wnd); - - SDL_UnlockTexture(ctx->yuv_texture); - - dstrc.w = dst_wnd->w; - dstrc.h = dst_wnd->h; - dstrc.x = dst_wnd->x; - dstrc.y = dst_wnd->y; - - SDL_ClearError(); - SDL_RenderCopy(ctx->renderer, ctx->yuv_texture, NULL, &dstrc); - SDL_RenderPresent(ctx->renderer); - return GF_OK; - -#else if (!video_src) { if (ctx->yuv_overlay) { SDL_FreeYUVOverlay(ctx->yuv_overlay); @@ -1853,7 +2041,6 @@ static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window dstrc.y = dst_wnd->y; SDL_DisplayYUVOverlay(ctx->yuv_overlay, &dstrc); return GF_OK; -#endif } /*SDL doesn't support stretching ...*/ @@ -1877,28 +2064,6 @@ static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window default: return GF_NOT_SUPPORTED; } -#if SDL_VERSION_ATLEAST(2,0,0) - if ((*pool)) SDL_FreeSurface((*pool)); - (*pool) = SDL_CreateRGBSurfaceFrom(video_src->video_buffer + video_src->pitch_y*src_wnd->y + src_wnd->x*bpp, - src_wnd->w, src_wnd->h, 8*bpp, video_src->pitch_y, -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - 0xFF000000, 0x00FF0000, 0x0000FF00, amask); -#else - 0x000000FF, 0x0000FF00, 0x00FF0000, amask); -#endif - dstrc.w = dst_wnd->w; - dstrc.h = dst_wnd->h; - dstrc.x = dst_wnd->x; - dstrc.y = dst_wnd->y; - - if (SDL_BlitSurface(*pool, NULL, ctx->back_buffer, &dstrc)) - GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Blit error: %s\n", SDL_GetError())); - - - SDL_FreeSurface((*pool)); - *pool = NULL; - -#else if (! *pool || ((*pool)->w < (int) src_wnd->w) || ((*pool)->h < (int) src_wnd->h) ) { if ((*pool)) SDL_FreeSurface((*pool)); @@ -1927,19 +2092,20 @@ static GF_Err SDL_Blit(GF_VideoOutput *dr, GF_VideoSurface *video_src, GF_Window if (SDL_BlitSurface(*pool, NULL, ctx->back_buffer, &dstrc)) GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[SDL] Blit error: %s\n", SDL_GetError())); -#endif - - return GF_OK; + return e; } - +#endif void *SDL_NewVideo() { +#if SDL_VERSION_ATLEAST(2,0,0) + const char *opt; +#endif SDLVidCtx *ctx; GF_VideoOutput *driv; - + driv = (GF_VideoOutput*)gf_malloc(sizeof(GF_VideoOutput)); memset(driv, 0, sizeof(GF_VideoOutput)); GF_REGISTER_MODULE_INTERFACE(driv, GF_VIDEO_OUTPUT_INTERFACE, "SDL Video Output", "gpac distribution"); @@ -1951,6 +2117,7 @@ void *SDL_NewVideo() #endif ctx->evt_mx = gf_mx_new("SDLEvents"); + driv->opaque = ctx; driv->Setup = SDLVid_Setup; driv->Shutdown = SDLVid_Shutdown; @@ -1961,27 +2128,29 @@ void *SDL_NewVideo() driv->hw_caps |= GF_VIDEO_HW_OPENGL; /*no YUV hardware blitting in SDL (only overlays)*/ - driv->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY | GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_RGBA;; - driv->Blit = SDL_Blit; - driv->LockBackBuffer = SDLVid_LockBackBuffer; - driv->LockOSContext = NULL; + driv->hw_caps |= GF_VIDEO_HW_HAS_RGB ; +#if SDL_VERSION_ATLEAST(2,0,0) - /*color keying with overlays are not supported in SDL ...*/ -#if 0 - /*get YUV overlay key*/ - opt = gf_modules_get_option((GF_BaseInterface *)driv, "Video", "OverlayColorKey"); - /*no set is the default*/ - if (!opt) { - opt = "0101FE"; - gf_modules_set_option((GF_BaseInterface *)driv, "Video", "OverlayColorKey", "0101FE"); - } - sscanf(opt, "%06x", &driv->overlay_color_key); - if (driv->overlay_color_key) driv->overlay_color_key |= 0xFF000000; - GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL Out] YUV Overlays enabled - ColorKey enabled: %s (key %x)\n", - driv->overlay_color_key ? "Yes" : "No", driv->overlay_color_key - )); + driv->hw_caps |= GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_STRETCH | GF_VIDEO_HW_HAS_RGBA; + + + opt = gf_modules_get_option((GF_BaseInterface *)driv, "Video", "SDL_DeferMode"); + ctx->enable_defer_mode = 0; + if (opt && !strcmp(opt, "yes")) + ctx->enable_defer_mode = 1; + + if (! ctx->enable_defer_mode) + driv->hw_caps |= GF_VIDEO_HW_DIRECT_ONLY; +#else + driv->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY; #endif + + + + driv->Blit = SDL_Blit; + driv->LockBackBuffer = SDLVid_LockBackBuffer; + driv->LockOSContext = NULL; #ifndef SDL_TEXTINPUTEVENT_TEXT_SIZE SDL_EnableUNICODE(1); #else diff --git a/modules/soft_raster/Makefile b/modules/soft_raster/Makefile index 222a4f1..1170304 100644 --- a/modules/soft_raster/Makefile +++ b/modules/soft_raster/Makefile @@ -25,7 +25,7 @@ OBJS= ftgrays.o raster_load.o raster_565.o raster_argb.o raster_rgb.o stencil.o SRCS := $(OBJS:.o=.c) -LIB=gm_soft_raster.$(DYN_LIB_SUFFIX) +LIB=gm_soft_raster$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols rast_soft.def endif @@ -37,7 +37,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_soft_raster-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_soft_raster-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/soft_raster/ftgrays.c b/modules/soft_raster/ftgrays.c index e68846c..c1ba294 100644 --- a/modules/soft_raster/ftgrays.c +++ b/modules/soft_raster/ftgrays.c @@ -155,7 +155,7 @@ static GFINLINE void gray_record_cell( TRaster *raster ) { if (( raster->area | raster->cover) && (raster->ey<raster->max_ey)) { AACell *cell; - int y = raster->ey - raster->min_ey; + long y = raster->ey - raster->min_ey; if (y>=0) { AAScanline *sl = &raster->scanlines[y]; if (sl->num >= sl->alloc) { @@ -695,7 +695,7 @@ static void gray_sweep_line( TRaster *raster, AAScanline *sl, int y, Bool zero_n if ( cur->x > x ) gray_hline( raster, x, y, cover * ( ONE_PIXEL * 2 ), cur->x - x, zero_non_zero_rule); } - raster->render_span(y + raster->min_ey, raster->num_gray_spans, raster->gray_spans, raster->render_span_data ); + raster->render_span((int) (y + raster->min_ey), raster->num_gray_spans, raster->gray_spans, raster->render_span_data ); } @@ -720,15 +720,15 @@ int evg_raster_render(EVG_Raster raster, EVG_Raster_Params* params) raster->mx = params->mx; #endif - size_y = raster->max_ey - raster->min_ey; + size_y = (int) (raster->max_ey - raster->min_ey); if (raster->max_lines < size_y) { raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y); memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) ); raster->max_lines = size_y; } - raster->ex = raster->max_ex+1; - raster->ey = raster->max_ey+1; + raster->ex = (int) (raster->max_ex+1); + raster->ey = (int) (raster->max_ey+1); raster->cover = 0; raster->area = 0; EVG_Outline_Decompose(outline, raster); diff --git a/modules/soft_raster/raster_argb.c b/modules/soft_raster/raster_argb.c index 115d7d9..44d5a3c 100644 --- a/modules/soft_raster/raster_argb.c +++ b/modules/soft_raster/raster_argb.c @@ -690,6 +690,13 @@ GF_Err evg_surface_clear_rgba(GF_SURFACE surf, GF_IRect rc, GF_Color col) w = rc.width; sy = rc.y; + if (sy+h > _this->height) { + h = _this->height - sy; + } + if (rc.x + w > _this->width) { + w = _this->width - rc.x; + } + a = GF_COL_A(col); r = GF_COL_R(col); g = GF_COL_G(col); diff --git a/modules/soft_raster/raster_load.c b/modules/soft_raster/raster_load.c index da73b94..91e8cb8 100644 --- a/modules/soft_raster/raster_load.c +++ b/modules/soft_raster/raster_load.c @@ -101,6 +101,6 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( soft_raster ) +GPAC_MODULE_STATIC_DECLARATION( soft_raster ) #endif diff --git a/modules/svg_in/Makefile b/modules/svg_in/Makefile index 85a4c6d..c0ada72 100644 --- a/modules/svg_in/Makefile +++ b/modules/svg_in/Makefile @@ -27,7 +27,7 @@ OBJS= svg_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_svg_in.$(DYN_LIB_SUFFIX) +LIB=gm_svg_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols svg_in.def endif @@ -39,7 +39,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_svg_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_svg_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif clean: diff --git a/modules/svg_in/svg_in.c b/modules/svg_in/svg_in.c index 645b7d6..8a5f0bf 100644 --- a/modules/svg_in/svg_in.c +++ b/modules/svg_in/svg_in.c @@ -48,11 +48,11 @@ typedef struct static Bool svg_check_download(SVGIn *svgin) { u64 size; - FILE *f = gf_f64_open(svgin->file_name, "rb"); + FILE *f = gf_fopen(svgin->file_name, "rb"); if (!f) return 0; - gf_f64_seek(f, 0, SEEK_END); - size = gf_f64_tell(f); - fclose(f); + gf_fseek(f, 0, SEEK_END); + size = gf_ftell(f); + gf_fclose(f); if (size==svgin->file_size) return 1; return 0; } @@ -85,7 +85,7 @@ static GF_Err svgin_deflate(SVGIn *svgin, const char *buffer, u32 buffer_len) svg_data[d_stream.total_out - done] = 0; e = gf_sm_load_string(&svgin->loader, svg_data, 0); if (e || (err== Z_STREAM_END)) break; - done = d_stream.total_out; + done = (u32) d_stream.total_out; d_stream.avail_out = 2048; d_stream.next_out = (Bytef*)svg_data; } @@ -195,7 +195,7 @@ static GF_Err SVG_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 i char * buf2 = gf_malloc(inBufferLength); GF_BitStream *bs = gf_bs_new(inBuffer, inBufferLength, GF_BITSTREAM_READ); memcpy(buf2, inBuffer, inBufferLength); -// FILE *f = gf_f64_open("dump.svg", "wb"); +// FILE *f = gf_fopen("dump.svg", "wb"); // while (gf_bs_available(bs)) { pos = gf_bs_get_position(bs); @@ -221,7 +221,7 @@ static GF_Err SVG_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 i gf_bs_skip_bytes(bs, size-1); } -// fclose(f); +// gf_fclose(f); gf_bs_del(bs); } break; @@ -458,4 +458,4 @@ const u32 *QueryInterfaces() return si; } -GPAC_MODULE_STATIC_DELARATION( svg_in ) +GPAC_MODULE_STATIC_DECLARATION( svg_in ) diff --git a/modules/timedtext/Makefile b/modules/timedtext/Makefile index 87dd1c5..f2d5505 100644 --- a/modules/timedtext/Makefile +++ b/modules/timedtext/Makefile @@ -19,7 +19,7 @@ OBJS=timedtext_dec.o timedtext_in.o SRCS := $(OBJS:.o=.c) -LIB=gm_timedtext.$(DYN_LIB_SUFFIX) +LIB=gm_timedtext$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols timedtext.def endif @@ -31,7 +31,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_timedtext-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_timedtext-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac_static endif diff --git a/modules/timedtext/timedtext_dec.c b/modules/timedtext/timedtext_dec.c index 54f83fe..40b9663 100644 --- a/modules/timedtext/timedtext_dec.c +++ b/modules/timedtext/timedtext_dec.c @@ -609,7 +609,7 @@ static void TTD_NewTextChunk(TTDPriv *priv, GF_TextSampleDescriptor *tsd, M_Form u32 len; s16 wsChunk[5000], *sp; - /*spliting lines, duplicate node*/ + /*splitting lines, duplicate node*/ n2 = gf_node_clone(priv->sg, txt_model, NULL, "", 1); if (tc->hlink && tc->hlink->URL) { @@ -1244,4 +1244,4 @@ const u32 *QueryInterfaces() return si; } -GPAC_MODULE_STATIC_DELARATION( timedtext ) +GPAC_MODULE_STATIC_DECLARATION( timedtext ) diff --git a/modules/ui_rec/Makefile b/modules/ui_rec/Makefile index ccc1e60..7ad035c 100644 --- a/modules/ui_rec/Makefile +++ b/modules/ui_rec/Makefile @@ -24,7 +24,7 @@ OBJS=ui_rec.o SRCS := $(OBJS:.o=.c) -LIB=gm_ui_rec.$(DYN_LIB_SUFFIX) +LIB=gm_ui_rec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols ui_rec.def endif diff --git a/modules/ui_rec/ui_rec.c b/modules/ui_rec/ui_rec.c index 8df04bd..65c921f 100644 --- a/modules/ui_rec/ui_rec.c +++ b/modules/ui_rec/ui_rec.c @@ -155,7 +155,7 @@ static Bool uir_process(GF_TermExt *termext, u32 action, void *param) if (!uifile) return 0; if (!strcmp(opt, "Play")) { - uir->uif = gf_f64_open(uifile, "rb"); + uir->uif = gf_fopen(uifile, "rb"); if (!uir->uif) return 0; uir->bs = gf_bs_from_file(uir->uif, GF_BITSTREAM_READ); termext->caps |= GF_TERM_EXTENSION_NOT_THREADED; @@ -166,7 +166,7 @@ static Bool uir_process(GF_TermExt *termext, u32 action, void *param) uir_load_event(uir); } else if (!strcmp(opt, "Record")) { - uir->uif = gf_f64_open(uifile, "wb"); + uir->uif = gf_fopen(uifile, "wb"); if (!uir->uif) return 0; uir->bs = gf_bs_from_file(uir->uif, GF_BITSTREAM_WRITE); @@ -179,7 +179,7 @@ static Bool uir_process(GF_TermExt *termext, u32 action, void *param) return 1; case GF_TERM_EXT_STOP: - if (uir->uif) fclose(uir->uif); + if (uir->uif) gf_fclose(uir->uif); if (uir->bs) gf_bs_del(uir->bs); gf_term_remove_event_filter(uir->term, &uir->evt_filter); uir->term = NULL; @@ -249,4 +249,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( ui_rec ) +GPAC_MODULE_STATIC_DECLARATION( ui_rec ) diff --git a/modules/validator/Makefile b/modules/validator/Makefile new file mode 100644 index 0000000..7e12921 --- /dev/null +++ b/modules/validator/Makefile @@ -0,0 +1,49 @@ +include ../../config.mak + +vpath %.c $(SRC_PATH)/modules/validator + +CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include" -DGPAC_HAVE_CONFIG_H -I../.. + +ifeq ($(DEBUGBUILD), yes) +CFLAGS+=-g +LDFLAGS+=-g +endif + +ifeq ($(GPROFBUILD), yes) +CFLAGS+=-pg +LDFLAGS+=-pg +endif + +#common obj +OBJS=validator.o + +SRCS := $(OBJS:.o=.c) + +LIB=gm_validator$(DYN_LIB_SUFFIX) +ifeq ($(CONFIG_WIN32),yes) +endif + + +all: $(LIB) + + +$(LIB): $(OBJS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) -L../../bin/gcc -lgpac +ifeq ($(STATICBUILD),yes) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_validator-static$(DYN_LIB_SUFFIX) $(OBJS) -L../../bin/gcc -lgpac_static +endif + + +clean: + rm -f $(OBJS) ../../bin/gcc/$(LIB) + +dep: depend + +depend: + rm -f .depend + $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend + +distclean: clean + rm -f Makefile.bak .depend + +-include .depend diff --git a/modules/validator/README.TXT b/modules/validator/README.TXT index 8fb86ac..072d4fa 100644 --- a/modules/validator/README.TXT +++ b/modules/validator/README.TXT @@ -1,41 +1,49 @@ -The validator allows recording user interactions and taking snapshots when playing back interactive content; and replaying the content simulating the interactions, generating and comparing snapshots. To activate it you need to modify the GPAC configuration as follows: - -Add a section: -[Validator] -Mode=Play - -Mode can be: Play, Record, or Disable - -The validator will try to load a single file to be tested or a playlist. -Single files are indicated with: -XVS=C:\Users\Cyril Concolato\code\tsi_svn\trunk\gpac_public\regression_tests\svg\file.xvs -XVS means XML Validation Sequence. An example of XVS is: - -<TestValidationScript file="C:\Users\Cyril Concolato\standards\SVG_WG\SVG\profiles\1.1F2\test\svg\animate-elem-09-t.svg" > -<snapshot time="237" image="animate-elem-09-t-reference-000.png" /> -<mousemove time="4749.000000" x="99" y="354" /> -<mousemove time="4749.000000" x="103" y="343" /> -<mousemove time="4749.000000" x="108" y="333" /> -</TestValidationScript> - - -Playlist of XVS are givin with: -XVL=C:\Users\Cyril Concolato\code\tsi_svn\trunk\gpac_public\regression_tests\svg\svg1.1f2.xvl -XVL means XML Validation List. An example of XVL is: - -<TestSuiteValidationScript content-base="C:\Users\Cyril Concolato\standards\SVG_WG\SVG\profiles\1.1F2\test\svg" > -<Test scenario="animate-elem-02-t.xvs" content="animate-elem-02-t.svg" /> -<Test scenario="animate-elem-03-t.xvs" content="animate-elem-03-t.svg" /> -<Test scenario="animate-dom-01-f.xvs" content="animate-dom-01-f.svg" /> -<Test scenario="animate-dom-02-f.xvs" content="animate-dom-02-f.svg" /> -</TestSuiteValidationScript> - -When recording and playing back, the GPAC player rendering is switched to 5 FPS without antialiasing. - -When recording, you can trigger some actions as follows: -CTRL+Insert: takes a snapshot and records it as a PNG. In replay mode, a PNG will be taken at the same scene time and the PNG will be compared. -CTRL+Fin: Quit -CTRL+F1: Takes snapshot at next frame change. -Page Down: Ends current XVS and switches to next in the XVL - -Note: after recording, upon closing the player, the Validator mode is automatically switched to Play to avoid losing recorded interactions. \ No newline at end of file +The validator allows recording user interactions and taking snapshots when playing back interactive content; and replaying the content simulating the interactions, generating and comparing snapshots. To activate it you need to modify the GPAC configuration as follows: + +Add a section: +[Validator] +Mode=Play + +Mode can be: Play, Record, or Disable + +The validator will try to load a trace file, a single file or a playlist. + +** Trace files are indicated with +Trace=SomeTrace + +A trace file does not contain any association with the source file nor screenshots, only mouse and keyboard events are used. +In trace mode the renderer is not reconfigured. + +** Single files are indicated with: +XVS=/PATH/TOfile.xvs +XVS means XML Validation Sequence. An example of XVS is: + +<TestValidationScript file="/PATH/TO/animate-elem-09-t.svg" > +<snapshot time="237" image="animate-elem-09-t-reference-000.png" /> +<mousemove time="4749.000000" x="99" y="354" /> +<mousemove time="4749.000000" x="103" y="343" /> +<mousemove time="4749.000000" x="108" y="333" /> +</TestValidationScript> + + +** Playlist of XVS are givin with: + +XVL=/PATH/TO/svg1.1f2.xvl +XVL means XML Validation List. An example of XVL is: + +<TestSuiteValidationScript content-base="/PATH/TO/svg" > +<Test scenario="animate-elem-02-t.xvs" content="animate-elem-02-t.svg" /> +<Test scenario="animate-elem-03-t.xvs" content="animate-elem-03-t.svg" /> +<Test scenario="animate-dom-01-f.xvs" content="animate-dom-01-f.svg" /> +<Test scenario="animate-dom-02-f.xvs" content="animate-dom-02-f.svg" /> +</TestSuiteValidationScript> + +When recording and playing back, the GPAC player rendering is switched to 5 FPS without antialiasing, except for Trace mode. + +When recording, you can trigger some actions as follows (except for trace mode): +CTRL+Insert: takes a snapshot and records it as a PNG. In replay mode, a PNG will be taken at the same scene time and the PNG will be compared. +CTRL+Fin: Quit +CTRL+F1: Takes snapshot at next frame change. +Page Down: Ends current XVS and switches to next in the XVL + +Note: after recording, upon closing the player, the Validator mode is automatically switched to Play to avoid losing recorded interactions, except in trace mode. diff --git a/modules/validator/validator.c b/modules/validator/validator.c index 9dab44c..4a69173 100644 --- a/modules/validator/validator.c +++ b/modules/validator/validator.c @@ -35,6 +35,7 @@ typedef struct __validation_module GF_Terminal *term; Bool is_recording; + Bool trace_mode; char *prev_fps; char *prev_alias; @@ -101,13 +102,14 @@ static void validator_xvs_add_snapshot_node(GF_Validator *validator, const char gf_list_add(validator->xvs_node->content, snap_node); } -static char *validator_get_snapshot_name(char *test_filename, Bool is_reference, u32 number) +static char *validator_get_snapshot_name(GF_Validator *validator, Bool is_reference, u32 number) { + char *name = validator->test_filename ? validator->test_filename : validator->xvs_filename; char *dot; char dumpname[GF_MAX_PATH]; - dot = strrchr(test_filename, '.'); + dot = strrchr(name, '.'); dot[0] = 0; - sprintf(dumpname, "%s-%s-%03d.png", test_filename, (is_reference?"reference":"newest"), number); + sprintf(dumpname, "%s-%s-%03d.png", name, (is_reference?"reference":"newest"), number); dot[0] = '.'; return gf_strdup(dumpname); } @@ -119,7 +121,7 @@ static char *validator_create_snapshot(GF_Validator *validator) GF_Terminal *term = validator->term; char *dumpname; - dumpname = validator_get_snapshot_name(validator->test_filename, validator->is_recording, validator->snapshot_number); + dumpname = validator_get_snapshot_name(validator, validator->is_recording, validator->snapshot_number); e = gf_term_get_screen_buffer(term, &fb); if (e) { @@ -132,12 +134,12 @@ static char *validator_create_snapshot(GF_Validator *validator) if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Error encoding PNG %s\n", gf_error_to_string(e))); } else { - FILE *png = gf_f64_open(dumpname, "wb"); + FILE *png = gf_fopen(dumpname, "wb"); if (!png) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[Validator] Error writing file %s\n", dumpname)); } else { gf_fwrite(dst, dst_size, 1, png); - fclose(png); + gf_fclose(png); GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[Validator] Writing file %s\n", dumpname)); } } @@ -159,8 +161,8 @@ static Bool validator_compare_snapshots(GF_Validator *validator) u32 i; u32 snap_number = validator->snapshot_number - 1; - ref_name = validator_get_snapshot_name(validator->test_filename, 1, snap_number); - new_name = validator_get_snapshot_name(validator->test_filename, 0, snap_number); + ref_name = validator_get_snapshot_name(validator, 1, snap_number); + new_name = validator_get_snapshot_name(validator, 0, snap_number); e = gf_img_file_dec(ref_name, NULL, &ref_width, &ref_height, &ref_pixel_format, &ref_data, &ref_data_size); if (e) { @@ -221,7 +223,10 @@ Bool validator_on_event_play(void *udta, GF_Event *event, Bool consumed_by_compo switch (event->type) { case GF_EVENT_CONNECT: if (event->connect.is_connected) { - gf_sc_add_video_listener(validator->term->compositor, &validator->video_listener); + if (!validator->trace_mode) { + gf_sc_add_video_listener(validator->term->compositor, &validator->video_listener); + } + validator->ck = validator->term->root_scene->scene_codec ? validator->term->root_scene->scene_codec->ck : validator->term->root_scene->dyn_ck; @@ -267,8 +272,10 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event case GF_EVENT_KEYUP: case GF_EVENT_KEYDOWN: case GF_EVENT_TEXTINPUT: - evt_node->name = gf_strdup(gf_dom_event_get_name(event->type)); - break; +#ifndef GPAC_DISABLE_SVG + evt_node->name = gf_strdup(gf_dom_event_get_name(event->type)); +#endif + break; } if (!evt_node->name) { @@ -322,7 +329,7 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event GF_SAFEALLOC(att, GF_XMLAttribute); att->name = gf_strdup("wheel_pos"); att->value = gf_malloc(100); - sprintf(att->value, "%f", event->mouse.wheel_pos); + sprintf(att->value, "%f", FIX2FLT( event->mouse.wheel_pos) ); gf_list_add(evt_node->attributes, att); } if (event->mouse.key_states & GF_KEY_MOD_SHIFT) { @@ -350,7 +357,9 @@ static void validator_xvs_add_event_dom(GF_Validator *validator, GF_Event *event case GF_EVENT_LONGKEYPRESS: GF_SAFEALLOC(att, GF_XMLAttribute); att->name = gf_strdup("key_identifier"); +#ifndef GPAC_DISABLE_SVG att->value = gf_strdup(gf_dom_get_key_name(event->key.key_code)); +#endif gf_list_add(evt_node->attributes, att); if (event->key.flags & GF_KEY_MOD_SHIFT) { GF_SAFEALLOC(att, GF_XMLAttribute); @@ -394,7 +403,9 @@ Bool validator_on_event_record(void *udta, GF_Event *event, Bool consumed_by_com switch (event->type) { case GF_EVENT_CONNECT: if (event->connect.is_connected) { - gf_sc_add_video_listener(validator->term->compositor, &validator->video_listener); + if (!validator->trace_mode) { + gf_sc_add_video_listener(validator->term->compositor, &validator->video_listener); + } validator->ck = validator->term->root_scene->scene_codec ? validator->term->root_scene->scene_codec->ck : validator->term->root_scene->dyn_ck; } break; @@ -494,9 +505,9 @@ static void validator_xvl_close(GF_Validator *validator) dot[0] = 0; sprintf(result_filename, "%s-result.xml", validator->xvl_filename); dot[0] = '.'; - xvl_fp = gf_f64_open(result_filename, "wt"); + xvl_fp = gf_fopen(result_filename, "wt"); gf_fwrite(xvl_content, strlen(xvl_content), 1, xvl_fp); - fclose(xvl_fp); + gf_fclose(xvl_fp); gf_free(xvl_content); } gf_xml_dom_del(validator->xvl_parser); @@ -574,6 +585,7 @@ static Bool validator_xvs_open(GF_Validator *validator) } att_index++; } + if (!att_file) { gf_xml_dom_del(validator->xvs_parser); validator->xvs_parser = NULL; @@ -642,9 +654,9 @@ static void validator_xvs_close(GF_Validator *validator) sprintf(filename, "%s%c%s", validator->test_base, GF_PATH_SEPARATOR, validator->test_filename); att->value = gf_strdup(filename); xvs_content = gf_xml_dom_serialize(validator->xvs_node, 0); - xvs_fp = gf_f64_open(validator->xvs_filename, "wt"); + xvs_fp = gf_fopen(validator->xvs_filename, "wt"); gf_fwrite(xvs_content, strlen(xvs_content), 1, xvs_fp); - fclose(xvs_fp); + gf_fclose(xvs_fp); gf_free(xvs_content); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[Validator] XVS Result : %s\n", (validator->xvs_result?"Success":"Failure"))); @@ -685,17 +697,20 @@ static void validator_xvs_close(GF_Validator *validator) static void validator_test_open(GF_Validator *validator) { char filename[100]; - if (validator->test_base) - sprintf(filename, "%s%c%s", validator->test_base, GF_PATH_SEPARATOR, validator->test_filename); - else - sprintf(filename, "%s", validator->test_filename); - gf_sc_add_video_listener(validator->term->compositor, &validator->video_listener); - if (validator->is_recording) - validator->snapshot_next_frame = 1; - gf_term_connect(validator->term, filename); - validator->ck = validator->term->root_scene->scene_codec ? - validator->term->root_scene->scene_codec->ck : - validator->term->root_scene->dyn_ck; + + if (!validator->trace_mode) { + if (validator->test_base) + sprintf(filename, "%s%c%s", validator->test_base, GF_PATH_SEPARATOR, validator->test_filename); + else + sprintf(filename, "%s", validator->test_filename); + + gf_sc_add_video_listener(validator->term->compositor, &validator->video_listener); + if (validator->is_recording) + validator->snapshot_next_frame = 1; + gf_term_connect(validator->term, filename); + + } +// validator->ck = validator->term->root_scene->scene_codec ? validator->term->root_scene->scene_codec->ck : validator->term->root_scene->dyn_ck; } static Bool validator_xvs_next(GF_Validator *validator, Bool reverse) @@ -749,8 +764,11 @@ static Bool validator_load_event(GF_Validator *validator) if (!strcmp(event_node->name, "snapshot")) { validator->next_event_snapshot = 1; } else { - validator->next_event.type = gf_dom_event_type_by_name(event_node->name); - if (validator->next_event.type == GF_EVENT_UNKNOWN) { +#ifndef GPAC_DISABLE_SVG + validator->next_event.type = gf_dom_event_type_by_name(event_node->name); + if (validator->next_event.type == GF_EVENT_UNKNOWN) +#endif + { return 1; } } @@ -781,9 +799,11 @@ static Bool validator_load_event(GF_Validator *validator) validator->next_event.mouse.key_states |= GF_KEY_MOD_ALT; } else if (!strcmp(att->name, "ctrl") && !strcmp(att->value, "true")) { validator->next_event.mouse.key_states |= GF_KEY_MOD_CTRL; - } else if (!strcmp(att->name, "key_identifier")) { +#ifndef GPAC_DISABLE_SVG + } else if (!strcmp(att->name, "key_identifier")) { validator->next_event.key.key_code = gf_dom_get_key_type(att->value); - } else if (!strcmp(att->name, "unicode-char")) { +#endif + } else if (!strcmp(att->name, "unicode-char")) { validator->next_event.character.unicode_char = atoi(att->value); } att_index++; @@ -835,8 +855,14 @@ static Bool validator_process(GF_TermExt *termext, u32 action, void *param) if (!validator->xvl_filename) { validator->xvs_filename = (char *)gf_modules_get_option((GF_BaseInterface*)termext, "Validator", "XVS"); if (!validator->xvs_filename) { - GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("Validator configuration without input, stopping.\n")); - return 0; + validator->xvs_filename = (char *)gf_modules_get_option((GF_BaseInterface*)termext, "Validator", "Trace"); + if (!validator->xvs_filename) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("Validator configuration without input, stopping.\n")); + return 0; + } + validator->test_filename = validator->xvs_filename; + validator->trace_mode = 1; + GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("Validator using trace file: %s\n", validator->xvs_filename)); } else { GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("Validator using scenario file: %s\n", validator->xvs_filename)); } @@ -845,21 +871,9 @@ static Bool validator_process(GF_TermExt *termext, u32 action, void *param) } /* since we changed parameters of the compositor, we need to trigger a reconfiguration */ - gf_modules_set_option((GF_BaseInterface*)termext, "Compositor", "FrameRate", "5.0"); - gf_modules_set_option((GF_BaseInterface*)termext, "Compositor", "AntiAlias", "None"); - gf_term_set_option(validator->term, GF_OPT_RELOAD_CONFIG, 1); - - validator->evt_filter.udta = validator; - if (!validator->is_recording) { - validator->evt_filter.on_event = validator_on_event_play; - termext->caps |= GF_TERM_EXTENSION_NOT_THREADED; - } else { - validator->evt_filter.on_event = validator_on_event_record; - } - gf_term_add_event_filter(validator->term, &validator->evt_filter); - validator->video_listener.udta = validator; - validator->video_listener.on_video_frame = validator_on_video_frame; - validator->video_listener.on_video_reconfig = validator_on_video_reconfig; +// gf_modules_set_option((GF_BaseInterface*)termext, "Compositor", "FrameRate", "5.0"); +// gf_modules_set_option((GF_BaseInterface*)termext, "Compositor", "AntiAlias", "None"); +// gf_term_set_option(validator->term, GF_OPT_RELOAD_CONFIG, 1); /* TODO: if start returns 0, the module is not loaded, so the above init (filter registration) is not removed, should probably return 1 all the time, to make sure stop is called */ @@ -886,6 +900,20 @@ static Bool validator_process(GF_TermExt *termext, u32 action, void *param) } else { return 0; } + + validator->evt_filter.udta = validator; + if (!validator->is_recording) { + validator->evt_filter.on_event = validator_on_event_play; + termext->caps |= GF_TERM_EXTENSION_NOT_THREADED; + } else { + validator->evt_filter.on_event = validator_on_event_record; + } + gf_term_add_event_filter(validator->term, &validator->evt_filter); + validator->video_listener.udta = validator; + validator->video_listener.on_video_frame = validator_on_video_frame; + validator->video_listener.on_video_reconfig = validator_on_video_reconfig; + + if (!validator->is_recording) { validator_load_event(validator); } @@ -904,10 +932,12 @@ static Bool validator_process(GF_TermExt *termext, u32 action, void *param) validator->test_base = NULL; } /*auto-disable the recording by default*/ - if (validator->is_recording) { - gf_modules_set_option((GF_BaseInterface*)termext, "Validator", "Mode", "Play"); - } else { - gf_modules_set_option((GF_BaseInterface*)termext, "Validator", "Mode", "Disable"); + if (!validator->trace_mode) { + if (validator->is_recording ) { + gf_modules_set_option((GF_BaseInterface*)termext, "Validator", "Mode", "Play"); + } else { + gf_modules_set_option((GF_BaseInterface*)termext, "Validator", "Mode", "Disable"); + } } GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("Stopping validator\n")); if (validator->prev_fps) { @@ -944,18 +974,20 @@ static Bool validator_process(GF_TermExt *termext, u32 action, void *param) has_more_events = validator_load_event(validator); if (!has_more_events) { validator_xvs_close(validator); - gf_term_disconnect(validator->term); - gf_sc_remove_video_listener(validator->term->compositor, &validator->video_listener); - validator_xvs_next(validator, 0); - if (!validator->xvs_node) { - GF_Event evt; - memset(&evt, 0, sizeof(GF_Event)); - evt.type = GF_EVENT_QUIT; - validator->term->compositor->video_out->on_event(validator->term->compositor->video_out->evt_cbk_hdl, &evt); - } else { - if (!validator->is_recording) { - validator_load_event(validator); - } + if (! validator->trace_mode) { + gf_term_disconnect(validator->term); + gf_sc_remove_video_listener(validator->term->compositor, &validator->video_listener); + validator_xvs_next(validator, 0); + if (!validator->xvs_node) { + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = GF_EVENT_QUIT; + validator->term->compositor->video_out->on_event(validator->term->compositor->video_out->evt_cbk_hdl, &evt); + } else { + if (!validator->is_recording) { + validator_load_event(validator); + } + } } } } @@ -1017,4 +1049,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( validator ) +GPAC_MODULE_STATIC_DECLARATION( validator ) diff --git a/modules/vtt_in/Makefile b/modules/vtt_in/Makefile index 77a287e..66e276e 100644 --- a/modules/vtt_in/Makefile +++ b/modules/vtt_in/Makefile @@ -22,7 +22,7 @@ OBJS= vtt_in.o vtt_dec.o SRCS := $(OBJS:.o=.c) -LIB=gm_vtt_in.$(DYN_LIB_SUFFIX) +LIB=gm_vtt_in$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols vtt_in.def endif @@ -33,7 +33,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(EXTRALIBS) $(LOCAL_LIB) $(LINKLIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_vtt_in-static.$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) $(LOCAL_LIB) -lgpac_static + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_vtt_in-static$(DYN_LIB_SUFFIX) $(OBJS) $(EXTRALIBS) $(LOCAL_LIB) -lgpac_static endif clean: diff --git a/modules/vtt_in/vtt_dec.c b/modules/vtt_in/vtt_dec.c index 03ea6d4..f84475a 100644 --- a/modules/vtt_in/vtt_dec.c +++ b/modules/vtt_in/vtt_dec.c @@ -32,7 +32,7 @@ #include <gpac/nodes_svg.h> #include <gpac/webvtt.h> -#ifndef GPAC_DISABLE_VTT +#if !defined(GPAC_DISABLE_VTT) && !defined(GPAC_DISABLE_SVG) typedef struct { GF_BaseInterface *module; @@ -85,11 +85,11 @@ typedef struct { static Bool vtt_check_download(VTTDec *vttdec) { u64 size; - FILE *f = gf_f64_open(vttdec->file_name, "rt"); + FILE *f = gf_fopen(vttdec->file_name, "rt"); if (!f) return GF_FALSE; - gf_f64_seek(f, 0, SEEK_END); - size = gf_f64_tell(f); - fclose(f); + gf_fseek(f, 0, SEEK_END); + size = gf_ftell(f); + gf_fclose(f); if (size==vttdec->file_size) return GF_TRUE; return GF_FALSE; } @@ -183,18 +183,18 @@ void VTT_load_script(VTTDec *vttdec, GF_SceneGraph *graph) /* try to find the JS renderer in the default GPAC installation folder */ const char *startuppath = gf_modules_get_option((GF_BaseInterface *)vttdec->module, "General", "StartupFile"); path = gf_url_concatenate(startuppath, "webvtt-renderer.js"); - jsfile = gf_f64_open(path, "rt"); + jsfile = gf_fopen(path, "rt"); if (jsfile) { gf_modules_set_option((GF_BaseInterface *)vttdec->module, "WebVTT", "RenderingScript", path); - fclose(jsfile); + gf_fclose(jsfile); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[WebVTT] Cannot find Rendering Script - check config file\n")); return; } } - jsfile = gf_f64_open(path, "rt"); + jsfile = gf_fopen(path, "rt"); if (jsfile) { - fclose(jsfile); + gf_fclose(jsfile); gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info); gf_svg_parse_attribute(n, &info, (char *) path, 0); vttdec->has_rendering_script = GF_TRUE; @@ -393,4 +393,4 @@ void DeleteVTTDec(GF_BaseDecoder *plug) gf_free(plug); } -#endif +#endif // !defined(GPAC_DISABLE_VTT) && !defined(GPAC_DISABLE_SVG) diff --git a/modules/vtt_in/vtt_in.c b/modules/vtt_in/vtt_in.c index 72b76f5..67f4e9a 100644 --- a/modules/vtt_in/vtt_in.c +++ b/modules/vtt_in/vtt_in.c @@ -369,21 +369,22 @@ void DeleteVTTInput(void *ifce) gf_free(plug); } +#if !defined(GPAC_DISABLE_SVG) void *NewVTTDec(); void DeleteVTTDec(GF_BaseDecoder *plug); -//GF_JSUserExtension *NewVTTJS(); -//void DeleteVTTJS(GF_BaseInterface *ifce); +#endif /*interface create*/ GPAC_MODULE_EXPORT GF_BaseInterface *LoadInterface(u32 InterfaceType) { switch (InterfaceType) { +#if !defined(GPAC_DISABLE_SVG) case GF_SCENE_DECODER_INTERFACE: return (GF_BaseInterface *)NewVTTDec(); +#endif case GF_NET_CLIENT_INTERFACE: return (GF_BaseInterface *)NewVTTInput(); -// case GF_JS_USER_EXT_INTERFACE: return (GF_BaseInterface *)NewVTTJS(); default: return NULL; } @@ -395,15 +396,14 @@ GPAC_MODULE_EXPORT void ShutdownInterface(GF_BaseInterface *ifce) { switch (ifce->InterfaceType) { +#if !defined(GPAC_DISABLE_SVG) case GF_SCENE_DECODER_INTERFACE: DeleteVTTDec((GF_BaseDecoder *)ifce); break; +#endif case GF_NET_CLIENT_INTERFACE: DeleteVTTInput(ifce); break; - //case GF_JS_USER_EXT_INTERFACE: - // DeleteVTTJS(ifce); - // break; } } @@ -431,14 +431,15 @@ GPAC_MODULE_EXPORT const u32 *QueryInterfaces() { static u32 si [] = { -#if !defined(GPAC_DISABLE_VTT) - GF_SCENE_DECODER_INTERFACE, +#if !defined(GPAC_DISABLE_VTT) GF_NET_CLIENT_INTERFACE, -// GF_JS_USER_EXT_INTERFACE, +#if !defined(GPAC_DISABLE_SVG) + GF_SCENE_DECODER_INTERFACE, +#endif #endif 0 }; return si; } -GPAC_MODULE_STATIC_DELARATION( vtt_in ) +GPAC_MODULE_STATIC_DECLARATION( vtt_in ) diff --git a/modules/wav_out/Makefile b/modules/wav_out/Makefile index 6e47796..8539468 100644 --- a/modules/wav_out/Makefile +++ b/modules/wav_out/Makefile @@ -20,7 +20,7 @@ OBJS=wav_out.o SRCS := $(OBJS:.o=.c) -LIB=gm_wav_audio.$(DYN_LIB_SUFFIX) +LIB=gm_wav_audio$(DYN_LIB_SUFFIX) #LDFLAGS+=-export-symbols wav_out.def all: $(LIB) diff --git a/modules/wav_out/wav_out.c b/modules/wav_out/wav_out.c index c0dbca8..b26833d 100644 --- a/modules/wav_out/wav_out.c +++ b/modules/wav_out/wav_out.c @@ -492,4 +492,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( wave_out ) +GPAC_MODULE_STATIC_DECLARATION( wave_out ) diff --git a/modules/widgetman/Makefile b/modules/widgetman/Makefile index 17e0c1c..ee19727 100644 --- a/modules/widgetman/Makefile +++ b/modules/widgetman/Makefile @@ -37,7 +37,7 @@ endif SRCS := $(OBJS:.o=.c) -LIB=gm_widgetman.$(DYN_LIB_SUFFIX) +LIB=gm_widgetman$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols widgetman.def endif diff --git a/modules/widgetman/unzip.c b/modules/widgetman/unzip.c index 4043a92..d884d60 100644 --- a/modules/widgetman/unzip.c +++ b/modules/widgetman/unzip.c @@ -98,7 +98,7 @@ int mode; mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) - file = fopen(filename, mode_fopen); + file = gf_fopen(filename, mode_fopen); return file; } @@ -167,7 +167,7 @@ voidpf opaque; voidpf stream; { int ret; - ret = fclose((FILE *)stream); + ret = gf_fclose((FILE *)stream); return ret; } @@ -1258,7 +1258,7 @@ unzFile uf; if ((skip==0) && (err==UNZ_OK)) { - fout=fopen(write_filename,"wb"); + fout = gf_fopen(write_filename,"wb"); /* some zipfile don't contain directory alone before file */ if ((fout==NULL) && (filename_withoutpath!=(char*)filename_inzip)) @@ -1267,7 +1267,7 @@ unzFile uf; *(filename_withoutpath-1)='\0'; makedir(write_filename); *(filename_withoutpath-1)=c; - fout=fopen(write_filename,"wb"); + fout = gf_fopen(write_filename,"wb"); } if (fout==NULL) @@ -1298,7 +1298,7 @@ unzFile uf; } while (err>0); if (fout) - fclose(fout); + gf_fclose(fout); } if (err==UNZ_OK) @@ -1367,13 +1367,13 @@ int gf_unzip_archive(const char *zipfilename, const char *dirname) int gf_unzip_probe(const char *zipfilename) { int ret = 0; - FILE *f = fopen(zipfilename, "r"); + FILE *f = gf_fopen(zipfilename, "r"); if (!f) return 0; if (fgetc(f)=='P') if (fgetc(f)=='K') if (fgetc(f)==3) if (fgetc(f)==4) ret = 1; - fclose(f); + gf_fclose(f); return ret; } diff --git a/modules/widgetman/unzip.h b/modules/widgetman/unzip.h index 073afc8..19a7c21 100644 --- a/modules/widgetman/unzip.h +++ b/modules/widgetman/unzip.h @@ -206,7 +206,7 @@ typedef struct char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ - uLong pos_in_zipfile; /* position in byte on the zipfile, for gf_f64_seek*/ + uLong pos_in_zipfile; /* position in byte on the zipfile, for gf_fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ uLong offset_local_extrafield;/* offset of the local extra field */ diff --git a/modules/widgetman/wgt_load.c b/modules/widgetman/wgt_load.c index db1e24b..6f8a96c 100644 --- a/modules/widgetman/wgt_load.c +++ b/modules/widgetman/wgt_load.c @@ -43,7 +43,7 @@ #include <gpac/nodes_svg.h> #include <gpac/constants.h> -#ifdef GPAC_HAS_SPIDERMONKEY +#if defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG) typedef struct { @@ -119,9 +119,9 @@ static GF_Err WGT_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 i gf_node_register(n, root); gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); path = gf_modules_get_option((GF_BaseInterface *)plug, "Widgets", "WidgetLoadScript"); - jsfile = path ? gf_f64_open(path, "rt") : NULL; + jsfile = path ? gf_fopen(path, "rt") : NULL; if (jsfile) { - fclose(jsfile); + gf_fclose(jsfile); gf_node_get_attribute_by_tag(n, TAG_XLINK_ATT_href, 1, 0, &info); gf_svg_parse_attribute(n, &info, (char *) path, 0); } else { @@ -142,9 +142,9 @@ static GF_Err WGT_ProcessData(GF_SceneDecoder *plug, const char *inBuffer, u32 i wmpath = gf_modules_get_option((GF_BaseInterface *)plug, "Widgets", "WidgetManagerScript"); - jsfile = wmpath ? gf_f64_open(wmpath, "rt") : NULL; + jsfile = wmpath ? gf_fopen(wmpath, "rt") : NULL; if (jsfile) { - fclose(jsfile); + gf_fclose(jsfile); n = gf_node_new(wgtload->scene->graph, TAG_SVG_script); gf_node_register(n, root); gf_node_list_add_child_last(&((GF_ParentNode *)root)->children, n, &last); @@ -299,4 +299,4 @@ void ShutdownWidgetReader(GF_BaseInterface *ifce) gf_free(sdec); } -#endif /*GPAC_HAS_SPIDERMONKEY*/ +#endif /* defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG) */ diff --git a/modules/widgetman/wgt_load_base.js b/modules/widgetman/wgt_load_base.js index bdaadbd..5a1a9c3 100644 --- a/modules/widgetman/wgt_load_base.js +++ b/modules/widgetman/wgt_load_base.js @@ -30,8 +30,8 @@ function load_widget(wid_url) { if (wid != null) { debug('Loading scene: '+wid.main); anim.setAttributeNS(xmlns_xlink, 'href', wid.main); - add_text_span(info, 'Widget Metadata'); - add_text_span(info, 'UA Locale: \'' + gpac.getOption('Systems', 'Language2CC') + '\''); + add_text_span(info, 'Widget Metadata'); + add_text_span(info, 'UA Locale: \'' + gpac.get_option('Systems', 'Language2CC') + '\''); add_text_span(info, 'widget src (abs.): \'' + wid.url + '\''); add_text_span(info, 'config src (abs.): \'' + wid.manifest + '\''); add_text_span(info, 'content src (rel.&loc./abs.): \''+wid.main+'\' / \''+wid.localizedSrc+'\' ('+wid.mainMimeType+';'+wid.mainEncoding+')'); diff --git a/modules/widgetman/widgetman.c b/modules/widgetman/widgetman.c index 0949240..721c524 100644 --- a/modules/widgetman/widgetman.c +++ b/modules/widgetman/widgetman.c @@ -104,7 +104,7 @@ static void widget_package_extract_file(GF_WidgetPackage *wpack, GF_WidgetPackag unzOpenCurrentFile3(uf, NULL, NULL, 0, NULL/*password*/); - fout=gf_f64_open(res->extracted_path, "wb"); + fout=gf_fopen(res->extracted_path, "wb"); if (!fout) break; do { err = unzReadCurrentFile(uf,buf,8192); @@ -115,7 +115,7 @@ static void widget_package_extract_file(GF_WidgetPackage *wpack, GF_WidgetPackag break; } } while (err>0); - if (fout) fclose(fout); + if (fout) gf_fclose(fout); res->extracted = 1; break; @@ -379,7 +379,7 @@ static GF_WidgetPackage *widget_zip_new(GF_WidgetManager *wm, const char *path) FILE *fout; unzOpenCurrentFile3(uf, NULL, NULL, 0, NULL/*password*/); - fout=gf_f64_open(szPath,"wb"); + fout=gf_fopen(szPath,"wb"); if (!fout) return NULL; do { @@ -392,7 +392,7 @@ static GF_WidgetPackage *widget_zip_new(GF_WidgetManager *wm, const char *path) break; } } while (err>0); - if (fout) fclose(fout); + if (fout) gf_fclose(fout); if (err==0) { GF_SAFEALLOC(pack_res, GF_WidgetPackageResource); pack_res->extracted_path = gf_strdup(szPath); @@ -1051,11 +1051,13 @@ static void wm_widget_set_pref_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *o if (evt->type != GF_EVENT_ATTR_MODIFIED) return; if (evt->detail == (u32) -1) { +#ifndef GPAC_DISABLE_SVG att = gf_dom_flatten_textContent(evt->target); +#endif } else { att = gf_node_dump_attribute(evt->target, evt->attr); - if (!att) return; } + if (!att) return; gf_cfg_set_key(wid->widget->wm->term->user->config, (const char *)wid->secname, pref->name, att); gf_free(att); } @@ -1190,7 +1192,9 @@ static void wm_widget_load_event(GF_Node *hdl, GF_DOM_Event *evt, GF_Node *obser static JSBool SMJS_FUNCTION(wm_widget_activate) { +#ifndef GPAC_DISABLE_SVG SVG_handlerElement *handler; +#endif GF_MediaObject *mo; Bool direct_trigger = 0; MFURL url; @@ -2024,8 +2028,10 @@ static JSBool wm_widget_bind_interface_ex(JSContext *c, JSObject *obj, uintN arg } } if (found) { +#ifndef GPAC_DISABLE_SVG GF_Node *listener = handler->sgprivate->parents->node; gf_dom_listener_del(listener, listener->sgprivate->UserPrivate); +#endif gf_list_rem(wid->output_triggers, i); i--; count--; @@ -3634,7 +3640,10 @@ const u32 *QueryInterfaces() static u32 si [] = { #ifdef GPAC_HAS_SPIDERMONKEY GF_JS_USER_EXT_INTERFACE, +#ifndef GPAC_DISABLE_SVG GF_SCENE_DECODER_INTERFACE, +#endif + #endif 0 }; @@ -3646,7 +3655,9 @@ GF_BaseInterface *LoadInterface(u32 InterfaceType) { #ifdef GPAC_HAS_SPIDERMONKEY if (InterfaceType == GF_JS_USER_EXT_INTERFACE) return (GF_BaseInterface *)gwm_new(); +#ifndef GPAC_DISABLE_SVG else if (InterfaceType == GF_SCENE_DECODER_INTERFACE) return (GF_BaseInterface *)LoadWidgetReader(); +#endif #endif return NULL; } @@ -3659,12 +3670,15 @@ void ShutdownInterface(GF_BaseInterface *ifce) case GF_JS_USER_EXT_INTERFACE: gwm_delete(ifce); break; +#ifndef GPAC_DISABLE_SVG case GF_SCENE_DECODER_INTERFACE: ShutdownWidgetReader(ifce); break; +#endif + #endif } } -GPAC_MODULE_STATIC_DELARATION( widgetman ) +GPAC_MODULE_STATIC_DECLARATION( widgetman ) diff --git a/modules/wiiis/Makefile b/modules/wiiis/Makefile index 27b10a0..90a4b02 100644 --- a/modules/wiiis/Makefile +++ b/modules/wiiis/Makefile @@ -22,7 +22,7 @@ OBJS= wiiis.o SRCS := $(OBJS:.o=.c) -LIB=gm_wiiis.$(DYN_LIB_SUFFIX) +LIB=gm_wiiis$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols wiiis.def endif diff --git a/modules/wiiis/wiiis.c b/modules/wiiis/wiiis.c index e2d01cc..405660e 100644 --- a/modules/wiiis/wiiis.c +++ b/modules/wiiis/wiiis.c @@ -261,4 +261,4 @@ void ShutdownInterface(GF_BaseInterface *bi) gf_free(bi); } -GPAC_MODULE_STATIC_DELARATION( wiiis ) \ No newline at end of file +GPAC_MODULE_STATIC_DECLARATION( wiiis ) diff --git a/modules/x11_out/Makefile b/modules/x11_out/Makefile index d05f44f..9801c37 100644 --- a/modules/x11_out/Makefile +++ b/modules/x11_out/Makefile @@ -53,7 +53,7 @@ OBJS=x11_out.o SRCS := $(OBJS:.o=.c) -LIB=gm_x11_out.$(DYN_LIB_SUFFIX) +LIB=gm_x11_out$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols endif @@ -65,7 +65,7 @@ all: $(LIB) $(LIB): $(OBJS) $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -lX11 -L../../bin/gcc -lgpac $(EXTRALIBS) ifeq ($(STATICBUILD),yes) - $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_x11_out-static.$(DYN_LIB_SUFFIX) $(OBJS) -lX11 -L../../bin/gcc -lgpac_static $(EXTRALIBS) + $(CC) $(SHFLAGS) $(LDFLAGS) -o ../../bin/gcc/gm_x11_out-static$(DYN_LIB_SUFFIX) $(OBJS) -lX11 -L../../bin/gcc -lgpac_static $(EXTRALIBS) endif diff --git a/modules/x11_out/x11_out.c b/modules/x11_out/x11_out.c index 3373612..de08605 100644 --- a/modules/x11_out/x11_out.c +++ b/modules/x11_out/x11_out.c @@ -749,7 +749,7 @@ static void X11_HandleEvents(GF_VideoOutput *vout) xWindow->w_height = evt.size.height = xevent.xconfigure.height; vout->on_event(vout->evt_cbk_hdl, &evt); } else { - evt.type = GF_EVENT_MOVE; + evt.type = GF_EVENT_MOVE_NOTIF; evt.move.x = xevent.xconfigure.x; evt.move.y = xevent.xconfigure.y; vout->on_event(vout->evt_cbk_hdl, &evt); @@ -1157,6 +1157,21 @@ GF_Err X11_ProcessEvent (struct _video_out * vout, GF_Event * evt) break; case GF_EVENT_SHOWHIDE: break; + case GF_EVENT_MOVE: + if (xWindow->fullscreen) return GF_OK; + + if (evt->move.relative == 2) { + } + else if (evt->move.relative) { + s32 x, y; + Window child; + x = y = 0; + XTranslateCoordinates(xWindow->display, xWindow->wnd, RootWindowOfScreen (xWindow->screenptr), 0, 0, &x, &y, &child ); + XMoveWindow(xWindow->display, xWindow->wnd, x + evt->move.x, y + evt->move.y); + } else { + XMoveWindow(xWindow->display, xWindow->wnd, evt->move.x, evt->move.y); + } + break; case GF_EVENT_SIZE: /*if owning the window and not in fullscreen, resize it (initial scene size)*/ xWindow->w_width = evt->size.width; @@ -1802,4 +1817,4 @@ void ShutdownInterface (GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( x11_out ) +GPAC_MODULE_STATIC_DECLARATION( x11_out ) diff --git a/modules/x11_out/x11_out.h b/modules/x11_out/x11_out.h index a02a4de..44e91e6 100644 --- a/modules/x11_out/x11_out.h +++ b/modules/x11_out/x11_out.h @@ -39,7 +39,7 @@ extern "C" #include <X11/Xutil.h> #include <X11/keysym.h> -#if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) #define GPAC_HAS_OPENGL #endif diff --git a/modules/xvid_dec/Makefile b/modules/xvid_dec/Makefile index 9923ba3..2c6d502 100644 --- a/modules/xvid_dec/Makefile +++ b/modules/xvid_dec/Makefile @@ -26,7 +26,7 @@ EXTRALIBS+= -lxvidcore -lpthread SRCS := $(OBJS:.o=.c) -LIB=gm_xvid_dec.$(DYN_LIB_SUFFIX) +LIB=gm_xvid_dec$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) #LDFLAGS+=-export-symbols xvid_dec.def endif diff --git a/modules/xvid_dec/xvid_dec.c b/modules/xvid_dec/xvid_dec.c index 9696f4c..0d34648 100644 --- a/modules/xvid_dec/xvid_dec.c +++ b/modules/xvid_dec/xvid_dec.c @@ -512,4 +512,4 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( xvid ) +GPAC_MODULE_STATIC_DECLARATION( xvid ) diff --git a/modules/xvid_dec/xvid_dec_wce.cpp b/modules/xvid_dec/xvid_dec_wce.cpp index 37ddce1..aa11716 100644 --- a/modules/xvid_dec/xvid_dec_wce.cpp +++ b/modules/xvid_dec/xvid_dec_wce.cpp @@ -296,7 +296,7 @@ void ShutdownInterface(GF_BaseInterface *ifce) } } -GPAC_MODULE_STATIC_DELARATION( xvid_dec_wce ) +GPAC_MODULE_STATIC_DECLARATION( xvid_dec_wce ) #ifdef __cplusplus } diff --git a/packagers/win32_64/nsis/gpac_installer.nsi b/packagers/win32_64/nsis/gpac_installer.nsi index 39d709b..f99d602 100644 --- a/packagers/win32_64/nsis/gpac_installer.nsi +++ b/packagers/win32_64/nsis/gpac_installer.nsi @@ -1,954 +1,964 @@ -;-------------------------------- -;General -!define GPAC_VERSION 0.5.1-DEV -!include default.out - -!define GPAC_ROOT ..\..\.. -!ifdef IS_WIN64 -!define GPAC_BIN ${GPAC_ROOT}\bin\x64\release -!define GPAC_EXTRA_LIB ${GPAC_ROOT}\extra_lib\lib\x64\release -InstallDir "$PROGRAMFILES64\GPAC" -!else -!define GPAC_BIN ${GPAC_ROOT}\bin\win32\release -!define GPAC_EXTRA_LIB ${GPAC_ROOT}\extra_lib\lib\win32\release -InstallDir "$PROGRAMFILES32\GPAC" -!endif - -InstallDirRegKey HKCU "SOFTWARE\GPAC" "InstallDir" - -RequestExecutionLevel highest -!include LogicLib.nsh - -Function .onInit -!ifdef IS_WIN64 -!include "x64.nsh" -${If} ${RunningX64} -${Else} - MessageBox MB_OK|MB_ICONSTOP "This installer is for 64bits operating systems only.$\n Please go to our website and get the 32 BITS installer." - Quit -${Endif} -!endif - -UserInfo::GetAccountType -pop $0 -FunctionEnd - -;-------------------------------- -;Include Modern UI - - !include "MUI2.nsh" - -WindowIcon on -Icon "${GPAC_ROOT}\doc\osmo4.ico" -UninstallIcon "${GPAC_ROOT}\doc\osmo4.ico" - -;-------------------------------- -;Interface Settings - - !define MUI_ABORTWARNING - -Var DIALOG -Var Label -Var Confirm - -LangString PAGE_TITLE ${LANG_ENGLISH} "Title" -LangString PAGE_SUBTITLE ${LANG_ENGLISH} "Subtitle" - -Function EnableNext - Pop $R1 - ${NSD_GetState} $Confirm $R1 - GetDlgItem $0 $HWNDPARENT 1 - ${If} $R1 == ${BST_CHECKED} - EnableWindow $0 1 - ${Else} - EnableWindow $0 0 - ${Endif} -FunctionEnd - -Function customPage - !insertmacro MUI_HEADER_TEXT "Patents and Royalties" "Please read carefully the following clause." - GetDlgItem $0 $HWNDPARENT 1 - EnableWindow $0 0 - nsDialogs::Create 1018 - Pop $DIALOG - - ${NSD_CreateLabel} 0 0 100% 120u "Multimedia technologies are often covered by various patents which are most of the time hard to identify. These patents may or may not apply in your local jurisdiction. By installing this software, you acknowledge that you may have to pay royaltee fees in order to legally use this software. Do not proceed with this setup if you do not understand or do not agree with these terms. In any case, the authors and/or distributors bears no liability for any infringing usage of this software, which is provided for educational or research purposes." - Pop $Label - - ${NSD_CreateCheckBox} 0 -30 100% 12u "I understand and accept the conditions" - Pop $Confirm - GetFunctionAddress $0 EnableNext - nsDialogs::OnClick $Confirm $0 - - - nsDialogs::Show -FunctionEnd - -;-------------------------------- -;Pages - - !insertmacro MUI_PAGE_WELCOME - !insertmacro MUI_PAGE_LICENSE "${GPAC_ROOT}\COPYING" - Page custom customPage - !insertmacro MUI_PAGE_COMPONENTS - !insertmacro MUI_PAGE_DIRECTORY - - !insertmacro MUI_PAGE_INSTFILES - !insertmacro MUI_PAGE_FINISH - - !insertmacro MUI_UNPAGE_CONFIRM - !insertmacro MUI_UNPAGE_INSTFILES - - !insertmacro MUI_LANGUAGE "English" - -ComponentText "This will install the GPAC Framework on your computer. Select which optional things you want installed." -DirText "This will install the GPAC Framework on your computer. Choose a directory" - - -Function FctWriteRegStrAuth - ;local var - Push $0 - Push $R0 - Push $R1 - Push $R2 - Push $R3 - ;pop function arguments - Exch 5 - Pop $R3 - Exch 5 - Pop $R2 - Exch 5 - Pop $R1 - Exch 5 - Pop $R0 - - ;test if calling HKCR - StrCmp $R0 "HKCR" +1 +3 - WriteRegStr HKCR $R1 $R2 $R3 - goto lbl_end - - #has current user admin privileges? - userInfo::getAccountType - Pop $0 - StrCmp $0 "Admin" lbl_admin lbl_not_admin - - lbl_admin: - WriteRegStr HKLM $R1 $R2 $R3 - goto lbl_end - - lbl_not_admin: - WriteRegStr HKCU $R1 $R2 $R3 - - lbl_end: - Pop $R3 - Pop $R2 - Pop $R1 - Pop $R0 - Pop $0 -FunctionEnd - -!macro WriteRegStrAuth HKREG SUBREG ENTRY VALUESTR - Push "${HKREG}" - Push "${SUBREG}" - Push "${ENTRY}" - Push "${VALUESTR}" - Call FctWriteRegStrAuth -!macroend - -!define WriteRegStrAuth "!insertmacro WriteRegStrAuth" - - -Function un.FctDeleteRegKeyAuth - ;local var - Push $0 - Push $R0 - Push $R1 - ;pop function arguments - Exch 3 - Pop $R1 - Exch 3 - Pop $R0 - - ;test if calling HKCR - StrCmp $R0 "HKCR" +1 +3 - DeleteRegKey HKCR $R1 - goto lbl_end - - #has current user admin privileges? - userInfo::getAccountType - Pop $0 - StrCmp $0 "Admin" lbl_admin lbl_not_admin - - lbl_admin: - DeleteRegKey HKLM $R1 - goto lbl_end - - lbl_not_admin: - DeleteRegKey HKCU $R1 - - lbl_end: - Pop $0 - Pop $R1 - Pop $R0 -FunctionEnd - -!macro DeleteRegKeyAuth HKREG SUBREG - Push "${HKREG}" - Push "${SUBREG}" - Call un.FctDeleteRegKeyAuth -!macroend - -!define DeleteRegKeyAuth "!insertmacro DeleteRegKeyAuth" - -Function InsertGDIPLUS - Push $R0 - Push $R1 - ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion - StrCmp $R0 "" 0 lbl_winnt - - ;NOT NT - ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion VersionNumber - - StrCpy $R1 $R0 1 - ; win95, NOT SUPPORTED - StrCmp $R1 '4' 0 lbl_err_95 - StrCpy $R1 $R0 3 - StrCmp $R1 '4.0' lbl_err_95 - ;winME or 98 otherwise - StrCmp $R1 '4.9' lbl_add lbl_add - -lbl_err_nt: - MessageBox MB_OK "Microsoft GDI+ cannot be installed on NT 3 Systems" - Goto lbl_done - -lbl_err_95: - MessageBox MB_OK "Microsoft GDI+ cannot be installed on Windows 95 and older Systems" - Goto lbl_done - -lbl_winnt: - StrCpy $R1 $R0 1 - StrCmp $R1 '3' lbl_err_nt - StrCmp $R1 '4' lbl_add - StrCpy $R1 $R0 3 - StrCmp $R1 '5.0' lbl_add ;2000 - StrCmp $R1 '5.1' lbl_xp ;XP - StrCmp $R1 '5.2' lbl_done ;.NET server - -lbl_add: - !ifndef IS_WIN64 - File "${GPAC_BIN}\Gdiplus.dll" - !endif - -lbl_xp: - File "${GPAC_BIN}\gm_gdip_raster.dll" - -lbl_done: -FunctionEnd - -;osmo4 install -Section "Osmo4/GPAC Player" SecOsmo4 - SectionIn RO - SetOutPath $INSTDIR - - File /oname=ReadMe.txt "${GPAC_ROOT}\README" - File /oname=License.txt "${GPAC_ROOT}\COPYING" - File /oname=Changelog.txt "${GPAC_ROOT}\Changelog" - File "${GPAC_ROOT}\doc\configuration.html" - File "${GPAC_ROOT}\doc\gpac.mp4" - - !ifndef IS_WIN64 - File "${GPAC_BIN}\Osmo4.exe" - !endif - File "${GPAC_ROOT}\doc\osmo4.ico" - File "${GPAC_BIN}\libgpac.dll" - File "${GPAC_BIN}\gm_dummy_in.dll" - File "${GPAC_BIN}\gm_dx_hw.dll" - File "${GPAC_BIN}\js.dll" - File "${GPAC_BIN}\gm_gpac_js.dll" - File "${GPAC_BIN}\libeay32.dll" - File "${GPAC_BIN}\ssleay32.dll" - File "${GPAC_BIN}\gm_ismacryp.dll" - - ;create default cache - SetOutPath $INSTDIR\cache - - - ;copy GUI - SetOutPath $INSTDIR\gui - File "${GPAC_ROOT}\gui\gui.bt" - File "${GPAC_ROOT}\gui\gui.js" - File "${GPAC_ROOT}\gui\gwlib.js" - File "${GPAC_ROOT}\gui\mpegu-core.js" - File "${GPAC_ROOT}\gui\webvtt-renderer.js" - SetOutPath $INSTDIR\gui\icons - File /r /x .svn ${GPAC_ROOT}\gui\icons\* - SetOutPath $INSTDIR\gui\extensions - File /r /x .svn ${GPAC_ROOT}\gui\extensions\* - - SetOutPath $INSTDIR - - ${WriteRegStrAuth} HKCU "SOFTWARE\GPAC" "InstallDir" "$INSTDIR" - ${WriteRegStrAuth} HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Osmo4" "DisplayName" "Osmo4/GPAC (remove only)" - ${WriteRegStrAuth} HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Osmo4" "UninstallString" "$INSTDIR\uninstall.exe" - WriteUninstaller "uninstall.exe" - -SectionEnd - -SubSection "GPAC Plugins" SecPlugins - - -; -; 2 install modes, normal one and full one - -Section "MPEG-4 BIFS Decoder" SecBIFS - SectionIn 1 - File "${GPAC_BIN}\gm_bifs_dec.dll" -SectionEnd - -Section "MPEG-4 ODF Decoder" SecODF - SectionIn 1 - File "${GPAC_BIN}\gm_odf_dec.dll" -SectionEnd - -Section "MPEG-4 LASeR Decoder" SecLASeR - SectionIn 1 - File "${GPAC_BIN}\gm_laser_dec.dll" -SectionEnd - -Section "MPEG-4 SAF Demultiplexer" SecSAF - SectionIn 1 - File "${GPAC_BIN}\gm_saf_in.dll" -SectionEnd - -Section "Textual MPEG-4 Loader" SecTextLoad - SectionIn 1 - File "${GPAC_BIN}\gm_ctx_load.dll" -SectionEnd - -Section "Image Package (PNG, JPEG, BMP)" SecIMG - SectionIn 1 - File "${GPAC_BIN}\gm_img_in.dll" -SectionEnd - -Section "AAC Audio" SecAAC - SectionIn 1 - File "${GPAC_BIN}\gm_aac_in.dll" -SectionEnd - -Section "MP3 Audio" SecMP3 - SectionIn 1 - File "${GPAC_BIN}\gm_mp3_in.dll" -SectionEnd - -Section "AC3 Audio" SecAC3 - SectionIn 1 - File "${GPAC_BIN}\gm_ac3_in.dll" -SectionEnd - -Section "FFMPEG" SecFFMPEG - SectionIn 1 - File "${GPAC_BIN}\gm_ffmpeg_in.dll" - File "${GPAC_BIN}\avcodec-*.dll" - File "${GPAC_BIN}\avdevice-*.dll" - File "${GPAC_BIN}\avfilter-*.dll" - File "${GPAC_BIN}\avformat-*.dll" - File "${GPAC_BIN}\avutil-*.dll" - File "${GPAC_BIN}\avresample-*.dll" - File "${GPAC_BIN}\swresample-*.dll" - File "${GPAC_BIN}\swscale-*.dll" - File "${GPAC_BIN}\libx264-*.dll" -SectionEnd - -Section "XviD Video Decoder" SecXVID - SectionIn 1 - File "${GPAC_BIN}\gm_xvid_dec.dll" -SectionEnd - -;Section "AMR NB & WB" SecAMRFT -; SectionIn 1 -; File "..\gm_amr_float_dec.dll" -;SectionEnd - -Section "Subtitles" SecSUBS - SectionIn 1 - File "${GPAC_BIN}\gm_timedtext.dll" -SectionEnd - -Section "ISO File Format" SecISOFF - SectionIn 1 - File "${GPAC_BIN}\gm_isom_in.dll" -SectionEnd - -Section "MPEG-2 TS" SecM2TS - SectionIn 1 - File "${GPAC_BIN}\gm_mpegts_in.dll" -SectionEnd - -Section "RTP/RTSP" SecRTP - SectionIn 1 - File "${GPAC_BIN}\gm_rtp_in.dll" -SectionEnd - -Section "SVG" SecSVG - SectionIn 1 - File "${GPAC_BIN}\gm_svg_in.dll" -SectionEnd - -Section "WebVTT" SecWebVTT - SectionIn 1 - File "${GPAC_BIN}\gm_vtt_in.dll" -SectionEnd - -Section "GDI+" SecGDIP - SectionIn 1 - call InsertGDIPLUS -SectionEnd - -Section "GPAC 2D Raster" SecG2DS - SectionIn 1 - File "${GPAC_BIN}\gm_soft_raster.dll" -SectionEnd - -Section "FreeType" SecFT - SectionIn 1 - File "${GPAC_BIN}\gm_ft_font.dll" -SectionEnd - -Section "Windows MME Audio" SecWAVE - SectionIn 1 - File "${GPAC_BIN}\gm_wav_out.dll" -SectionEnd - -Section "Xiph" SecXIPH - SectionIn 1 - File "${GPAC_BIN}\gm_ogg.dll" -SectionEnd - -Section "OpenSVC Decoder" SecOSVC - SectionIn 1 - File "${GPAC_BIN}\OpenSVCDecoder.dll" - File "${GPAC_BIN}\gm_opensvc_dec.dll" -SectionEnd - -Section "OpenHEVC Decoder" SecOHEVC - SectionIn 1 - File "${GPAC_BIN}\libLibOpenHevcWrapper.dll" - File "${GPAC_BIN}\gm_openhevc_dec.dll" -SectionEnd - -Section "MPEG DASH Suppport" SecDASH - SectionIn 1 - File "${GPAC_BIN}\gm_mpd_in.dll" -SectionEnd - -Section "HTML 5 Media Source Extensions Suppport" SecMSE - SectionIn 1 - File "${GPAC_BIN}\gm_mse_in.dll" -SectionEnd - -Section "UPnP Support" SecUPnP - SectionIn 1 - File "${GPAC_BIN}\gm_platinum.dll" -SectionEnd - -Section "Widget Manager" SecMPEGU - SectionIn 1 - File "${GPAC_BIN}\gm_widgetman.dll" -SectionEnd - -;Section "MobileIP Framework" SecMobIP -; SectionIn 1 -; File "..\gm_mobile_ip.dll" -; File "..\MobileSession.dll" -;SectionEnd - - -;Section "OFFIS Audio compressor" SecOffisComp -; SectionIn 1 -; ;copy GUI -; File "..\gm_offis_compressor.dll" -; File "..\QtCore4.dll" -; File "..\QtGui4.dll" -; SetOutPath $INSTDIR\gui\extensions -; File /r /x .svn ..\..\..\..\gui\extensions\offis* -; SetOutPath $INSTDIR -;SectionEnd - -SubSectionEnd - - -Section "MP4Box" SecMP4B - SectionIn 1 - SetOutPath $INSTDIR - File "${GPAC_BIN}\MP4Box.exe" - File "${GPAC_BIN}\MP42TS.exe" - File "${GPAC_BIN}\dashcast.exe" - - Push $INSTDIR - Call AddToPath -SectionEnd - - -Section "GPAC SDK" SecSDK - SectionIn 1 - SetOutPath $INSTDIR\sdk\include - File /r /x CVS ${GPAC_ROOT}\include\*.h - SetOutPath $INSTDIR\sdk\lib - File ${GPAC_BIN}\libgpac.lib - File ${GPAC_EXTRA_LIB}\js.lib -SectionEnd - - -!ifndef IS_WIN64 -!define HK_MOZ "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" - -Section "Osmozilla" SecZILLA - SectionIn 1 - SetOutPath $INSTDIR - File "${GPAC_BIN}\nposmozilla.dll" - File "${GPAC_BIN}\nposmozilla.xpt" - - ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Path" "$INSTDIR\nposmozilla.dll" - ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "XPTPath" "$INSTDIR\nposmozilla.xpt" - ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Version" "${GPAC_VERSION}" - ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Vendor" "GPAC" - ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Description" "GPAC plugin" - ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "ProductName" "Osmozilla" -SectionEnd -!endif - -Section "GPAX" SecGPAX - SectionIn 1 - SetOutPath $INSTDIR - File "${GPAC_BIN}\GPAX.dll" - RegDLL "$INSTDIR\GPAX.dll" -SectionEnd - - -Section "MP4Client" SecMP4C - SectionIn 1 - SetOutPath $INSTDIR - File "${GPAC_BIN}\MP4Client.exe" -SectionEnd - - - -Section "Windows Runtime Libraries" SecMSVCRT - SectionIn 1 -; File "..\Microsoft.VC100.CRT.manifest" -; File "..\Microsoft.VC100.MFC.manifest" - File "${GPAC_BIN}\msvcr100.dll" - File "${GPAC_BIN}\mfc100.dll" -SectionEnd - - - - -SubSection "Osmo4 Shortcuts" - -Section "Add Start Menu Shortcuts" - SectionIn 1 - #has current user admin privileges? - userInfo::getAccountType - Pop $0 - StrCmp $0 "Admin" +1 +2 - SetShellVarContext all - CreateDirectory "$SMPROGRAMS\Osmo4" - CreateShortCut "$SMPROGRAMS\Osmo4\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - !ifndef IS_WIN64 - CreateShortCut "$SMPROGRAMS\Osmo4\Osmo4 (Classic UI).lnk" "$INSTDIR\Osmo4.exe" "" - !endif - CreateShortCut "$SMPROGRAMS\Osmo4\Osmo4 (New UI).lnk" "$INSTDIR\MP4Client.exe" "-gui" - CreateShortCut "$SMPROGRAMS\Osmo4\Osmo4 (New UI With Console).lnk" "$INSTDIR\MP4Client.exe" "" - CreateShortCut "$SMPROGRAMS\Osmo4\Readme.lnk" "$INSTDIR\ReadMe.txt" - CreateShortCut "$SMPROGRAMS\Osmo4\License.lnk" "$INSTDIR\License.txt" - CreateShortCut "$SMPROGRAMS\Osmo4\History.lnk" "$INSTDIR\changelog.txt" - CreateShortCut "$SMPROGRAMS\Osmo4\Configuration Info.lnk" "$INSTDIR\configuration.html" -SectionEnd - -!ifndef IS_WIN64 -Section "Add shortcut to QuickLaunch" - SectionIn 1 - CreateShortCut "$QUICKLAUNCH\Osmo4.lnk" "$INSTDIR\Osmo4.exe" "" "$INSTDIR\Osmo4.exe" 0 -SectionEnd - -Section "Add shortcut to Desktop" - SectionIn 1 - CreateShortCut "$DESKTOP\Osmo4.lnk" "$INSTDIR\Osmo4.exe" "" "$INSTDIR\Osmo4.exe" 0 -SectionEnd - -!define SHCNE_ASSOCCHANGED 0x08000000 -!define SHCNF_IDLIST 0 - -Section "Make Osmo4 the default MPEG-4 Player" - SectionIn 1 - ;write file association - ${WriteRegStrAuth} HKCR GPAC\mp4\DefaultIcon "" "$INSTDIR\Osmo4.ico, 0" - ${WriteRegStrAuth} HKCR GPAC\mp4\Shell\open\command "" "$INSTDIR\Osmo4.exe %L" - ${WriteRegStrAuth} HKCR .mp4 "" "GPAC\mp4" - !system 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)' - -SectionEnd - -Section "Associate 3GPP files (3GP) with Osmo4" - SectionIn 1 - ;write file association - ${WriteRegStrAuth} HKCR GPAC\3gp\DefaultIcon "" "$INSTDIR\Osmo4.ico, 0" - ${WriteRegStrAuth} HKCR GPAC\3gp\Shell\open\command "" "$INSTDIR\Osmo4.exe %L" - ${WriteRegStrAuth} HKCR .3gp "" "GPAC\3gp" - !system 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)' -SectionEnd - -Section "Associate 3GPP2 files (3G2) with Osmo4" - SectionIn 1 - ;write file association - ${WriteRegStrAuth} HKCR GPAC\3g2\DefaultIcon "" "$INSTDIR\Osmo4.ico, 0" - ${WriteRegStrAuth} HKCR GPAC\3g2\Shell\open\command "" "$INSTDIR\Osmo4.exe %L" - ${WriteRegStrAuth} HKCR .3g2 "" "GPAC\3g2" - !system 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)' -SectionEnd -!endif - -SubSectionEnd - - - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${SecOsmo4} "Osmo4 player" - !insertmacro MUI_DESCRIPTION_TEXT ${SecPlugins} "GPAC Plugins" - !insertmacro MUI_DESCRIPTION_TEXT ${SecBIFS} "MPEG-4 BIFS Scene Decoder" - !insertmacro MUI_DESCRIPTION_TEXT ${SecODF} "MPEG-4 Object Descriptor Decoder" - !insertmacro MUI_DESCRIPTION_TEXT ${SecLASeR} "MPEG-4 LASeR Scene Decoder" - !insertmacro MUI_DESCRIPTION_TEXT ${SecTextLoad} "Support for uncompressed MPEG-4 (BT and XMT), VRML and X3D textual formats" - !insertmacro MUI_DESCRIPTION_TEXT ${SecSAF} "MPEG-4 SAF Demultiplexer" - !insertmacro MUI_DESCRIPTION_TEXT ${SecIMG} "Support for PNG, JPEG, BMP and JPEG2000 images" - !insertmacro MUI_DESCRIPTION_TEXT ${SecAAC} "Support for MPEG-4 Audio HE-AAC decoder and web radios" - !insertmacro MUI_DESCRIPTION_TEXT ${SecMP3} "Support for MPEG-1/2 Audio (inc. MP3) decoder and web radios" - !insertmacro MUI_DESCRIPTION_TEXT ${SecAC3} "Support for Dolby AC3 decoder and web radios" - !insertmacro MUI_DESCRIPTION_TEXT ${SecFFMPEG} "Support for FFMPEG libraries for various format decoding and demultiplexing" - !insertmacro MUI_DESCRIPTION_TEXT ${SecXVID} "Support for XVID library for MPEG-4 Video Part 2 decoding" - !insertmacro MUI_DESCRIPTION_TEXT ${SecAMRFT} "Support for AMR and AMR WideBand decoder and web radios" - !insertmacro MUI_DESCRIPTION_TEXT ${SecSUBS} "Subtitle support include SRT, SUB, 3GPP and MPEG-4 Text formats" - !insertmacro MUI_DESCRIPTION_TEXT ${SecISOFF} "Support for ISO-based file formats (3GP, MP4, MJ2K)" - !insertmacro MUI_DESCRIPTION_TEXT ${SecM2TS} "Support for MPEG-2 Transport Stream" - !insertmacro MUI_DESCRIPTION_TEXT ${SecRTP} "Support for RTP and RTSP IP streaming" - !insertmacro MUI_DESCRIPTION_TEXT ${SecSVG} "Support for SVG including progressive loading" - !insertmacro MUI_DESCRIPTION_TEXT ${SecWebVTT} "Support for WebVTT subtitles" - !insertmacro MUI_DESCRIPTION_TEXT ${SecGDIP} "GDIPlus-based rasterizer" - !insertmacro MUI_DESCRIPTION_TEXT ${SecG2DS} "GPAC software rasterizer" - !insertmacro MUI_DESCRIPTION_TEXT ${SecFT} "FreeType font parsing" - !insertmacro MUI_DESCRIPTION_TEXT ${SecWAVE} "Windows MME Audio output support" - !insertmacro MUI_DESCRIPTION_TEXT ${SecXIPH} "Support for XIPP OGG, Vorbis and Theora media" - !insertmacro MUI_DESCRIPTION_TEXT ${SecOSVC} "Support for SVC decoding through OpenSVC Decoder" - !insertmacro MUI_DESCRIPTION_TEXT ${SecOHEVC} "Support for HEVC decoding through OpenHEVC Decoder" - !insertmacro MUI_DESCRIPTION_TEXT ${SecDASH} "HTTP Streaming using MPEG DASH" - !insertmacro MUI_DESCRIPTION_TEXT ${SecMSE} "HTTP Streaming using HTML 5 Media Source Extensions" - !insertmacro MUI_DESCRIPTION_TEXT ${SecUPnP} "Support for UPnP based on Platinum" - !insertmacro MUI_DESCRIPTION_TEXT ${SecMPEGU} "Support for W3C and MPEG-U Widgets" - !insertmacro MUI_DESCRIPTION_TEXT ${SecMobIP} "UNIGE Mobile IP Framework" - !insertmacro MUI_DESCRIPTION_TEXT ${SecOffisComp} "OFFIS Audio Compressor" - !insertmacro MUI_DESCRIPTION_TEXT ${SecMP4B} "MP4Box command-line tool for various multimedia operations" - !insertmacro MUI_DESCRIPTION_TEXT ${SecSDK} "GPAC SDK: headers and library files needed to develop modules for GPAC or appllication based on GPAC" - !insertmacro MUI_DESCRIPTION_TEXT ${SecZILLA} "GPAC playback support NPAPI-based browsers (FireFox/Gecko, Safari/WebKit)" - !insertmacro MUI_DESCRIPTION_TEXT ${SecGPAX} "GPAC playback support using ActiveX component (Internet Explorer)" - !insertmacro MUI_DESCRIPTION_TEXT ${SecMP4C} "GPAC command-line player and AVI dumper" - -!insertmacro MUI_FUNCTION_DESCRIPTION_END - - -Function .onInstSuccess -; MessageBox MB_YESNO "GPAC Framework installation complete. Do you want to launch the Osmo4 player?" IDNO NoLaunch -; Exec $INSTDIR\Osmo4.exe -; NoLaunch: -FunctionEnd - - - - - -; uninstall stuff - -UninstallText "This will uninstall OSMO4/GPAC from your computer. Hit next to continue." - -; special uninstall section. -Section "Uninstall" - ; remove registry keys - ${DeleteRegKeyAuth} HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Osmo4" - ${DeleteRegKeyAuth} HKCU "SOFTWARE\GPAC" - ${DeleteRegKeyAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" - ${DeleteRegKeyAuth} HKCR GPAC\mp4\DefaultIcon - ${DeleteRegKeyAuth} HKCR GPAC\mp4\shell\open\command - ${DeleteRegKeyAuth} HKCR GPAC\mp4 - ${DeleteRegKeyAuth} HKCR .mp4 - ${DeleteRegKeyAuth} HKCR GPAC\3gp\DefaultIcon - ${DeleteRegKeyAuth} HKCR GPAC\3gp\shell\open\command - ${DeleteRegKeyAuth} HKCR GPAC\3gp - ${DeleteRegKeyAuth} HKCR .3gp - ${DeleteRegKeyAuth} HKCR GPAC\3g2\DefaultIcon - ${DeleteRegKeyAuth} HKCR GPAC\3g2\shell\open\command - ${DeleteRegKeyAuth} HKCR GPAC\3g2 - ${DeleteRegKeyAuth} HKCR .3g2 - ${DeleteRegKeyAuth} HKCR GPAC - - UnRegDLL "$INSTDIR\GPAX.dll" - RMDir /r $INSTDIR - Push $INSTDIR - Call un.RemoveFromPath - #has current user admin privileges? - userInfo::getAccountType - Pop $0 - StrCmp $0 "Admin" +1 +2 - SetShellVarContext all - Delete "$SMPROGRAMS\Osmo4\*.*" - RMDir "$SMPROGRAMS\Osmo4" - Delete "$QUICKLAUNCH\Osmo4.lnk" - Delete "$DESKTOP\Osmo4.lnk" - -SectionEnd - -;path modif functions -!verbose 3 -!include "WinMessages.NSH" -!verbose 4 - -!ifndef WriteEnvStr_RegKey - !ifdef ALL_USERS - !define WriteEnvStr_RegKey \ - 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' - !else - !define WriteEnvStr_RegKey 'HKCU "Environment"' - !endif -!endif - -; AddToPath - Adds the given dir to the search path. -; Input - head of the stack -; Note - Win9x systems requires reboot - -Function AddToPath - Exch $0 - Push $1 - Push $2 - Push $3 - - # don't add if the path doesn't exist - IfFileExists "$0\*.*" "" AddToPath_done - - ReadEnvStr $1 PATH - Push "$1;" - Push "$0;" - Call StrStr - Pop $2 - StrCmp $2 "" "" AddToPath_done - Push "$1;" - Push "$0\;" - Call StrStr - Pop $2 - StrCmp $2 "" "" AddToPath_done - GetFullPathName /SHORT $3 $0 - Push "$1;" - Push "$3;" - Call StrStr - Pop $2 - StrCmp $2 "" "" AddToPath_done - Push "$1;" - Push "$3\;" - Call StrStr - Pop $2 - StrCmp $2 "" "" AddToPath_done - - Call IsNT - Pop $1 - StrCmp $1 1 AddToPath_NT - ; Not on NT - StrCpy $1 $WINDIR 2 - FileOpen $1 "$1\autoexec.bat" a - FileSeek $1 -1 END - FileReadByte $1 $2 - IntCmp $2 26 0 +2 +2 # DOS EOF - FileSeek $1 -1 END # write over EOF - FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" - FileClose $1 - SetRebootFlag true - Goto AddToPath_done - - AddToPath_NT: - ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH" - StrCpy $2 $1 1 -1 # copy last char - StrCmp $2 ";" 0 +2 # if last char == ; - StrCpy $1 $1 -1 # remove last char - StrCmp $1 "" AddToPath_NTdoIt - StrCpy $0 "$1;$0" - AddToPath_NTdoIt: - WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $0 - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - - AddToPath_done: - Pop $3 - Pop $2 - Pop $1 - Pop $0 -FunctionEnd - -; RemoveFromPath - Remove a given dir from the path -; Input: head of the stack - -Function un.RemoveFromPath - Exch $0 - Push $1 - Push $2 - Push $3 - Push $4 - Push $5 - Push $6 - - IntFmt $6 "%c" 26 # DOS EOF - - Call un.IsNT - Pop $1 - StrCmp $1 1 unRemoveFromPath_NT - ; Not on NT - StrCpy $1 $WINDIR 2 - FileOpen $1 "$1\autoexec.bat" r - GetTempFileName $4 - FileOpen $2 $4 w - GetFullPathName /SHORT $0 $0 - StrCpy $0 "SET PATH=%PATH%;$0" - Goto unRemoveFromPath_dosLoop - - unRemoveFromPath_dosLoop: - FileRead $1 $3 - StrCpy $5 $3 1 -1 # read last char - StrCmp $5 $6 0 +2 # if DOS EOF - StrCpy $3 $3 -1 # remove DOS EOF so we can compare - StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine - StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine - StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine - StrCmp $3 "" unRemoveFromPath_dosLoopEnd - FileWrite $2 $3 - Goto unRemoveFromPath_dosLoop - unRemoveFromPath_dosLoopRemoveLine: - SetRebootFlag true - Goto unRemoveFromPath_dosLoop - - unRemoveFromPath_dosLoopEnd: - FileClose $2 - FileClose $1 - StrCpy $1 $WINDIR 2 - Delete "$1\autoexec.bat" - CopyFiles /SILENT $4 "$1\autoexec.bat" - Delete $4 - Goto unRemoveFromPath_done - - unRemoveFromPath_NT: - ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH" - StrCpy $5 $1 1 -1 # copy last char - StrCmp $5 ";" +2 # if last char != ; - StrCpy $1 "$1;" # append ; - Push $1 - Push "$0;" - Call un.StrStr ; Find `$0;` in $1 - Pop $2 ; pos of our dir - StrCmp $2 "" unRemoveFromPath_done - ; else, it is in path - # $0 - path to add - # $1 - path var - StrLen $3 "$0;" - StrLen $4 $2 - StrCpy $5 $1 -$4 # $5 is now the part before the path to remove - StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove - StrCpy $3 $5$6 - - StrCpy $5 $3 1 -1 # copy last char - StrCmp $5 ";" 0 +2 # if last char == ; - StrCpy $3 $3 -1 # remove last char - - WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $3 - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - - unRemoveFromPath_done: - Pop $6 - Pop $5 - Pop $4 - Pop $3 - Pop $2 - Pop $1 - Pop $0 -FunctionEnd - -########################################### -# Utility Functions # -########################################### - -; IsNT -; no input -; output, top of the stack = 1 if NT or 0 if not -; -; Usage: -; Call IsNT -; Pop $R0 -; ($R0 at this point is 1 or 0) - -!macro IsNT un -Function ${un}IsNT - Push $0 - ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion - StrCmp $0 "" 0 IsNT_yes - ; we are not NT. - Pop $0 - Push 0 - Return - - IsNT_yes: - ; NT!!! - Pop $0 - Push 1 -FunctionEnd -!macroend -!insertmacro IsNT "" -!insertmacro IsNT "un." - -; StrStr -; input, top of stack = string to search for -; top of stack-1 = string to search in -; output, top of stack (replaces with the portion of the string remaining) -; modifies no other variables. -; -; Usage: -; Push "this is a long ass string" -; Push "ass" -; Call StrStr -; Pop $R0 -; ($R0 at this point is "ass string") - -!macro StrStr un -Function ${un}StrStr -Exch $R1 ; st=haystack,old$R1, $R1=needle - Exch ; st=old$R1,haystack - Exch $R2 ; st=old$R1,old$R2, $R2=haystack - Push $R3 - Push $R4 - Push $R5 - StrLen $R3 $R1 - StrCpy $R4 0 - ; $R1=needle - ; $R2=haystack - ; $R3=len(needle) - ; $R4=cnt - ; $R5=tmp - loop: - StrCpy $R5 $R2 $R3 $R4 - StrCmp $R5 $R1 done - StrCmp $R5 "" done - IntOp $R4 $R4 + 1 - Goto loop -done: - StrCpy $R1 $R2 "" $R4 - Pop $R5 - Pop $R4 - Pop $R3 - Pop $R2 - Exch $R1 -FunctionEnd -!macroend -!insertmacro StrStr "" -!insertmacro StrStr "un." +;-------------------------------- +;General +!define GPAC_VERSION 0.5.2-DEV +!include default.out + +!define GPAC_ROOT ..\..\.. +!ifdef IS_WIN64 +!define GPAC_BIN ${GPAC_ROOT}\bin\x64\release +!define GPAC_EXTRA_LIB ${GPAC_ROOT}\extra_lib\lib\x64\release +InstallDir "$PROGRAMFILES64\GPAC" +!else +!define GPAC_BIN ${GPAC_ROOT}\bin\win32\release +!define GPAC_EXTRA_LIB ${GPAC_ROOT}\extra_lib\lib\win32\release +InstallDir "$PROGRAMFILES32\GPAC" +!endif + +InstallDirRegKey HKCU "SOFTWARE\GPAC" "InstallDir" + +RequestExecutionLevel highest +!include LogicLib.nsh + +Function .onInit +!ifdef IS_WIN64 +!include "x64.nsh" +${If} ${RunningX64} +${Else} + MessageBox MB_OK|MB_ICONSTOP "This installer is for 64bits operating systems only.$\n Please go to our website and get the 32 BITS installer." + Quit +${Endif} +!endif + +UserInfo::GetAccountType +pop $0 +FunctionEnd + +;-------------------------------- +;Include Modern UI + + !include "MUI2.nsh" + +WindowIcon on +Icon "${GPAC_ROOT}\doc\osmo4.ico" +UninstallIcon "${GPAC_ROOT}\doc\osmo4.ico" + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +Var DIALOG +Var Label +Var Confirm + +LangString PAGE_TITLE ${LANG_ENGLISH} "Title" +LangString PAGE_SUBTITLE ${LANG_ENGLISH} "Subtitle" + +Function EnableNext + Pop $R1 + ${NSD_GetState} $Confirm $R1 + GetDlgItem $0 $HWNDPARENT 1 + ${If} $R1 == ${BST_CHECKED} + EnableWindow $0 1 + ${Else} + EnableWindow $0 0 + ${Endif} +FunctionEnd + +Function customPage + !insertmacro MUI_HEADER_TEXT "Patents and Royalties" "Please read carefully the following clause." + GetDlgItem $0 $HWNDPARENT 1 + EnableWindow $0 0 + nsDialogs::Create 1018 + Pop $DIALOG + + ${NSD_CreateLabel} 0 0 100% 120u "Multimedia technologies are often covered by various patents which are most of the time hard to identify. These patents may or may not apply in your local jurisdiction. By installing this software, you acknowledge that you may have to pay royaltee fees in order to legally use this software. Do not proceed with this setup if you do not understand or do not agree with these terms. In any case, the authors and/or distributors bears no liability for any infringing usage of this software, which is provided for educational or research purposes." + Pop $Label + + ${NSD_CreateCheckBox} 0 -30 100% 12u "I understand and accept the conditions" + Pop $Confirm + GetFunctionAddress $0 EnableNext + nsDialogs::OnClick $Confirm $0 + + + nsDialogs::Show +FunctionEnd + +;-------------------------------- +;Pages + + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE "${GPAC_ROOT}\COPYING" + Page custom customPage + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + + !insertmacro MUI_LANGUAGE "English" + +ComponentText "This will install the GPAC Framework on your computer. Select which optional things you want installed." +DirText "This will install the GPAC Framework on your computer. Choose a directory" + + +Function FctWriteRegStrAuth + ;local var + Push $0 + Push $R0 + Push $R1 + Push $R2 + Push $R3 + ;pop function arguments + Exch 5 + Pop $R3 + Exch 5 + Pop $R2 + Exch 5 + Pop $R1 + Exch 5 + Pop $R0 + + ;test if calling HKCR + StrCmp $R0 "HKCR" +1 +3 + WriteRegStr HKCR $R1 $R2 $R3 + goto lbl_end + + #has current user admin privileges? + userInfo::getAccountType + Pop $0 + StrCmp $0 "Admin" lbl_admin lbl_not_admin + + lbl_admin: + WriteRegStr HKLM $R1 $R2 $R3 + goto lbl_end + + lbl_not_admin: + WriteRegStr HKCU $R1 $R2 $R3 + + lbl_end: + Pop $R3 + Pop $R2 + Pop $R1 + Pop $R0 + Pop $0 +FunctionEnd + +!macro WriteRegStrAuth HKREG SUBREG ENTRY VALUESTR + Push "${HKREG}" + Push "${SUBREG}" + Push "${ENTRY}" + Push "${VALUESTR}" + Call FctWriteRegStrAuth +!macroend + +!define WriteRegStrAuth "!insertmacro WriteRegStrAuth" + + +Function un.FctDeleteRegKeyAuth + ;local var + Push $0 + Push $R0 + Push $R1 + ;pop function arguments + Exch 3 + Pop $R1 + Exch 3 + Pop $R0 + + ;test if calling HKCR + StrCmp $R0 "HKCR" +1 +3 + DeleteRegKey HKCR $R1 + goto lbl_end + + #has current user admin privileges? + userInfo::getAccountType + Pop $0 + StrCmp $0 "Admin" lbl_admin lbl_not_admin + + lbl_admin: + DeleteRegKey HKLM $R1 + goto lbl_end + + lbl_not_admin: + DeleteRegKey HKCU $R1 + + lbl_end: + Pop $0 + Pop $R1 + Pop $R0 +FunctionEnd + +!macro DeleteRegKeyAuth HKREG SUBREG + Push "${HKREG}" + Push "${SUBREG}" + Call un.FctDeleteRegKeyAuth +!macroend + +!define DeleteRegKeyAuth "!insertmacro DeleteRegKeyAuth" + +Function InsertGDIPLUS + Push $R0 + Push $R1 + ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $R0 "" 0 lbl_winnt + + ;NOT NT + ReadRegStr $R0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion VersionNumber + + StrCpy $R1 $R0 1 + ; win95, NOT SUPPORTED + StrCmp $R1 '4' 0 lbl_err_95 + StrCpy $R1 $R0 3 + StrCmp $R1 '4.0' lbl_err_95 + ;winME or 98 otherwise + StrCmp $R1 '4.9' lbl_add lbl_add + +lbl_err_nt: + MessageBox MB_OK "Microsoft GDI+ cannot be installed on NT 3 Systems" + Goto lbl_done + +lbl_err_95: + MessageBox MB_OK "Microsoft GDI+ cannot be installed on Windows 95 and older Systems" + Goto lbl_done + +lbl_winnt: + StrCpy $R1 $R0 1 + StrCmp $R1 '3' lbl_err_nt + StrCmp $R1 '4' lbl_add + StrCpy $R1 $R0 3 + StrCmp $R1 '5.0' lbl_add ;2000 + StrCmp $R1 '5.1' lbl_xp ;XP + StrCmp $R1 '5.2' lbl_done ;.NET server + +lbl_add: + !ifndef IS_WIN64 + File "${GPAC_BIN}\Gdiplus.dll" + !endif + +lbl_xp: + File "${GPAC_BIN}\gm_gdip_raster.dll" + +lbl_done: +FunctionEnd + +;GPAC core +Section "GPAC Core" SecGPAC + SectionIn RO + SetOutPath $INSTDIR + + File /oname=ReadMe.txt "${GPAC_ROOT}\README" + File /oname=License.txt "${GPAC_ROOT}\COPYING" + File /oname=Changelog.txt "${GPAC_ROOT}\Changelog" + File "${GPAC_ROOT}\doc\configuration.html" + File "${GPAC_ROOT}\doc\gpac.mp4" + File "${GPAC_ROOT}\doc\osmo4.ico" + File "${GPAC_BIN}\libgpac.dll" + File "${GPAC_BIN}\js.dll" + File "${GPAC_BIN}\libeay32.dll" + File "${GPAC_BIN}\ssleay32.dll" + + ;create default cache + SetOutPath $INSTDIR\cache + + SetOutPath $INSTDIR + + ${WriteRegStrAuth} HKCU "SOFTWARE\GPAC" "InstallDir" "$INSTDIR" + ${WriteRegStrAuth} HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\GPAC" "DisplayName" "GPAC (remove only)" + ${WriteRegStrAuth} HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\GPAC" "UninstallString" "$INSTDIR\uninstall.exe" + WriteUninstaller "uninstall.exe" + +SectionEnd + +;player install +Section "GPAC Player" SecOsmo4 + SectionIn 1 + + !ifndef IS_WIN64 + File "${GPAC_BIN}\Osmo4.exe" + !endif + File "${GPAC_BIN}\gm_dummy_in.dll" + File "${GPAC_BIN}\gm_dx_hw.dll" + File "${GPAC_BIN}\gm_gpac_js.dll" + File "${GPAC_BIN}\gm_ismacryp.dll" + + ;copy GUI + SetOutPath $INSTDIR\gui + File "${GPAC_ROOT}\gui\gui.bt" + File "${GPAC_ROOT}\gui\gui.js" + File "${GPAC_ROOT}\gui\gwlib.js" + File "${GPAC_ROOT}\gui\mpegu-core.js" + File "${GPAC_ROOT}\gui\webvtt-renderer.js" + SetOutPath $INSTDIR\gui\icons + File /r /x .git ${GPAC_ROOT}\gui\icons\* + SetOutPath $INSTDIR\gui\extensions + File /r /x .git ${GPAC_ROOT}\gui\extensions\* + + SetOutPath $INSTDIR +SectionEnd + +SubSection "GPAC Plugins" SecPlugins + + +; +; 2 install modes, normal one and full one + +Section "MPEG-4 BIFS Decoder" SecBIFS + SectionIn 1 + File "${GPAC_BIN}\gm_bifs_dec.dll" +SectionEnd + +Section "MPEG-4 ODF Decoder" SecODF + SectionIn 1 + File "${GPAC_BIN}\gm_odf_dec.dll" +SectionEnd + +Section "MPEG-4 LASeR Decoder" SecLASeR + SectionIn 1 + File "${GPAC_BIN}\gm_laser_dec.dll" +SectionEnd + +Section "MPEG-4 SAF Demultiplexer" SecSAF + SectionIn 1 + File "${GPAC_BIN}\gm_saf_in.dll" +SectionEnd + +Section "Textual MPEG-4 Loader" SecTextLoad + SectionIn 1 + File "${GPAC_BIN}\gm_ctx_load.dll" +SectionEnd + +Section "Image Package (PNG, JPEG, BMP)" SecIMG + SectionIn 1 + File "${GPAC_BIN}\gm_img_in.dll" +SectionEnd + +Section "AAC Audio" SecAAC + SectionIn 1 + File "${GPAC_BIN}\gm_aac_in.dll" +SectionEnd + +Section "MP3 Audio" SecMP3 + SectionIn 1 + File "${GPAC_BIN}\gm_mp3_in.dll" +SectionEnd + +Section "AC3 Audio" SecAC3 + SectionIn 1 + File "${GPAC_BIN}\gm_ac3_in.dll" +SectionEnd + +Section "FFMPEG" SecFFMPEG + SectionIn 1 + File "${GPAC_BIN}\gm_ffmpeg_in.dll" + File "${GPAC_BIN}\avcodec-*.dll" + File "${GPAC_BIN}\avdevice-*.dll" + File "${GPAC_BIN}\avfilter-*.dll" + File "${GPAC_BIN}\avformat-*.dll" + File "${GPAC_BIN}\avutil-*.dll" + File "${GPAC_BIN}\avresample-*.dll" + File "${GPAC_BIN}\swresample-*.dll" + File "${GPAC_BIN}\swscale-*.dll" + File "${GPAC_BIN}\libx264-*.dll" +SectionEnd + +Section "XviD Video Decoder" SecXVID + SectionIn 1 + File "${GPAC_BIN}\gm_xvid_dec.dll" +SectionEnd + +;Section "AMR NB & WB" SecAMRFT +; SectionIn 1 +; File "..\gm_amr_float_dec.dll" +;SectionEnd + +Section "Subtitles" SecSUBS + SectionIn 1 + File "${GPAC_BIN}\gm_timedtext.dll" +SectionEnd + +Section "ISO File Format" SecISOFF + SectionIn 1 + File "${GPAC_BIN}\gm_isom_in.dll" +SectionEnd + +Section "MPEG-2 TS" SecM2TS + SectionIn 1 + File "${GPAC_BIN}\gm_mpegts_in.dll" +SectionEnd + +Section "RTP/RTSP" SecRTP + SectionIn 1 + File "${GPAC_BIN}\gm_rtp_in.dll" +SectionEnd + +Section "SVG" SecSVG + SectionIn 1 + File "${GPAC_BIN}\gm_svg_in.dll" +SectionEnd + +Section "WebVTT" SecWebVTT + SectionIn 1 + File "${GPAC_BIN}\gm_vtt_in.dll" +SectionEnd + +Section "GDI+" SecGDIP + SectionIn 1 + call InsertGDIPLUS +SectionEnd + +Section "GPAC 2D Raster" SecG2DS + SectionIn 1 + File "${GPAC_BIN}\gm_soft_raster.dll" +SectionEnd + +Section "FreeType" SecFT + SectionIn 1 + File "${GPAC_BIN}\gm_ft_font.dll" +SectionEnd + +Section "Windows MME Audio" SecWAVE + SectionIn 1 + File "${GPAC_BIN}\gm_wav_out.dll" +SectionEnd + +Section "Xiph" SecXIPH + SectionIn 1 + File "${GPAC_BIN}\gm_ogg.dll" +SectionEnd + +Section "OpenSVC Decoder" SecOSVC + SectionIn 1 + File "${GPAC_BIN}\OpenSVCDecoder.dll" + File "${GPAC_BIN}\gm_opensvc_dec.dll" +SectionEnd + +Section "OpenHEVC Decoder" SecOHEVC + SectionIn 1 + File "${GPAC_BIN}\libLibOpenHevcWrapper.dll" + File "${GPAC_BIN}\gm_openhevc_dec.dll" +SectionEnd + +Section "MPEG DASH Support" SecDASH + SectionIn 1 + File "${GPAC_BIN}\gm_mpd_in.dll" +SectionEnd + +Section "HTML 5 Media Source Extensions Support" SecMSE + SectionIn 1 + File "${GPAC_BIN}\gm_mse_in.dll" +SectionEnd + +Section "UPnP Support" SecUPnP + SectionIn 1 + File "${GPAC_BIN}\gm_platinum.dll" +SectionEnd + +Section "Widget Manager" SecMPEGU + SectionIn 1 + File "${GPAC_BIN}\gm_widgetman.dll" +SectionEnd + +;Section "MobileIP Framework" SecMobIP +; SectionIn 1 +; File "..\gm_mobile_ip.dll" +; File "..\MobileSession.dll" +;SectionEnd + +SubSectionEnd + + +Section "MP4Box" SecMP4B + SectionIn 1 + SetOutPath $INSTDIR + File "${GPAC_BIN}\MP4Box.exe" + Push $INSTDIR + Call AddToPath +SectionEnd + +Section "MP42TS" SecMP42TS + SectionIn 1 + SetOutPath $INSTDIR + File "${GPAC_BIN}\MP42TS.exe" + Push $INSTDIR + Call AddToPath +SectionEnd + +Section "DashCast" SecDC + SectionIn 1 + SetOutPath $INSTDIR + File "${GPAC_BIN}\dashcast.exe" + Push $INSTDIR + Call AddToPath +SectionEnd + + +Section "GPAC SDK" SecSDK + SectionIn 1 + SetOutPath $INSTDIR\sdk\include + File /r ${GPAC_ROOT}\include\*.h + SetOutPath $INSTDIR\sdk\lib + File ${GPAC_BIN}\libgpac.lib + File ${GPAC_EXTRA_LIB}\js.lib +SectionEnd + + +!ifndef IS_WIN64 +!define HK_MOZ "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" + +Section "Osmozilla" SecZILLA + SectionIn 1 + SetOutPath $INSTDIR + File "${GPAC_BIN}\nposmozilla.dll" + File "${GPAC_BIN}\nposmozilla.xpt" + + ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Path" "$INSTDIR\nposmozilla.dll" + ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "XPTPath" "$INSTDIR\nposmozilla.xpt" + ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Version" "${GPAC_VERSION}" + ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Vendor" "GPAC" + ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "Description" "GPAC plugin" + ${WriteRegStrAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" "ProductName" "Osmozilla" +SectionEnd +!endif + +Section "GPAX" SecGPAX + SectionIn 1 + SetOutPath $INSTDIR + File "${GPAC_BIN}\GPAX.dll" + RegDLL "$INSTDIR\GPAX.dll" +SectionEnd + + +Section "MP4Client" SecMP4C + SectionIn 1 + SetOutPath $INSTDIR + File "${GPAC_BIN}\MP4Client.exe" +SectionEnd + + + +Section "Windows Runtime Libraries" SecMSVCRT + SectionIn 1 +; File "..\Microsoft.VC100.CRT.manifest" +; File "..\Microsoft.VC100.MFC.manifest" + File "${GPAC_BIN}\msvcr100.dll" + File "${GPAC_BIN}\mfc100.dll" +SectionEnd + + + + +SubSection "GPAC Shortcuts" + +Section "Add Start Menu Shortcuts" + SectionIn 1 + #has current user admin privileges? + userInfo::getAccountType + Pop $0 + StrCmp $0 "Admin" +1 +2 + SetShellVarContext all + CreateDirectory "$SMPROGRAMS\GPAC" + CreateShortCut "$SMPROGRAMS\GPAC\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 + CreateShortCut "$SMPROGRAMS\GPAC\Osmo4.lnk" "$INSTDIR\MP4Client.exe" "" + CreateShortCut "$SMPROGRAMS\GPAC\Osmo4 (with Console).lnk" "$INSTDIR\MP4Client.exe" "-guid" + !ifndef IS_WIN64 + CreateShortCut "$SMPROGRAMS\GPAC\Osmo4 (Old UI).lnk" "$INSTDIR\Osmo4.exe" "" + !endif + CreateShortCut "$SMPROGRAMS\GPAC\Readme.lnk" "$INSTDIR\ReadMe.txt" + CreateShortCut "$SMPROGRAMS\GPAC\License.lnk" "$INSTDIR\License.txt" + CreateShortCut "$SMPROGRAMS\GPAC\History.lnk" "$INSTDIR\changelog.txt" + CreateShortCut "$SMPROGRAMS\GPAC\Configuration Info.lnk" "$INSTDIR\configuration.html" +SectionEnd + +!ifndef IS_WIN64 +Section "Add shortcut to QuickLaunch" + SectionIn 1 + CreateShortCut "$QUICKLAUNCH\GPAC.lnk" "$INSTDIR\Osmo4.exe" "" "$INSTDIR\Osmo4.exe" 0 +SectionEnd + +Section "Add shortcut to Desktop" + SectionIn 1 + CreateShortCut "$DESKTOP\Osmo4.lnk" "$INSTDIR\Osmo4.exe" "" "$INSTDIR\Osmo4.exe" 0 +SectionEnd + +!define SHCNE_ASSOCCHANGED 0x08000000 +!define SHCNF_IDLIST 0 + +Section "Make Osmo4 the default MPEG-4 Player" + SectionIn 1 + ;write file association + ${WriteRegStrAuth} HKCR GPAC\mp4\DefaultIcon "" "$INSTDIR\Osmo4.ico, 0" + ${WriteRegStrAuth} HKCR GPAC\mp4\Shell\open\command "" "$INSTDIR\Osmo4.exe %L" + ${WriteRegStrAuth} HKCR .mp4 "" "GPAC\mp4" + !system 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)' + +SectionEnd + +Section "Associate 3GPP files (3GP) with Osmo4" + SectionIn 1 + ;write file association + ${WriteRegStrAuth} HKCR GPAC\3gp\DefaultIcon "" "$INSTDIR\Osmo4.ico, 0" + ${WriteRegStrAuth} HKCR GPAC\3gp\Shell\open\command "" "$INSTDIR\Osmo4.exe %L" + ${WriteRegStrAuth} HKCR .3gp "" "GPAC\3gp" + !system 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)' +SectionEnd + +Section "Associate 3GPP2 files (3G2) with Osmo4" + SectionIn 1 + ;write file association + ${WriteRegStrAuth} HKCR GPAC\3g2\DefaultIcon "" "$INSTDIR\Osmo4.ico, 0" + ${WriteRegStrAuth} HKCR GPAC\3g2\Shell\open\command "" "$INSTDIR\Osmo4.exe %L" + ${WriteRegStrAuth} HKCR .3g2 "" "GPAC\3g2" + !system 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)' +SectionEnd +!endif + +SubSectionEnd + + + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecGPAC} "GPAC Core" + !insertmacro MUI_DESCRIPTION_TEXT ${SecOsmo4} "GPAC Player" + !insertmacro MUI_DESCRIPTION_TEXT ${SecPlugins} "GPAC Plugins" + !insertmacro MUI_DESCRIPTION_TEXT ${SecBIFS} "MPEG-4 BIFS Scene Decoder" + !insertmacro MUI_DESCRIPTION_TEXT ${SecODF} "MPEG-4 Object Descriptor Decoder" + !insertmacro MUI_DESCRIPTION_TEXT ${SecLASeR} "MPEG-4 LASeR Scene Decoder" + !insertmacro MUI_DESCRIPTION_TEXT ${SecTextLoad} "Support for uncompressed MPEG-4 (BT and XMT), VRML and X3D textual formats" + !insertmacro MUI_DESCRIPTION_TEXT ${SecSAF} "MPEG-4 SAF Demultiplexer" + !insertmacro MUI_DESCRIPTION_TEXT ${SecIMG} "Support for PNG, JPEG, BMP and JPEG2000 images" + !insertmacro MUI_DESCRIPTION_TEXT ${SecAAC} "Support for MPEG-4 Audio HE-AAC decoder and web radios" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMP3} "Support for MPEG-1/2 Audio (inc. MP3) decoder and web radios" + !insertmacro MUI_DESCRIPTION_TEXT ${SecAC3} "Support for Dolby AC3 decoder and web radios" + !insertmacro MUI_DESCRIPTION_TEXT ${SecFFMPEG} "Support for FFMPEG libraries for various format decoding and demultiplexing" + !insertmacro MUI_DESCRIPTION_TEXT ${SecXVID} "Support for XVID library for MPEG-4 Video Part 2 decoding" + !insertmacro MUI_DESCRIPTION_TEXT ${SecAMRFT} "Support for AMR and AMR WideBand decoder and web radios" + !insertmacro MUI_DESCRIPTION_TEXT ${SecSUBS} "Subtitle support include SRT, SUB, 3GPP and MPEG-4 Text formats" + !insertmacro MUI_DESCRIPTION_TEXT ${SecISOFF} "Support for ISO-based file formats (3GP, MP4, MJ2K)" + !insertmacro MUI_DESCRIPTION_TEXT ${SecM2TS} "Support for MPEG-2 Transport Stream" + !insertmacro MUI_DESCRIPTION_TEXT ${SecRTP} "Support for RTP and RTSP IP streaming" + !insertmacro MUI_DESCRIPTION_TEXT ${SecSVG} "Support for SVG including progressive loading" + !insertmacro MUI_DESCRIPTION_TEXT ${SecWebVTT} "Support for WebVTT subtitles" + !insertmacro MUI_DESCRIPTION_TEXT ${SecGDIP} "GDIPlus-based rasterizer" + !insertmacro MUI_DESCRIPTION_TEXT ${SecG2DS} "GPAC software rasterizer" + !insertmacro MUI_DESCRIPTION_TEXT ${SecFT} "FreeType font parsing" + !insertmacro MUI_DESCRIPTION_TEXT ${SecWAVE} "Windows MME Audio output support" + !insertmacro MUI_DESCRIPTION_TEXT ${SecXIPH} "Support for XIPP OGG, Vorbis and Theora media" + !insertmacro MUI_DESCRIPTION_TEXT ${SecOSVC} "Support for SVC decoding through OpenSVC Decoder" + !insertmacro MUI_DESCRIPTION_TEXT ${SecOHEVC} "Support for HEVC decoding through OpenHEVC Decoder" + !insertmacro MUI_DESCRIPTION_TEXT ${SecDASH} "HTTP Streaming using MPEG DASH" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMSE} "HTTP Streaming using HTML 5 Media Source Extensions" + !insertmacro MUI_DESCRIPTION_TEXT ${SecUPnP} "Support for UPnP based on Platinum" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMPEGU} "Support for W3C and MPEG-U Widgets" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMobIP} "UNIGE Mobile IP Framework" + !insertmacro MUI_DESCRIPTION_TEXT ${SecOffisComp} "OFFIS Audio Compressor" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMP4B} "MP4Box command-line tool for various multimedia operations" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMP42TS} "MP42TS command-line tool for MPEG-2 TS multiplexing" + !insertmacro MUI_DESCRIPTION_TEXT ${SecDC} "DashCast offline and live MPEG-DASH Encoder" + !insertmacro MUI_DESCRIPTION_TEXT ${SecSDK} "GPAC SDK: headers and library files needed to develop modules for GPAC or appllication based on GPAC" + !insertmacro MUI_DESCRIPTION_TEXT ${SecZILLA} "GPAC playback support NPAPI-based browsers (FireFox/Gecko, Safari/WebKit)" + !insertmacro MUI_DESCRIPTION_TEXT ${SecGPAX} "GPAC playback support using ActiveX component (Internet Explorer)" + !insertmacro MUI_DESCRIPTION_TEXT ${SecMP4C} "GPAC command-line player and AVI dumper" + +!insertmacro MUI_FUNCTION_DESCRIPTION_END + + +Function .onInstSuccess +; MessageBox MB_YESNO "GPAC Framework installation complete. Do you want to launch the player?" IDNO NoLaunch +; Exec $INSTDIR\Osmo4.exe +; NoLaunch: +FunctionEnd + + + + + +; uninstall stuff + +UninstallText "This will uninstall GPAC from your computer. Hit next to continue." + +; special uninstall section. +Section "Uninstall" + ; remove registry keys + ${DeleteRegKeyAuth} HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\GPAC" + ${DeleteRegKeyAuth} HKCU "SOFTWARE\GPAC" + ${DeleteRegKeyAuth} HKCU "SOFTWARE\MozillaPlugins\@gpac/osmozilla,version=1.0" + ${DeleteRegKeyAuth} HKCR GPAC\mp4\DefaultIcon + ${DeleteRegKeyAuth} HKCR GPAC\mp4\shell\open\command + ${DeleteRegKeyAuth} HKCR GPAC\mp4 + ${DeleteRegKeyAuth} HKCR .mp4 + ${DeleteRegKeyAuth} HKCR GPAC\3gp\DefaultIcon + ${DeleteRegKeyAuth} HKCR GPAC\3gp\shell\open\command + ${DeleteRegKeyAuth} HKCR GPAC\3gp + ${DeleteRegKeyAuth} HKCR .3gp + ${DeleteRegKeyAuth} HKCR GPAC\3g2\DefaultIcon + ${DeleteRegKeyAuth} HKCR GPAC\3g2\shell\open\command + ${DeleteRegKeyAuth} HKCR GPAC\3g2 + ${DeleteRegKeyAuth} HKCR .3g2 + ${DeleteRegKeyAuth} HKCR GPAC + + UnRegDLL "$INSTDIR\GPAX.dll" + RMDir /r $INSTDIR + Push $INSTDIR + Call un.RemoveFromPath + #has current user admin privileges? + userInfo::getAccountType + Pop $0 + StrCmp $0 "Admin" +1 +2 + SetShellVarContext all + Delete "$SMPROGRAMS\GPAC\*.*" + RMDir "$SMPROGRAMS\GPAC" + Delete "$QUICKLAUNCH\Osmo4.lnk" + Delete "$DESKTOP\Osmo4.lnk" + +SectionEnd + +;path modif functions +!verbose 3 +!include "WinMessages.NSH" +!verbose 4 + +!ifndef WriteEnvStr_RegKey + !ifdef ALL_USERS + !define WriteEnvStr_RegKey \ + 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + !else + !define WriteEnvStr_RegKey 'HKCU "Environment"' + !endif +!endif + +; AddToPath - Adds the given dir to the search path. +; Input - head of the stack +; Note - Win9x systems requires reboot + +Function AddToPath + Exch $0 + Push $1 + Push $2 + Push $3 + + # don't add if the path doesn't exist + IfFileExists "$0\*.*" "" AddToPath_done + + ReadEnvStr $1 PATH + Push "$1;" + Push "$0;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$0\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + GetFullPathName /SHORT $3 $0 + Push "$1;" + Push "$3;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$3\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + + Call IsNT + Pop $1 + StrCmp $1 1 AddToPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 -1 END + FileReadByte $1 $2 + IntCmp $2 26 0 +2 +2 # DOS EOF + FileSeek $1 -1 END # write over EOF + FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" + FileClose $1 + SetRebootFlag true + Goto AddToPath_done + + AddToPath_NT: + ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH" + StrCpy $2 $1 1 -1 # copy last char + StrCmp $2 ";" 0 +2 # if last char == ; + StrCpy $1 $1 -1 # remove last char + StrCmp $1 "" AddToPath_NTdoIt + StrCpy $0 "$1;$0" + AddToPath_NTdoIt: + WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $0 + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + AddToPath_done: + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +; RemoveFromPath - Remove a given dir from the path +; Input: head of the stack + +Function un.RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + IntFmt $6 "%c" 26 # DOS EOF + + Call un.IsNT + Pop $1 + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCpy $5 $3 1 -1 # read last char + StrCmp $5 $6 0 +2 # if DOS EOF + StrCpy $3 $3 -1 # remove DOS EOF so we can compare + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + unRemoveFromPath_dosLoopRemoveLine: + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + ReadRegStr $1 ${WriteEnvStr_RegKey} "PATH" + StrCpy $5 $1 1 -1 # copy last char + StrCmp $5 ";" +2 # if last char != ; + StrCpy $1 "$1;" # append ; + Push $1 + Push "$0;" + Call un.StrStr ; Find `$0;` in $1 + Pop $2 ; pos of our dir + StrCmp $2 "" unRemoveFromPath_done + ; else, it is in path + # $0 - path to add + # $1 - path var + StrLen $3 "$0;" + StrLen $4 $2 + StrCpy $5 $1 -$4 # $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 # copy last char + StrCmp $5 ";" 0 +2 # if last char == ; + StrCpy $3 $3 -1 # remove last char + + WriteRegExpandStr ${WriteEnvStr_RegKey} "PATH" $3 + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + unRemoveFromPath_done: + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +########################################### +# Utility Functions # +########################################### + +; IsNT +; no input +; output, top of the stack = 1 if NT or 0 if not +; +; Usage: +; Call IsNT +; Pop $R0 +; ($R0 at this point is 1 or 0) + +!macro IsNT un +Function ${un}IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 IsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + + IsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd +!macroend +!insertmacro IsNT "" +!insertmacro IsNT "un." + +; StrStr +; input, top of stack = string to search for +; top of stack-1 = string to search in +; output, top of stack (replaces with the portion of the string remaining) +; modifies no other variables. +; +; Usage: +; Push "this is a long ass string" +; Push "ass" +; Call StrStr +; Pop $R0 +; ($R0 at this point is "ass string") + +!macro StrStr un +Function ${un}StrStr +Exch $R1 ; st=haystack,old$R1, $R1=needle + Exch ; st=old$R1,haystack + Exch $R2 ; st=old$R1,old$R2, $R2=haystack + Push $R3 + Push $R4 + Push $R5 + StrLen $R3 $R1 + StrCpy $R4 0 + ; $R1=needle + ; $R2=haystack + ; $R3=len(needle) + ; $R4=cnt + ; $R5=tmp + loop: + StrCpy $R5 $R2 $R3 $R4 + StrCmp $R5 $R1 done + StrCmp $R5 "" done + IntOp $R4 $R4 + 1 + Goto loop +done: + StrCpy $R1 $R2 "" $R4 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Exch $R1 +FunctionEnd +!macroend +!insertmacro StrStr "" +!insertmacro StrStr "un." diff --git a/regression_tests/auxiliary_files/logo.bt b/regression_tests/auxiliary_files/logo.bt index b2231bf..e7f5885 100644 --- a/regression_tests/auxiliary_files/logo.bt +++ b/regression_tests/auxiliary_files/logo.bt @@ -1,126 +1,126 @@ -InitialObjectDescriptor { - objectDescriptorID 1 - sceneProfileLevelIndication 254 - graphicsProfileLevelIndication 254 - ODProfileLevelIndication 254 - esDescr [ - ES_Descriptor { - ES_ID 1 - decConfigDescr DecoderConfigDescriptor { - objectTypeIndication 1 - streamType 3 - bufferSizeDB 2038 - decSpecificInfo BIFSConfig { - nodeIDbits 4 - isCommandStream true - pixelMetric true - } - } - slConfigDescr SLConfigDescriptor { - useAccessUnitStartFlag true - useAccessUnitEndFlag true - useTimeStampsFlag true - timeStampResolution 1000 - timeStampLength 32 - } - } - ] -} - -OrderedGroup { - children [ -# Background2D { backColor 1 1 1 } - DEF N0 Viewport { - size 140 140 - fit 1 - } - - Transform2D { - scale 0.5 0.5 - children [ - Transform2D { - translation 1 -2 - children [ - Shape { - appearance Appearance { - material Material2D { - lineProps XLineProperties { - lineColor 0.2 0.2 0.2 - width 20 - } - } - } - geometry Circle { - radius 100 - } - } - ] - } - Transform2D { - translation 0 -30 - children [ - Shape { - appearance DEF N3 Appearance { - texture RadialGradient { - focalPoint 0.45 0.8 - key [0 1] - keyValue [0.5 0.5 0.5 0 0 0] - } - material Material2D { - filled TRUE - } - } - geometry Circle { - radius 60 - } - } - ] - } - Transform2D { - translation 0 90 - children [ - Shape { - appearance Appearance { - material Material2D { - filled true - } - texture RadialGradient { - focalPoint 0.45 0.2 - key [0 1] - keyValue [0.2 0.2 0.2 0 0 0] - } - } - geometry IndexedFaceSet2D { - colorPerVertex false - coord Coordinate2D { - point [-40 5 40 5 0 -60] - } - } - } - ] - } - Shape { - appearance Appearance { - material DEF N4 Material2D { - lineProps DEF N5 XLineProperties { - lineColor 1 0 0 - width 20 - texture RadialGradient { - focalPoint 0.5 0.5 - key [0 0.8 0.9 1] - keyValue [0 0 0 0.5 0 0 1 0 0 0.5 0 0] - } - } - } - } - geometry Circle { - radius 100 - } - } - ] - } - - ] -} - - +InitialObjectDescriptor { + objectDescriptorID 1 + sceneProfileLevelIndication 254 + graphicsProfileLevelIndication 254 + ODProfileLevelIndication 254 + esDescr [ + ES_Descriptor { + ES_ID 1 + decConfigDescr DecoderConfigDescriptor { + objectTypeIndication 1 + streamType 3 + bufferSizeDB 2038 + decSpecificInfo BIFSConfig { + nodeIDbits 4 + isCommandStream true + pixelMetric true + } + } + slConfigDescr SLConfigDescriptor { + useAccessUnitStartFlag true + useAccessUnitEndFlag true + useTimeStampsFlag true + timeStampResolution 1000 + timeStampLength 32 + } + } + ] +} + +OrderedGroup { + children [ +# Background2D { backColor 1 1 1 } + DEF N0 Viewport { + size 140 140 + fit 1 + } + + Transform2D { + scale 0.5 0.5 + children [ + Transform2D { + translation 1 -2 + children [ + Shape { + appearance Appearance { + material Material2D { + lineProps XLineProperties { + lineColor 0.2 0.2 0.2 + width 20 + } + } + } + geometry Circle { + radius 100 + } + } + ] + } + Transform2D { + translation 0 -30 + children [ + Shape { + appearance DEF N3 Appearance { + texture RadialGradient { + focalPoint 0.45 0.8 + key [0 1] + keyValue [0.5 0.5 0.5 0 0 0] + } + material Material2D { + filled TRUE + } + } + geometry Circle { + radius 60 + } + } + ] + } + Transform2D { + translation 0 90 + children [ + Shape { + appearance Appearance { + material Material2D { + filled true + } + texture RadialGradient { + focalPoint 0.45 0.2 + key [0 1] + keyValue [0.2 0.2 0.2 0 0 0] + } + } + geometry IndexedFaceSet2D { + colorPerVertex false + coord Coordinate2D { + point [-40 5 40 5 0 -60] + } + } + } + ] + } + Shape { + appearance Appearance { + material DEF N4 Material2D { + lineProps DEF N5 XLineProperties { + lineColor 1 0 0 + width 20 + texture RadialGradient { + focalPoint 0.5 0.5 + key [0 0.8 0.9 1] + keyValue [0 0 0 0.5 0 0 1 0 0 0.5 0 0] + } + } + } + } + geometry Circle { + radius 100 + } + } + ] + } + + ] +} + + diff --git a/regression_tests/auxiliary_files/subtitle.srt b/regression_tests/auxiliary_files/subtitle.srt index c0a7139..ffc9b14 100644 --- a/regression_tests/auxiliary_files/subtitle.srt +++ b/regression_tests/auxiliary_files/subtitle.srt @@ -9,7 +9,7 @@ on 2 lines 3 00:00:05,986 --> 00:00:06,419 -<b>and also bold</b> +<b><font color="cyan">and</font> also bold</b> 4 00:00:07,223 --> 00:00:08,487 diff --git a/regression_tests/bifs/bifs-cachetexture_cache.bt b/regression_tests/bifs/bifs-cachetexture_cache.bt index 66712ad..153ed63 100644 --- a/regression_tests/bifs/bifs-cachetexture_cache.bt +++ b/regression_tests/bifs/bifs-cachetexture_cache.bt @@ -1,90 +1,90 @@ -InitialObjectDescriptor { - objectDescriptorID 1 - ODProfileLevelIndication 1 - esDescr [ - ES_Descriptor { - ES_ID 1 - decConfigDescr DecoderConfigDescriptor { - objectTypeIndication 1 - streamType 3 - bufferSizeDB 177 - decSpecificInfo BIFSConfig { - nodeIDbits 24 - isCommandStream true - pixelMetric true - pixelWidth 400 - pixelHeight 300 - } - } - } - ] -} - -OrderedGroup { - children [ - Background2D {backColor 1 1 1} - WorldInfo { - info [ - "This test shows usage of the CacheTexture node. The texture is cached for 3 seconds only." - "" - "GPAC Regression Tests" "$Date: $ - $Revision: $" - "(C) 2010-200X GPAC Team" - ] - title "CacheTexture Node for testing cache" - } - DEF TR Transform2D { - children [ - Shape { - appearance Appearance { - texture CacheTexture { - objectTypeIndication 108 - image "../auxiliary_files/sky.jpg" - cacheURL "MyCachedPicture.jpg" - expirationDate 3 - } - } - geometry Rectangle { - size 160 120 - } - } - ] - } - ] -} - -AT 1000 { - REPLACE TR.children[0] BY Shape {} -} - -AT 2000 { - REPLACE TR.children[0] BY Shape { - appearance Appearance { - texture ImageTexture { - url "MyCachedPicture.jpg" - } - } - geometry Circle { - radius 80 - } - } - } -} - -AT 3000 { - REPLACE TR.children[0] BY Shape {} -} - -AT 4000 { - REPLACE TR.children[0] BY Shape { - appearance Appearance { - texture ImageTexture { - url "MyCachedPicture.jpg" - } - } - geometry Rectangle { - size 160 80 - } - } - } -} - +InitialObjectDescriptor { + objectDescriptorID 1 + ODProfileLevelIndication 1 + esDescr [ + ES_Descriptor { + ES_ID 1 + decConfigDescr DecoderConfigDescriptor { + objectTypeIndication 1 + streamType 3 + bufferSizeDB 177 + decSpecificInfo BIFSConfig { + nodeIDbits 24 + isCommandStream true + pixelMetric true + pixelWidth 400 + pixelHeight 300 + } + } + } + ] +} + +OrderedGroup { + children [ + Background2D {backColor 1 1 1} + WorldInfo { + info [ + "This test shows usage of the CacheTexture node. The texture is cached for 3 seconds only." + "" + "GPAC Regression Tests" "$Date: $ - $Revision: $" + "(C) 2010-200X GPAC Team" + ] + title "CacheTexture Node for testing cache" + } + DEF TR Transform2D { + children [ + Shape { + appearance Appearance { + texture CacheTexture { + objectTypeIndication 108 + image "../auxiliary_files/sky.jpg" + cacheURL "MyCachedPicture.jpg" + expirationDate 3 + } + } + geometry Rectangle { + size 160 120 + } + } + ] + } + ] +} + +AT 1000 { + REPLACE TR.children[0] BY Shape {} +} + +AT 2000 { + REPLACE TR.children[0] BY Shape { + appearance Appearance { + texture ImageTexture { + url "MyCachedPicture.jpg" + } + } + geometry Circle { + radius 80 + } + } + } +} + +AT 3000 { + REPLACE TR.children[0] BY Shape {} +} + +AT 4000 { + REPLACE TR.children[0] BY Shape { + appearance Appearance { + texture ImageTexture { + url "MyCachedPicture.jpg" + } + } + geometry Rectangle { + size 160 80 + } + } + } +} + diff --git a/regression_tests/bifs/bifs-cachetexture_nocache.bt b/regression_tests/bifs/bifs-cachetexture_nocache.bt index 37e0990..ddecb2a 100644 --- a/regression_tests/bifs/bifs-cachetexture_nocache.bt +++ b/regression_tests/bifs/bifs-cachetexture_nocache.bt @@ -1,57 +1,57 @@ -InitialObjectDescriptor { - objectDescriptorID 1 - ODProfileLevelIndication 1 - esDescr [ - ES_Descriptor { - ES_ID 1 - decConfigDescr DecoderConfigDescriptor { - objectTypeIndication 1 - streamType 3 - bufferSizeDB 177 - decSpecificInfo BIFSConfig { - nodeIDbits 24 - isCommandStream true - pixelMetric true - pixelWidth 400 - pixelHeight 300 - } - } - } - ] -} - -OrderedGroup { - children [ - Background2D {backColor 1 1 1} - WorldInfo { - info [ - "This test shows usage of the CacheTexture node for embedding images in the BIFS bitstream." - "" - "GPAC Regression Tests" "$Date: $ - $Revision: $" - "(C) 2010-200X GPAC Team" - ] - title "CacheTexture Node for in-band images" - } - DEF TR Transform2D { - children [ - Shape { - appearance Appearance { - texture CacheTexture { - objectTypeIndication 108 - image "../auxiliary_files/sky.jpg" - } - } - geometry Rectangle { - size 160 120 - } - } - DEF PS PlaneSensor2D { - maxPosition -1 -1 - autoOffset TRUE - } - ] - } - ] -} - -ROUTE PS.translation_changed TO TR.translation +InitialObjectDescriptor { + objectDescriptorID 1 + ODProfileLevelIndication 1 + esDescr [ + ES_Descriptor { + ES_ID 1 + decConfigDescr DecoderConfigDescriptor { + objectTypeIndication 1 + streamType 3 + bufferSizeDB 177 + decSpecificInfo BIFSConfig { + nodeIDbits 24 + isCommandStream true + pixelMetric true + pixelWidth 400 + pixelHeight 300 + } + } + } + ] +} + +OrderedGroup { + children [ + Background2D {backColor 1 1 1} + WorldInfo { + info [ + "This test shows usage of the CacheTexture node for embedding images in the BIFS bitstream." + "" + "GPAC Regression Tests" "$Date: $ - $Revision: $" + "(C) 2010-200X GPAC Team" + ] + title "CacheTexture Node for in-band images" + } + DEF TR Transform2D { + children [ + Shape { + appearance Appearance { + texture CacheTexture { + objectTypeIndication 108 + image "../auxiliary_files/sky.jpg" + } + } + geometry Rectangle { + size 160 120 + } + } + DEF PS PlaneSensor2D { + maxPosition -1 -1 + autoOffset TRUE + } + ] + } + ] +} + +ROUTE PS.translation_changed TO TR.translation diff --git a/regression_tests/bifs/bifs-environmenttest.bt b/regression_tests/bifs/bifs-environmenttest.bt index a86bdc6..5a20525 100644 --- a/regression_tests/bifs/bifs-environmenttest.bt +++ b/regression_tests/bifs/bifs-environmenttest.bt @@ -1,129 +1,129 @@ -InitialObjectDescriptor { - objectDescriptorID 1 - ODProfileLevelIndication 1 - esDescr [ - ES_Descriptor { - ES_ID 1 - decConfigDescr DecoderConfigDescriptor { - objectTypeIndication 1 - streamType 3 - bufferSizeDB 177 - decSpecificInfo BIFSConfig { - nodeIDbits 24 - isCommandStream true - pixelMetric true - pixelWidth 400 - pixelHeight 300 - } - } - } - ] -} - -OrderedGroup { - children [ - Background2D {backColor 1 1 1} - WorldInfo { - info [ - "This test shows usage of the EnvironmentTest node. The various settings of the node are tested." - "" - "GPAC Regression Tests" "$Date: $ - $Revision: $" - "(C) 2010-200X GPAC Team" - ] - title "EnvironmentTest Node testing" - } - - Transform2D { - translation 0 50 - children [ - Shape { - appearance DEF APP Appearance { - material Material2D { - emissiveColor 0 0 0 - filled true - } - } - geometry Text { - string ["Width:"] - fontStyle DEF FSEND FontStyle { - size 24 - justify "END" - } - } - } - Shape { - appearance USE APP - geometry DEF T1 Text { - string [""] - fontStyle DEF FSBEGIN FontStyle { - size 24 - justify "BEGIN" - } - } - } - ] - } - Transform2D { - children [ - Shape { - appearance USE APP - geometry Text { - string ["Height:"] - fontStyle USE FSEND - } - } - Shape { - appearance USE APP - geometry DEF T2 Text { - string [""] - fontStyle USE FSBEGIN - } - } - ] - } - - Transform2D { - translation 0 -50 - children [ - Shape { - appearance USE APP - geometry Text { - string ["Portrait:"] - fontStyle USE FSEND - } - } - Shape { - appearance USE APP - geometry DEF T3 Text { - string [""] - fontStyle USE FSBEGIN - } - } - ] - } - - DEF V1 Valuator {} - DEF EV1 EnvironmentTest { - parameter 2 - } - - DEF V2 Valuator {} - DEF EV2 EnvironmentTest { - parameter 3 - } - - DEF V3 Valuator {} - DEF EV3 EnvironmentTest { - parameter 1 - } - ] -} - -ROUTE EV1.parameterValue TO V1.inSFString -ROUTE V1.outMFString TO T1.string - -ROUTE EV2.parameterValue TO V2.inSFString -ROUTE V2.outMFString TO T2.string - -ROUTE EV3.valueEqual TO V3.inSFBool -ROUTE V3.outMFString TO T3.string +InitialObjectDescriptor { + objectDescriptorID 1 + ODProfileLevelIndication 1 + esDescr [ + ES_Descriptor { + ES_ID 1 + decConfigDescr DecoderConfigDescriptor { + objectTypeIndication 1 + streamType 3 + bufferSizeDB 177 + decSpecificInfo BIFSConfig { + nodeIDbits 24 + isCommandStream true + pixelMetric true + pixelWidth 400 + pixelHeight 300 + } + } + } + ] +} + +OrderedGroup { + children [ + Background2D {backColor 1 1 1} + WorldInfo { + info [ + "This test shows usage of the EnvironmentTest node. The various settings of the node are tested." + "" + "GPAC Regression Tests" "$Date: $ - $Revision: $" + "(C) 2010-200X GPAC Team" + ] + title "EnvironmentTest Node testing" + } + + Transform2D { + translation 0 50 + children [ + Shape { + appearance DEF APP Appearance { + material Material2D { + emissiveColor 0 0 0 + filled true + } + } + geometry Text { + string ["Width:"] + fontStyle DEF FSEND FontStyle { + size 24 + justify "END" + } + } + } + Shape { + appearance USE APP + geometry DEF T1 Text { + string [""] + fontStyle DEF FSBEGIN FontStyle { + size 24 + justify "BEGIN" + } + } + } + ] + } + Transform2D { + children [ + Shape { + appearance USE APP + geometry Text { + string ["Height:"] + fontStyle USE FSEND + } + } + Shape { + appearance USE APP + geometry DEF T2 Text { + string [""] + fontStyle USE FSBEGIN + } + } + ] + } + + Transform2D { + translation 0 -50 + children [ + Shape { + appearance USE APP + geometry Text { + string ["Portrait:"] + fontStyle USE FSEND + } + } + Shape { + appearance USE APP + geometry DEF T3 Text { + string [""] + fontStyle USE FSBEGIN + } + } + ] + } + + DEF V1 Valuator {} + DEF EV1 EnvironmentTest { + parameter 2 + } + + DEF V2 Valuator {} + DEF EV2 EnvironmentTest { + parameter 3 + } + + DEF V3 Valuator {} + DEF EV3 EnvironmentTest { + parameter 1 + } + ] +} + +ROUTE EV1.parameterValue TO V1.inSFString +ROUTE V1.outMFString TO T1.string + +ROUTE EV2.parameterValue TO V2.inSFString +ROUTE V2.outMFString TO T2.string + +ROUTE EV3.valueEqual TO V3.inSFBool +ROUTE V3.outMFString TO T3.string diff --git a/regression_tests/bifs/bifs-keynavigator.bt b/regression_tests/bifs/bifs-keynavigator.bt index 757220d..8adbba8 100644 --- a/regression_tests/bifs/bifs-keynavigator.bt +++ b/regression_tests/bifs/bifs-keynavigator.bt @@ -1,220 +1,220 @@ -InitialObjectDescriptor { - objectDescriptorID 1 - ODProfileLevelIndication 1 - esDescr [ - ES_Descriptor { - ES_ID 1 - decConfigDescr DecoderConfigDescriptor { - objectTypeIndication 1 - streamType 3 - bufferSizeDB 177 - decSpecificInfo BIFSConfig { - nodeIDbits 24 - isCommandStream true - pixelMetric true - pixelWidth 400 - pixelHeight 300 - } - } - } - ] -} - -OrderedGroup { - children [ - Background2D {backColor 1 1 1} - WorldInfo { - info [ - "This test shows usage of the KeyNavigator node. Navigate through the keypad between the various items." - "" - "GPAC Regression Tests" "$Date: $ - $Revision: $" - "(C) 2010-200X GPAC Team" - ] - title "KeyNavigator Node for testing keypad navigation" - } - Transform2D { - translation -100 100 - children [ - Shape { - appearance Appearance { - material DEF M1 Material2D { - emissiveColor 1 0 0 - } - } - geometry Rectangle { - size 60 60 - } - } - DEF TS1 TouchSensor {} - DEF V1 Valuator { Factor1 0.75 } - ] - } - - Transform2D { - translation 100 100 - children [ - Shape { - appearance Appearance { - material DEF M2 Material2D { - emissiveColor 0 1 0 - } - } - geometry Rectangle { - size 60 60 - } - } - DEF TS2 TouchSensor {} - DEF V2 Valuator { Factor1 0.75 } - ] - } - - Transform2D { - translation -100 -50 - children [ - Shape { - appearance Appearance { - material DEF M3 Material2D { - emissiveColor 1 0 1 - } - } - geometry Rectangle { - size 60 60 - } - } - DEF TS3 TouchSensor {} - DEF V3 Valuator { Factor1 0.75 } - ] - } - - Transform2D { - translation 100 -50 - children [ - Shape { - appearance Appearance { - material DEF M4 Material2D { - emissiveColor 0 0 1 - } - } - geometry Rectangle { - size 60 60 - } - } - DEF TS4 TouchSensor {} - DEF V4 Valuator { Factor1 0.75 } - ] - } - - Transform2D { - translation 0 -100 - children [ - Shape { - appearance Appearance { - material Material2D { - emissiveColor 0 0 0 - filled TRUE - } - } - geometry DEF TXT Text { - string [".", "."] - fontStyle FontStyle { - justify ["MIDDLE"] - size 24 - } - } - } - ] - } - - DEF C1 Conditional { - buffer { - REPLACE TXT.string[0] BY "KN1 got focus" - } - } - DEF RC1 Conditional { - buffer { - REPLACE TXT.string[1] BY "KN1 lost focus" - } - } - DEF KN1 KeyNavigator { - sensor USE TS1 - right USE KN2 - down USE KN3 - } - - DEF C2 Conditional { - buffer { - REPLACE TXT.string[0] BY "KN2 got focus" - } - } - DEF RC2 Conditional { - buffer { - REPLACE TXT.string[1] BY "KN2 lost focus" - } - } - DEF KN2 KeyNavigator { - sensor USE TS2 - left USE KN1 - down USE KN4 - } - - DEF C3 Conditional { - buffer { - REPLACE TXT.string[0] BY "KN3 got focus" - } - } - DEF RC3 Conditional { - buffer { - REPLACE TXT.string[1] BY "KN3 lost focus" - } - } - DEF KN3 KeyNavigator { - sensor USE TS3 - right USE KN4 - up USE KN1 - select USE KN2 - } - - DEF C4 Conditional { - buffer { - REPLACE TXT.string[0] BY "KN4 got focus" - } - } - DEF RC4 Conditional { - buffer { - REPLACE TXT.string[1] BY "KN4 lost focus" - } - } - DEF KN4 KeyNavigator { - sensor USE TS4 - left USE KN3 - up USE KN2 - } - - DEF AC1 Conditional { buffer { REPLACE KN4.setFocus BY TRUE}} - ] -} - -ROUTE TS1.isOver TO M1.filled -ROUTE TS1.isActive TO V1.inSFBool -ROUTE V1.outSFFloat TO M1.transparency -ROUTE TS1.isActive TO AC1.activate -ROUTE KN1.focusSet TO C1.activate -ROUTE KN1.focusSet TO RC1.reverseActivate - -ROUTE TS2.isOver TO M2.filled -ROUTE TS2.isActive TO V2.inSFBool -ROUTE V2.outSFFloat TO M2.transparency -ROUTE KN2.focusSet TO C2.activate -ROUTE KN2.focusSet TO RC2.reverseActivate - -ROUTE TS3.isOver TO M3.filled -ROUTE TS3.isActive TO V3.inSFBool -ROUTE V3.outSFFloat TO M3.transparency -ROUTE KN3.focusSet TO C3.activate -ROUTE KN3.focusSet TO RC3.reverseActivate - -ROUTE TS4.isOver TO M4.filled -ROUTE TS4.isActive TO V4.inSFBool -ROUTE V4.outSFFloat TO M4.transparency -ROUTE KN4.focusSet TO C4.activate -ROUTE KN4.focusSet TO RC4.reverseActivate +InitialObjectDescriptor { + objectDescriptorID 1 + ODProfileLevelIndication 1 + esDescr [ + ES_Descriptor { + ES_ID 1 + decConfigDescr DecoderConfigDescriptor { + objectTypeIndication 1 + streamType 3 + bufferSizeDB 177 + decSpecificInfo BIFSConfig { + nodeIDbits 24 + isCommandStream true + pixelMetric true + pixelWidth 400 + pixelHeight 300 + } + } + } + ] +} + +OrderedGroup { + children [ + Background2D {backColor 1 1 1} + WorldInfo { + info [ + "This test shows usage of the KeyNavigator node. Navigate through the keypad between the various items." + "" + "GPAC Regression Tests" "$Date: $ - $Revision: $" + "(C) 2010-200X GPAC Team" + ] + title "KeyNavigator Node for testing keypad navigation" + } + Transform2D { + translation -100 100 + children [ + Shape { + appearance Appearance { + material DEF M1 Material2D { + emissiveColor 1 0 0 + } + } + geometry Rectangle { + size 60 60 + } + } + DEF TS1 TouchSensor {} + DEF V1 Valuator { Factor1 0.75 } + ] + } + + Transform2D { + translation 100 100 + children [ + Shape { + appearance Appearance { + material DEF M2 Material2D { + emissiveColor 0 1 0 + } + } + geometry Rectangle { + size 60 60 + } + } + DEF TS2 TouchSensor {} + DEF V2 Valuator { Factor1 0.75 } + ] + } + + Transform2D { + translation -100 -50 + children [ + Shape { + appearance Appearance { + material DEF M3 Material2D { + emissiveColor 1 0 1 + } + } + geometry Rectangle { + size 60 60 + } + } + DEF TS3 TouchSensor {} + DEF V3 Valuator { Factor1 0.75 } + ] + } + + Transform2D { + translation 100 -50 + children [ + Shape { + appearance Appearance { + material DEF M4 Material2D { + emissiveColor 0 0 1 + } + } + geometry Rectangle { + size 60 60 + } + } + DEF TS4 TouchSensor {} + DEF V4 Valuator { Factor1 0.75 } + ] + } + + Transform2D { + translation 0 -100 + children [ + Shape { + appearance Appearance { + material Material2D { + emissiveColor 0 0 0 + filled TRUE + } + } + geometry DEF TXT Text { + string [".", "."] + fontStyle FontStyle { + justify ["MIDDLE"] + size 24 + } + } + } + ] + } + + DEF C1 Conditional { + buffer { + REPLACE TXT.string[0] BY "KN1 got focus" + } + } + DEF RC1 Conditional { + buffer { + REPLACE TXT.string[1] BY "KN1 lost focus" + } + } + DEF KN1 KeyNavigator { + sensor USE TS1 + right USE KN2 + down USE KN3 + } + + DEF C2 Conditional { + buffer { + REPLACE TXT.string[0] BY "KN2 got focus" + } + } + DEF RC2 Conditional { + buffer { + REPLACE TXT.string[1] BY "KN2 lost focus" + } + } + DEF KN2 KeyNavigator { + sensor USE TS2 + left USE KN1 + down USE KN4 + } + + DEF C3 Conditional { + buffer { + REPLACE TXT.string[0] BY "KN3 got focus" + } + } + DEF RC3 Conditional { + buffer { + REPLACE TXT.string[1] BY "KN3 lost focus" + } + } + DEF KN3 KeyNavigator { + sensor USE TS3 + right USE KN4 + up USE KN1 + select USE KN2 + } + + DEF C4 Conditional { + buffer { + REPLACE TXT.string[0] BY "KN4 got focus" + } + } + DEF RC4 Conditional { + buffer { + REPLACE TXT.string[1] BY "KN4 lost focus" + } + } + DEF KN4 KeyNavigator { + sensor USE TS4 + left USE KN3 + up USE KN2 + } + + DEF AC1 Conditional { buffer { REPLACE KN4.setFocus BY TRUE}} + ] +} + +ROUTE TS1.isOver TO M1.filled +ROUTE TS1.isActive TO V1.inSFBool +ROUTE V1.outSFFloat TO M1.transparency +ROUTE TS1.isActive TO AC1.activate +ROUTE KN1.focusSet TO C1.activate +ROUTE KN1.focusSet TO RC1.reverseActivate + +ROUTE TS2.isOver TO M2.filled +ROUTE TS2.isActive TO V2.inSFBool +ROUTE V2.outSFFloat TO M2.transparency +ROUTE KN2.focusSet TO C2.activate +ROUTE KN2.focusSet TO RC2.reverseActivate + +ROUTE TS3.isOver TO M3.filled +ROUTE TS3.isActive TO V3.inSFBool +ROUTE V3.outSFFloat TO M3.transparency +ROUTE KN3.focusSet TO C3.activate +ROUTE KN3.focusSet TO RC3.reverseActivate + +ROUTE TS4.isOver TO M4.filled +ROUTE TS4.isActive TO V4.inSFBool +ROUTE V4.outSFFloat TO M4.transparency +ROUTE KN4.focusSet TO C4.activate +ROUTE KN4.focusSet TO RC4.reverseActivate diff --git a/regression_tests/bifs/bifs-misc-hc-proto-events.bt b/regression_tests/bifs/bifs-misc-hc-proto-events.bt new file mode 100644 index 0000000..d6d2c6d --- /dev/null +++ b/regression_tests/bifs/bifs-misc-hc-proto-events.bt @@ -0,0 +1,57 @@ +InitialObjectDescriptor { + objectDescriptorID 1 + ODProfileLevelIndication 0xFF + sceneProfileLevelIndication 0xFE + audioProfileLevelIndication 0xFF + visualProfileLevelIndication 0xFF + graphicsProfileLevelIndication 0xFE + + esdescr [ + ES_Descriptor { + es_id 1 + decConfigDescr DecoderConfigDescriptor { + streamType 3 + decSpecificInfo BIFSConfig { + isCommandStream true + pixelMetric true + pixelWidth 600 + pixelHeight 400 + } + } + } + ] +} + + +EXTERNPROTO TestSensor [ + eventIn SFBool trigger + exposedField SFFloat value 0.25 + eventOut SFFloat result +] +[ "urn:inet:gpac:builtin:TestSensor"] + + + +OrderedGroup { children [ + WorldInfo { + info ["This tests GPAC HardcodedProto eventIn and eventOut" "GPAC Regression Tests" "$Date: 2007-07-27 09:46:10 $ - $Revision: 1.2 $" "(C) 2002-2014 GPAC Team"] + title "Events in HardcodedProto" + } + Background2D { backColor 1 1 0} + Transform2D { children [ + Shape { + appearance Appearance { material DEF MAT Material2D { emissiveColor 1 0 0 filled TRUE} } + geometry Rectangle { size 100 50 } + } + DEF TS TouchSensor {} + ]} + DEF TES TestSensor {} +] } + + +ROUTE TS.isOver TO TES.trigger +ROUTE TES.result TO MAT.transparency + + + + diff --git a/regression_tests/bifs/bifs-storage.bt b/regression_tests/bifs/bifs-storage.bt index f181a67..e2ff932 100644 --- a/regression_tests/bifs/bifs-storage.bt +++ b/regression_tests/bifs/bifs-storage.bt @@ -1,65 +1,65 @@ -InitialObjectDescriptor { - objectDescriptorID 1 - ODProfileLevelIndication 1 - esDescr [ - ES_Descriptor { - ES_ID 1 - decConfigDescr DecoderConfigDescriptor { - objectTypeIndication 1 - streamType 3 - bufferSizeDB 177 - decSpecificInfo BIFSConfig { - nodeIDbits 24 - isCommandStream true - pixelMetric true - pixelWidth 400 - pixelHeight 300 - } - } - } - ] -} - -OrderedGroup { - children [ - Background2D {backColor 1 1 1} - WorldInfo { - info [ - "This test shows usage of the Storage node. The rectangle position is stored upon closing of the scene in the player. It is restored if the scene is re-opened less than 10 seconds later." - "" - "GPAC Regression Tests" "$Date: $ - $Revision: $" - "(C) 2010-200X GPAC Team" - ] - title "Storage Node for testing persistent storage" - } - DEF TR Transform2D { - children [ - Shape { - appearance Appearance { - material Material2D { - emissiveColor 1 0 0 - filled true - } - } - geometry Rectangle { - size 160 120 - } - } - DEF PS PlaneSensor2D { - maxPosition -1 -1 - autoOffset TRUE - } - ] - } - Storage { - expireAfter 10 - name "test storage" - storageList [ - TR.translation - PS.offset - ] - } - ] -} - -ROUTE PS.translation_changed TO TR.translation +InitialObjectDescriptor { + objectDescriptorID 1 + ODProfileLevelIndication 1 + esDescr [ + ES_Descriptor { + ES_ID 1 + decConfigDescr DecoderConfigDescriptor { + objectTypeIndication 1 + streamType 3 + bufferSizeDB 177 + decSpecificInfo BIFSConfig { + nodeIDbits 24 + isCommandStream true + pixelMetric true + pixelWidth 400 + pixelHeight 300 + } + } + } + ] +} + +OrderedGroup { + children [ + Background2D {backColor 1 1 1} + WorldInfo { + info [ + "This test shows usage of the Storage node. The rectangle position is stored upon closing of the scene in the player. It is restored if the scene is re-opened less than 10 seconds later." + "" + "GPAC Regression Tests" "$Date: $ - $Revision: $" + "(C) 2010-200X GPAC Team" + ] + title "Storage Node for testing persistent storage" + } + DEF TR Transform2D { + children [ + Shape { + appearance Appearance { + material Material2D { + emissiveColor 1 0 0 + filled true + } + } + geometry Rectangle { + size 160 120 + } + } + DEF PS PlaneSensor2D { + maxPosition -1 -1 + autoOffset TRUE + } + ] + } + Storage { + expireAfter 10 + name "test storage" + storageList [ + TR.translation + PS.offset + ] + } + ] +} + +ROUTE PS.translation_changed TO TR.translation diff --git a/regression_tests/bifs/bifs-timeline-mediasensor-segment-switch.bt b/regression_tests/bifs/bifs-timeline-mediasensor-segment-switch.bt index 6761ac5..9708cb3 100644 --- a/regression_tests/bifs/bifs-timeline-mediasensor-segment-switch.bt +++ b/regression_tests/bifs/bifs-timeline-mediasensor-segment-switch.bt @@ -34,7 +34,7 @@ OrderedGroup { } WorldInfo { info ["This shows usage of MediaSensor" "with media segments defined" "and dynamic changes of watched segments" "" "GPAC Regression Tests" "$Date: 2007-07-27 09:46:10 $ - $Revision: 1.3 $" "(C) 2002-2004 GPAC Team"] - title "Media Sensor Test #3" + title "MediaSensor Test #3" } Shape { appearance Appearance { diff --git a/regression_tests/bifs/bifs-timeline-mediasensor-segment.bt b/regression_tests/bifs/bifs-timeline-mediasensor-segment.bt index 4f090fd..83df262 100644 --- a/regression_tests/bifs/bifs-timeline-mediasensor-segment.bt +++ b/regression_tests/bifs/bifs-timeline-mediasensor-segment.bt @@ -34,7 +34,7 @@ OrderedGroup { } WorldInfo { info ["This shows usage of MediaSensor" "with media segments defined" "" "GPAC Regression Tests" "$Date: 2007-07-27 09:46:10 $ - $Revision: 1.3 $" "(C) 2002-2004 GPAC Team"] - title "Media Sensor Test #2" + title "MediaSensor Test #2" } Shape { appearance Appearance { diff --git a/regression_tests/bifs/bifs-timeline-mediasensor.bt b/regression_tests/bifs/bifs-timeline-mediasensor.bt index 7054ca5..52e228f 100644 --- a/regression_tests/bifs/bifs-timeline-mediasensor.bt +++ b/regression_tests/bifs/bifs-timeline-mediasensor.bt @@ -34,7 +34,7 @@ OrderedGroup { } WorldInfo { info ["This shows usage of MediaSensor" "without media segments defined" "" "GPAC Regression Tests" "$Date: 2007-07-27 09:46:10 $ - $Revision: 1.3 $" "(C) 2002-2004 GPAC Team"] - title "Media Sensor Test #1" + title "MediaSensor Test #1" } Shape { appearance Appearance { diff --git a/regression_tests/html5_video/basic_arraybuffer.js b/regression_tests/html5_video/basic_arraybuffer.js index b6c3b43..1dffe7d 100644 --- a/regression_tests/html5_video/basic_arraybuffer.js +++ b/regression_tests/html5_video/basic_arraybuffer.js @@ -1,21 +1,21 @@ -/***************************************************************************************** - * Testing basic support for the ArrayBuffer JavaScript object - *****************************************************************************************/ - -alert("Script loaded"); - -function enumerate(e) -{ - for(var propertyName in e) { - alert(" "+propertyName+": "+e[propertyName]); - } -} - -function init() -{ - alert("Creating ArrayBuffer(100)"); - var ab = new ArrayBuffer(100); - alert("Typeof(ArrayBuffer): "+typeof(ab)); - alert("ArrayBuffer: "+ab); - enumerate(ab); +/***************************************************************************************** + * Testing basic support for the ArrayBuffer JavaScript object + *****************************************************************************************/ + +alert("Script loaded"); + +function enumerate(e) +{ + for(var propertyName in e) { + alert(" "+propertyName+": "+e[propertyName]); + } +} + +function init() +{ + alert("Creating ArrayBuffer(100)"); + var ab = new ArrayBuffer(100); + alert("Typeof(ArrayBuffer): "+typeof(ab)); + alert("ArrayBuffer: "+ab); + enumerate(ab); } \ No newline at end of file diff --git a/regression_tests/html5_video/basic_audio.svg b/regression_tests/html5_video/basic_audio.svg index 86d8ab0..f4f3cb4 100644 --- a/regression_tests/html5_video/basic_audio.svg +++ b/regression_tests/html5_video/basic_audio.svg @@ -1,12 +1,12 @@ -<svg width="100%" height="100%" viewBox="0 0 800 600" - xmlns="http://www.w3.org/2000/svg"> - - <audio id="a"/> - - <script type="application/ecmascript"> - a = document.getElementById("a"); - alert(""+a); - a.src = "media/counter-10mn_I25_640x360_160kbps_openGOP_dash.mp4"; - alert(""+a.src); - </script> +<svg width="100%" height="100%" viewBox="0 0 800 600" + xmlns="http://www.w3.org/2000/svg"> + + <audio id="a"/> + + <script type="application/ecmascript"> + a = document.getElementById("a"); + alert(""+a); + a.src = "media/counter-10mn_I25_640x360_160kbps_openGOP_dash.mp4"; + alert(""+a.src); + </script> </svg> \ No newline at end of file diff --git a/regression_tests/html5_video/basic_mediasource.js b/regression_tests/html5_video/basic_mediasource.js index 70a3a55..e883f6d 100644 --- a/regression_tests/html5_video/basic_mediasource.js +++ b/regression_tests/html5_video/basic_mediasource.js @@ -1,25 +1,25 @@ -/***************************************************************************************** - * Testing basic support for the MediaSource JavaScript object - *****************************************************************************************/ - -alert("Script loaded"); - -function enumerate(e, s) -{ - for(var propertyName in e) { - alert((s==null?"":s)+" "+propertyName+": "+e[propertyName]); - if (typeof(e[propertyName]) == "object") { - enumerate(e[propertyName], " "); - } - } -} - -function init() -{ - alert("Creating new MediaSource"); - var ms = new MediaSource(); - alert("MediaSource object: "+ms); - enumerate(ms); -} - +/***************************************************************************************** + * Testing basic support for the MediaSource JavaScript object + *****************************************************************************************/ + +alert("Script loaded"); + +function enumerate(e, s) +{ + for(var propertyName in e) { + alert((s==null?"":s)+" "+propertyName+": "+e[propertyName]); + if (typeof(e[propertyName]) == "object") { + enumerate(e[propertyName], " "); + } + } +} + +function init() +{ + alert("Creating new MediaSource"); + var ms = new MediaSource(); + alert("MediaSource object: "+ms); + enumerate(ms); +} + document.documentElement.addEventListener("load", init); \ No newline at end of file diff --git a/regression_tests/html5_video/basic_sourcebuffer.js b/regression_tests/html5_video/basic_sourcebuffer.js index 2bb05c0..fbd85ec 100644 --- a/regression_tests/html5_video/basic_sourcebuffer.js +++ b/regression_tests/html5_video/basic_sourcebuffer.js @@ -1,53 +1,53 @@ -/***************************************************************************************** - * Testing basic support for the MSE SourceBuffer JavaScript object - *****************************************************************************************/ - -alert("Script loaded"); - -function enumerate(e, s) -{ - for(var propertyName in e) { - alert((s==null?"":s)+" "+propertyName+": "+e[propertyName]); - if (typeof(e[propertyName]) == "object") { - enumerate(e[propertyName], " "); - } - } -} - -function onSourceOpen(event) -{ - alert("MediaSource opened"); - /* GPAC Hack: since the event is not targeted to the MediaSource, we need to get the MediaSource back */ - var ms = event.target.ms; - enumerate(ms); - - alert("Checking if type video/mp4 is supported: "+MediaSource.isTypeSupported("video/mp4")); - alert("Checking if type video/ogg is supported: "+MediaSource.isTypeSupported("video/ogg")); - alert("Checking if type text/plain is supported: "+MediaSource.isTypeSupported("text/plain")); - alert("Checking if type application/octet-stream is supported: "+MediaSource.isTypeSupported("application/octet-stream")); - - alert("Adding Source Buffer of type video/mp4 to the MediaSource"); - var sb = ms.addSourceBuffer("video/mp4"); - alert("SourceBuffer "+sb); - enumerate(sb); - enumerate(sb.buffered); -} - -function init() -{ - var v = document.getElementById("v"); - - alert("Creating new MediaSource"); - var ms = new MediaSource(); - - /* GPAC Hack: the event should be dispatched to the MediaSource object */ - v.addEventListener("sourceopen", onSourceOpen); - - var url = URL.createObjectURL(ms); - alert("Attaching Media Source "+url+" to Video"); - v.src = url; - - /* GPAC hack to retrieve the MediaSource from the video when the sourceopen event is dispatched */ - v.ms = ms; - +/***************************************************************************************** + * Testing basic support for the MSE SourceBuffer JavaScript object + *****************************************************************************************/ + +alert("Script loaded"); + +function enumerate(e, s) +{ + for(var propertyName in e) { + alert((s==null?"":s)+" "+propertyName+": "+e[propertyName]); + if (typeof(e[propertyName]) == "object") { + enumerate(e[propertyName], " "); + } + } +} + +function onSourceOpen(event) +{ + alert("MediaSource opened"); + /* GPAC Hack: since the event is not targeted to the MediaSource, we need to get the MediaSource back */ + var ms = event.target.ms; + enumerate(ms); + + alert("Checking if type video/mp4 is supported: "+MediaSource.isTypeSupported("video/mp4")); + alert("Checking if type video/ogg is supported: "+MediaSource.isTypeSupported("video/ogg")); + alert("Checking if type text/plain is supported: "+MediaSource.isTypeSupported("text/plain")); + alert("Checking if type application/octet-stream is supported: "+MediaSource.isTypeSupported("application/octet-stream")); + + alert("Adding Source Buffer of type video/mp4 to the MediaSource"); + var sb = ms.addSourceBuffer("video/mp4"); + alert("SourceBuffer "+sb); + enumerate(sb); + enumerate(sb.buffered); +} + +function init() +{ + var v = document.getElementById("v"); + + alert("Creating new MediaSource"); + var ms = new MediaSource(); + + /* GPAC Hack: the event should be dispatched to the MediaSource object */ + v.addEventListener("sourceopen", onSourceOpen); + + var url = URL.createObjectURL(ms); + alert("Attaching Media Source "+url+" to Video"); + v.src = url; + + /* GPAC hack to retrieve the MediaSource from the video when the sourceopen event is dispatched */ + v.ms = ms; + } \ No newline at end of file diff --git a/regression_tests/html5_video/basic_url.js b/regression_tests/html5_video/basic_url.js index fab6233..f2e182e 100644 --- a/regression_tests/html5_video/basic_url.js +++ b/regression_tests/html5_video/basic_url.js @@ -1,26 +1,26 @@ -/***************************************************************************************** - * Testing basic support for the HTML5 URL object - *****************************************************************************************/ - -alert("Script loaded"); - -function enumerate(e) -{ - for(var propertyName in e) { - alert(" "+propertyName+": "+e[propertyName]); - } -} - -function init() -{ - alert("Creating URL from nothing"); - alert("URL: "+URL.createObjectURL()); - alert("Creating URL from null"); - alert("URL: "+URL.createObjectURL(null)); - alert("Creating URL from dummy value"); - alert("URL: "+URL.createObjectURL(1)); - alert("Creating URL from Media Source"); - var ms = new MediaSource(); - var url = URL.createObjectURL(ms); - alert("URL: "+ url); +/***************************************************************************************** + * Testing basic support for the HTML5 URL object + *****************************************************************************************/ + +alert("Script loaded"); + +function enumerate(e) +{ + for(var propertyName in e) { + alert(" "+propertyName+": "+e[propertyName]); + } +} + +function init() +{ + alert("Creating URL from nothing"); + alert("URL: "+URL.createObjectURL()); + alert("Creating URL from null"); + alert("URL: "+URL.createObjectURL(null)); + alert("Creating URL from dummy value"); + alert("URL: "+URL.createObjectURL(1)); + alert("Creating URL from Media Source"); + var ms = new MediaSource(); + var url = URL.createObjectURL(ms); + alert("URL: "+ url); } \ No newline at end of file diff --git a/regression_tests/html5_video/basic_video.js b/regression_tests/html5_video/basic_video.js index e3e8af8..4b6127e 100644 --- a/regression_tests/html5_video/basic_video.js +++ b/regression_tests/html5_video/basic_video.js @@ -1,81 +1,81 @@ -/***************************************************************************************** - * Testing support for the basic HTML5 Video object - *****************************************************************************************/ - -alert("Script loaded"); - -function enumerate(e) -{ - for(var propertyName in e) { - alert(" "+propertyName+": "+e[propertyName]); - } -} - -function print_ranges(r) { - alert(" time ranges length:" + r.length); - for (var i = 0; i < r.length; i++) { - alert(" (" + r.start(i) + "," + r.end(i) + ")"); - } -} - -function print_tracks(t) { -} - -function print_media_info() -{ - var v = document.getElementById("v"); - alert(""); - alert("Element: "+v); - alert("HTMLMediaElement Properties: "); - alert("src: "+v.src); - alert("error & code: "+v.error+":"+v.error.code); - alert("currentSrc: "+v.currentSrc); - alert("crossOrigin: "+v.crossOrigin); - alert("networkState: "+v.networkState); - alert("preload: "+v.preload); - alert("buffered: "+v.buffered); - print_ranges(v.buffered); - alert("readyState: "+v.readyState); - alert("seeking: "+v.seeking); - alert("currentTime: "+v.currentTime); - alert("duration: "+v.duration); - alert("startDate: "+v.startDate); - alert("paused: "+v.paused); - alert("def playrate: "+v.defaultPlaybackRate); - alert("play rate: "+v.playbackRate); - alert("played: "+v.played); - print_ranges(v.played); - alert("seekable: "+v.seekable); - print_ranges(v.seekable); - alert("ended: "+v.ended); - alert("autoplay: "+v.autoplay); - alert("loop: "+v.loop); - alert("mediaGroup: "+v.mediaGroup); - alert("controller: "+v.controller); - alert("controls: "+v.controls); - alert("volume: "+v.volume); - alert("muted: "+v.muted); - alert("defaultMuted: "+v.defaultMuted); - alert("audioTracks: "+v.audioTracks+ " length ("+v.audioTracks.length+")"); - print_tracks(v.audioTracks); - alert("videoTracks: "+v.videoTracks+ " length ("+v.videoTracks.length+")"); - print_tracks(v.videoTracks); - alert("textTracks: "+v.textTracks+ " length ("+v.textTracks.length+")"); - print_tracks(v.textTracks); - alert(""); - alert("HTMLVideoElement specific properties: "); - alert("width: "+v.width); - alert("height: "+v.height); - alert("wideoWidth: "+v.videoWidth); - alert("videoHeight: "+v.videoHeight); - alert("poster: "+v.poster); - alert(""); -} - -function init() -{ - var v = document.getElementById("v"); - v.src = "media/counter-10mn_I25_640x360_160kbps_openGOP_dash.mp4"; - v.addEventListener("click", print_media_info); - enumerate(v); +/***************************************************************************************** + * Testing support for the basic HTML5 Video object + *****************************************************************************************/ + +alert("Script loaded"); + +function enumerate(e) +{ + for(var propertyName in e) { + alert(" "+propertyName+": "+e[propertyName]); + } +} + +function print_ranges(r) { + alert(" time ranges length:" + r.length); + for (var i = 0; i < r.length; i++) { + alert(" (" + r.start(i) + "," + r.end(i) + ")"); + } +} + +function print_tracks(t) { +} + +function print_media_info() +{ + var v = document.getElementById("v"); + alert(""); + alert("Element: "+v); + alert("HTMLMediaElement Properties: "); + alert("src: "+v.src); + alert("error & code: "+v.error+":"+v.error.code); + alert("currentSrc: "+v.currentSrc); + alert("crossOrigin: "+v.crossOrigin); + alert("networkState: "+v.networkState); + alert("preload: "+v.preload); + alert("buffered: "+v.buffered); + print_ranges(v.buffered); + alert("readyState: "+v.readyState); + alert("seeking: "+v.seeking); + alert("currentTime: "+v.currentTime); + alert("duration: "+v.duration); + alert("startDate: "+v.startDate); + alert("paused: "+v.paused); + alert("def playrate: "+v.defaultPlaybackRate); + alert("play rate: "+v.playbackRate); + alert("played: "+v.played); + print_ranges(v.played); + alert("seekable: "+v.seekable); + print_ranges(v.seekable); + alert("ended: "+v.ended); + alert("autoplay: "+v.autoplay); + alert("loop: "+v.loop); + alert("mediaGroup: "+v.mediaGroup); + alert("controller: "+v.controller); + alert("controls: "+v.controls); + alert("volume: "+v.volume); + alert("muted: "+v.muted); + alert("defaultMuted: "+v.defaultMuted); + alert("audioTracks: "+v.audioTracks+ " length ("+v.audioTracks.length+")"); + print_tracks(v.audioTracks); + alert("videoTracks: "+v.videoTracks+ " length ("+v.videoTracks.length+")"); + print_tracks(v.videoTracks); + alert("textTracks: "+v.textTracks+ " length ("+v.textTracks.length+")"); + print_tracks(v.textTracks); + alert(""); + alert("HTMLVideoElement specific properties: "); + alert("width: "+v.width); + alert("height: "+v.height); + alert("wideoWidth: "+v.videoWidth); + alert("videoHeight: "+v.videoHeight); + alert("poster: "+v.poster); + alert(""); +} + +function init() +{ + var v = document.getElementById("v"); + v.src = "media/counter-10mn_I25_640x360_160kbps_openGOP_dash.mp4"; + v.addEventListener("click", print_media_info); + enumerate(v); } \ No newline at end of file diff --git a/regression_tests/html5_video/gpac-mse.js b/regression_tests/html5_video/gpac-mse.js index 3d11909..f7d4ae6 100644 --- a/regression_tests/html5_video/gpac-mse.js +++ b/regression_tests/html5_video/gpac-mse.js @@ -1,358 +1,358 @@ -'use strict'; -/***************************************************************************************** - * - * Example code using the Media Source Extension API with GPAC - * - *****************************************************************************************/ -alert("Media Source Script loaded"); - -var DEBUG = true; -var UPDATE_TEXT_INFO = true; - -function reportMessage(msg) { - if (DEBUG) { - alert(msg); - } -} - -function createLabel(x, y, fill, textContent) -{ - var label = document.createElement("text"); - label.setAttribute("x", x); - label.setAttribute("y", y); - label.setAttribute("fill", fill); - label.textContent = textContent; - return label; -} - -function createBar(x, y, w, h, fill) { - var bar = document.createElement("rect"); - bar.setAttribute("x", x); - bar.setAttribute("y", y); - bar.setAttribute("width", w); - bar.setAttribute("height", h); - bar.setAttribute("rx", h/2); - bar.setAttribute("ry", h/2); - bar.setAttribute("fill", fill); - return bar; -} - -Player.prototype.createInfoStructure = function(id) { - this.info = {}; - var width = 330; - var ta; - var g = document.getElementById(id); - ta = document.createElement("textArea"); - ta.setAttribute("x", 100); - ta.setAttribute("y", -50); - ta.setAttribute("width", width); - g.appendChild(ta); - /* status info */ - this.info.se = document.createElement("tspan"); - ta.appendChild(this.info.se); - ta.appendChild(document.createElement("tbreak")); - /* Quality info */ - this.info.qe = document.createElement("tspan"); - ta.appendChild(this.info.qe); - ta.appendChild(document.createElement("tbreak")); - /* Document time info */ - this.info.dte = document.createElement("tspan"); - //ta.appendChild(this.info.dte); - //ta.appendChild(document.createElement("tbreak")); - /* Video time info */ - this.info.vte = document.createElement("tspan"); - //ta.appendChild(this.info.vte); - //ta.appendChild(document.createElement("tbreak")); - /* Buffer info */ - this.info.be = document.createElement("tspan"); - //ta.appendChild(this.info.be); - //ta.appendChild(document.createElement("tbreak")); - /* URL info */ - this.info.ue = document.createElement("tspan"); - ta.appendChild(this.info.ue); - - this.ui = {}; - this.ui.playbackRect = createBar(10, 5, width-10, 5, "black"); - g.appendChild(this.ui.playbackRect); - - this.ui.bufferedRect = createBar(10, 5, 0, 5, "url(#backColor)"); - g.appendChild(this.ui.bufferedRect); - this.ui.bufferedRect.max = width; - - this.ui.zeroLabel = createLabel(0, 10, "black", '0'); - g.appendChild(this.ui.zeroLabel); - - this.ui.playLabel = createLabel(0, 20, "black", ''); - g.appendChild(this.ui.playLabel); - - this.ui.playBar = createBar(0, 5, 1, 5, "black"); - g.appendChild(this.ui.playBar); - - this.ui.startLabel = createLabel(0, 0, "black", ''); - g.appendChild(this.ui.startLabel); - - this.ui.endLabel = createLabel(width+5, 10, "black", 'end'); - g.appendChild(this.ui.endLabel); -} - -Player.prototype.updateInfo = function() { - if (!UPDATE_TEXT_INFO) return; - var start = 0; - var end = 1; - var nowVideo = this.v.currentTime.toFixed(3); -// this.info.dte.textContent = "Document time:" + document.documentElement.getCurrentTime(); -// this.info.vte.textContent = "Video time: " + nowVideo; - if (this.qualityChangeRequested) { - this.info.qe.textContent = "Quality : " + (this.qualityIndex - this.qualityChangeRequested) + "/"+(this.segmentFiles.length-1)+", requested: "+this.qualityIndex; - } else { - this.info.qe.textContent = "Quality : " + this.qualityIndex + "/"+(this.segmentFiles.length-1); - } - if (this.sb != null && this.sb.buffered.length > 0) { - start = this.sb.buffered.start(0).toFixed(3); - end = this.sb.buffered.end(0).toFixed(3); - //this.info.be.textContent = "Media Data Buffered: (" + start + "," + end + ")"; - } else { - //this.info.be.textContent = "empty buffer"; - } - this.ui.playLabel.textContent = nowVideo; - this.ui.playLabel.setAttribute("x", nowVideo/end*this.ui.bufferedRect.max); - this.ui.playBar.setAttribute("x", 10+nowVideo/end*this.ui.bufferedRect.max); - this.ui.startLabel.textContent = start; - this.ui.endLabel.textContent = end; - this.ui.startLabel.setAttribute("x", 10+start/end*this.ui.bufferedRect.max); - this.ui.bufferedRect.setAttribute("x", 10+start/end*this.ui.bufferedRect.max); - this.ui.bufferedRect.setAttribute("width", (end - start)/end*this.ui.bufferedRect.max-10); -} - -Player.prototype.updateDownloadInfo = function(index, url, done) { - if (!UPDATE_TEXT_INFO) return; - this.info.ue.textContent = "Segment #" + index + " ..." + url.slice(-30); - this.info.se.textContent = "Download Status:"+ (done ?" done" : " in progress"); -} - -Player.prototype.toggleQuality = function() { - reportMessage("[video "+this.v.getAttribute("id")+"] Toggling quality"); - var newQuality = (this.qualityIndex + 1) % this.segmentFiles.length; - this.qualityChangeRequested = (newQuality - this.qualityIndex); - this.qualityIndex = newQuality; - this.updateInfo(); -} - -Player.prototype.switchUp = function() { - reportMessage("[video "+this.v.getAttribute("id")+"] Switching quality up"); - if (this.qualityIndex < this.segmentFiles.length - 1) { - this.qualityIndex++; - this.qualityChangeRequested++; - } - this.updateInfo(); -} - -Player.prototype.switchDown = function() { - reportMessage("[video "+this.v.getAttribute("id")+"] Switching quality down"); - if (this.qualityIndex > 0) { - this.qualityIndex--; - this.qualityChangeRequested--; - } - this.updateInfo(); -} - -Player.prototype.getNextSegment = function () { - /* apply the limit (if any) to the number of segments to download */ - if (this.maxSeg > 0 && this.fileIndex >= this.maxSeg && this.playing) return; - - if (!this.qualityChangeRequested) { - /* we increment the segment index only when we need a media segment (not an init segment) */ - this.fileIndex++; - } - - /* apply the segment reordering pattern (if any) */ - if (this.appendOrder != null && this.fileIndex < this.appendOrder.length) { - this.fileIndexReordered = this.appendOrder[this.fileIndex]; - reportMessage("[video "+this.v.getAttribute("id")+"] Changing file index from: " + this.fileIndex + "to : " + this.fileIndexReordered); - } else { - this.fileIndexReordered = this.fileIndex; - reportMessage("[video "+this.v.getAttribute("id")+"] Using file index: " + this.fileIndex); - } - - /* determine the url to use */ - if (this.qualityChangeRequested || this.fileIndexReordered < this.segmentFiles[this.qualityIndex].segStartIndex) { - /* Setting the url with the initialization segment */ - this.url = this.segmentFiles[this.qualityIndex].baseURL + this.segmentFiles[this.qualityIndex].initName; - } - else if (this.fileIndexReordered >= this.segmentFiles[this.qualityIndex].segStartIndex - && this.fileIndexReordered < this.segmentFiles[this.qualityIndex].segEndIndex) { - /* Setting the url with a regular media segment */ - this.url = this.segmentFiles[this.qualityIndex].baseURL - + this.segmentFiles[this.qualityIndex].segmentPrefix - + this.fileIndexReordered - + this.segmentFiles[this.qualityIndex].segmentSuffix; - } - - reportMessage("[video "+this.v.getAttribute("id")+"] Downloading resource from url: " + this.url); - /* starting the download */ - if (this.url) { - this.updateDownloadInfo(this.fileIndexReordered, this.url); - this.xhr.url = this.url; - this.xhr.qualityChangeRequested = this.qualityChangeRequested; - this.xhr.open("GET", this.url); - this.xhr.responseType = "arraybuffer"; - this.xhr.onreadystatechange = onDone; - this.xhr.send(); - } - - this.updateInfo(); -} - -function onDone(e) { - if (this.readyState == 4/*this.DONE*/) { - this.player.updateDownloadInfo(this.player.fileIndexReordered, this.url, true); - var arraybuffer = this.response; - reportMessage("[video "+this.player.v.getAttribute("id")+"] Received ArrayBuffer (size: " + arraybuffer.byteLength + ")"); - /* Appending the downloaded segment to the SourceBuffer */ - if (this.player.sb) { - /* if there is a discontinuity in the file index, we need to inform the SourceBuffer */ - if (this.player.prevFileIndex != 0 && this.player.fileIndexReordered != this.player.prevFileIndex + 1) { - this.player.sb.abort("continuation"); - reportMessage("[video "+this.player.v.getAttribute("id")+"] Changing append mode"); - } - this.player.prevFileIndex = this.player.fileIndexReordered; - /* we assume everything will be fine with this append */ - this.player.sb.appendBuffer(arraybuffer); - reportMessage("[video "+this.player.v.getAttribute("id")+"] Appending Buffer ArrayBuffer (size: " + arraybuffer.byteLength + ")"); - } - this.player.url = null; - if (this.qualityChangeRequested != 0) { - this.player.qualityChangeRequested = 0; - } - if (!this.player.use_regulation) { - this.player.getNextSegment(); - } - } -} - -Player.prototype.onSourceOpen = function (event) { - reportMessage("[video "+this.v.getAttribute("id")+"] MediaSource opened"); - var ms = event.target; - - reportMessage("[video "+this.v.getAttribute("id")+"] Adding Source Buffer of type video/mp4 to the MediaSource"); - ms.player.sb = ms.addSourceBuffer("video/mp4"); - ms.player.sb.id = ms.sourceBuffers.length; - ms.player.getNextSegment(); -} - -Player.prototype.checkBufferLevel = function() { - /* don't download a new segment if: - - the SourceBuffer is not created - - there is already a download going on */ - reportMessage("[video "+this.v.getAttribute("id")+"] Checking buffer level on SourceBuffer "+this.sb+" "+this.url); - if (this.sb != null && this.url == null) { - if (this.sb.buffered.length > 0) { - if (this.v.currentTime >= this.sb.buffered.end(0)) { - this.pause(); - } else { - reportMessage("[video "+this.v.getAttribute("id")+"] Video time "+this.v.currentTime + ", Source Buffer #"+this.sb.id+" buffered data range: (" + this.sb.buffered.start(0) + "," + this.sb.buffered.end(0) + ")"); - if (this.sb.updating == false && this.sb.buffered.end(0) - this.v.currentTime < this.TIME_THRESOLD) { - reportMessage("[video "+this.v.getAttribute("id")+"] buffered attribute has not enough data, downloading new segment"); - this.getNextSegment(); - } - } - } - else { - if (!this.sb.updating) { - reportMessage("[video "+this.v.getAttribute("id")+"] buffered attribute has no data, downloading new segment"); - this.getNextSegment(); - } else { - reportMessage("[video "+this.v.getAttribute("id")+"] Source Buffer still updating"); - } - } - } -} - -/* Function called repeatedly to monitor the playback time versus download time difference -and to trigger a new download if needed */ -Player.prototype.repeatFunc = function() { - if (!this.playing) return; - this.updateInfo(); - this.checkBufferLevel(); -} - -Player.prototype.play = function() { - reportMessage("[video "+this.v.getAttribute("id")+"] Starting video playback"); - this.playing = true; - this.v.play(); -} - -Player.prototype.pause = function() { - reportMessage("[video "+this.v.getAttribute("id")+"] Pausing video playback"); - this.playing = false; - this.v.pause(); -} - -Player.prototype.changeSegmentList = function(newSegments) { - this.segmentFiles = newSegments; - this.qualityChangeRequested++; -} - -/* - vId: id of the video element - iId: id of a group where debug info will be displayed - aId: id of a animation used to refresh downloads -*/ -function Player(vId, iId, aId, segmentFiles, segmentOrder) { - reportMessage("[video "+vId+"] Creating Player"); - /* Boolean to define the download policy: - - depending on the buffer occupancy (true) (see TIME_THRESOLD below), - - as fast as possible (false) */ - this.use_regulation = true; - /* difference in seconds between the latest media time downloaded and the media time being played, - used to trigger a new download when the regulation mode is on */ - this.TIME_THRESOLD = 2; - /* Current file being downloaded */ - this.fileIndex = -1; - /* URL of the segment being downloaded */ - this.url = null; - /* Current quality being downloaded */ - this.qualityIndex = 0; - this.qualityChangeRequested = 0; - /* using 1 XHR for all downloads */ - this.xhr = new XMLHttpRequest(); - this.xhr.player = this; - /* The source buffer used by the player (only one at the moment) */ - this.sb = null; - /* maximum number of segments to download */ - this.maxSeg = Infinity; - this.playing = false; - /* Array representing the download order of each segments (for out-of-order append), - segments not listed are downloaded in the right order */ - this.appendOrder = segmentOrder; - this.fileIndexReordered = 0; - this.prevFileIndex = 0; - /* references to objects used to display information regarding this player */ - this.info = null; - - this.segmentFiles = segmentFiles; - - if (this.use_regulation) { - /* GPAC workaround: adding the event listener on the repeatEvent of a dummy animation to simulate window.setInterval */ - var animation = document.getElementById(aId); - animation.addEventListener("repeatEvent", this.repeatFunc.bind(this)); - reportMessage("[video "+vId+"] Using buffer regulation to download segments "); - } else { - reportMessage("[video "+vId+"] Not using any regulation - downloading segments as fast as possible"); - } - - this.createInfoStructure(iId); - - reportMessage("[video "+vId+"] Creating new MediaSource"); - this.ms = new MediaSource(); - this.ms.player = this; - - var bloburl = URL.createObjectURL(this.ms); - reportMessage("[video "+vId+"] Attaching Media Source " + bloburl + " to video element"); - - this.v = document.getElementById(vId); - this.ms.addEventListener("sourceopen", this.onSourceOpen.bind(this)); - this.v.src = bloburl; - - return this; -} +'use strict'; +/***************************************************************************************** + * + * Example code using the Media Source Extension API with GPAC + * + *****************************************************************************************/ +alert("Media Source Script loaded"); + +var DEBUG = true; +var UPDATE_TEXT_INFO = true; + +function reportMessage(msg) { + if (DEBUG) { + alert(msg); + } +} + +function createLabel(x, y, fill, textContent) +{ + var label = document.createElement("text"); + label.setAttribute("x", x); + label.setAttribute("y", y); + label.setAttribute("fill", fill); + label.textContent = textContent; + return label; +} + +function createBar(x, y, w, h, fill) { + var bar = document.createElement("rect"); + bar.setAttribute("x", x); + bar.setAttribute("y", y); + bar.setAttribute("width", w); + bar.setAttribute("height", h); + bar.setAttribute("rx", h/2); + bar.setAttribute("ry", h/2); + bar.setAttribute("fill", fill); + return bar; +} + +Player.prototype.createInfoStructure = function(id) { + this.info = {}; + var width = 330; + var ta; + var g = document.getElementById(id); + ta = document.createElement("textArea"); + ta.setAttribute("x", 100); + ta.setAttribute("y", -50); + ta.setAttribute("width", width); + g.appendChild(ta); + /* status info */ + this.info.se = document.createElement("tspan"); + ta.appendChild(this.info.se); + ta.appendChild(document.createElement("tbreak")); + /* Quality info */ + this.info.qe = document.createElement("tspan"); + ta.appendChild(this.info.qe); + ta.appendChild(document.createElement("tbreak")); + /* Document time info */ + this.info.dte = document.createElement("tspan"); + //ta.appendChild(this.info.dte); + //ta.appendChild(document.createElement("tbreak")); + /* Video time info */ + this.info.vte = document.createElement("tspan"); + //ta.appendChild(this.info.vte); + //ta.appendChild(document.createElement("tbreak")); + /* Buffer info */ + this.info.be = document.createElement("tspan"); + //ta.appendChild(this.info.be); + //ta.appendChild(document.createElement("tbreak")); + /* URL info */ + this.info.ue = document.createElement("tspan"); + ta.appendChild(this.info.ue); + + this.ui = {}; + this.ui.playbackRect = createBar(10, 5, width-10, 5, "black"); + g.appendChild(this.ui.playbackRect); + + this.ui.bufferedRect = createBar(10, 5, 0, 5, "url(#backColor)"); + g.appendChild(this.ui.bufferedRect); + this.ui.bufferedRect.max = width; + + this.ui.zeroLabel = createLabel(0, 10, "black", '0'); + g.appendChild(this.ui.zeroLabel); + + this.ui.playLabel = createLabel(0, 20, "black", ''); + g.appendChild(this.ui.playLabel); + + this.ui.playBar = createBar(0, 5, 1, 5, "black"); + g.appendChild(this.ui.playBar); + + this.ui.startLabel = createLabel(0, 0, "black", ''); + g.appendChild(this.ui.startLabel); + + this.ui.endLabel = createLabel(width+5, 10, "black", 'end'); + g.appendChild(this.ui.endLabel); +} + +Player.prototype.updateInfo = function() { + if (!UPDATE_TEXT_INFO) return; + var start = 0; + var end = 1; + var nowVideo = this.v.currentTime.toFixed(3); +// this.info.dte.textContent = "Document time:" + document.documentElement.getCurrentTime(); +// this.info.vte.textContent = "Video time: " + nowVideo; + if (this.qualityChangeRequested) { + this.info.qe.textContent = "Quality : " + (this.qualityIndex - this.qualityChangeRequested) + "/"+(this.segmentFiles.length-1)+", requested: "+this.qualityIndex; + } else { + this.info.qe.textContent = "Quality : " + this.qualityIndex + "/"+(this.segmentFiles.length-1); + } + if (this.sb != null && this.sb.buffered.length > 0) { + start = this.sb.buffered.start(0).toFixed(3); + end = this.sb.buffered.end(0).toFixed(3); + //this.info.be.textContent = "Media Data Buffered: (" + start + "," + end + ")"; + } else { + //this.info.be.textContent = "empty buffer"; + } + this.ui.playLabel.textContent = nowVideo; + this.ui.playLabel.setAttribute("x", nowVideo/end*this.ui.bufferedRect.max); + this.ui.playBar.setAttribute("x", 10+nowVideo/end*this.ui.bufferedRect.max); + this.ui.startLabel.textContent = start; + this.ui.endLabel.textContent = end; + this.ui.startLabel.setAttribute("x", 10+start/end*this.ui.bufferedRect.max); + this.ui.bufferedRect.setAttribute("x", 10+start/end*this.ui.bufferedRect.max); + this.ui.bufferedRect.setAttribute("width", (end - start)/end*this.ui.bufferedRect.max-10); +} + +Player.prototype.updateDownloadInfo = function(index, url, done) { + if (!UPDATE_TEXT_INFO) return; + this.info.ue.textContent = "Segment #" + index + " ..." + url.slice(-30); + this.info.se.textContent = "Download Status:"+ (done ?" done" : " in progress"); +} + +Player.prototype.toggleQuality = function() { + reportMessage("[video "+this.v.getAttribute("id")+"] Toggling quality"); + var newQuality = (this.qualityIndex + 1) % this.segmentFiles.length; + this.qualityChangeRequested = (newQuality - this.qualityIndex); + this.qualityIndex = newQuality; + this.updateInfo(); +} + +Player.prototype.switchUp = function() { + reportMessage("[video "+this.v.getAttribute("id")+"] Switching quality up"); + if (this.qualityIndex < this.segmentFiles.length - 1) { + this.qualityIndex++; + this.qualityChangeRequested++; + } + this.updateInfo(); +} + +Player.prototype.switchDown = function() { + reportMessage("[video "+this.v.getAttribute("id")+"] Switching quality down"); + if (this.qualityIndex > 0) { + this.qualityIndex--; + this.qualityChangeRequested--; + } + this.updateInfo(); +} + +Player.prototype.getNextSegment = function () { + /* apply the limit (if any) to the number of segments to download */ + if (this.maxSeg > 0 && this.fileIndex >= this.maxSeg && this.playing) return; + + if (!this.qualityChangeRequested) { + /* we increment the segment index only when we need a media segment (not an init segment) */ + this.fileIndex++; + } + + /* apply the segment reordering pattern (if any) */ + if (this.appendOrder != null && this.fileIndex < this.appendOrder.length) { + this.fileIndexReordered = this.appendOrder[this.fileIndex]; + reportMessage("[video "+this.v.getAttribute("id")+"] Changing file index from: " + this.fileIndex + "to : " + this.fileIndexReordered); + } else { + this.fileIndexReordered = this.fileIndex; + reportMessage("[video "+this.v.getAttribute("id")+"] Using file index: " + this.fileIndex); + } + + /* determine the url to use */ + if (this.qualityChangeRequested || this.fileIndexReordered < this.segmentFiles[this.qualityIndex].segStartIndex) { + /* Setting the url with the initialization segment */ + this.url = this.segmentFiles[this.qualityIndex].baseURL + this.segmentFiles[this.qualityIndex].initName; + } + else if (this.fileIndexReordered >= this.segmentFiles[this.qualityIndex].segStartIndex + && this.fileIndexReordered < this.segmentFiles[this.qualityIndex].segEndIndex) { + /* Setting the url with a regular media segment */ + this.url = this.segmentFiles[this.qualityIndex].baseURL + + this.segmentFiles[this.qualityIndex].segmentPrefix + + this.fileIndexReordered + + this.segmentFiles[this.qualityIndex].segmentSuffix; + } + + reportMessage("[video "+this.v.getAttribute("id")+"] Downloading resource from url: " + this.url); + /* starting the download */ + if (this.url) { + this.updateDownloadInfo(this.fileIndexReordered, this.url); + this.xhr.url = this.url; + this.xhr.qualityChangeRequested = this.qualityChangeRequested; + this.xhr.open("GET", this.url); + this.xhr.responseType = "arraybuffer"; + this.xhr.onreadystatechange = onDone; + this.xhr.send(); + } + + this.updateInfo(); +} + +function onDone(e) { + if (this.readyState == 4/*this.DONE*/) { + this.player.updateDownloadInfo(this.player.fileIndexReordered, this.url, true); + var arraybuffer = this.response; + reportMessage("[video "+this.player.v.getAttribute("id")+"] Received ArrayBuffer (size: " + arraybuffer.byteLength + ")"); + /* Appending the downloaded segment to the SourceBuffer */ + if (this.player.sb) { + /* if there is a discontinuity in the file index, we need to inform the SourceBuffer */ + if (this.player.prevFileIndex != 0 && this.player.fileIndexReordered != this.player.prevFileIndex + 1) { + this.player.sb.abort("continuation"); + reportMessage("[video "+this.player.v.getAttribute("id")+"] Changing append mode"); + } + this.player.prevFileIndex = this.player.fileIndexReordered; + /* we assume everything will be fine with this append */ + this.player.sb.appendBuffer(arraybuffer); + reportMessage("[video "+this.player.v.getAttribute("id")+"] Appending Buffer ArrayBuffer (size: " + arraybuffer.byteLength + ")"); + } + this.player.url = null; + if (this.qualityChangeRequested != 0) { + this.player.qualityChangeRequested = 0; + } + if (!this.player.use_regulation) { + this.player.getNextSegment(); + } + } +} + +Player.prototype.onSourceOpen = function (event) { + reportMessage("[video "+this.v.getAttribute("id")+"] MediaSource opened"); + var ms = event.target; + + reportMessage("[video "+this.v.getAttribute("id")+"] Adding Source Buffer of type video/mp4 to the MediaSource"); + ms.player.sb = ms.addSourceBuffer("video/mp4"); + ms.player.sb.id = ms.sourceBuffers.length; + ms.player.getNextSegment(); +} + +Player.prototype.checkBufferLevel = function() { + /* don't download a new segment if: + - the SourceBuffer is not created + - there is already a download going on */ + reportMessage("[video "+this.v.getAttribute("id")+"] Checking buffer level on SourceBuffer "+this.sb+" "+this.url); + if (this.sb != null && this.url == null) { + if (this.sb.buffered.length > 0) { + if (this.v.currentTime >= this.sb.buffered.end(0)) { + this.pause(); + } else { + reportMessage("[video "+this.v.getAttribute("id")+"] Video time "+this.v.currentTime + ", Source Buffer #"+this.sb.id+" buffered data range: (" + this.sb.buffered.start(0) + "," + this.sb.buffered.end(0) + ")"); + if (this.sb.updating == false && this.sb.buffered.end(0) - this.v.currentTime < this.TIME_THRESOLD) { + reportMessage("[video "+this.v.getAttribute("id")+"] buffered attribute has not enough data, downloading new segment"); + this.getNextSegment(); + } + } + } + else { + if (!this.sb.updating) { + reportMessage("[video "+this.v.getAttribute("id")+"] buffered attribute has no data, downloading new segment"); + this.getNextSegment(); + } else { + reportMessage("[video "+this.v.getAttribute("id")+"] Source Buffer still updating"); + } + } + } +} + +/* Function called repeatedly to monitor the playback time versus download time difference +and to trigger a new download if needed */ +Player.prototype.repeatFunc = function() { + if (!this.playing) return; + this.updateInfo(); + this.checkBufferLevel(); +} + +Player.prototype.play = function() { + reportMessage("[video "+this.v.getAttribute("id")+"] Starting video playback"); + this.playing = true; + this.v.play(); +} + +Player.prototype.pause = function() { + reportMessage("[video "+this.v.getAttribute("id")+"] Pausing video playback"); + this.playing = false; + this.v.pause(); +} + +Player.prototype.changeSegmentList = function(newSegments) { + this.segmentFiles = newSegments; + this.qualityChangeRequested++; +} + +/* + vId: id of the video element + iId: id of a group where debug info will be displayed + aId: id of a animation used to refresh downloads +*/ +function Player(vId, iId, aId, segmentFiles, segmentOrder) { + reportMessage("[video "+vId+"] Creating Player"); + /* Boolean to define the download policy: + - depending on the buffer occupancy (true) (see TIME_THRESOLD below), + - as fast as possible (false) */ + this.use_regulation = true; + /* difference in seconds between the latest media time downloaded and the media time being played, + used to trigger a new download when the regulation mode is on */ + this.TIME_THRESOLD = 2; + /* Current file being downloaded */ + this.fileIndex = -1; + /* URL of the segment being downloaded */ + this.url = null; + /* Current quality being downloaded */ + this.qualityIndex = 0; + this.qualityChangeRequested = 0; + /* using 1 XHR for all downloads */ + this.xhr = new XMLHttpRequest(); + this.xhr.player = this; + /* The source buffer used by the player (only one at the moment) */ + this.sb = null; + /* maximum number of segments to download */ + this.maxSeg = Infinity; + this.playing = false; + /* Array representing the download order of each segments (for out-of-order append), + segments not listed are downloaded in the right order */ + this.appendOrder = segmentOrder; + this.fileIndexReordered = 0; + this.prevFileIndex = 0; + /* references to objects used to display information regarding this player */ + this.info = null; + + this.segmentFiles = segmentFiles; + + if (this.use_regulation) { + /* GPAC workaround: adding the event listener on the repeatEvent of a dummy animation to simulate window.setInterval */ + var animation = document.getElementById(aId); + animation.addEventListener("repeatEvent", this.repeatFunc.bind(this)); + reportMessage("[video "+vId+"] Using buffer regulation to download segments "); + } else { + reportMessage("[video "+vId+"] Not using any regulation - downloading segments as fast as possible"); + } + + this.createInfoStructure(iId); + + reportMessage("[video "+vId+"] Creating new MediaSource"); + this.ms = new MediaSource(); + this.ms.player = this; + + var bloburl = URL.createObjectURL(this.ms); + reportMessage("[video "+vId+"] Attaching Media Source " + bloburl + " to video element"); + + this.v = document.getElementById(vId); + this.ms.addEventListener("sourceopen", this.onSourceOpen.bind(this)); + this.v.src = bloburl; + + return this; +} diff --git a/regression_tests/html5_video/video.svg b/regression_tests/html5_video/video.svg index 8c9ab31..0a7c0b2 100644 --- a/regression_tests/html5_video/video.svg +++ b/regression_tests/html5_video/video.svg @@ -1,30 +1,30 @@ -<svg width="800" height="800" viewBox="0 0 800 800" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init()"> - - <!-- A button to toggle video quality --> - <rect id="r" fill="orange" x="10" y="10" width="180" height="40" rx="5"/> - <text x="30" y="30">Click to toggle quality</text> - - <!-- Displaying info --> - <g id="t" transform="translate(10, 60)"/> - - <video id="v" y="100" width="800" height="600"/> - - <!-- Fake animation to trigger periodic events (no support for setTimeout in GPAC) --> - <g> - <animate id="a" begin="0" dur="0.1" repeatCount="indefinite" attributeName="visibilty" from="visible" to="hidden" /> - </g> - - <!--<script type="application/ecmascript" xlink:href="basic_video.js"/>--> - <!--<script type="application/ecmascript" xlink:href="basic_mediasource.js"/>--> - <!--<script type="application/ecmascript" xlink:href="basic_url.js"/>--> - <!--<script type="application/ecmascript" xlink:href="basic_sourcebuffer.js"/>--> - - <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-video-only.js"/>--> - <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-video-only-local.js"/>--> - <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-audio-only.js"/>--> - <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-video-audio-multiplexed.js"/>--> - <!--<script type="application/ecmascript" xlink:href="video_html5_mse.js"/>--> - <!--<script type="application/ecmascript" xlink:href="mse-overlap.js"/>--> - <script type="application/ecmascript" xlink:href="mse-events.js"/> +<svg width="800" height="800" viewBox="0 0 800 800" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init()"> + + <!-- A button to toggle video quality --> + <rect id="r" fill="orange" x="10" y="10" width="180" height="40" rx="5"/> + <text x="30" y="30">Click to toggle quality</text> + + <!-- Displaying info --> + <g id="t" transform="translate(10, 60)"/> + + <video id="v" y="100" width="800" height="600"/> + + <!-- Fake animation to trigger periodic events (no support for setTimeout in GPAC) --> + <g> + <animate id="a" begin="0" dur="0.1" repeatCount="indefinite" attributeName="visibilty" from="visible" to="hidden" /> + </g> + + <!--<script type="application/ecmascript" xlink:href="basic_video.js"/>--> + <!--<script type="application/ecmascript" xlink:href="basic_mediasource.js"/>--> + <!--<script type="application/ecmascript" xlink:href="basic_url.js"/>--> + <!--<script type="application/ecmascript" xlink:href="basic_sourcebuffer.js"/>--> + + <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-video-only.js"/>--> + <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-video-only-local.js"/>--> + <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-audio-only.js"/>--> + <!--<script type="application/ecmascript" xlink:href="mediasegments-mp4-video-audio-multiplexed.js"/>--> + <!--<script type="application/ecmascript" xlink:href="video_html5_mse.js"/>--> + <!--<script type="application/ecmascript" xlink:href="mse-overlap.js"/>--> + <script type="application/ecmascript" xlink:href="mse-events.js"/> </svg> \ No newline at end of file diff --git a/regression_tests/html5_video/xhr.svg b/regression_tests/html5_video/xhr.svg index 768a668..594a4cb 100644 --- a/regression_tests/html5_video/xhr.svg +++ b/regression_tests/html5_video/xhr.svg @@ -1,4 +1,4 @@ -<svg width="100%" height="100%" viewBox="0 0 800 600" - xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - <script type="application/ecmascript" xlink:href="xhr.js"/> +<svg width="100%" height="100%" viewBox="0 0 800 600" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <script type="application/ecmascript" xlink:href="xhr.js"/> </svg> \ No newline at end of file diff --git a/regression_tests/ttml/ebu-ttd_sample.ttml b/regression_tests/ttml/ebu-ttd_sample.ttml new file mode 100644 index 0000000..0f5d7ec --- /dev/null +++ b/regression_tests/ttml/ebu-ttd_sample.ttml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tt xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p begin="00:00:00.000" end="00:00:01.400" region="bottom" xml:id="sub1">00:00:00.000<br/>00:00:01.400</p> + <p begin="00:00:02.120" end="00:00:03.800" region="bottom" xml:id="sub2">00:00:02.120<br/>00:00:03.800</p> + <p begin="00:00:22.720" end="00:00:25.840" region="bottom" xml:id="sub3">00:00:22.720<br/>00:00:25.840</p> + <p begin="00:00:26.080" end="00:00:29.120" region="bottom" xml:id="sub4">00:00:26.080<br/>00:00:29.120</p> + <p begin="00:00:29.120" end="00:00:30.640" region="bottom" xml:id="sub5">00:00:29.120<br/>00:00:30.640</p> + <p begin="00:00:30.960" end="00:00:33.200" region="bottom" xml:id="sub6">00:00:30.960<br/>00:00:33.200</p> + <p begin="00:00:33.200" end="00:00:36.320" region="bottom" xml:id="sub7">00:00:33.200<br/>00:00:36.320</p> + <p begin="00:00:36.320" end="00:00:40.040" region="bottom" xml:id="sub8">00:00:36.320<br/>00:00:40.040</p> + <p begin="00:00:40.040" end="00:00:43.520" region="bottom" xml:id="sub9">00:00:40.040<br/>00:00:43.520</p> + <p begin="00:00:43.520" end="00:00:46.920" region="bottom" xml:id="sub10">00:00:43.520<br/>00:00:46.920</p> + <p begin="00:00:46.920" end="00:00:51.040" region="bottom" xml:id="sub11">00:00:46.920<br/>00:00:51.040</p> + <p begin="00:00:51.080" end="00:00:54.160" region="bottom" xml:id="sub12">00:00:51.080<br/>00:00:54.160</p> + <p begin="00:00:54.480" end="00:00:58.240" region="bottom" xml:id="sub13">00:00:54.480<br/>00:00:58.240</p> + </div> + </body> +</tt> + diff --git a/regression_tests/ttml/ebu-ttd_sample_invalid_ns.ttml b/regression_tests/ttml/ebu-ttd_sample_invalid_ns.ttml new file mode 100644 index 0000000..04ef725 --- /dev/null +++ b/regression_tests/ttml/ebu-ttd_sample_invalid_ns.ttml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ttxxx xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p begin="00:00:00.000" end="00:00:01.400" region="bottom" xml:id="sub1">00:00:00.000<br/>00:00:01.400</p> + <p begin="00:00:02.120" end="00:00:03.800" region="bottom" xml:id="sub2">00:00:02.120<br/>00:00:03.800</p> + </div> + </body> +</ttxxx> + diff --git a/regression_tests/ttml/ebu-ttd_sample_span.ttml b/regression_tests/ttml/ebu-ttd_sample_span.ttml new file mode 100644 index 0000000..11e19be --- /dev/null +++ b/regression_tests/ttml/ebu-ttd_sample_span.ttml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tt xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p><span begin="00:00:00.000" end="00:00:01.400" xml:id="sub1">00:00:00.000<br/>00:00:01.400</span></p> + <p><span begin="00:00:02.120" end="00:00:03.800" xml:id="sub2">00:00:02.120<br/>00:00:03.800</span></p> + <p><span begin="00:00:22.720" end="00:00:25.840" xml:id="sub3">00:00:22.720<br/>00:00:25.840</span></p> + </div> + </body> +</tt> + diff --git a/regression_tests/ttml/ebu-ttd_timing_contiguous.ttml b/regression_tests/ttml/ebu-ttd_timing_contiguous.ttml new file mode 100644 index 0000000..caa3c18 --- /dev/null +++ b/regression_tests/ttml/ebu-ttd_timing_contiguous.ttml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tt xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p begin="00:00:00.000" end="00:00:01.400" region="bottom" xml:id="sub1">00:00:00.000<br/>00:00:01.400</p> + <p begin="00:00:01.400" end="00:00:02.120" region="bottom" xml:id="sub1">00:00:01.400<br/>00:00:02.120</p> + <p begin="00:00:02.120" end="00:00:03.800" region="bottom" xml:id="sub2">00:00:02.120<br/>00:00:03.800</p> + <p begin="00:00:03.800" end="00:00:25.840" region="bottom" xml:id="sub3">00:00:03.800<br/>00:00:25.840</p> + </div> + </body> +</tt> + diff --git a/regression_tests/ttml/ebu-ttd_timing_non-contiguous.ttml b/regression_tests/ttml/ebu-ttd_timing_non-contiguous.ttml new file mode 100644 index 0000000..d654769 --- /dev/null +++ b/regression_tests/ttml/ebu-ttd_timing_non-contiguous.ttml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tt xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p begin="00:00:00.000" end="00:00:01.400" region="bottom" xml:id="sub1">00:00:00.000<br/>00:00:01.400</p> + <p begin="00:00:02.120" end="00:00:03.800" region="bottom" xml:id="sub2">00:00:02.120<br/>00:00:03.800</p> + <p begin="00:00:22.720" end="00:00:25.840" region="bottom" xml:id="sub3">00:00:22.720<br/>00:00:25.840</p> + <p begin="00:00:26.080" end="00:00:29.120" region="bottom" xml:id="sub4">00:00:26.080<br/>00:00:29.120</p> + </div> + </body> +</tt> + diff --git a/regression_tests/ttml/ebu-ttd_timing_overlapping_fail.ttml b/regression_tests/ttml/ebu-ttd_timing_overlapping_fail.ttml new file mode 100644 index 0000000..5559525 --- /dev/null +++ b/regression_tests/ttml/ebu-ttd_timing_overlapping_fail.ttml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tt xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p begin="00:00:00.000" end="00:00:01.400" region="bottom" xml:id="sub1">00:00:00.000<br/>00:00:01.400</p> + <p begin="00:00:01.120" end="00:00:23.800" region="bottom" xml:id="sub2">00:00:01.120<br/>00:00:23.800</p> + <p begin="00:00:22.720" end="00:00:25.840" region="bottom" xml:id="sub3">00:00:22.720<br/>00:00:25.840</p> + </div> + </body> +</tt> + diff --git a/regression_tests/webvtt/counter.vtt b/regression_tests/webvtt/counter.vtt index b0a3b37..5463891 100644 --- a/regression_tests/webvtt/counter.vtt +++ b/regression_tests/webvtt/counter.vtt @@ -1,4502 +1,4502 @@ -WEBVTT - -00:00.000 --> 00:00.040 -0 - 00:00.000 - -00:00.040 --> 00:00.080 -1 - 00:00.040 - -00:00.080 --> 00:00.120 -2 - 00:00.080 - -00:00.120 --> 00:00.160 -3 - 00:00.120 - -00:00.160 --> 00:00.200 -4 - 00:00.160 - -00:00.200 --> 00:00.240 -5 - 00:00.200 - -00:00.240 --> 00:00.280 -6 - 00:00.240 - -00:00.280 --> 00:00.320 -7 - 00:00.280 - -00:00.320 --> 00:00.360 -8 - 00:00.320 - -00:00.360 --> 00:00.400 -9 - 00:00.360 - -00:00.400 --> 00:00.440 -10 - 00:00.400 - -00:00.440 --> 00:00.480 -11 - 00:00.440 - -00:00.480 --> 00:00.520 -12 - 00:00.480 - -00:00.520 --> 00:00.560 -13 - 00:00.520 - -00:00.560 --> 00:00.600 -14 - 00:00.560 - -00:00.600 --> 00:00.640 -15 - 00:00.600 - -00:00.640 --> 00:00.680 -16 - 00:00.640 - -00:00.680 --> 00:00.720 -17 - 00:00.680 - -00:00.720 --> 00:00.760 -18 - 00:00.720 - -00:00.760 --> 00:00.800 -19 - 00:00.760 - -00:00.800 --> 00:00.840 -20 - 00:00.800 - -00:00.840 --> 00:00.880 -21 - 00:00.840 - -00:00.880 --> 00:00.920 -22 - 00:00.880 - -00:00.920 --> 00:00.960 -23 - 00:00.920 - -00:00.960 --> 00:01.000 -24 - 00:00.960 - -00:01.000 --> 00:01.040 -25 - 00:01.000 - -00:01.040 --> 00:01.080 -26 - 00:01.040 - -00:01.080 --> 00:01.120 -27 - 00:01.080 - -00:01.120 --> 00:01.160 -28 - 00:01.120 - -00:01.160 --> 00:01.200 -29 - 00:01.160 - -00:01.200 --> 00:01.240 -30 - 00:01.200 - -00:01.240 --> 00:01.280 -31 - 00:01.240 - -00:01.280 --> 00:01.320 -32 - 00:01.280 - -00:01.320 --> 00:01.360 -33 - 00:01.320 - -00:01.360 --> 00:01.400 -34 - 00:01.360 - -00:01.400 --> 00:01.440 -35 - 00:01.400 - -00:01.440 --> 00:01.480 -36 - 00:01.440 - -00:01.480 --> 00:01.520 -37 - 00:01.480 - -00:01.520 --> 00:01.560 -38 - 00:01.520 - -00:01.560 --> 00:01.600 -39 - 00:01.560 - -00:01.600 --> 00:01.640 -40 - 00:01.600 - -00:01.640 --> 00:01.680 -41 - 00:01.640 - -00:01.680 --> 00:01.720 -42 - 00:01.680 - -00:01.720 --> 00:01.760 -43 - 00:01.720 - -00:01.760 --> 00:01.800 -44 - 00:01.760 - -00:01.800 --> 00:01.840 -45 - 00:01.800 - -00:01.840 --> 00:01.880 -46 - 00:01.840 - -00:01.880 --> 00:01.920 -47 - 00:01.880 - -00:01.920 --> 00:01.960 -48 - 00:01.920 - -00:01.960 --> 00:02.000 -49 - 00:01.960 - -00:02.000 --> 00:02.040 -50 - 00:02.000 - -00:02.040 --> 00:02.080 -51 - 00:02.040 - -00:02.080 --> 00:02.120 -52 - 00:02.080 - -00:02.120 --> 00:02.160 -53 - 00:02.120 - -00:02.160 --> 00:02.200 -54 - 00:02.160 - -00:02.200 --> 00:02.240 -55 - 00:02.200 - -00:02.240 --> 00:02.280 -56 - 00:02.240 - -00:02.280 --> 00:02.320 -57 - 00:02.280 - -00:02.320 --> 00:02.360 -58 - 00:02.320 - -00:02.360 --> 00:02.400 -59 - 00:02.360 - -00:02.400 --> 00:02.440 -60 - 00:02.400 - -00:02.440 --> 00:02.480 -61 - 00:02.440 - -00:02.480 --> 00:02.520 -62 - 00:02.480 - -00:02.520 --> 00:02.560 -63 - 00:02.520 - -00:02.560 --> 00:02.600 -64 - 00:02.560 - -00:02.600 --> 00:02.640 -65 - 00:02.600 - -00:02.640 --> 00:02.680 -66 - 00:02.640 - -00:02.680 --> 00:02.720 -67 - 00:02.680 - -00:02.720 --> 00:02.760 -68 - 00:02.720 - -00:02.760 --> 00:02.800 -69 - 00:02.760 - -00:02.800 --> 00:02.840 -70 - 00:02.800 - -00:02.840 --> 00:02.880 -71 - 00:02.840 - -00:02.880 --> 00:02.920 -72 - 00:02.880 - -00:02.920 --> 00:02.960 -73 - 00:02.920 - -00:02.960 --> 00:03.000 -74 - 00:02.960 - -00:03.000 --> 00:03.040 -75 - 00:03.000 - -00:03.040 --> 00:03.080 -76 - 00:03.040 - -00:03.080 --> 00:03.120 -77 - 00:03.080 - -00:03.120 --> 00:03.160 -78 - 00:03.120 - -00:03.160 --> 00:03.200 -79 - 00:03.160 - -00:03.200 --> 00:03.240 -80 - 00:03.200 - -00:03.240 --> 00:03.280 -81 - 00:03.240 - -00:03.280 --> 00:03.320 -82 - 00:03.280 - -00:03.320 --> 00:03.360 -83 - 00:03.320 - -00:03.360 --> 00:03.400 -84 - 00:03.360 - -00:03.400 --> 00:03.440 -85 - 00:03.400 - -00:03.440 --> 00:03.480 -86 - 00:03.440 - -00:03.480 --> 00:03.520 -87 - 00:03.480 - -00:03.520 --> 00:03.560 -88 - 00:03.520 - -00:03.560 --> 00:03.600 -89 - 00:03.560 - -00:03.600 --> 00:03.640 -90 - 00:03.600 - -00:03.640 --> 00:03.680 -91 - 00:03.640 - -00:03.680 --> 00:03.720 -92 - 00:03.680 - -00:03.720 --> 00:03.760 -93 - 00:03.720 - -00:03.760 --> 00:03.800 -94 - 00:03.760 - -00:03.800 --> 00:03.840 -95 - 00:03.800 - -00:03.840 --> 00:03.880 -96 - 00:03.840 - -00:03.880 --> 00:03.920 -97 - 00:03.880 - -00:03.920 --> 00:03.960 -98 - 00:03.920 - -00:03.960 --> 00:04.000 -99 - 00:03.960 - -00:04.000 --> 00:04.040 -100 - 00:04.000 - -00:04.040 --> 00:04.080 -101 - 00:04.040 - -00:04.080 --> 00:04.120 -102 - 00:04.080 - -00:04.120 --> 00:04.160 -103 - 00:04.120 - -00:04.160 --> 00:04.200 -104 - 00:04.160 - -00:04.200 --> 00:04.240 -105 - 00:04.200 - -00:04.240 --> 00:04.280 -106 - 00:04.240 - -00:04.280 --> 00:04.320 -107 - 00:04.280 - -00:04.320 --> 00:04.360 -108 - 00:04.320 - -00:04.360 --> 00:04.400 -109 - 00:04.360 - -00:04.400 --> 00:04.440 -110 - 00:04.400 - -00:04.440 --> 00:04.480 -111 - 00:04.440 - -00:04.480 --> 00:04.520 -112 - 00:04.480 - -00:04.520 --> 00:04.560 -113 - 00:04.520 - -00:04.560 --> 00:04.600 -114 - 00:04.560 - -00:04.600 --> 00:04.640 -115 - 00:04.600 - -00:04.640 --> 00:04.680 -116 - 00:04.640 - -00:04.680 --> 00:04.720 -117 - 00:04.680 - -00:04.720 --> 00:04.760 -118 - 00:04.720 - -00:04.760 --> 00:04.800 -119 - 00:04.760 - -00:04.800 --> 00:04.840 -120 - 00:04.800 - -00:04.840 --> 00:04.880 -121 - 00:04.840 - -00:04.880 --> 00:04.920 -122 - 00:04.880 - -00:04.920 --> 00:04.960 -123 - 00:04.920 - -00:04.960 --> 00:05.000 -124 - 00:04.960 - -00:05.000 --> 00:05.040 -125 - 00:05.000 - -00:05.040 --> 00:05.080 -126 - 00:05.040 - -00:05.080 --> 00:05.120 -127 - 00:05.080 - -00:05.120 --> 00:05.160 -128 - 00:05.120 - -00:05.160 --> 00:05.200 -129 - 00:05.160 - -00:05.200 --> 00:05.240 -130 - 00:05.200 - -00:05.240 --> 00:05.280 -131 - 00:05.240 - -00:05.280 --> 00:05.320 -132 - 00:05.280 - -00:05.320 --> 00:05.360 -133 - 00:05.320 - -00:05.360 --> 00:05.400 -134 - 00:05.360 - -00:05.400 --> 00:05.440 -135 - 00:05.400 - -00:05.440 --> 00:05.480 -136 - 00:05.440 - -00:05.480 --> 00:05.520 -137 - 00:05.480 - -00:05.520 --> 00:05.560 -138 - 00:05.520 - -00:05.560 --> 00:05.600 -139 - 00:05.560 - -00:05.600 --> 00:05.640 -140 - 00:05.600 - -00:05.640 --> 00:05.680 -141 - 00:05.640 - -00:05.680 --> 00:05.720 -142 - 00:05.680 - -00:05.720 --> 00:05.760 -143 - 00:05.720 - -00:05.760 --> 00:05.800 -144 - 00:05.760 - -00:05.800 --> 00:05.840 -145 - 00:05.800 - -00:05.840 --> 00:05.880 -146 - 00:05.840 - -00:05.880 --> 00:05.920 -147 - 00:05.880 - -00:05.920 --> 00:05.960 -148 - 00:05.920 - -00:05.960 --> 00:06.000 -149 - 00:05.960 - -00:06.000 --> 00:06.040 -150 - 00:06.000 - -00:06.040 --> 00:06.080 -151 - 00:06.040 - -00:06.080 --> 00:06.120 -152 - 00:06.080 - -00:06.120 --> 00:06.160 -153 - 00:06.120 - -00:06.160 --> 00:06.200 -154 - 00:06.160 - -00:06.200 --> 00:06.240 -155 - 00:06.200 - -00:06.240 --> 00:06.280 -156 - 00:06.240 - -00:06.280 --> 00:06.320 -157 - 00:06.280 - -00:06.320 --> 00:06.360 -158 - 00:06.320 - -00:06.360 --> 00:06.400 -159 - 00:06.360 - -00:06.400 --> 00:06.440 -160 - 00:06.400 - -00:06.440 --> 00:06.480 -161 - 00:06.440 - -00:06.480 --> 00:06.520 -162 - 00:06.480 - -00:06.520 --> 00:06.560 -163 - 00:06.520 - -00:06.560 --> 00:06.600 -164 - 00:06.560 - -00:06.600 --> 00:06.640 -165 - 00:06.600 - -00:06.640 --> 00:06.680 -166 - 00:06.640 - -00:06.680 --> 00:06.720 -167 - 00:06.680 - -00:06.720 --> 00:06.760 -168 - 00:06.720 - -00:06.760 --> 00:06.800 -169 - 00:06.760 - -00:06.800 --> 00:06.840 -170 - 00:06.800 - -00:06.840 --> 00:06.880 -171 - 00:06.840 - -00:06.880 --> 00:06.920 -172 - 00:06.880 - -00:06.920 --> 00:06.960 -173 - 00:06.920 - -00:06.960 --> 00:07.000 -174 - 00:06.960 - -00:07.000 --> 00:07.040 -175 - 00:07.000 - -00:07.040 --> 00:07.080 -176 - 00:07.040 - -00:07.080 --> 00:07.120 -177 - 00:07.080 - -00:07.120 --> 00:07.160 -178 - 00:07.120 - -00:07.160 --> 00:07.200 -179 - 00:07.160 - -00:07.200 --> 00:07.240 -180 - 00:07.200 - -00:07.240 --> 00:07.280 -181 - 00:07.240 - -00:07.280 --> 00:07.320 -182 - 00:07.280 - -00:07.320 --> 00:07.360 -183 - 00:07.320 - -00:07.360 --> 00:07.400 -184 - 00:07.360 - -00:07.400 --> 00:07.440 -185 - 00:07.400 - -00:07.440 --> 00:07.480 -186 - 00:07.440 - -00:07.480 --> 00:07.520 -187 - 00:07.480 - -00:07.520 --> 00:07.560 -188 - 00:07.520 - -00:07.560 --> 00:07.600 -189 - 00:07.560 - -00:07.600 --> 00:07.640 -190 - 00:07.600 - -00:07.640 --> 00:07.680 -191 - 00:07.640 - -00:07.680 --> 00:07.720 -192 - 00:07.680 - -00:07.720 --> 00:07.760 -193 - 00:07.720 - -00:07.760 --> 00:07.800 -194 - 00:07.760 - -00:07.800 --> 00:07.840 -195 - 00:07.800 - -00:07.840 --> 00:07.880 -196 - 00:07.840 - -00:07.880 --> 00:07.920 -197 - 00:07.880 - -00:07.920 --> 00:07.960 -198 - 00:07.920 - -00:07.960 --> 00:08.000 -199 - 00:07.960 - -00:08.000 --> 00:08.040 -200 - 00:08.000 - -00:08.040 --> 00:08.080 -201 - 00:08.040 - -00:08.080 --> 00:08.120 -202 - 00:08.080 - -00:08.120 --> 00:08.160 -203 - 00:08.120 - -00:08.160 --> 00:08.200 -204 - 00:08.160 - -00:08.200 --> 00:08.240 -205 - 00:08.200 - -00:08.240 --> 00:08.280 -206 - 00:08.240 - -00:08.280 --> 00:08.320 -207 - 00:08.280 - -00:08.320 --> 00:08.360 -208 - 00:08.320 - -00:08.360 --> 00:08.400 -209 - 00:08.360 - -00:08.400 --> 00:08.440 -210 - 00:08.400 - -00:08.440 --> 00:08.480 -211 - 00:08.440 - -00:08.480 --> 00:08.520 -212 - 00:08.480 - -00:08.520 --> 00:08.560 -213 - 00:08.520 - -00:08.560 --> 00:08.600 -214 - 00:08.560 - -00:08.600 --> 00:08.640 -215 - 00:08.600 - -00:08.640 --> 00:08.680 -216 - 00:08.640 - -00:08.680 --> 00:08.720 -217 - 00:08.680 - -00:08.720 --> 00:08.760 -218 - 00:08.720 - -00:08.760 --> 00:08.800 -219 - 00:08.760 - -00:08.800 --> 00:08.840 -220 - 00:08.800 - -00:08.840 --> 00:08.880 -221 - 00:08.840 - -00:08.880 --> 00:08.920 -222 - 00:08.880 - -00:08.920 --> 00:08.960 -223 - 00:08.920 - -00:08.960 --> 00:09.000 -224 - 00:08.960 - -00:09.000 --> 00:09.040 -225 - 00:09.000 - -00:09.040 --> 00:09.080 -226 - 00:09.040 - -00:09.080 --> 00:09.120 -227 - 00:09.080 - -00:09.120 --> 00:09.160 -228 - 00:09.120 - -00:09.160 --> 00:09.200 -229 - 00:09.160 - -00:09.200 --> 00:09.240 -230 - 00:09.200 - -00:09.240 --> 00:09.280 -231 - 00:09.240 - -00:09.280 --> 00:09.320 -232 - 00:09.280 - -00:09.320 --> 00:09.360 -233 - 00:09.320 - -00:09.360 --> 00:09.400 -234 - 00:09.360 - -00:09.400 --> 00:09.440 -235 - 00:09.400 - -00:09.440 --> 00:09.480 -236 - 00:09.440 - -00:09.480 --> 00:09.520 -237 - 00:09.480 - -00:09.520 --> 00:09.560 -238 - 00:09.520 - -00:09.560 --> 00:09.600 -239 - 00:09.560 - -00:09.600 --> 00:09.640 -240 - 00:09.600 - -00:09.640 --> 00:09.680 -241 - 00:09.640 - -00:09.680 --> 00:09.720 -242 - 00:09.680 - -00:09.720 --> 00:09.760 -243 - 00:09.720 - -00:09.760 --> 00:09.800 -244 - 00:09.760 - -00:09.800 --> 00:09.840 -245 - 00:09.800 - -00:09.840 --> 00:09.880 -246 - 00:09.840 - -00:09.880 --> 00:09.920 -247 - 00:09.880 - -00:09.920 --> 00:09.960 -248 - 00:09.920 - -00:09.960 --> 00:10.000 -249 - 00:09.960 - -00:10.000 --> 00:10.040 -250 - 00:10.000 - -00:10.040 --> 00:10.080 -251 - 00:10.040 - -00:10.080 --> 00:10.120 -252 - 00:10.080 - -00:10.120 --> 00:10.160 -253 - 00:10.120 - -00:10.160 --> 00:10.200 -254 - 00:10.160 - -00:10.200 --> 00:10.240 -255 - 00:10.200 - -00:10.240 --> 00:10.280 -256 - 00:10.240 - -00:10.280 --> 00:10.320 -257 - 00:10.280 - -00:10.320 --> 00:10.360 -258 - 00:10.320 - -00:10.360 --> 00:10.400 -259 - 00:10.360 - -00:10.400 --> 00:10.440 -260 - 00:10.400 - -00:10.440 --> 00:10.480 -261 - 00:10.440 - -00:10.480 --> 00:10.520 -262 - 00:10.480 - -00:10.520 --> 00:10.560 -263 - 00:10.520 - -00:10.560 --> 00:10.600 -264 - 00:10.560 - -00:10.600 --> 00:10.640 -265 - 00:10.600 - -00:10.640 --> 00:10.680 -266 - 00:10.640 - -00:10.680 --> 00:10.720 -267 - 00:10.680 - -00:10.720 --> 00:10.760 -268 - 00:10.720 - -00:10.760 --> 00:10.800 -269 - 00:10.760 - -00:10.800 --> 00:10.840 -270 - 00:10.800 - -00:10.840 --> 00:10.880 -271 - 00:10.840 - -00:10.880 --> 00:10.920 -272 - 00:10.880 - -00:10.920 --> 00:10.960 -273 - 00:10.920 - -00:10.960 --> 00:11.000 -274 - 00:10.960 - -00:11.000 --> 00:11.040 -275 - 00:11.000 - -00:11.040 --> 00:11.080 -276 - 00:11.040 - -00:11.080 --> 00:11.120 -277 - 00:11.080 - -00:11.120 --> 00:11.160 -278 - 00:11.120 - -00:11.160 --> 00:11.200 -279 - 00:11.160 - -00:11.200 --> 00:11.240 -280 - 00:11.200 - -00:11.240 --> 00:11.280 -281 - 00:11.240 - -00:11.280 --> 00:11.320 -282 - 00:11.280 - -00:11.320 --> 00:11.360 -283 - 00:11.320 - -00:11.360 --> 00:11.400 -284 - 00:11.360 - -00:11.400 --> 00:11.440 -285 - 00:11.400 - -00:11.440 --> 00:11.480 -286 - 00:11.440 - -00:11.480 --> 00:11.520 -287 - 00:11.480 - -00:11.520 --> 00:11.560 -288 - 00:11.520 - -00:11.560 --> 00:11.600 -289 - 00:11.560 - -00:11.600 --> 00:11.640 -290 - 00:11.600 - -00:11.640 --> 00:11.680 -291 - 00:11.640 - -00:11.680 --> 00:11.720 -292 - 00:11.680 - -00:11.720 --> 00:11.760 -293 - 00:11.720 - -00:11.760 --> 00:11.800 -294 - 00:11.760 - -00:11.800 --> 00:11.840 -295 - 00:11.800 - -00:11.840 --> 00:11.880 -296 - 00:11.840 - -00:11.880 --> 00:11.920 -297 - 00:11.880 - -00:11.920 --> 00:11.960 -298 - 00:11.920 - -00:11.960 --> 00:12.000 -299 - 00:11.960 - -00:12.000 --> 00:12.040 -300 - 00:12.000 - -00:12.040 --> 00:12.080 -301 - 00:12.040 - -00:12.080 --> 00:12.120 -302 - 00:12.080 - -00:12.120 --> 00:12.160 -303 - 00:12.120 - -00:12.160 --> 00:12.200 -304 - 00:12.160 - -00:12.200 --> 00:12.240 -305 - 00:12.200 - -00:12.240 --> 00:12.280 -306 - 00:12.240 - -00:12.280 --> 00:12.320 -307 - 00:12.280 - -00:12.320 --> 00:12.360 -308 - 00:12.320 - -00:12.360 --> 00:12.400 -309 - 00:12.360 - -00:12.400 --> 00:12.440 -310 - 00:12.400 - -00:12.440 --> 00:12.480 -311 - 00:12.440 - -00:12.480 --> 00:12.520 -312 - 00:12.480 - -00:12.520 --> 00:12.560 -313 - 00:12.520 - -00:12.560 --> 00:12.600 -314 - 00:12.560 - -00:12.600 --> 00:12.640 -315 - 00:12.600 - -00:12.640 --> 00:12.680 -316 - 00:12.640 - -00:12.680 --> 00:12.720 -317 - 00:12.680 - -00:12.720 --> 00:12.760 -318 - 00:12.720 - -00:12.760 --> 00:12.800 -319 - 00:12.760 - -00:12.800 --> 00:12.840 -320 - 00:12.800 - -00:12.840 --> 00:12.880 -321 - 00:12.840 - -00:12.880 --> 00:12.920 -322 - 00:12.880 - -00:12.920 --> 00:12.960 -323 - 00:12.920 - -00:12.960 --> 00:13.000 -324 - 00:12.960 - -00:13.000 --> 00:13.040 -325 - 00:13.000 - -00:13.040 --> 00:13.080 -326 - 00:13.040 - -00:13.080 --> 00:13.120 -327 - 00:13.080 - -00:13.120 --> 00:13.160 -328 - 00:13.120 - -00:13.160 --> 00:13.200 -329 - 00:13.160 - -00:13.200 --> 00:13.240 -330 - 00:13.200 - -00:13.240 --> 00:13.280 -331 - 00:13.240 - -00:13.280 --> 00:13.320 -332 - 00:13.280 - -00:13.320 --> 00:13.360 -333 - 00:13.320 - -00:13.360 --> 00:13.400 -334 - 00:13.360 - -00:13.400 --> 00:13.440 -335 - 00:13.400 - -00:13.440 --> 00:13.480 -336 - 00:13.440 - -00:13.480 --> 00:13.520 -337 - 00:13.480 - -00:13.520 --> 00:13.560 -338 - 00:13.520 - -00:13.560 --> 00:13.600 -339 - 00:13.560 - -00:13.600 --> 00:13.640 -340 - 00:13.600 - -00:13.640 --> 00:13.680 -341 - 00:13.640 - -00:13.680 --> 00:13.720 -342 - 00:13.680 - -00:13.720 --> 00:13.760 -343 - 00:13.720 - -00:13.760 --> 00:13.800 -344 - 00:13.760 - -00:13.800 --> 00:13.840 -345 - 00:13.800 - -00:13.840 --> 00:13.880 -346 - 00:13.840 - -00:13.880 --> 00:13.920 -347 - 00:13.880 - -00:13.920 --> 00:13.960 -348 - 00:13.920 - -00:13.960 --> 00:14.000 -349 - 00:13.960 - -00:14.000 --> 00:14.040 -350 - 00:14.000 - -00:14.040 --> 00:14.080 -351 - 00:14.040 - -00:14.080 --> 00:14.120 -352 - 00:14.080 - -00:14.120 --> 00:14.160 -353 - 00:14.120 - -00:14.160 --> 00:14.200 -354 - 00:14.160 - -00:14.200 --> 00:14.240 -355 - 00:14.200 - -00:14.240 --> 00:14.280 -356 - 00:14.240 - -00:14.280 --> 00:14.320 -357 - 00:14.280 - -00:14.320 --> 00:14.360 -358 - 00:14.320 - -00:14.360 --> 00:14.400 -359 - 00:14.360 - -00:14.400 --> 00:14.440 -360 - 00:14.400 - -00:14.440 --> 00:14.480 -361 - 00:14.440 - -00:14.480 --> 00:14.520 -362 - 00:14.480 - -00:14.520 --> 00:14.560 -363 - 00:14.520 - -00:14.560 --> 00:14.600 -364 - 00:14.560 - -00:14.600 --> 00:14.640 -365 - 00:14.600 - -00:14.640 --> 00:14.680 -366 - 00:14.640 - -00:14.680 --> 00:14.720 -367 - 00:14.680 - -00:14.720 --> 00:14.760 -368 - 00:14.720 - -00:14.760 --> 00:14.800 -369 - 00:14.760 - -00:14.800 --> 00:14.840 -370 - 00:14.800 - -00:14.840 --> 00:14.880 -371 - 00:14.840 - -00:14.880 --> 00:14.920 -372 - 00:14.880 - -00:14.920 --> 00:14.960 -373 - 00:14.920 - -00:14.960 --> 00:15.000 -374 - 00:14.960 - -00:15.000 --> 00:15.040 -375 - 00:15.000 - -00:15.040 --> 00:15.080 -376 - 00:15.040 - -00:15.080 --> 00:15.120 -377 - 00:15.080 - -00:15.120 --> 00:15.160 -378 - 00:15.120 - -00:15.160 --> 00:15.200 -379 - 00:15.160 - -00:15.200 --> 00:15.240 -380 - 00:15.200 - -00:15.240 --> 00:15.280 -381 - 00:15.240 - -00:15.280 --> 00:15.320 -382 - 00:15.280 - -00:15.320 --> 00:15.360 -383 - 00:15.320 - -00:15.360 --> 00:15.400 -384 - 00:15.360 - -00:15.400 --> 00:15.440 -385 - 00:15.400 - -00:15.440 --> 00:15.480 -386 - 00:15.440 - -00:15.480 --> 00:15.520 -387 - 00:15.480 - -00:15.520 --> 00:15.560 -388 - 00:15.520 - -00:15.560 --> 00:15.600 -389 - 00:15.560 - -00:15.600 --> 00:15.640 -390 - 00:15.600 - -00:15.640 --> 00:15.680 -391 - 00:15.640 - -00:15.680 --> 00:15.720 -392 - 00:15.680 - -00:15.720 --> 00:15.760 -393 - 00:15.720 - -00:15.760 --> 00:15.800 -394 - 00:15.760 - -00:15.800 --> 00:15.840 -395 - 00:15.800 - -00:15.840 --> 00:15.880 -396 - 00:15.840 - -00:15.880 --> 00:15.920 -397 - 00:15.880 - -00:15.920 --> 00:15.960 -398 - 00:15.920 - -00:15.960 --> 00:16.000 -399 - 00:15.960 - -00:16.000 --> 00:16.040 -400 - 00:16.000 - -00:16.040 --> 00:16.080 -401 - 00:16.040 - -00:16.080 --> 00:16.120 -402 - 00:16.080 - -00:16.120 --> 00:16.160 -403 - 00:16.120 - -00:16.160 --> 00:16.200 -404 - 00:16.160 - -00:16.200 --> 00:16.240 -405 - 00:16.200 - -00:16.240 --> 00:16.280 -406 - 00:16.240 - -00:16.280 --> 00:16.320 -407 - 00:16.280 - -00:16.320 --> 00:16.360 -408 - 00:16.320 - -00:16.360 --> 00:16.400 -409 - 00:16.360 - -00:16.400 --> 00:16.440 -410 - 00:16.400 - -00:16.440 --> 00:16.480 -411 - 00:16.440 - -00:16.480 --> 00:16.520 -412 - 00:16.480 - -00:16.520 --> 00:16.560 -413 - 00:16.520 - -00:16.560 --> 00:16.600 -414 - 00:16.560 - -00:16.600 --> 00:16.640 -415 - 00:16.600 - -00:16.640 --> 00:16.680 -416 - 00:16.640 - -00:16.680 --> 00:16.720 -417 - 00:16.680 - -00:16.720 --> 00:16.760 -418 - 00:16.720 - -00:16.760 --> 00:16.800 -419 - 00:16.760 - -00:16.800 --> 00:16.840 -420 - 00:16.800 - -00:16.840 --> 00:16.880 -421 - 00:16.840 - -00:16.880 --> 00:16.920 -422 - 00:16.880 - -00:16.920 --> 00:16.960 -423 - 00:16.920 - -00:16.960 --> 00:17.000 -424 - 00:16.960 - -00:17.000 --> 00:17.040 -425 - 00:17.000 - -00:17.040 --> 00:17.080 -426 - 00:17.040 - -00:17.080 --> 00:17.120 -427 - 00:17.080 - -00:17.120 --> 00:17.160 -428 - 00:17.120 - -00:17.160 --> 00:17.200 -429 - 00:17.160 - -00:17.200 --> 00:17.240 -430 - 00:17.200 - -00:17.240 --> 00:17.280 -431 - 00:17.240 - -00:17.280 --> 00:17.320 -432 - 00:17.280 - -00:17.320 --> 00:17.360 -433 - 00:17.320 - -00:17.360 --> 00:17.400 -434 - 00:17.360 - -00:17.400 --> 00:17.440 -435 - 00:17.400 - -00:17.440 --> 00:17.480 -436 - 00:17.440 - -00:17.480 --> 00:17.520 -437 - 00:17.480 - -00:17.520 --> 00:17.560 -438 - 00:17.520 - -00:17.560 --> 00:17.600 -439 - 00:17.560 - -00:17.600 --> 00:17.640 -440 - 00:17.600 - -00:17.640 --> 00:17.680 -441 - 00:17.640 - -00:17.680 --> 00:17.720 -442 - 00:17.680 - -00:17.720 --> 00:17.760 -443 - 00:17.720 - -00:17.760 --> 00:17.800 -444 - 00:17.760 - -00:17.800 --> 00:17.840 -445 - 00:17.800 - -00:17.840 --> 00:17.880 -446 - 00:17.840 - -00:17.880 --> 00:17.920 -447 - 00:17.880 - -00:17.920 --> 00:17.960 -448 - 00:17.920 - -00:17.960 --> 00:18.000 -449 - 00:17.960 - -00:18.000 --> 00:18.040 -450 - 00:18.000 - -00:18.040 --> 00:18.080 -451 - 00:18.040 - -00:18.080 --> 00:18.120 -452 - 00:18.080 - -00:18.120 --> 00:18.160 -453 - 00:18.120 - -00:18.160 --> 00:18.200 -454 - 00:18.160 - -00:18.200 --> 00:18.240 -455 - 00:18.200 - -00:18.240 --> 00:18.280 -456 - 00:18.240 - -00:18.280 --> 00:18.320 -457 - 00:18.280 - -00:18.320 --> 00:18.360 -458 - 00:18.320 - -00:18.360 --> 00:18.400 -459 - 00:18.360 - -00:18.400 --> 00:18.440 -460 - 00:18.400 - -00:18.440 --> 00:18.480 -461 - 00:18.440 - -00:18.480 --> 00:18.520 -462 - 00:18.480 - -00:18.520 --> 00:18.560 -463 - 00:18.520 - -00:18.560 --> 00:18.600 -464 - 00:18.560 - -00:18.600 --> 00:18.640 -465 - 00:18.600 - -00:18.640 --> 00:18.680 -466 - 00:18.640 - -00:18.680 --> 00:18.720 -467 - 00:18.680 - -00:18.720 --> 00:18.760 -468 - 00:18.720 - -00:18.760 --> 00:18.800 -469 - 00:18.760 - -00:18.800 --> 00:18.840 -470 - 00:18.800 - -00:18.840 --> 00:18.880 -471 - 00:18.840 - -00:18.880 --> 00:18.920 -472 - 00:18.880 - -00:18.920 --> 00:18.960 -473 - 00:18.920 - -00:18.960 --> 00:19.000 -474 - 00:18.960 - -00:19.000 --> 00:19.040 -475 - 00:19.000 - -00:19.040 --> 00:19.080 -476 - 00:19.040 - -00:19.080 --> 00:19.120 -477 - 00:19.080 - -00:19.120 --> 00:19.160 -478 - 00:19.120 - -00:19.160 --> 00:19.200 -479 - 00:19.160 - -00:19.200 --> 00:19.240 -480 - 00:19.200 - -00:19.240 --> 00:19.280 -481 - 00:19.240 - -00:19.280 --> 00:19.320 -482 - 00:19.280 - -00:19.320 --> 00:19.360 -483 - 00:19.320 - -00:19.360 --> 00:19.400 -484 - 00:19.360 - -00:19.400 --> 00:19.440 -485 - 00:19.400 - -00:19.440 --> 00:19.480 -486 - 00:19.440 - -00:19.480 --> 00:19.520 -487 - 00:19.480 - -00:19.520 --> 00:19.560 -488 - 00:19.520 - -00:19.560 --> 00:19.600 -489 - 00:19.560 - -00:19.600 --> 00:19.640 -490 - 00:19.600 - -00:19.640 --> 00:19.680 -491 - 00:19.640 - -00:19.680 --> 00:19.720 -492 - 00:19.680 - -00:19.720 --> 00:19.760 -493 - 00:19.720 - -00:19.760 --> 00:19.800 -494 - 00:19.760 - -00:19.800 --> 00:19.840 -495 - 00:19.800 - -00:19.840 --> 00:19.880 -496 - 00:19.840 - -00:19.880 --> 00:19.920 -497 - 00:19.880 - -00:19.920 --> 00:19.960 -498 - 00:19.920 - -00:19.960 --> 00:20.000 -499 - 00:19.960 - -00:20.000 --> 00:20.040 -500 - 00:20.000 - -00:20.040 --> 00:20.080 -501 - 00:20.040 - -00:20.080 --> 00:20.120 -502 - 00:20.080 - -00:20.120 --> 00:20.160 -503 - 00:20.120 - -00:20.160 --> 00:20.200 -504 - 00:20.160 - -00:20.200 --> 00:20.240 -505 - 00:20.200 - -00:20.240 --> 00:20.280 -506 - 00:20.240 - -00:20.280 --> 00:20.320 -507 - 00:20.280 - -00:20.320 --> 00:20.360 -508 - 00:20.320 - -00:20.360 --> 00:20.400 -509 - 00:20.360 - -00:20.400 --> 00:20.440 -510 - 00:20.400 - -00:20.440 --> 00:20.480 -511 - 00:20.440 - -00:20.480 --> 00:20.520 -512 - 00:20.480 - -00:20.520 --> 00:20.560 -513 - 00:20.520 - -00:20.560 --> 00:20.600 -514 - 00:20.560 - -00:20.600 --> 00:20.640 -515 - 00:20.600 - -00:20.640 --> 00:20.680 -516 - 00:20.640 - -00:20.680 --> 00:20.720 -517 - 00:20.680 - -00:20.720 --> 00:20.760 -518 - 00:20.720 - -00:20.760 --> 00:20.800 -519 - 00:20.760 - -00:20.800 --> 00:20.840 -520 - 00:20.800 - -00:20.840 --> 00:20.880 -521 - 00:20.840 - -00:20.880 --> 00:20.920 -522 - 00:20.880 - -00:20.920 --> 00:20.960 -523 - 00:20.920 - -00:20.960 --> 00:21.000 -524 - 00:20.960 - -00:21.000 --> 00:21.040 -525 - 00:21.000 - -00:21.040 --> 00:21.080 -526 - 00:21.040 - -00:21.080 --> 00:21.120 -527 - 00:21.080 - -00:21.120 --> 00:21.160 -528 - 00:21.120 - -00:21.160 --> 00:21.200 -529 - 00:21.160 - -00:21.200 --> 00:21.240 -530 - 00:21.200 - -00:21.240 --> 00:21.280 -531 - 00:21.240 - -00:21.280 --> 00:21.320 -532 - 00:21.280 - -00:21.320 --> 00:21.360 -533 - 00:21.320 - -00:21.360 --> 00:21.400 -534 - 00:21.360 - -00:21.400 --> 00:21.440 -535 - 00:21.400 - -00:21.440 --> 00:21.480 -536 - 00:21.440 - -00:21.480 --> 00:21.520 -537 - 00:21.480 - -00:21.520 --> 00:21.560 -538 - 00:21.520 - -00:21.560 --> 00:21.600 -539 - 00:21.560 - -00:21.600 --> 00:21.640 -540 - 00:21.600 - -00:21.640 --> 00:21.680 -541 - 00:21.640 - -00:21.680 --> 00:21.720 -542 - 00:21.680 - -00:21.720 --> 00:21.760 -543 - 00:21.720 - -00:21.760 --> 00:21.800 -544 - 00:21.760 - -00:21.800 --> 00:21.840 -545 - 00:21.800 - -00:21.840 --> 00:21.880 -546 - 00:21.840 - -00:21.880 --> 00:21.920 -547 - 00:21.880 - -00:21.920 --> 00:21.960 -548 - 00:21.920 - -00:21.960 --> 00:22.000 -549 - 00:21.960 - -00:22.000 --> 00:22.040 -550 - 00:22.000 - -00:22.040 --> 00:22.080 -551 - 00:22.040 - -00:22.080 --> 00:22.120 -552 - 00:22.080 - -00:22.120 --> 00:22.160 -553 - 00:22.120 - -00:22.160 --> 00:22.200 -554 - 00:22.160 - -00:22.200 --> 00:22.240 -555 - 00:22.200 - -00:22.240 --> 00:22.280 -556 - 00:22.240 - -00:22.280 --> 00:22.320 -557 - 00:22.280 - -00:22.320 --> 00:22.360 -558 - 00:22.320 - -00:22.360 --> 00:22.400 -559 - 00:22.360 - -00:22.400 --> 00:22.440 -560 - 00:22.400 - -00:22.440 --> 00:22.480 -561 - 00:22.440 - -00:22.480 --> 00:22.520 -562 - 00:22.480 - -00:22.520 --> 00:22.560 -563 - 00:22.520 - -00:22.560 --> 00:22.600 -564 - 00:22.560 - -00:22.600 --> 00:22.640 -565 - 00:22.600 - -00:22.640 --> 00:22.680 -566 - 00:22.640 - -00:22.680 --> 00:22.720 -567 - 00:22.680 - -00:22.720 --> 00:22.760 -568 - 00:22.720 - -00:22.760 --> 00:22.800 -569 - 00:22.760 - -00:22.800 --> 00:22.840 -570 - 00:22.800 - -00:22.840 --> 00:22.880 -571 - 00:22.840 - -00:22.880 --> 00:22.920 -572 - 00:22.880 - -00:22.920 --> 00:22.960 -573 - 00:22.920 - -00:22.960 --> 00:23.000 -574 - 00:22.960 - -00:23.000 --> 00:23.040 -575 - 00:23.000 - -00:23.040 --> 00:23.080 -576 - 00:23.040 - -00:23.080 --> 00:23.120 -577 - 00:23.080 - -00:23.120 --> 00:23.160 -578 - 00:23.120 - -00:23.160 --> 00:23.200 -579 - 00:23.160 - -00:23.200 --> 00:23.240 -580 - 00:23.200 - -00:23.240 --> 00:23.280 -581 - 00:23.240 - -00:23.280 --> 00:23.320 -582 - 00:23.280 - -00:23.320 --> 00:23.360 -583 - 00:23.320 - -00:23.360 --> 00:23.400 -584 - 00:23.360 - -00:23.400 --> 00:23.440 -585 - 00:23.400 - -00:23.440 --> 00:23.480 -586 - 00:23.440 - -00:23.480 --> 00:23.520 -587 - 00:23.480 - -00:23.520 --> 00:23.560 -588 - 00:23.520 - -00:23.560 --> 00:23.600 -589 - 00:23.560 - -00:23.600 --> 00:23.640 -590 - 00:23.600 - -00:23.640 --> 00:23.680 -591 - 00:23.640 - -00:23.680 --> 00:23.720 -592 - 00:23.680 - -00:23.720 --> 00:23.760 -593 - 00:23.720 - -00:23.760 --> 00:23.800 -594 - 00:23.760 - -00:23.800 --> 00:23.840 -595 - 00:23.800 - -00:23.840 --> 00:23.880 -596 - 00:23.840 - -00:23.880 --> 00:23.920 -597 - 00:23.880 - -00:23.920 --> 00:23.960 -598 - 00:23.920 - -00:23.960 --> 00:24.000 -599 - 00:23.960 - -00:24.000 --> 00:24.040 -600 - 00:24.000 - -00:24.040 --> 00:24.080 -601 - 00:24.040 - -00:24.080 --> 00:24.120 -602 - 00:24.080 - -00:24.120 --> 00:24.160 -603 - 00:24.120 - -00:24.160 --> 00:24.200 -604 - 00:24.160 - -00:24.200 --> 00:24.240 -605 - 00:24.200 - -00:24.240 --> 00:24.280 -606 - 00:24.240 - -00:24.280 --> 00:24.320 -607 - 00:24.280 - -00:24.320 --> 00:24.360 -608 - 00:24.320 - -00:24.360 --> 00:24.400 -609 - 00:24.360 - -00:24.400 --> 00:24.440 -610 - 00:24.400 - -00:24.440 --> 00:24.480 -611 - 00:24.440 - -00:24.480 --> 00:24.520 -612 - 00:24.480 - -00:24.520 --> 00:24.560 -613 - 00:24.520 - -00:24.560 --> 00:24.600 -614 - 00:24.560 - -00:24.600 --> 00:24.640 -615 - 00:24.600 - -00:24.640 --> 00:24.680 -616 - 00:24.640 - -00:24.680 --> 00:24.720 -617 - 00:24.680 - -00:24.720 --> 00:24.760 -618 - 00:24.720 - -00:24.760 --> 00:24.800 -619 - 00:24.760 - -00:24.800 --> 00:24.840 -620 - 00:24.800 - -00:24.840 --> 00:24.880 -621 - 00:24.840 - -00:24.880 --> 00:24.920 -622 - 00:24.880 - -00:24.920 --> 00:24.960 -623 - 00:24.920 - -00:24.960 --> 00:25.000 -624 - 00:24.960 - -00:25.000 --> 00:25.040 -625 - 00:25.000 - -00:25.040 --> 00:25.080 -626 - 00:25.040 - -00:25.080 --> 00:25.120 -627 - 00:25.080 - -00:25.120 --> 00:25.160 -628 - 00:25.120 - -00:25.160 --> 00:25.200 -629 - 00:25.160 - -00:25.200 --> 00:25.240 -630 - 00:25.200 - -00:25.240 --> 00:25.280 -631 - 00:25.240 - -00:25.280 --> 00:25.320 -632 - 00:25.280 - -00:25.320 --> 00:25.360 -633 - 00:25.320 - -00:25.360 --> 00:25.400 -634 - 00:25.360 - -00:25.400 --> 00:25.440 -635 - 00:25.400 - -00:25.440 --> 00:25.480 -636 - 00:25.440 - -00:25.480 --> 00:25.520 -637 - 00:25.480 - -00:25.520 --> 00:25.560 -638 - 00:25.520 - -00:25.560 --> 00:25.600 -639 - 00:25.560 - -00:25.600 --> 00:25.640 -640 - 00:25.600 - -00:25.640 --> 00:25.680 -641 - 00:25.640 - -00:25.680 --> 00:25.720 -642 - 00:25.680 - -00:25.720 --> 00:25.760 -643 - 00:25.720 - -00:25.760 --> 00:25.800 -644 - 00:25.760 - -00:25.800 --> 00:25.840 -645 - 00:25.800 - -00:25.840 --> 00:25.880 -646 - 00:25.840 - -00:25.880 --> 00:25.920 -647 - 00:25.880 - -00:25.920 --> 00:25.960 -648 - 00:25.920 - -00:25.960 --> 00:26.000 -649 - 00:25.960 - -00:26.000 --> 00:26.040 -650 - 00:26.000 - -00:26.040 --> 00:26.080 -651 - 00:26.040 - -00:26.080 --> 00:26.120 -652 - 00:26.080 - -00:26.120 --> 00:26.160 -653 - 00:26.120 - -00:26.160 --> 00:26.200 -654 - 00:26.160 - -00:26.200 --> 00:26.240 -655 - 00:26.200 - -00:26.240 --> 00:26.280 -656 - 00:26.240 - -00:26.280 --> 00:26.320 -657 - 00:26.280 - -00:26.320 --> 00:26.360 -658 - 00:26.320 - -00:26.360 --> 00:26.400 -659 - 00:26.360 - -00:26.400 --> 00:26.440 -660 - 00:26.400 - -00:26.440 --> 00:26.480 -661 - 00:26.440 - -00:26.480 --> 00:26.520 -662 - 00:26.480 - -00:26.520 --> 00:26.560 -663 - 00:26.520 - -00:26.560 --> 00:26.600 -664 - 00:26.560 - -00:26.600 --> 00:26.640 -665 - 00:26.600 - -00:26.640 --> 00:26.680 -666 - 00:26.640 - -00:26.680 --> 00:26.720 -667 - 00:26.680 - -00:26.720 --> 00:26.760 -668 - 00:26.720 - -00:26.760 --> 00:26.800 -669 - 00:26.760 - -00:26.800 --> 00:26.840 -670 - 00:26.800 - -00:26.840 --> 00:26.880 -671 - 00:26.840 - -00:26.880 --> 00:26.920 -672 - 00:26.880 - -00:26.920 --> 00:26.960 -673 - 00:26.920 - -00:26.960 --> 00:27.000 -674 - 00:26.960 - -00:27.000 --> 00:27.040 -675 - 00:27.000 - -00:27.040 --> 00:27.080 -676 - 00:27.040 - -00:27.080 --> 00:27.120 -677 - 00:27.080 - -00:27.120 --> 00:27.160 -678 - 00:27.120 - -00:27.160 --> 00:27.200 -679 - 00:27.160 - -00:27.200 --> 00:27.240 -680 - 00:27.200 - -00:27.240 --> 00:27.280 -681 - 00:27.240 - -00:27.280 --> 00:27.320 -682 - 00:27.280 - -00:27.320 --> 00:27.360 -683 - 00:27.320 - -00:27.360 --> 00:27.400 -684 - 00:27.360 - -00:27.400 --> 00:27.440 -685 - 00:27.400 - -00:27.440 --> 00:27.480 -686 - 00:27.440 - -00:27.480 --> 00:27.520 -687 - 00:27.480 - -00:27.520 --> 00:27.560 -688 - 00:27.520 - -00:27.560 --> 00:27.600 -689 - 00:27.560 - -00:27.600 --> 00:27.640 -690 - 00:27.600 - -00:27.640 --> 00:27.680 -691 - 00:27.640 - -00:27.680 --> 00:27.720 -692 - 00:27.680 - -00:27.720 --> 00:27.760 -693 - 00:27.720 - -00:27.760 --> 00:27.800 -694 - 00:27.760 - -00:27.800 --> 00:27.840 -695 - 00:27.800 - -00:27.840 --> 00:27.880 -696 - 00:27.840 - -00:27.880 --> 00:27.920 -697 - 00:27.880 - -00:27.920 --> 00:27.960 -698 - 00:27.920 - -00:27.960 --> 00:28.000 -699 - 00:27.960 - -00:28.000 --> 00:28.040 -700 - 00:28.000 - -00:28.040 --> 00:28.080 -701 - 00:28.040 - -00:28.080 --> 00:28.120 -702 - 00:28.080 - -00:28.120 --> 00:28.160 -703 - 00:28.120 - -00:28.160 --> 00:28.200 -704 - 00:28.160 - -00:28.200 --> 00:28.240 -705 - 00:28.200 - -00:28.240 --> 00:28.280 -706 - 00:28.240 - -00:28.280 --> 00:28.320 -707 - 00:28.280 - -00:28.320 --> 00:28.360 -708 - 00:28.320 - -00:28.360 --> 00:28.400 -709 - 00:28.360 - -00:28.400 --> 00:28.440 -710 - 00:28.400 - -00:28.440 --> 00:28.480 -711 - 00:28.440 - -00:28.480 --> 00:28.520 -712 - 00:28.480 - -00:28.520 --> 00:28.560 -713 - 00:28.520 - -00:28.560 --> 00:28.600 -714 - 00:28.560 - -00:28.600 --> 00:28.640 -715 - 00:28.600 - -00:28.640 --> 00:28.680 -716 - 00:28.640 - -00:28.680 --> 00:28.720 -717 - 00:28.680 - -00:28.720 --> 00:28.760 -718 - 00:28.720 - -00:28.760 --> 00:28.800 -719 - 00:28.760 - -00:28.800 --> 00:28.840 -720 - 00:28.800 - -00:28.840 --> 00:28.880 -721 - 00:28.840 - -00:28.880 --> 00:28.920 -722 - 00:28.880 - -00:28.920 --> 00:28.960 -723 - 00:28.920 - -00:28.960 --> 00:29.000 -724 - 00:28.960 - -00:29.000 --> 00:29.040 -725 - 00:29.000 - -00:29.040 --> 00:29.080 -726 - 00:29.040 - -00:29.080 --> 00:29.120 -727 - 00:29.080 - -00:29.120 --> 00:29.160 -728 - 00:29.120 - -00:29.160 --> 00:29.200 -729 - 00:29.160 - -00:29.200 --> 00:29.240 -730 - 00:29.200 - -00:29.240 --> 00:29.280 -731 - 00:29.240 - -00:29.280 --> 00:29.320 -732 - 00:29.280 - -00:29.320 --> 00:29.360 -733 - 00:29.320 - -00:29.360 --> 00:29.400 -734 - 00:29.360 - -00:29.400 --> 00:29.440 -735 - 00:29.400 - -00:29.440 --> 00:29.480 -736 - 00:29.440 - -00:29.480 --> 00:29.520 -737 - 00:29.480 - -00:29.520 --> 00:29.560 -738 - 00:29.520 - -00:29.560 --> 00:29.600 -739 - 00:29.560 - -00:29.600 --> 00:29.640 -740 - 00:29.600 - -00:29.640 --> 00:29.680 -741 - 00:29.640 - -00:29.680 --> 00:29.720 -742 - 00:29.680 - -00:29.720 --> 00:29.760 -743 - 00:29.720 - -00:29.760 --> 00:29.800 -744 - 00:29.760 - -00:29.800 --> 00:29.840 -745 - 00:29.800 - -00:29.840 --> 00:29.880 -746 - 00:29.840 - -00:29.880 --> 00:29.920 -747 - 00:29.880 - -00:29.920 --> 00:29.960 -748 - 00:29.920 - -00:29.960 --> 00:30.000 -749 - 00:29.960 - -00:30.000 --> 00:30.040 -750 - 00:30.000 - -00:30.040 --> 00:30.080 -751 - 00:30.040 - -00:30.080 --> 00:30.120 -752 - 00:30.080 - -00:30.120 --> 00:30.160 -753 - 00:30.120 - -00:30.160 --> 00:30.200 -754 - 00:30.160 - -00:30.200 --> 00:30.240 -755 - 00:30.200 - -00:30.240 --> 00:30.280 -756 - 00:30.240 - -00:30.280 --> 00:30.320 -757 - 00:30.280 - -00:30.320 --> 00:30.360 -758 - 00:30.320 - -00:30.360 --> 00:30.400 -759 - 00:30.360 - -00:30.400 --> 00:30.440 -760 - 00:30.400 - -00:30.440 --> 00:30.480 -761 - 00:30.440 - -00:30.480 --> 00:30.520 -762 - 00:30.480 - -00:30.520 --> 00:30.560 -763 - 00:30.520 - -00:30.560 --> 00:30.600 -764 - 00:30.560 - -00:30.600 --> 00:30.640 -765 - 00:30.600 - -00:30.640 --> 00:30.680 -766 - 00:30.640 - -00:30.680 --> 00:30.720 -767 - 00:30.680 - -00:30.720 --> 00:30.760 -768 - 00:30.720 - -00:30.760 --> 00:30.800 -769 - 00:30.760 - -00:30.800 --> 00:30.840 -770 - 00:30.800 - -00:30.840 --> 00:30.880 -771 - 00:30.840 - -00:30.880 --> 00:30.920 -772 - 00:30.880 - -00:30.920 --> 00:30.960 -773 - 00:30.920 - -00:30.960 --> 00:31.000 -774 - 00:30.960 - -00:31.000 --> 00:31.040 -775 - 00:31.000 - -00:31.040 --> 00:31.080 -776 - 00:31.040 - -00:31.080 --> 00:31.120 -777 - 00:31.080 - -00:31.120 --> 00:31.160 -778 - 00:31.120 - -00:31.160 --> 00:31.200 -779 - 00:31.160 - -00:31.200 --> 00:31.240 -780 - 00:31.200 - -00:31.240 --> 00:31.280 -781 - 00:31.240 - -00:31.280 --> 00:31.320 -782 - 00:31.280 - -00:31.320 --> 00:31.360 -783 - 00:31.320 - -00:31.360 --> 00:31.400 -784 - 00:31.360 - -00:31.400 --> 00:31.440 -785 - 00:31.400 - -00:31.440 --> 00:31.480 -786 - 00:31.440 - -00:31.480 --> 00:31.520 -787 - 00:31.480 - -00:31.520 --> 00:31.560 -788 - 00:31.520 - -00:31.560 --> 00:31.600 -789 - 00:31.560 - -00:31.600 --> 00:31.640 -790 - 00:31.600 - -00:31.640 --> 00:31.680 -791 - 00:31.640 - -00:31.680 --> 00:31.720 -792 - 00:31.680 - -00:31.720 --> 00:31.760 -793 - 00:31.720 - -00:31.760 --> 00:31.800 -794 - 00:31.760 - -00:31.800 --> 00:31.840 -795 - 00:31.800 - -00:31.840 --> 00:31.880 -796 - 00:31.840 - -00:31.880 --> 00:31.920 -797 - 00:31.880 - -00:31.920 --> 00:31.960 -798 - 00:31.920 - -00:31.960 --> 00:32.000 -799 - 00:31.960 - -00:32.000 --> 00:32.040 -800 - 00:32.000 - -00:32.040 --> 00:32.080 -801 - 00:32.040 - -00:32.080 --> 00:32.120 -802 - 00:32.080 - -00:32.120 --> 00:32.160 -803 - 00:32.120 - -00:32.160 --> 00:32.200 -804 - 00:32.160 - -00:32.200 --> 00:32.240 -805 - 00:32.200 - -00:32.240 --> 00:32.280 -806 - 00:32.240 - -00:32.280 --> 00:32.320 -807 - 00:32.280 - -00:32.320 --> 00:32.360 -808 - 00:32.320 - -00:32.360 --> 00:32.400 -809 - 00:32.360 - -00:32.400 --> 00:32.440 -810 - 00:32.400 - -00:32.440 --> 00:32.480 -811 - 00:32.440 - -00:32.480 --> 00:32.520 -812 - 00:32.480 - -00:32.520 --> 00:32.560 -813 - 00:32.520 - -00:32.560 --> 00:32.600 -814 - 00:32.560 - -00:32.600 --> 00:32.640 -815 - 00:32.600 - -00:32.640 --> 00:32.680 -816 - 00:32.640 - -00:32.680 --> 00:32.720 -817 - 00:32.680 - -00:32.720 --> 00:32.760 -818 - 00:32.720 - -00:32.760 --> 00:32.800 -819 - 00:32.760 - -00:32.800 --> 00:32.840 -820 - 00:32.800 - -00:32.840 --> 00:32.880 -821 - 00:32.840 - -00:32.880 --> 00:32.920 -822 - 00:32.880 - -00:32.920 --> 00:32.960 -823 - 00:32.920 - -00:32.960 --> 00:33.000 -824 - 00:32.960 - -00:33.000 --> 00:33.040 -825 - 00:33.000 - -00:33.040 --> 00:33.080 -826 - 00:33.040 - -00:33.080 --> 00:33.120 -827 - 00:33.080 - -00:33.120 --> 00:33.160 -828 - 00:33.120 - -00:33.160 --> 00:33.200 -829 - 00:33.160 - -00:33.200 --> 00:33.240 -830 - 00:33.200 - -00:33.240 --> 00:33.280 -831 - 00:33.240 - -00:33.280 --> 00:33.320 -832 - 00:33.280 - -00:33.320 --> 00:33.360 -833 - 00:33.320 - -00:33.360 --> 00:33.400 -834 - 00:33.360 - -00:33.400 --> 00:33.440 -835 - 00:33.400 - -00:33.440 --> 00:33.480 -836 - 00:33.440 - -00:33.480 --> 00:33.520 -837 - 00:33.480 - -00:33.520 --> 00:33.560 -838 - 00:33.520 - -00:33.560 --> 00:33.600 -839 - 00:33.560 - -00:33.600 --> 00:33.640 -840 - 00:33.600 - -00:33.640 --> 00:33.680 -841 - 00:33.640 - -00:33.680 --> 00:33.720 -842 - 00:33.680 - -00:33.720 --> 00:33.760 -843 - 00:33.720 - -00:33.760 --> 00:33.800 -844 - 00:33.760 - -00:33.800 --> 00:33.840 -845 - 00:33.800 - -00:33.840 --> 00:33.880 -846 - 00:33.840 - -00:33.880 --> 00:33.920 -847 - 00:33.880 - -00:33.920 --> 00:33.960 -848 - 00:33.920 - -00:33.960 --> 00:34.000 -849 - 00:33.960 - -00:34.000 --> 00:34.040 -850 - 00:34.000 - -00:34.040 --> 00:34.080 -851 - 00:34.040 - -00:34.080 --> 00:34.120 -852 - 00:34.080 - -00:34.120 --> 00:34.160 -853 - 00:34.120 - -00:34.160 --> 00:34.200 -854 - 00:34.160 - -00:34.200 --> 00:34.240 -855 - 00:34.200 - -00:34.240 --> 00:34.280 -856 - 00:34.240 - -00:34.280 --> 00:34.320 -857 - 00:34.280 - -00:34.320 --> 00:34.360 -858 - 00:34.320 - -00:34.360 --> 00:34.400 -859 - 00:34.360 - -00:34.400 --> 00:34.440 -860 - 00:34.400 - -00:34.440 --> 00:34.480 -861 - 00:34.440 - -00:34.480 --> 00:34.520 -862 - 00:34.480 - -00:34.520 --> 00:34.560 -863 - 00:34.520 - -00:34.560 --> 00:34.600 -864 - 00:34.560 - -00:34.600 --> 00:34.640 -865 - 00:34.600 - -00:34.640 --> 00:34.680 -866 - 00:34.640 - -00:34.680 --> 00:34.720 -867 - 00:34.680 - -00:34.720 --> 00:34.760 -868 - 00:34.720 - -00:34.760 --> 00:34.800 -869 - 00:34.760 - -00:34.800 --> 00:34.840 -870 - 00:34.800 - -00:34.840 --> 00:34.880 -871 - 00:34.840 - -00:34.880 --> 00:34.920 -872 - 00:34.880 - -00:34.920 --> 00:34.960 -873 - 00:34.920 - -00:34.960 --> 00:35.000 -874 - 00:34.960 - -00:35.000 --> 00:35.040 -875 - 00:35.000 - -00:35.040 --> 00:35.080 -876 - 00:35.040 - -00:35.080 --> 00:35.120 -877 - 00:35.080 - -00:35.120 --> 00:35.160 -878 - 00:35.120 - -00:35.160 --> 00:35.200 -879 - 00:35.160 - -00:35.200 --> 00:35.240 -880 - 00:35.200 - -00:35.240 --> 00:35.280 -881 - 00:35.240 - -00:35.280 --> 00:35.320 -882 - 00:35.280 - -00:35.320 --> 00:35.360 -883 - 00:35.320 - -00:35.360 --> 00:35.400 -884 - 00:35.360 - -00:35.400 --> 00:35.440 -885 - 00:35.400 - -00:35.440 --> 00:35.480 -886 - 00:35.440 - -00:35.480 --> 00:35.520 -887 - 00:35.480 - -00:35.520 --> 00:35.560 -888 - 00:35.520 - -00:35.560 --> 00:35.600 -889 - 00:35.560 - -00:35.600 --> 00:35.640 -890 - 00:35.600 - -00:35.640 --> 00:35.680 -891 - 00:35.640 - -00:35.680 --> 00:35.720 -892 - 00:35.680 - -00:35.720 --> 00:35.760 -893 - 00:35.720 - -00:35.760 --> 00:35.800 -894 - 00:35.760 - -00:35.800 --> 00:35.840 -895 - 00:35.800 - -00:35.840 --> 00:35.880 -896 - 00:35.840 - -00:35.880 --> 00:35.920 -897 - 00:35.880 - -00:35.920 --> 00:35.960 -898 - 00:35.920 - -00:35.960 --> 00:36.000 -899 - 00:35.960 - -00:36.000 --> 00:36.040 -900 - 00:36.000 - -00:36.040 --> 00:36.080 -901 - 00:36.040 - -00:36.080 --> 00:36.120 -902 - 00:36.080 - -00:36.120 --> 00:36.160 -903 - 00:36.120 - -00:36.160 --> 00:36.200 -904 - 00:36.160 - -00:36.200 --> 00:36.240 -905 - 00:36.200 - -00:36.240 --> 00:36.280 -906 - 00:36.240 - -00:36.280 --> 00:36.320 -907 - 00:36.280 - -00:36.320 --> 00:36.360 -908 - 00:36.320 - -00:36.360 --> 00:36.400 -909 - 00:36.360 - -00:36.400 --> 00:36.440 -910 - 00:36.400 - -00:36.440 --> 00:36.480 -911 - 00:36.440 - -00:36.480 --> 00:36.520 -912 - 00:36.480 - -00:36.520 --> 00:36.560 -913 - 00:36.520 - -00:36.560 --> 00:36.600 -914 - 00:36.560 - -00:36.600 --> 00:36.640 -915 - 00:36.600 - -00:36.640 --> 00:36.680 -916 - 00:36.640 - -00:36.680 --> 00:36.720 -917 - 00:36.680 - -00:36.720 --> 00:36.760 -918 - 00:36.720 - -00:36.760 --> 00:36.800 -919 - 00:36.760 - -00:36.800 --> 00:36.840 -920 - 00:36.800 - -00:36.840 --> 00:36.880 -921 - 00:36.840 - -00:36.880 --> 00:36.920 -922 - 00:36.880 - -00:36.920 --> 00:36.960 -923 - 00:36.920 - -00:36.960 --> 00:37.000 -924 - 00:36.960 - -00:37.000 --> 00:37.040 -925 - 00:37.000 - -00:37.040 --> 00:37.080 -926 - 00:37.040 - -00:37.080 --> 00:37.120 -927 - 00:37.080 - -00:37.120 --> 00:37.160 -928 - 00:37.120 - -00:37.160 --> 00:37.200 -929 - 00:37.160 - -00:37.200 --> 00:37.240 -930 - 00:37.200 - -00:37.240 --> 00:37.280 -931 - 00:37.240 - -00:37.280 --> 00:37.320 -932 - 00:37.280 - -00:37.320 --> 00:37.360 -933 - 00:37.320 - -00:37.360 --> 00:37.400 -934 - 00:37.360 - -00:37.400 --> 00:37.440 -935 - 00:37.400 - -00:37.440 --> 00:37.480 -936 - 00:37.440 - -00:37.480 --> 00:37.520 -937 - 00:37.480 - -00:37.520 --> 00:37.560 -938 - 00:37.520 - -00:37.560 --> 00:37.600 -939 - 00:37.560 - -00:37.600 --> 00:37.640 -940 - 00:37.600 - -00:37.640 --> 00:37.680 -941 - 00:37.640 - -00:37.680 --> 00:37.720 -942 - 00:37.680 - -00:37.720 --> 00:37.760 -943 - 00:37.720 - -00:37.760 --> 00:37.800 -944 - 00:37.760 - -00:37.800 --> 00:37.840 -945 - 00:37.800 - -00:37.840 --> 00:37.880 -946 - 00:37.840 - -00:37.880 --> 00:37.920 -947 - 00:37.880 - -00:37.920 --> 00:37.960 -948 - 00:37.920 - -00:37.960 --> 00:38.000 -949 - 00:37.960 - -00:38.000 --> 00:38.040 -950 - 00:38.000 - -00:38.040 --> 00:38.080 -951 - 00:38.040 - -00:38.080 --> 00:38.120 -952 - 00:38.080 - -00:38.120 --> 00:38.160 -953 - 00:38.120 - -00:38.160 --> 00:38.200 -954 - 00:38.160 - -00:38.200 --> 00:38.240 -955 - 00:38.200 - -00:38.240 --> 00:38.280 -956 - 00:38.240 - -00:38.280 --> 00:38.320 -957 - 00:38.280 - -00:38.320 --> 00:38.360 -958 - 00:38.320 - -00:38.360 --> 00:38.400 -959 - 00:38.360 - -00:38.400 --> 00:38.440 -960 - 00:38.400 - -00:38.440 --> 00:38.480 -961 - 00:38.440 - -00:38.480 --> 00:38.520 -962 - 00:38.480 - -00:38.520 --> 00:38.560 -963 - 00:38.520 - -00:38.560 --> 00:38.600 -964 - 00:38.560 - -00:38.600 --> 00:38.640 -965 - 00:38.600 - -00:38.640 --> 00:38.680 -966 - 00:38.640 - -00:38.680 --> 00:38.720 -967 - 00:38.680 - -00:38.720 --> 00:38.760 -968 - 00:38.720 - -00:38.760 --> 00:38.800 -969 - 00:38.760 - -00:38.800 --> 00:38.840 -970 - 00:38.800 - -00:38.840 --> 00:38.880 -971 - 00:38.840 - -00:38.880 --> 00:38.920 -972 - 00:38.880 - -00:38.920 --> 00:38.960 -973 - 00:38.920 - -00:38.960 --> 00:39.000 -974 - 00:38.960 - -00:39.000 --> 00:39.040 -975 - 00:39.000 - -00:39.040 --> 00:39.080 -976 - 00:39.040 - -00:39.080 --> 00:39.120 -977 - 00:39.080 - -00:39.120 --> 00:39.160 -978 - 00:39.120 - -00:39.160 --> 00:39.200 -979 - 00:39.160 - -00:39.200 --> 00:39.240 -980 - 00:39.200 - -00:39.240 --> 00:39.280 -981 - 00:39.240 - -00:39.280 --> 00:39.320 -982 - 00:39.280 - -00:39.320 --> 00:39.360 -983 - 00:39.320 - -00:39.360 --> 00:39.400 -984 - 00:39.360 - -00:39.400 --> 00:39.440 -985 - 00:39.400 - -00:39.440 --> 00:39.480 -986 - 00:39.440 - -00:39.480 --> 00:39.520 -987 - 00:39.480 - -00:39.520 --> 00:39.560 -988 - 00:39.520 - -00:39.560 --> 00:39.600 -989 - 00:39.560 - -00:39.600 --> 00:39.640 -990 - 00:39.600 - -00:39.640 --> 00:39.680 -991 - 00:39.640 - -00:39.680 --> 00:39.720 -992 - 00:39.680 - -00:39.720 --> 00:39.760 -993 - 00:39.720 - -00:39.760 --> 00:39.800 -994 - 00:39.760 - -00:39.800 --> 00:39.840 -995 - 00:39.800 - -00:39.840 --> 00:39.880 -996 - 00:39.840 - -00:39.880 --> 00:39.920 -997 - 00:39.880 - -00:39.920 --> 00:39.960 -998 - 00:39.920 - -00:39.960 --> 00:40.000 -999 - 00:39.960 - -00:40.000 --> 00:40.040 -1000 - 00:40.000 - -00:40.040 --> 00:40.080 -1001 - 00:40.040 - -00:40.080 --> 00:40.120 -1002 - 00:40.080 - -00:40.120 --> 00:40.160 -1003 - 00:40.120 - -00:40.160 --> 00:40.200 -1004 - 00:40.160 - -00:40.200 --> 00:40.240 -1005 - 00:40.200 - -00:40.240 --> 00:40.280 -1006 - 00:40.240 - -00:40.280 --> 00:40.320 -1007 - 00:40.280 - -00:40.320 --> 00:40.360 -1008 - 00:40.320 - -00:40.360 --> 00:40.400 -1009 - 00:40.360 - -00:40.400 --> 00:40.440 -1010 - 00:40.400 - -00:40.440 --> 00:40.480 -1011 - 00:40.440 - -00:40.480 --> 00:40.520 -1012 - 00:40.480 - -00:40.520 --> 00:40.560 -1013 - 00:40.520 - -00:40.560 --> 00:40.600 -1014 - 00:40.560 - -00:40.600 --> 00:40.640 -1015 - 00:40.600 - -00:40.640 --> 00:40.680 -1016 - 00:40.640 - -00:40.680 --> 00:40.720 -1017 - 00:40.680 - -00:40.720 --> 00:40.760 -1018 - 00:40.720 - -00:40.760 --> 00:40.800 -1019 - 00:40.760 - -00:40.800 --> 00:40.840 -1020 - 00:40.800 - -00:40.840 --> 00:40.880 -1021 - 00:40.840 - -00:40.880 --> 00:40.920 -1022 - 00:40.880 - -00:40.920 --> 00:40.960 -1023 - 00:40.920 - -00:40.960 --> 00:41.000 -1024 - 00:40.960 - -00:41.000 --> 00:41.040 -1025 - 00:41.000 - -00:41.040 --> 00:41.080 -1026 - 00:41.040 - -00:41.080 --> 00:41.120 -1027 - 00:41.080 - -00:41.120 --> 00:41.160 -1028 - 00:41.120 - -00:41.160 --> 00:41.200 -1029 - 00:41.160 - -00:41.200 --> 00:41.240 -1030 - 00:41.200 - -00:41.240 --> 00:41.280 -1031 - 00:41.240 - -00:41.280 --> 00:41.320 -1032 - 00:41.280 - -00:41.320 --> 00:41.360 -1033 - 00:41.320 - -00:41.360 --> 00:41.400 -1034 - 00:41.360 - -00:41.400 --> 00:41.440 -1035 - 00:41.400 - -00:41.440 --> 00:41.480 -1036 - 00:41.440 - -00:41.480 --> 00:41.520 -1037 - 00:41.480 - -00:41.520 --> 00:41.560 -1038 - 00:41.520 - -00:41.560 --> 00:41.600 -1039 - 00:41.560 - -00:41.600 --> 00:41.640 -1040 - 00:41.600 - -00:41.640 --> 00:41.680 -1041 - 00:41.640 - -00:41.680 --> 00:41.720 -1042 - 00:41.680 - -00:41.720 --> 00:41.760 -1043 - 00:41.720 - -00:41.760 --> 00:41.800 -1044 - 00:41.760 - -00:41.800 --> 00:41.840 -1045 - 00:41.800 - -00:41.840 --> 00:41.880 -1046 - 00:41.840 - -00:41.880 --> 00:41.920 -1047 - 00:41.880 - -00:41.920 --> 00:41.960 -1048 - 00:41.920 - -00:41.960 --> 00:42.000 -1049 - 00:41.960 - -00:42.000 --> 00:42.040 -1050 - 00:42.000 - -00:42.040 --> 00:42.080 -1051 - 00:42.040 - -00:42.080 --> 00:42.120 -1052 - 00:42.080 - -00:42.120 --> 00:42.160 -1053 - 00:42.120 - -00:42.160 --> 00:42.200 -1054 - 00:42.160 - -00:42.200 --> 00:42.240 -1055 - 00:42.200 - -00:42.240 --> 00:42.280 -1056 - 00:42.240 - -00:42.280 --> 00:42.320 -1057 - 00:42.280 - -00:42.320 --> 00:42.360 -1058 - 00:42.320 - -00:42.360 --> 00:42.400 -1059 - 00:42.360 - -00:42.400 --> 00:42.440 -1060 - 00:42.400 - -00:42.440 --> 00:42.480 -1061 - 00:42.440 - -00:42.480 --> 00:42.520 -1062 - 00:42.480 - -00:42.520 --> 00:42.560 -1063 - 00:42.520 - -00:42.560 --> 00:42.600 -1064 - 00:42.560 - -00:42.600 --> 00:42.640 -1065 - 00:42.600 - -00:42.640 --> 00:42.680 -1066 - 00:42.640 - -00:42.680 --> 00:42.720 -1067 - 00:42.680 - -00:42.720 --> 00:42.760 -1068 - 00:42.720 - -00:42.760 --> 00:42.800 -1069 - 00:42.760 - -00:42.800 --> 00:42.840 -1070 - 00:42.800 - -00:42.840 --> 00:42.880 -1071 - 00:42.840 - -00:42.880 --> 00:42.920 -1072 - 00:42.880 - -00:42.920 --> 00:42.960 -1073 - 00:42.920 - -00:42.960 --> 00:43.000 -1074 - 00:42.960 - -00:43.000 --> 00:43.040 -1075 - 00:43.000 - -00:43.040 --> 00:43.080 -1076 - 00:43.040 - -00:43.080 --> 00:43.120 -1077 - 00:43.080 - -00:43.120 --> 00:43.160 -1078 - 00:43.120 - -00:43.160 --> 00:43.200 -1079 - 00:43.160 - -00:43.200 --> 00:43.240 -1080 - 00:43.200 - -00:43.240 --> 00:43.280 -1081 - 00:43.240 - -00:43.280 --> 00:43.320 -1082 - 00:43.280 - -00:43.320 --> 00:43.360 -1083 - 00:43.320 - -00:43.360 --> 00:43.400 -1084 - 00:43.360 - -00:43.400 --> 00:43.440 -1085 - 00:43.400 - -00:43.440 --> 00:43.480 -1086 - 00:43.440 - -00:43.480 --> 00:43.520 -1087 - 00:43.480 - -00:43.520 --> 00:43.560 -1088 - 00:43.520 - -00:43.560 --> 00:43.600 -1089 - 00:43.560 - -00:43.600 --> 00:43.640 -1090 - 00:43.600 - -00:43.640 --> 00:43.680 -1091 - 00:43.640 - -00:43.680 --> 00:43.720 -1092 - 00:43.680 - -00:43.720 --> 00:43.760 -1093 - 00:43.720 - -00:43.760 --> 00:43.800 -1094 - 00:43.760 - -00:43.800 --> 00:43.840 -1095 - 00:43.800 - -00:43.840 --> 00:43.880 -1096 - 00:43.840 - -00:43.880 --> 00:43.920 -1097 - 00:43.880 - -00:43.920 --> 00:43.960 -1098 - 00:43.920 - -00:43.960 --> 00:44.000 -1099 - 00:43.960 - -00:44.000 --> 00:44.040 -1100 - 00:44.000 - -00:44.040 --> 00:44.080 -1101 - 00:44.040 - -00:44.080 --> 00:44.120 -1102 - 00:44.080 - -00:44.120 --> 00:44.160 -1103 - 00:44.120 - -00:44.160 --> 00:44.200 -1104 - 00:44.160 - -00:44.200 --> 00:44.240 -1105 - 00:44.200 - -00:44.240 --> 00:44.280 -1106 - 00:44.240 - -00:44.280 --> 00:44.320 -1107 - 00:44.280 - -00:44.320 --> 00:44.360 -1108 - 00:44.320 - -00:44.360 --> 00:44.400 -1109 - 00:44.360 - -00:44.400 --> 00:44.440 -1110 - 00:44.400 - -00:44.440 --> 00:44.480 -1111 - 00:44.440 - -00:44.480 --> 00:44.520 -1112 - 00:44.480 - -00:44.520 --> 00:44.560 -1113 - 00:44.520 - -00:44.560 --> 00:44.600 -1114 - 00:44.560 - -00:44.600 --> 00:44.640 -1115 - 00:44.600 - -00:44.640 --> 00:44.680 -1116 - 00:44.640 - -00:44.680 --> 00:44.720 -1117 - 00:44.680 - -00:44.720 --> 00:44.760 -1118 - 00:44.720 - -00:44.760 --> 00:44.800 -1119 - 00:44.760 - -00:44.800 --> 00:44.840 -1120 - 00:44.800 - -00:44.840 --> 00:44.880 -1121 - 00:44.840 - -00:44.880 --> 00:44.920 -1122 - 00:44.880 - -00:44.920 --> 00:44.960 -1123 - 00:44.920 - -00:44.960 --> 00:45.000 -1124 - 00:44.960 - -00:45.000 --> 00:45.040 -1125 - 00:45.000 - -00:45.040 --> 00:45.080 -1126 - 00:45.040 - -00:45.080 --> 00:45.120 -1127 - 00:45.080 - -00:45.120 --> 00:45.160 -1128 - 00:45.120 - -00:45.160 --> 00:45.200 -1129 - 00:45.160 - -00:45.200 --> 00:45.240 -1130 - 00:45.200 - -00:45.240 --> 00:45.280 -1131 - 00:45.240 - -00:45.280 --> 00:45.320 -1132 - 00:45.280 - -00:45.320 --> 00:45.360 -1133 - 00:45.320 - -00:45.360 --> 00:45.400 -1134 - 00:45.360 - -00:45.400 --> 00:45.440 -1135 - 00:45.400 - -00:45.440 --> 00:45.480 -1136 - 00:45.440 - -00:45.480 --> 00:45.520 -1137 - 00:45.480 - -00:45.520 --> 00:45.560 -1138 - 00:45.520 - -00:45.560 --> 00:45.600 -1139 - 00:45.560 - -00:45.600 --> 00:45.640 -1140 - 00:45.600 - -00:45.640 --> 00:45.680 -1141 - 00:45.640 - -00:45.680 --> 00:45.720 -1142 - 00:45.680 - -00:45.720 --> 00:45.760 -1143 - 00:45.720 - -00:45.760 --> 00:45.800 -1144 - 00:45.760 - -00:45.800 --> 00:45.840 -1145 - 00:45.800 - -00:45.840 --> 00:45.880 -1146 - 00:45.840 - -00:45.880 --> 00:45.920 -1147 - 00:45.880 - -00:45.920 --> 00:45.960 -1148 - 00:45.920 - -00:45.960 --> 00:46.000 -1149 - 00:45.960 - -00:46.000 --> 00:46.040 -1150 - 00:46.000 - -00:46.040 --> 00:46.080 -1151 - 00:46.040 - -00:46.080 --> 00:46.120 -1152 - 00:46.080 - -00:46.120 --> 00:46.160 -1153 - 00:46.120 - -00:46.160 --> 00:46.200 -1154 - 00:46.160 - -00:46.200 --> 00:46.240 -1155 - 00:46.200 - -00:46.240 --> 00:46.280 -1156 - 00:46.240 - -00:46.280 --> 00:46.320 -1157 - 00:46.280 - -00:46.320 --> 00:46.360 -1158 - 00:46.320 - -00:46.360 --> 00:46.400 -1159 - 00:46.360 - -00:46.400 --> 00:46.440 -1160 - 00:46.400 - -00:46.440 --> 00:46.480 -1161 - 00:46.440 - -00:46.480 --> 00:46.520 -1162 - 00:46.480 - -00:46.520 --> 00:46.560 -1163 - 00:46.520 - -00:46.560 --> 00:46.600 -1164 - 00:46.560 - -00:46.600 --> 00:46.640 -1165 - 00:46.600 - -00:46.640 --> 00:46.680 -1166 - 00:46.640 - -00:46.680 --> 00:46.720 -1167 - 00:46.680 - -00:46.720 --> 00:46.760 -1168 - 00:46.720 - -00:46.760 --> 00:46.800 -1169 - 00:46.760 - -00:46.800 --> 00:46.840 -1170 - 00:46.800 - -00:46.840 --> 00:46.880 -1171 - 00:46.840 - -00:46.880 --> 00:46.920 -1172 - 00:46.880 - -00:46.920 --> 00:46.960 -1173 - 00:46.920 - -00:46.960 --> 00:47.000 -1174 - 00:46.960 - -00:47.000 --> 00:47.040 -1175 - 00:47.000 - -00:47.040 --> 00:47.080 -1176 - 00:47.040 - -00:47.080 --> 00:47.120 -1177 - 00:47.080 - -00:47.120 --> 00:47.160 -1178 - 00:47.120 - -00:47.160 --> 00:47.200 -1179 - 00:47.160 - -00:47.200 --> 00:47.240 -1180 - 00:47.200 - -00:47.240 --> 00:47.280 -1181 - 00:47.240 - -00:47.280 --> 00:47.320 -1182 - 00:47.280 - -00:47.320 --> 00:47.360 -1183 - 00:47.320 - -00:47.360 --> 00:47.400 -1184 - 00:47.360 - -00:47.400 --> 00:47.440 -1185 - 00:47.400 - -00:47.440 --> 00:47.480 -1186 - 00:47.440 - -00:47.480 --> 00:47.520 -1187 - 00:47.480 - -00:47.520 --> 00:47.560 -1188 - 00:47.520 - -00:47.560 --> 00:47.600 -1189 - 00:47.560 - -00:47.600 --> 00:47.640 -1190 - 00:47.600 - -00:47.640 --> 00:47.680 -1191 - 00:47.640 - -00:47.680 --> 00:47.720 -1192 - 00:47.680 - -00:47.720 --> 00:47.760 -1193 - 00:47.720 - -00:47.760 --> 00:47.800 -1194 - 00:47.760 - -00:47.800 --> 00:47.840 -1195 - 00:47.800 - -00:47.840 --> 00:47.880 -1196 - 00:47.840 - -00:47.880 --> 00:47.920 -1197 - 00:47.880 - -00:47.920 --> 00:47.960 -1198 - 00:47.920 - -00:47.960 --> 00:48.000 -1199 - 00:47.960 - -00:48.000 --> 00:48.040 -1200 - 00:48.000 - -00:48.040 --> 00:48.080 -1201 - 00:48.040 - -00:48.080 --> 00:48.120 -1202 - 00:48.080 - -00:48.120 --> 00:48.160 -1203 - 00:48.120 - -00:48.160 --> 00:48.200 -1204 - 00:48.160 - -00:48.200 --> 00:48.240 -1205 - 00:48.200 - -00:48.240 --> 00:48.280 -1206 - 00:48.240 - -00:48.280 --> 00:48.320 -1207 - 00:48.280 - -00:48.320 --> 00:48.360 -1208 - 00:48.320 - -00:48.360 --> 00:48.400 -1209 - 00:48.360 - -00:48.400 --> 00:48.440 -1210 - 00:48.400 - -00:48.440 --> 00:48.480 -1211 - 00:48.440 - -00:48.480 --> 00:48.520 -1212 - 00:48.480 - -00:48.520 --> 00:48.560 -1213 - 00:48.520 - -00:48.560 --> 00:48.600 -1214 - 00:48.560 - -00:48.600 --> 00:48.640 -1215 - 00:48.600 - -00:48.640 --> 00:48.680 -1216 - 00:48.640 - -00:48.680 --> 00:48.720 -1217 - 00:48.680 - -00:48.720 --> 00:48.760 -1218 - 00:48.720 - -00:48.760 --> 00:48.800 -1219 - 00:48.760 - -00:48.800 --> 00:48.840 -1220 - 00:48.800 - -00:48.840 --> 00:48.880 -1221 - 00:48.840 - -00:48.880 --> 00:48.920 -1222 - 00:48.880 - -00:48.920 --> 00:48.960 -1223 - 00:48.920 - -00:48.960 --> 00:49.000 -1224 - 00:48.960 - -00:49.000 --> 00:49.040 -1225 - 00:49.000 - -00:49.040 --> 00:49.080 -1226 - 00:49.040 - -00:49.080 --> 00:49.120 -1227 - 00:49.080 - -00:49.120 --> 00:49.160 -1228 - 00:49.120 - -00:49.160 --> 00:49.200 -1229 - 00:49.160 - -00:49.200 --> 00:49.240 -1230 - 00:49.200 - -00:49.240 --> 00:49.280 -1231 - 00:49.240 - -00:49.280 --> 00:49.320 -1232 - 00:49.280 - -00:49.320 --> 00:49.360 -1233 - 00:49.320 - -00:49.360 --> 00:49.400 -1234 - 00:49.360 - -00:49.400 --> 00:49.440 -1235 - 00:49.400 - -00:49.440 --> 00:49.480 -1236 - 00:49.440 - -00:49.480 --> 00:49.520 -1237 - 00:49.480 - -00:49.520 --> 00:49.560 -1238 - 00:49.520 - -00:49.560 --> 00:49.600 -1239 - 00:49.560 - -00:49.600 --> 00:49.640 -1240 - 00:49.600 - -00:49.640 --> 00:49.680 -1241 - 00:49.640 - -00:49.680 --> 00:49.720 -1242 - 00:49.680 - -00:49.720 --> 00:49.760 -1243 - 00:49.720 - -00:49.760 --> 00:49.800 -1244 - 00:49.760 - -00:49.800 --> 00:49.840 -1245 - 00:49.800 - -00:49.840 --> 00:49.880 -1246 - 00:49.840 - -00:49.880 --> 00:49.920 -1247 - 00:49.880 - -00:49.920 --> 00:49.960 -1248 - 00:49.920 - -00:49.960 --> 00:50.000 -1249 - 00:49.960 - -00:50.000 --> 00:50.040 -1250 - 00:50.000 - -00:50.040 --> 00:50.080 -1251 - 00:50.040 - -00:50.080 --> 00:50.120 -1252 - 00:50.080 - -00:50.120 --> 00:50.160 -1253 - 00:50.120 - -00:50.160 --> 00:50.200 -1254 - 00:50.160 - -00:50.200 --> 00:50.240 -1255 - 00:50.200 - -00:50.240 --> 00:50.280 -1256 - 00:50.240 - -00:50.280 --> 00:50.320 -1257 - 00:50.280 - -00:50.320 --> 00:50.360 -1258 - 00:50.320 - -00:50.360 --> 00:50.400 -1259 - 00:50.360 - -00:50.400 --> 00:50.440 -1260 - 00:50.400 - -00:50.440 --> 00:50.480 -1261 - 00:50.440 - -00:50.480 --> 00:50.520 -1262 - 00:50.480 - -00:50.520 --> 00:50.560 -1263 - 00:50.520 - -00:50.560 --> 00:50.600 -1264 - 00:50.560 - -00:50.600 --> 00:50.640 -1265 - 00:50.600 - -00:50.640 --> 00:50.680 -1266 - 00:50.640 - -00:50.680 --> 00:50.720 -1267 - 00:50.680 - -00:50.720 --> 00:50.760 -1268 - 00:50.720 - -00:50.760 --> 00:50.800 -1269 - 00:50.760 - -00:50.800 --> 00:50.840 -1270 - 00:50.800 - -00:50.840 --> 00:50.880 -1271 - 00:50.840 - -00:50.880 --> 00:50.920 -1272 - 00:50.880 - -00:50.920 --> 00:50.960 -1273 - 00:50.920 - -00:50.960 --> 00:51.000 -1274 - 00:50.960 - -00:51.000 --> 00:51.040 -1275 - 00:51.000 - -00:51.040 --> 00:51.080 -1276 - 00:51.040 - -00:51.080 --> 00:51.120 -1277 - 00:51.080 - -00:51.120 --> 00:51.160 -1278 - 00:51.120 - -00:51.160 --> 00:51.200 -1279 - 00:51.160 - -00:51.200 --> 00:51.240 -1280 - 00:51.200 - -00:51.240 --> 00:51.280 -1281 - 00:51.240 - -00:51.280 --> 00:51.320 -1282 - 00:51.280 - -00:51.320 --> 00:51.360 -1283 - 00:51.320 - -00:51.360 --> 00:51.400 -1284 - 00:51.360 - -00:51.400 --> 00:51.440 -1285 - 00:51.400 - -00:51.440 --> 00:51.480 -1286 - 00:51.440 - -00:51.480 --> 00:51.520 -1287 - 00:51.480 - -00:51.520 --> 00:51.560 -1288 - 00:51.520 - -00:51.560 --> 00:51.600 -1289 - 00:51.560 - -00:51.600 --> 00:51.640 -1290 - 00:51.600 - -00:51.640 --> 00:51.680 -1291 - 00:51.640 - -00:51.680 --> 00:51.720 -1292 - 00:51.680 - -00:51.720 --> 00:51.760 -1293 - 00:51.720 - -00:51.760 --> 00:51.800 -1294 - 00:51.760 - -00:51.800 --> 00:51.840 -1295 - 00:51.800 - -00:51.840 --> 00:51.880 -1296 - 00:51.840 - -00:51.880 --> 00:51.920 -1297 - 00:51.880 - -00:51.920 --> 00:51.960 -1298 - 00:51.920 - -00:51.960 --> 00:52.000 -1299 - 00:51.960 - -00:52.000 --> 00:52.040 -1300 - 00:52.000 - -00:52.040 --> 00:52.080 -1301 - 00:52.040 - -00:52.080 --> 00:52.120 -1302 - 00:52.080 - -00:52.120 --> 00:52.160 -1303 - 00:52.120 - -00:52.160 --> 00:52.200 -1304 - 00:52.160 - -00:52.200 --> 00:52.240 -1305 - 00:52.200 - -00:52.240 --> 00:52.280 -1306 - 00:52.240 - -00:52.280 --> 00:52.320 -1307 - 00:52.280 - -00:52.320 --> 00:52.360 -1308 - 00:52.320 - -00:52.360 --> 00:52.400 -1309 - 00:52.360 - -00:52.400 --> 00:52.440 -1310 - 00:52.400 - -00:52.440 --> 00:52.480 -1311 - 00:52.440 - -00:52.480 --> 00:52.520 -1312 - 00:52.480 - -00:52.520 --> 00:52.560 -1313 - 00:52.520 - -00:52.560 --> 00:52.600 -1314 - 00:52.560 - -00:52.600 --> 00:52.640 -1315 - 00:52.600 - -00:52.640 --> 00:52.680 -1316 - 00:52.640 - -00:52.680 --> 00:52.720 -1317 - 00:52.680 - -00:52.720 --> 00:52.760 -1318 - 00:52.720 - -00:52.760 --> 00:52.800 -1319 - 00:52.760 - -00:52.800 --> 00:52.840 -1320 - 00:52.800 - -00:52.840 --> 00:52.880 -1321 - 00:52.840 - -00:52.880 --> 00:52.920 -1322 - 00:52.880 - -00:52.920 --> 00:52.960 -1323 - 00:52.920 - -00:52.960 --> 00:53.000 -1324 - 00:52.960 - -00:53.000 --> 00:53.040 -1325 - 00:53.000 - -00:53.040 --> 00:53.080 -1326 - 00:53.040 - -00:53.080 --> 00:53.120 -1327 - 00:53.080 - -00:53.120 --> 00:53.160 -1328 - 00:53.120 - -00:53.160 --> 00:53.200 -1329 - 00:53.160 - -00:53.200 --> 00:53.240 -1330 - 00:53.200 - -00:53.240 --> 00:53.280 -1331 - 00:53.240 - -00:53.280 --> 00:53.320 -1332 - 00:53.280 - -00:53.320 --> 00:53.360 -1333 - 00:53.320 - -00:53.360 --> 00:53.400 -1334 - 00:53.360 - -00:53.400 --> 00:53.440 -1335 - 00:53.400 - -00:53.440 --> 00:53.480 -1336 - 00:53.440 - -00:53.480 --> 00:53.520 -1337 - 00:53.480 - -00:53.520 --> 00:53.560 -1338 - 00:53.520 - -00:53.560 --> 00:53.600 -1339 - 00:53.560 - -00:53.600 --> 00:53.640 -1340 - 00:53.600 - -00:53.640 --> 00:53.680 -1341 - 00:53.640 - -00:53.680 --> 00:53.720 -1342 - 00:53.680 - -00:53.720 --> 00:53.760 -1343 - 00:53.720 - -00:53.760 --> 00:53.800 -1344 - 00:53.760 - -00:53.800 --> 00:53.840 -1345 - 00:53.800 - -00:53.840 --> 00:53.880 -1346 - 00:53.840 - -00:53.880 --> 00:53.920 -1347 - 00:53.880 - -00:53.920 --> 00:53.960 -1348 - 00:53.920 - -00:53.960 --> 00:54.000 -1349 - 00:53.960 - -00:54.000 --> 00:54.040 -1350 - 00:54.000 - -00:54.040 --> 00:54.080 -1351 - 00:54.040 - -00:54.080 --> 00:54.120 -1352 - 00:54.080 - -00:54.120 --> 00:54.160 -1353 - 00:54.120 - -00:54.160 --> 00:54.200 -1354 - 00:54.160 - -00:54.200 --> 00:54.240 -1355 - 00:54.200 - -00:54.240 --> 00:54.280 -1356 - 00:54.240 - -00:54.280 --> 00:54.320 -1357 - 00:54.280 - -00:54.320 --> 00:54.360 -1358 - 00:54.320 - -00:54.360 --> 00:54.400 -1359 - 00:54.360 - -00:54.400 --> 00:54.440 -1360 - 00:54.400 - -00:54.440 --> 00:54.480 -1361 - 00:54.440 - -00:54.480 --> 00:54.520 -1362 - 00:54.480 - -00:54.520 --> 00:54.560 -1363 - 00:54.520 - -00:54.560 --> 00:54.600 -1364 - 00:54.560 - -00:54.600 --> 00:54.640 -1365 - 00:54.600 - -00:54.640 --> 00:54.680 -1366 - 00:54.640 - -00:54.680 --> 00:54.720 -1367 - 00:54.680 - -00:54.720 --> 00:54.760 -1368 - 00:54.720 - -00:54.760 --> 00:54.800 -1369 - 00:54.760 - -00:54.800 --> 00:54.840 -1370 - 00:54.800 - -00:54.840 --> 00:54.880 -1371 - 00:54.840 - -00:54.880 --> 00:54.920 -1372 - 00:54.880 - -00:54.920 --> 00:54.960 -1373 - 00:54.920 - -00:54.960 --> 00:55.000 -1374 - 00:54.960 - -00:55.000 --> 00:55.040 -1375 - 00:55.000 - -00:55.040 --> 00:55.080 -1376 - 00:55.040 - -00:55.080 --> 00:55.120 -1377 - 00:55.080 - -00:55.120 --> 00:55.160 -1378 - 00:55.120 - -00:55.160 --> 00:55.200 -1379 - 00:55.160 - -00:55.200 --> 00:55.240 -1380 - 00:55.200 - -00:55.240 --> 00:55.280 -1381 - 00:55.240 - -00:55.280 --> 00:55.320 -1382 - 00:55.280 - -00:55.320 --> 00:55.360 -1383 - 00:55.320 - -00:55.360 --> 00:55.400 -1384 - 00:55.360 - -00:55.400 --> 00:55.440 -1385 - 00:55.400 - -00:55.440 --> 00:55.480 -1386 - 00:55.440 - -00:55.480 --> 00:55.520 -1387 - 00:55.480 - -00:55.520 --> 00:55.560 -1388 - 00:55.520 - -00:55.560 --> 00:55.600 -1389 - 00:55.560 - -00:55.600 --> 00:55.640 -1390 - 00:55.600 - -00:55.640 --> 00:55.680 -1391 - 00:55.640 - -00:55.680 --> 00:55.720 -1392 - 00:55.680 - -00:55.720 --> 00:55.760 -1393 - 00:55.720 - -00:55.760 --> 00:55.800 -1394 - 00:55.760 - -00:55.800 --> 00:55.840 -1395 - 00:55.800 - -00:55.840 --> 00:55.880 -1396 - 00:55.840 - -00:55.880 --> 00:55.920 -1397 - 00:55.880 - -00:55.920 --> 00:55.960 -1398 - 00:55.920 - -00:55.960 --> 00:56.000 -1399 - 00:55.960 - -00:56.000 --> 00:56.040 -1400 - 00:56.000 - -00:56.040 --> 00:56.080 -1401 - 00:56.040 - -00:56.080 --> 00:56.120 -1402 - 00:56.080 - -00:56.120 --> 00:56.160 -1403 - 00:56.120 - -00:56.160 --> 00:56.200 -1404 - 00:56.160 - -00:56.200 --> 00:56.240 -1405 - 00:56.200 - -00:56.240 --> 00:56.280 -1406 - 00:56.240 - -00:56.280 --> 00:56.320 -1407 - 00:56.280 - -00:56.320 --> 00:56.360 -1408 - 00:56.320 - -00:56.360 --> 00:56.400 -1409 - 00:56.360 - -00:56.400 --> 00:56.440 -1410 - 00:56.400 - -00:56.440 --> 00:56.480 -1411 - 00:56.440 - -00:56.480 --> 00:56.520 -1412 - 00:56.480 - -00:56.520 --> 00:56.560 -1413 - 00:56.520 - -00:56.560 --> 00:56.600 -1414 - 00:56.560 - -00:56.600 --> 00:56.640 -1415 - 00:56.600 - -00:56.640 --> 00:56.680 -1416 - 00:56.640 - -00:56.680 --> 00:56.720 -1417 - 00:56.680 - -00:56.720 --> 00:56.760 -1418 - 00:56.720 - -00:56.760 --> 00:56.800 -1419 - 00:56.760 - -00:56.800 --> 00:56.840 -1420 - 00:56.800 - -00:56.840 --> 00:56.880 -1421 - 00:56.840 - -00:56.880 --> 00:56.920 -1422 - 00:56.880 - -00:56.920 --> 00:56.960 -1423 - 00:56.920 - -00:56.960 --> 00:57.000 -1424 - 00:56.960 - -00:57.000 --> 00:57.040 -1425 - 00:57.000 - -00:57.040 --> 00:57.080 -1426 - 00:57.040 - -00:57.080 --> 00:57.120 -1427 - 00:57.080 - -00:57.120 --> 00:57.160 -1428 - 00:57.120 - -00:57.160 --> 00:57.200 -1429 - 00:57.160 - -00:57.200 --> 00:57.240 -1430 - 00:57.200 - -00:57.240 --> 00:57.280 -1431 - 00:57.240 - -00:57.280 --> 00:57.320 -1432 - 00:57.280 - -00:57.320 --> 00:57.360 -1433 - 00:57.320 - -00:57.360 --> 00:57.400 -1434 - 00:57.360 - -00:57.400 --> 00:57.440 -1435 - 00:57.400 - -00:57.440 --> 00:57.480 -1436 - 00:57.440 - -00:57.480 --> 00:57.520 -1437 - 00:57.480 - -00:57.520 --> 00:57.560 -1438 - 00:57.520 - -00:57.560 --> 00:57.600 -1439 - 00:57.560 - -00:57.600 --> 00:57.640 -1440 - 00:57.600 - -00:57.640 --> 00:57.680 -1441 - 00:57.640 - -00:57.680 --> 00:57.720 -1442 - 00:57.680 - -00:57.720 --> 00:57.760 -1443 - 00:57.720 - -00:57.760 --> 00:57.800 -1444 - 00:57.760 - -00:57.800 --> 00:57.840 -1445 - 00:57.800 - -00:57.840 --> 00:57.880 -1446 - 00:57.840 - -00:57.880 --> 00:57.920 -1447 - 00:57.880 - -00:57.920 --> 00:57.960 -1448 - 00:57.920 - -00:57.960 --> 00:58.000 -1449 - 00:57.960 - -00:58.000 --> 00:58.040 -1450 - 00:58.000 - -00:58.040 --> 00:58.080 -1451 - 00:58.040 - -00:58.080 --> 00:58.120 -1452 - 00:58.080 - -00:58.120 --> 00:58.160 -1453 - 00:58.120 - -00:58.160 --> 00:58.200 -1454 - 00:58.160 - -00:58.200 --> 00:58.240 -1455 - 00:58.200 - -00:58.240 --> 00:58.280 -1456 - 00:58.240 - -00:58.280 --> 00:58.320 -1457 - 00:58.280 - -00:58.320 --> 00:58.360 -1458 - 00:58.320 - -00:58.360 --> 00:58.400 -1459 - 00:58.360 - -00:58.400 --> 00:58.440 -1460 - 00:58.400 - -00:58.440 --> 00:58.480 -1461 - 00:58.440 - -00:58.480 --> 00:58.520 -1462 - 00:58.480 - -00:58.520 --> 00:58.560 -1463 - 00:58.520 - -00:58.560 --> 00:58.600 -1464 - 00:58.560 - -00:58.600 --> 00:58.640 -1465 - 00:58.600 - -00:58.640 --> 00:58.680 -1466 - 00:58.640 - -00:58.680 --> 00:58.720 -1467 - 00:58.680 - -00:58.720 --> 00:58.760 -1468 - 00:58.720 - -00:58.760 --> 00:58.800 -1469 - 00:58.760 - -00:58.800 --> 00:58.840 -1470 - 00:58.800 - -00:58.840 --> 00:58.880 -1471 - 00:58.840 - -00:58.880 --> 00:58.920 -1472 - 00:58.880 - -00:58.920 --> 00:58.960 -1473 - 00:58.920 - -00:58.960 --> 00:59.000 -1474 - 00:58.960 - -00:59.000 --> 00:59.040 -1475 - 00:59.000 - -00:59.040 --> 00:59.080 -1476 - 00:59.040 - -00:59.080 --> 00:59.120 -1477 - 00:59.080 - -00:59.120 --> 00:59.160 -1478 - 00:59.120 - -00:59.160 --> 00:59.200 -1479 - 00:59.160 - -00:59.200 --> 00:59.240 -1480 - 00:59.200 - -00:59.240 --> 00:59.280 -1481 - 00:59.240 - -00:59.280 --> 00:59.320 -1482 - 00:59.280 - -00:59.320 --> 00:59.360 -1483 - 00:59.320 - -00:59.360 --> 00:59.400 -1484 - 00:59.360 - -00:59.400 --> 00:59.440 -1485 - 00:59.400 - -00:59.440 --> 00:59.480 -1486 - 00:59.440 - -00:59.480 --> 00:59.520 -1487 - 00:59.480 - -00:59.520 --> 00:59.560 -1488 - 00:59.520 - -00:59.560 --> 00:59.600 -1489 - 00:59.560 - -00:59.600 --> 00:59.640 -1490 - 00:59.600 - -00:59.640 --> 00:59.680 -1491 - 00:59.640 - -00:59.680 --> 00:59.720 -1492 - 00:59.680 - -00:59.720 --> 00:59.760 -1493 - 00:59.720 - -00:59.760 --> 00:59.800 -1494 - 00:59.760 - -00:59.800 --> 00:59.840 -1495 - 00:59.800 - -00:59.840 --> 00:59.880 -1496 - 00:59.840 - -00:59.880 --> 00:59.920 -1497 - 00:59.880 - -00:59.920 --> 00:59.960 -1498 - 00:59.920 - -00:59.960 --> 01:00.000 -1499 - 00:59.960 - +WEBVTT + +00:00.000 --> 00:00.040 +0 - 00:00.000 + +00:00.040 --> 00:00.080 +1 - 00:00.040 + +00:00.080 --> 00:00.120 +2 - 00:00.080 + +00:00.120 --> 00:00.160 +3 - 00:00.120 + +00:00.160 --> 00:00.200 +4 - 00:00.160 + +00:00.200 --> 00:00.240 +5 - 00:00.200 + +00:00.240 --> 00:00.280 +6 - 00:00.240 + +00:00.280 --> 00:00.320 +7 - 00:00.280 + +00:00.320 --> 00:00.360 +8 - 00:00.320 + +00:00.360 --> 00:00.400 +9 - 00:00.360 + +00:00.400 --> 00:00.440 +10 - 00:00.400 + +00:00.440 --> 00:00.480 +11 - 00:00.440 + +00:00.480 --> 00:00.520 +12 - 00:00.480 + +00:00.520 --> 00:00.560 +13 - 00:00.520 + +00:00.560 --> 00:00.600 +14 - 00:00.560 + +00:00.600 --> 00:00.640 +15 - 00:00.600 + +00:00.640 --> 00:00.680 +16 - 00:00.640 + +00:00.680 --> 00:00.720 +17 - 00:00.680 + +00:00.720 --> 00:00.760 +18 - 00:00.720 + +00:00.760 --> 00:00.800 +19 - 00:00.760 + +00:00.800 --> 00:00.840 +20 - 00:00.800 + +00:00.840 --> 00:00.880 +21 - 00:00.840 + +00:00.880 --> 00:00.920 +22 - 00:00.880 + +00:00.920 --> 00:00.960 +23 - 00:00.920 + +00:00.960 --> 00:01.000 +24 - 00:00.960 + +00:01.000 --> 00:01.040 +25 - 00:01.000 + +00:01.040 --> 00:01.080 +26 - 00:01.040 + +00:01.080 --> 00:01.120 +27 - 00:01.080 + +00:01.120 --> 00:01.160 +28 - 00:01.120 + +00:01.160 --> 00:01.200 +29 - 00:01.160 + +00:01.200 --> 00:01.240 +30 - 00:01.200 + +00:01.240 --> 00:01.280 +31 - 00:01.240 + +00:01.280 --> 00:01.320 +32 - 00:01.280 + +00:01.320 --> 00:01.360 +33 - 00:01.320 + +00:01.360 --> 00:01.400 +34 - 00:01.360 + +00:01.400 --> 00:01.440 +35 - 00:01.400 + +00:01.440 --> 00:01.480 +36 - 00:01.440 + +00:01.480 --> 00:01.520 +37 - 00:01.480 + +00:01.520 --> 00:01.560 +38 - 00:01.520 + +00:01.560 --> 00:01.600 +39 - 00:01.560 + +00:01.600 --> 00:01.640 +40 - 00:01.600 + +00:01.640 --> 00:01.680 +41 - 00:01.640 + +00:01.680 --> 00:01.720 +42 - 00:01.680 + +00:01.720 --> 00:01.760 +43 - 00:01.720 + +00:01.760 --> 00:01.800 +44 - 00:01.760 + +00:01.800 --> 00:01.840 +45 - 00:01.800 + +00:01.840 --> 00:01.880 +46 - 00:01.840 + +00:01.880 --> 00:01.920 +47 - 00:01.880 + +00:01.920 --> 00:01.960 +48 - 00:01.920 + +00:01.960 --> 00:02.000 +49 - 00:01.960 + +00:02.000 --> 00:02.040 +50 - 00:02.000 + +00:02.040 --> 00:02.080 +51 - 00:02.040 + +00:02.080 --> 00:02.120 +52 - 00:02.080 + +00:02.120 --> 00:02.160 +53 - 00:02.120 + +00:02.160 --> 00:02.200 +54 - 00:02.160 + +00:02.200 --> 00:02.240 +55 - 00:02.200 + +00:02.240 --> 00:02.280 +56 - 00:02.240 + +00:02.280 --> 00:02.320 +57 - 00:02.280 + +00:02.320 --> 00:02.360 +58 - 00:02.320 + +00:02.360 --> 00:02.400 +59 - 00:02.360 + +00:02.400 --> 00:02.440 +60 - 00:02.400 + +00:02.440 --> 00:02.480 +61 - 00:02.440 + +00:02.480 --> 00:02.520 +62 - 00:02.480 + +00:02.520 --> 00:02.560 +63 - 00:02.520 + +00:02.560 --> 00:02.600 +64 - 00:02.560 + +00:02.600 --> 00:02.640 +65 - 00:02.600 + +00:02.640 --> 00:02.680 +66 - 00:02.640 + +00:02.680 --> 00:02.720 +67 - 00:02.680 + +00:02.720 --> 00:02.760 +68 - 00:02.720 + +00:02.760 --> 00:02.800 +69 - 00:02.760 + +00:02.800 --> 00:02.840 +70 - 00:02.800 + +00:02.840 --> 00:02.880 +71 - 00:02.840 + +00:02.880 --> 00:02.920 +72 - 00:02.880 + +00:02.920 --> 00:02.960 +73 - 00:02.920 + +00:02.960 --> 00:03.000 +74 - 00:02.960 + +00:03.000 --> 00:03.040 +75 - 00:03.000 + +00:03.040 --> 00:03.080 +76 - 00:03.040 + +00:03.080 --> 00:03.120 +77 - 00:03.080 + +00:03.120 --> 00:03.160 +78 - 00:03.120 + +00:03.160 --> 00:03.200 +79 - 00:03.160 + +00:03.200 --> 00:03.240 +80 - 00:03.200 + +00:03.240 --> 00:03.280 +81 - 00:03.240 + +00:03.280 --> 00:03.320 +82 - 00:03.280 + +00:03.320 --> 00:03.360 +83 - 00:03.320 + +00:03.360 --> 00:03.400 +84 - 00:03.360 + +00:03.400 --> 00:03.440 +85 - 00:03.400 + +00:03.440 --> 00:03.480 +86 - 00:03.440 + +00:03.480 --> 00:03.520 +87 - 00:03.480 + +00:03.520 --> 00:03.560 +88 - 00:03.520 + +00:03.560 --> 00:03.600 +89 - 00:03.560 + +00:03.600 --> 00:03.640 +90 - 00:03.600 + +00:03.640 --> 00:03.680 +91 - 00:03.640 + +00:03.680 --> 00:03.720 +92 - 00:03.680 + +00:03.720 --> 00:03.760 +93 - 00:03.720 + +00:03.760 --> 00:03.800 +94 - 00:03.760 + +00:03.800 --> 00:03.840 +95 - 00:03.800 + +00:03.840 --> 00:03.880 +96 - 00:03.840 + +00:03.880 --> 00:03.920 +97 - 00:03.880 + +00:03.920 --> 00:03.960 +98 - 00:03.920 + +00:03.960 --> 00:04.000 +99 - 00:03.960 + +00:04.000 --> 00:04.040 +100 - 00:04.000 + +00:04.040 --> 00:04.080 +101 - 00:04.040 + +00:04.080 --> 00:04.120 +102 - 00:04.080 + +00:04.120 --> 00:04.160 +103 - 00:04.120 + +00:04.160 --> 00:04.200 +104 - 00:04.160 + +00:04.200 --> 00:04.240 +105 - 00:04.200 + +00:04.240 --> 00:04.280 +106 - 00:04.240 + +00:04.280 --> 00:04.320 +107 - 00:04.280 + +00:04.320 --> 00:04.360 +108 - 00:04.320 + +00:04.360 --> 00:04.400 +109 - 00:04.360 + +00:04.400 --> 00:04.440 +110 - 00:04.400 + +00:04.440 --> 00:04.480 +111 - 00:04.440 + +00:04.480 --> 00:04.520 +112 - 00:04.480 + +00:04.520 --> 00:04.560 +113 - 00:04.520 + +00:04.560 --> 00:04.600 +114 - 00:04.560 + +00:04.600 --> 00:04.640 +115 - 00:04.600 + +00:04.640 --> 00:04.680 +116 - 00:04.640 + +00:04.680 --> 00:04.720 +117 - 00:04.680 + +00:04.720 --> 00:04.760 +118 - 00:04.720 + +00:04.760 --> 00:04.800 +119 - 00:04.760 + +00:04.800 --> 00:04.840 +120 - 00:04.800 + +00:04.840 --> 00:04.880 +121 - 00:04.840 + +00:04.880 --> 00:04.920 +122 - 00:04.880 + +00:04.920 --> 00:04.960 +123 - 00:04.920 + +00:04.960 --> 00:05.000 +124 - 00:04.960 + +00:05.000 --> 00:05.040 +125 - 00:05.000 + +00:05.040 --> 00:05.080 +126 - 00:05.040 + +00:05.080 --> 00:05.120 +127 - 00:05.080 + +00:05.120 --> 00:05.160 +128 - 00:05.120 + +00:05.160 --> 00:05.200 +129 - 00:05.160 + +00:05.200 --> 00:05.240 +130 - 00:05.200 + +00:05.240 --> 00:05.280 +131 - 00:05.240 + +00:05.280 --> 00:05.320 +132 - 00:05.280 + +00:05.320 --> 00:05.360 +133 - 00:05.320 + +00:05.360 --> 00:05.400 +134 - 00:05.360 + +00:05.400 --> 00:05.440 +135 - 00:05.400 + +00:05.440 --> 00:05.480 +136 - 00:05.440 + +00:05.480 --> 00:05.520 +137 - 00:05.480 + +00:05.520 --> 00:05.560 +138 - 00:05.520 + +00:05.560 --> 00:05.600 +139 - 00:05.560 + +00:05.600 --> 00:05.640 +140 - 00:05.600 + +00:05.640 --> 00:05.680 +141 - 00:05.640 + +00:05.680 --> 00:05.720 +142 - 00:05.680 + +00:05.720 --> 00:05.760 +143 - 00:05.720 + +00:05.760 --> 00:05.800 +144 - 00:05.760 + +00:05.800 --> 00:05.840 +145 - 00:05.800 + +00:05.840 --> 00:05.880 +146 - 00:05.840 + +00:05.880 --> 00:05.920 +147 - 00:05.880 + +00:05.920 --> 00:05.960 +148 - 00:05.920 + +00:05.960 --> 00:06.000 +149 - 00:05.960 + +00:06.000 --> 00:06.040 +150 - 00:06.000 + +00:06.040 --> 00:06.080 +151 - 00:06.040 + +00:06.080 --> 00:06.120 +152 - 00:06.080 + +00:06.120 --> 00:06.160 +153 - 00:06.120 + +00:06.160 --> 00:06.200 +154 - 00:06.160 + +00:06.200 --> 00:06.240 +155 - 00:06.200 + +00:06.240 --> 00:06.280 +156 - 00:06.240 + +00:06.280 --> 00:06.320 +157 - 00:06.280 + +00:06.320 --> 00:06.360 +158 - 00:06.320 + +00:06.360 --> 00:06.400 +159 - 00:06.360 + +00:06.400 --> 00:06.440 +160 - 00:06.400 + +00:06.440 --> 00:06.480 +161 - 00:06.440 + +00:06.480 --> 00:06.520 +162 - 00:06.480 + +00:06.520 --> 00:06.560 +163 - 00:06.520 + +00:06.560 --> 00:06.600 +164 - 00:06.560 + +00:06.600 --> 00:06.640 +165 - 00:06.600 + +00:06.640 --> 00:06.680 +166 - 00:06.640 + +00:06.680 --> 00:06.720 +167 - 00:06.680 + +00:06.720 --> 00:06.760 +168 - 00:06.720 + +00:06.760 --> 00:06.800 +169 - 00:06.760 + +00:06.800 --> 00:06.840 +170 - 00:06.800 + +00:06.840 --> 00:06.880 +171 - 00:06.840 + +00:06.880 --> 00:06.920 +172 - 00:06.880 + +00:06.920 --> 00:06.960 +173 - 00:06.920 + +00:06.960 --> 00:07.000 +174 - 00:06.960 + +00:07.000 --> 00:07.040 +175 - 00:07.000 + +00:07.040 --> 00:07.080 +176 - 00:07.040 + +00:07.080 --> 00:07.120 +177 - 00:07.080 + +00:07.120 --> 00:07.160 +178 - 00:07.120 + +00:07.160 --> 00:07.200 +179 - 00:07.160 + +00:07.200 --> 00:07.240 +180 - 00:07.200 + +00:07.240 --> 00:07.280 +181 - 00:07.240 + +00:07.280 --> 00:07.320 +182 - 00:07.280 + +00:07.320 --> 00:07.360 +183 - 00:07.320 + +00:07.360 --> 00:07.400 +184 - 00:07.360 + +00:07.400 --> 00:07.440 +185 - 00:07.400 + +00:07.440 --> 00:07.480 +186 - 00:07.440 + +00:07.480 --> 00:07.520 +187 - 00:07.480 + +00:07.520 --> 00:07.560 +188 - 00:07.520 + +00:07.560 --> 00:07.600 +189 - 00:07.560 + +00:07.600 --> 00:07.640 +190 - 00:07.600 + +00:07.640 --> 00:07.680 +191 - 00:07.640 + +00:07.680 --> 00:07.720 +192 - 00:07.680 + +00:07.720 --> 00:07.760 +193 - 00:07.720 + +00:07.760 --> 00:07.800 +194 - 00:07.760 + +00:07.800 --> 00:07.840 +195 - 00:07.800 + +00:07.840 --> 00:07.880 +196 - 00:07.840 + +00:07.880 --> 00:07.920 +197 - 00:07.880 + +00:07.920 --> 00:07.960 +198 - 00:07.920 + +00:07.960 --> 00:08.000 +199 - 00:07.960 + +00:08.000 --> 00:08.040 +200 - 00:08.000 + +00:08.040 --> 00:08.080 +201 - 00:08.040 + +00:08.080 --> 00:08.120 +202 - 00:08.080 + +00:08.120 --> 00:08.160 +203 - 00:08.120 + +00:08.160 --> 00:08.200 +204 - 00:08.160 + +00:08.200 --> 00:08.240 +205 - 00:08.200 + +00:08.240 --> 00:08.280 +206 - 00:08.240 + +00:08.280 --> 00:08.320 +207 - 00:08.280 + +00:08.320 --> 00:08.360 +208 - 00:08.320 + +00:08.360 --> 00:08.400 +209 - 00:08.360 + +00:08.400 --> 00:08.440 +210 - 00:08.400 + +00:08.440 --> 00:08.480 +211 - 00:08.440 + +00:08.480 --> 00:08.520 +212 - 00:08.480 + +00:08.520 --> 00:08.560 +213 - 00:08.520 + +00:08.560 --> 00:08.600 +214 - 00:08.560 + +00:08.600 --> 00:08.640 +215 - 00:08.600 + +00:08.640 --> 00:08.680 +216 - 00:08.640 + +00:08.680 --> 00:08.720 +217 - 00:08.680 + +00:08.720 --> 00:08.760 +218 - 00:08.720 + +00:08.760 --> 00:08.800 +219 - 00:08.760 + +00:08.800 --> 00:08.840 +220 - 00:08.800 + +00:08.840 --> 00:08.880 +221 - 00:08.840 + +00:08.880 --> 00:08.920 +222 - 00:08.880 + +00:08.920 --> 00:08.960 +223 - 00:08.920 + +00:08.960 --> 00:09.000 +224 - 00:08.960 + +00:09.000 --> 00:09.040 +225 - 00:09.000 + +00:09.040 --> 00:09.080 +226 - 00:09.040 + +00:09.080 --> 00:09.120 +227 - 00:09.080 + +00:09.120 --> 00:09.160 +228 - 00:09.120 + +00:09.160 --> 00:09.200 +229 - 00:09.160 + +00:09.200 --> 00:09.240 +230 - 00:09.200 + +00:09.240 --> 00:09.280 +231 - 00:09.240 + +00:09.280 --> 00:09.320 +232 - 00:09.280 + +00:09.320 --> 00:09.360 +233 - 00:09.320 + +00:09.360 --> 00:09.400 +234 - 00:09.360 + +00:09.400 --> 00:09.440 +235 - 00:09.400 + +00:09.440 --> 00:09.480 +236 - 00:09.440 + +00:09.480 --> 00:09.520 +237 - 00:09.480 + +00:09.520 --> 00:09.560 +238 - 00:09.520 + +00:09.560 --> 00:09.600 +239 - 00:09.560 + +00:09.600 --> 00:09.640 +240 - 00:09.600 + +00:09.640 --> 00:09.680 +241 - 00:09.640 + +00:09.680 --> 00:09.720 +242 - 00:09.680 + +00:09.720 --> 00:09.760 +243 - 00:09.720 + +00:09.760 --> 00:09.800 +244 - 00:09.760 + +00:09.800 --> 00:09.840 +245 - 00:09.800 + +00:09.840 --> 00:09.880 +246 - 00:09.840 + +00:09.880 --> 00:09.920 +247 - 00:09.880 + +00:09.920 --> 00:09.960 +248 - 00:09.920 + +00:09.960 --> 00:10.000 +249 - 00:09.960 + +00:10.000 --> 00:10.040 +250 - 00:10.000 + +00:10.040 --> 00:10.080 +251 - 00:10.040 + +00:10.080 --> 00:10.120 +252 - 00:10.080 + +00:10.120 --> 00:10.160 +253 - 00:10.120 + +00:10.160 --> 00:10.200 +254 - 00:10.160 + +00:10.200 --> 00:10.240 +255 - 00:10.200 + +00:10.240 --> 00:10.280 +256 - 00:10.240 + +00:10.280 --> 00:10.320 +257 - 00:10.280 + +00:10.320 --> 00:10.360 +258 - 00:10.320 + +00:10.360 --> 00:10.400 +259 - 00:10.360 + +00:10.400 --> 00:10.440 +260 - 00:10.400 + +00:10.440 --> 00:10.480 +261 - 00:10.440 + +00:10.480 --> 00:10.520 +262 - 00:10.480 + +00:10.520 --> 00:10.560 +263 - 00:10.520 + +00:10.560 --> 00:10.600 +264 - 00:10.560 + +00:10.600 --> 00:10.640 +265 - 00:10.600 + +00:10.640 --> 00:10.680 +266 - 00:10.640 + +00:10.680 --> 00:10.720 +267 - 00:10.680 + +00:10.720 --> 00:10.760 +268 - 00:10.720 + +00:10.760 --> 00:10.800 +269 - 00:10.760 + +00:10.800 --> 00:10.840 +270 - 00:10.800 + +00:10.840 --> 00:10.880 +271 - 00:10.840 + +00:10.880 --> 00:10.920 +272 - 00:10.880 + +00:10.920 --> 00:10.960 +273 - 00:10.920 + +00:10.960 --> 00:11.000 +274 - 00:10.960 + +00:11.000 --> 00:11.040 +275 - 00:11.000 + +00:11.040 --> 00:11.080 +276 - 00:11.040 + +00:11.080 --> 00:11.120 +277 - 00:11.080 + +00:11.120 --> 00:11.160 +278 - 00:11.120 + +00:11.160 --> 00:11.200 +279 - 00:11.160 + +00:11.200 --> 00:11.240 +280 - 00:11.200 + +00:11.240 --> 00:11.280 +281 - 00:11.240 + +00:11.280 --> 00:11.320 +282 - 00:11.280 + +00:11.320 --> 00:11.360 +283 - 00:11.320 + +00:11.360 --> 00:11.400 +284 - 00:11.360 + +00:11.400 --> 00:11.440 +285 - 00:11.400 + +00:11.440 --> 00:11.480 +286 - 00:11.440 + +00:11.480 --> 00:11.520 +287 - 00:11.480 + +00:11.520 --> 00:11.560 +288 - 00:11.520 + +00:11.560 --> 00:11.600 +289 - 00:11.560 + +00:11.600 --> 00:11.640 +290 - 00:11.600 + +00:11.640 --> 00:11.680 +291 - 00:11.640 + +00:11.680 --> 00:11.720 +292 - 00:11.680 + +00:11.720 --> 00:11.760 +293 - 00:11.720 + +00:11.760 --> 00:11.800 +294 - 00:11.760 + +00:11.800 --> 00:11.840 +295 - 00:11.800 + +00:11.840 --> 00:11.880 +296 - 00:11.840 + +00:11.880 --> 00:11.920 +297 - 00:11.880 + +00:11.920 --> 00:11.960 +298 - 00:11.920 + +00:11.960 --> 00:12.000 +299 - 00:11.960 + +00:12.000 --> 00:12.040 +300 - 00:12.000 + +00:12.040 --> 00:12.080 +301 - 00:12.040 + +00:12.080 --> 00:12.120 +302 - 00:12.080 + +00:12.120 --> 00:12.160 +303 - 00:12.120 + +00:12.160 --> 00:12.200 +304 - 00:12.160 + +00:12.200 --> 00:12.240 +305 - 00:12.200 + +00:12.240 --> 00:12.280 +306 - 00:12.240 + +00:12.280 --> 00:12.320 +307 - 00:12.280 + +00:12.320 --> 00:12.360 +308 - 00:12.320 + +00:12.360 --> 00:12.400 +309 - 00:12.360 + +00:12.400 --> 00:12.440 +310 - 00:12.400 + +00:12.440 --> 00:12.480 +311 - 00:12.440 + +00:12.480 --> 00:12.520 +312 - 00:12.480 + +00:12.520 --> 00:12.560 +313 - 00:12.520 + +00:12.560 --> 00:12.600 +314 - 00:12.560 + +00:12.600 --> 00:12.640 +315 - 00:12.600 + +00:12.640 --> 00:12.680 +316 - 00:12.640 + +00:12.680 --> 00:12.720 +317 - 00:12.680 + +00:12.720 --> 00:12.760 +318 - 00:12.720 + +00:12.760 --> 00:12.800 +319 - 00:12.760 + +00:12.800 --> 00:12.840 +320 - 00:12.800 + +00:12.840 --> 00:12.880 +321 - 00:12.840 + +00:12.880 --> 00:12.920 +322 - 00:12.880 + +00:12.920 --> 00:12.960 +323 - 00:12.920 + +00:12.960 --> 00:13.000 +324 - 00:12.960 + +00:13.000 --> 00:13.040 +325 - 00:13.000 + +00:13.040 --> 00:13.080 +326 - 00:13.040 + +00:13.080 --> 00:13.120 +327 - 00:13.080 + +00:13.120 --> 00:13.160 +328 - 00:13.120 + +00:13.160 --> 00:13.200 +329 - 00:13.160 + +00:13.200 --> 00:13.240 +330 - 00:13.200 + +00:13.240 --> 00:13.280 +331 - 00:13.240 + +00:13.280 --> 00:13.320 +332 - 00:13.280 + +00:13.320 --> 00:13.360 +333 - 00:13.320 + +00:13.360 --> 00:13.400 +334 - 00:13.360 + +00:13.400 --> 00:13.440 +335 - 00:13.400 + +00:13.440 --> 00:13.480 +336 - 00:13.440 + +00:13.480 --> 00:13.520 +337 - 00:13.480 + +00:13.520 --> 00:13.560 +338 - 00:13.520 + +00:13.560 --> 00:13.600 +339 - 00:13.560 + +00:13.600 --> 00:13.640 +340 - 00:13.600 + +00:13.640 --> 00:13.680 +341 - 00:13.640 + +00:13.680 --> 00:13.720 +342 - 00:13.680 + +00:13.720 --> 00:13.760 +343 - 00:13.720 + +00:13.760 --> 00:13.800 +344 - 00:13.760 + +00:13.800 --> 00:13.840 +345 - 00:13.800 + +00:13.840 --> 00:13.880 +346 - 00:13.840 + +00:13.880 --> 00:13.920 +347 - 00:13.880 + +00:13.920 --> 00:13.960 +348 - 00:13.920 + +00:13.960 --> 00:14.000 +349 - 00:13.960 + +00:14.000 --> 00:14.040 +350 - 00:14.000 + +00:14.040 --> 00:14.080 +351 - 00:14.040 + +00:14.080 --> 00:14.120 +352 - 00:14.080 + +00:14.120 --> 00:14.160 +353 - 00:14.120 + +00:14.160 --> 00:14.200 +354 - 00:14.160 + +00:14.200 --> 00:14.240 +355 - 00:14.200 + +00:14.240 --> 00:14.280 +356 - 00:14.240 + +00:14.280 --> 00:14.320 +357 - 00:14.280 + +00:14.320 --> 00:14.360 +358 - 00:14.320 + +00:14.360 --> 00:14.400 +359 - 00:14.360 + +00:14.400 --> 00:14.440 +360 - 00:14.400 + +00:14.440 --> 00:14.480 +361 - 00:14.440 + +00:14.480 --> 00:14.520 +362 - 00:14.480 + +00:14.520 --> 00:14.560 +363 - 00:14.520 + +00:14.560 --> 00:14.600 +364 - 00:14.560 + +00:14.600 --> 00:14.640 +365 - 00:14.600 + +00:14.640 --> 00:14.680 +366 - 00:14.640 + +00:14.680 --> 00:14.720 +367 - 00:14.680 + +00:14.720 --> 00:14.760 +368 - 00:14.720 + +00:14.760 --> 00:14.800 +369 - 00:14.760 + +00:14.800 --> 00:14.840 +370 - 00:14.800 + +00:14.840 --> 00:14.880 +371 - 00:14.840 + +00:14.880 --> 00:14.920 +372 - 00:14.880 + +00:14.920 --> 00:14.960 +373 - 00:14.920 + +00:14.960 --> 00:15.000 +374 - 00:14.960 + +00:15.000 --> 00:15.040 +375 - 00:15.000 + +00:15.040 --> 00:15.080 +376 - 00:15.040 + +00:15.080 --> 00:15.120 +377 - 00:15.080 + +00:15.120 --> 00:15.160 +378 - 00:15.120 + +00:15.160 --> 00:15.200 +379 - 00:15.160 + +00:15.200 --> 00:15.240 +380 - 00:15.200 + +00:15.240 --> 00:15.280 +381 - 00:15.240 + +00:15.280 --> 00:15.320 +382 - 00:15.280 + +00:15.320 --> 00:15.360 +383 - 00:15.320 + +00:15.360 --> 00:15.400 +384 - 00:15.360 + +00:15.400 --> 00:15.440 +385 - 00:15.400 + +00:15.440 --> 00:15.480 +386 - 00:15.440 + +00:15.480 --> 00:15.520 +387 - 00:15.480 + +00:15.520 --> 00:15.560 +388 - 00:15.520 + +00:15.560 --> 00:15.600 +389 - 00:15.560 + +00:15.600 --> 00:15.640 +390 - 00:15.600 + +00:15.640 --> 00:15.680 +391 - 00:15.640 + +00:15.680 --> 00:15.720 +392 - 00:15.680 + +00:15.720 --> 00:15.760 +393 - 00:15.720 + +00:15.760 --> 00:15.800 +394 - 00:15.760 + +00:15.800 --> 00:15.840 +395 - 00:15.800 + +00:15.840 --> 00:15.880 +396 - 00:15.840 + +00:15.880 --> 00:15.920 +397 - 00:15.880 + +00:15.920 --> 00:15.960 +398 - 00:15.920 + +00:15.960 --> 00:16.000 +399 - 00:15.960 + +00:16.000 --> 00:16.040 +400 - 00:16.000 + +00:16.040 --> 00:16.080 +401 - 00:16.040 + +00:16.080 --> 00:16.120 +402 - 00:16.080 + +00:16.120 --> 00:16.160 +403 - 00:16.120 + +00:16.160 --> 00:16.200 +404 - 00:16.160 + +00:16.200 --> 00:16.240 +405 - 00:16.200 + +00:16.240 --> 00:16.280 +406 - 00:16.240 + +00:16.280 --> 00:16.320 +407 - 00:16.280 + +00:16.320 --> 00:16.360 +408 - 00:16.320 + +00:16.360 --> 00:16.400 +409 - 00:16.360 + +00:16.400 --> 00:16.440 +410 - 00:16.400 + +00:16.440 --> 00:16.480 +411 - 00:16.440 + +00:16.480 --> 00:16.520 +412 - 00:16.480 + +00:16.520 --> 00:16.560 +413 - 00:16.520 + +00:16.560 --> 00:16.600 +414 - 00:16.560 + +00:16.600 --> 00:16.640 +415 - 00:16.600 + +00:16.640 --> 00:16.680 +416 - 00:16.640 + +00:16.680 --> 00:16.720 +417 - 00:16.680 + +00:16.720 --> 00:16.760 +418 - 00:16.720 + +00:16.760 --> 00:16.800 +419 - 00:16.760 + +00:16.800 --> 00:16.840 +420 - 00:16.800 + +00:16.840 --> 00:16.880 +421 - 00:16.840 + +00:16.880 --> 00:16.920 +422 - 00:16.880 + +00:16.920 --> 00:16.960 +423 - 00:16.920 + +00:16.960 --> 00:17.000 +424 - 00:16.960 + +00:17.000 --> 00:17.040 +425 - 00:17.000 + +00:17.040 --> 00:17.080 +426 - 00:17.040 + +00:17.080 --> 00:17.120 +427 - 00:17.080 + +00:17.120 --> 00:17.160 +428 - 00:17.120 + +00:17.160 --> 00:17.200 +429 - 00:17.160 + +00:17.200 --> 00:17.240 +430 - 00:17.200 + +00:17.240 --> 00:17.280 +431 - 00:17.240 + +00:17.280 --> 00:17.320 +432 - 00:17.280 + +00:17.320 --> 00:17.360 +433 - 00:17.320 + +00:17.360 --> 00:17.400 +434 - 00:17.360 + +00:17.400 --> 00:17.440 +435 - 00:17.400 + +00:17.440 --> 00:17.480 +436 - 00:17.440 + +00:17.480 --> 00:17.520 +437 - 00:17.480 + +00:17.520 --> 00:17.560 +438 - 00:17.520 + +00:17.560 --> 00:17.600 +439 - 00:17.560 + +00:17.600 --> 00:17.640 +440 - 00:17.600 + +00:17.640 --> 00:17.680 +441 - 00:17.640 + +00:17.680 --> 00:17.720 +442 - 00:17.680 + +00:17.720 --> 00:17.760 +443 - 00:17.720 + +00:17.760 --> 00:17.800 +444 - 00:17.760 + +00:17.800 --> 00:17.840 +445 - 00:17.800 + +00:17.840 --> 00:17.880 +446 - 00:17.840 + +00:17.880 --> 00:17.920 +447 - 00:17.880 + +00:17.920 --> 00:17.960 +448 - 00:17.920 + +00:17.960 --> 00:18.000 +449 - 00:17.960 + +00:18.000 --> 00:18.040 +450 - 00:18.000 + +00:18.040 --> 00:18.080 +451 - 00:18.040 + +00:18.080 --> 00:18.120 +452 - 00:18.080 + +00:18.120 --> 00:18.160 +453 - 00:18.120 + +00:18.160 --> 00:18.200 +454 - 00:18.160 + +00:18.200 --> 00:18.240 +455 - 00:18.200 + +00:18.240 --> 00:18.280 +456 - 00:18.240 + +00:18.280 --> 00:18.320 +457 - 00:18.280 + +00:18.320 --> 00:18.360 +458 - 00:18.320 + +00:18.360 --> 00:18.400 +459 - 00:18.360 + +00:18.400 --> 00:18.440 +460 - 00:18.400 + +00:18.440 --> 00:18.480 +461 - 00:18.440 + +00:18.480 --> 00:18.520 +462 - 00:18.480 + +00:18.520 --> 00:18.560 +463 - 00:18.520 + +00:18.560 --> 00:18.600 +464 - 00:18.560 + +00:18.600 --> 00:18.640 +465 - 00:18.600 + +00:18.640 --> 00:18.680 +466 - 00:18.640 + +00:18.680 --> 00:18.720 +467 - 00:18.680 + +00:18.720 --> 00:18.760 +468 - 00:18.720 + +00:18.760 --> 00:18.800 +469 - 00:18.760 + +00:18.800 --> 00:18.840 +470 - 00:18.800 + +00:18.840 --> 00:18.880 +471 - 00:18.840 + +00:18.880 --> 00:18.920 +472 - 00:18.880 + +00:18.920 --> 00:18.960 +473 - 00:18.920 + +00:18.960 --> 00:19.000 +474 - 00:18.960 + +00:19.000 --> 00:19.040 +475 - 00:19.000 + +00:19.040 --> 00:19.080 +476 - 00:19.040 + +00:19.080 --> 00:19.120 +477 - 00:19.080 + +00:19.120 --> 00:19.160 +478 - 00:19.120 + +00:19.160 --> 00:19.200 +479 - 00:19.160 + +00:19.200 --> 00:19.240 +480 - 00:19.200 + +00:19.240 --> 00:19.280 +481 - 00:19.240 + +00:19.280 --> 00:19.320 +482 - 00:19.280 + +00:19.320 --> 00:19.360 +483 - 00:19.320 + +00:19.360 --> 00:19.400 +484 - 00:19.360 + +00:19.400 --> 00:19.440 +485 - 00:19.400 + +00:19.440 --> 00:19.480 +486 - 00:19.440 + +00:19.480 --> 00:19.520 +487 - 00:19.480 + +00:19.520 --> 00:19.560 +488 - 00:19.520 + +00:19.560 --> 00:19.600 +489 - 00:19.560 + +00:19.600 --> 00:19.640 +490 - 00:19.600 + +00:19.640 --> 00:19.680 +491 - 00:19.640 + +00:19.680 --> 00:19.720 +492 - 00:19.680 + +00:19.720 --> 00:19.760 +493 - 00:19.720 + +00:19.760 --> 00:19.800 +494 - 00:19.760 + +00:19.800 --> 00:19.840 +495 - 00:19.800 + +00:19.840 --> 00:19.880 +496 - 00:19.840 + +00:19.880 --> 00:19.920 +497 - 00:19.880 + +00:19.920 --> 00:19.960 +498 - 00:19.920 + +00:19.960 --> 00:20.000 +499 - 00:19.960 + +00:20.000 --> 00:20.040 +500 - 00:20.000 + +00:20.040 --> 00:20.080 +501 - 00:20.040 + +00:20.080 --> 00:20.120 +502 - 00:20.080 + +00:20.120 --> 00:20.160 +503 - 00:20.120 + +00:20.160 --> 00:20.200 +504 - 00:20.160 + +00:20.200 --> 00:20.240 +505 - 00:20.200 + +00:20.240 --> 00:20.280 +506 - 00:20.240 + +00:20.280 --> 00:20.320 +507 - 00:20.280 + +00:20.320 --> 00:20.360 +508 - 00:20.320 + +00:20.360 --> 00:20.400 +509 - 00:20.360 + +00:20.400 --> 00:20.440 +510 - 00:20.400 + +00:20.440 --> 00:20.480 +511 - 00:20.440 + +00:20.480 --> 00:20.520 +512 - 00:20.480 + +00:20.520 --> 00:20.560 +513 - 00:20.520 + +00:20.560 --> 00:20.600 +514 - 00:20.560 + +00:20.600 --> 00:20.640 +515 - 00:20.600 + +00:20.640 --> 00:20.680 +516 - 00:20.640 + +00:20.680 --> 00:20.720 +517 - 00:20.680 + +00:20.720 --> 00:20.760 +518 - 00:20.720 + +00:20.760 --> 00:20.800 +519 - 00:20.760 + +00:20.800 --> 00:20.840 +520 - 00:20.800 + +00:20.840 --> 00:20.880 +521 - 00:20.840 + +00:20.880 --> 00:20.920 +522 - 00:20.880 + +00:20.920 --> 00:20.960 +523 - 00:20.920 + +00:20.960 --> 00:21.000 +524 - 00:20.960 + +00:21.000 --> 00:21.040 +525 - 00:21.000 + +00:21.040 --> 00:21.080 +526 - 00:21.040 + +00:21.080 --> 00:21.120 +527 - 00:21.080 + +00:21.120 --> 00:21.160 +528 - 00:21.120 + +00:21.160 --> 00:21.200 +529 - 00:21.160 + +00:21.200 --> 00:21.240 +530 - 00:21.200 + +00:21.240 --> 00:21.280 +531 - 00:21.240 + +00:21.280 --> 00:21.320 +532 - 00:21.280 + +00:21.320 --> 00:21.360 +533 - 00:21.320 + +00:21.360 --> 00:21.400 +534 - 00:21.360 + +00:21.400 --> 00:21.440 +535 - 00:21.400 + +00:21.440 --> 00:21.480 +536 - 00:21.440 + +00:21.480 --> 00:21.520 +537 - 00:21.480 + +00:21.520 --> 00:21.560 +538 - 00:21.520 + +00:21.560 --> 00:21.600 +539 - 00:21.560 + +00:21.600 --> 00:21.640 +540 - 00:21.600 + +00:21.640 --> 00:21.680 +541 - 00:21.640 + +00:21.680 --> 00:21.720 +542 - 00:21.680 + +00:21.720 --> 00:21.760 +543 - 00:21.720 + +00:21.760 --> 00:21.800 +544 - 00:21.760 + +00:21.800 --> 00:21.840 +545 - 00:21.800 + +00:21.840 --> 00:21.880 +546 - 00:21.840 + +00:21.880 --> 00:21.920 +547 - 00:21.880 + +00:21.920 --> 00:21.960 +548 - 00:21.920 + +00:21.960 --> 00:22.000 +549 - 00:21.960 + +00:22.000 --> 00:22.040 +550 - 00:22.000 + +00:22.040 --> 00:22.080 +551 - 00:22.040 + +00:22.080 --> 00:22.120 +552 - 00:22.080 + +00:22.120 --> 00:22.160 +553 - 00:22.120 + +00:22.160 --> 00:22.200 +554 - 00:22.160 + +00:22.200 --> 00:22.240 +555 - 00:22.200 + +00:22.240 --> 00:22.280 +556 - 00:22.240 + +00:22.280 --> 00:22.320 +557 - 00:22.280 + +00:22.320 --> 00:22.360 +558 - 00:22.320 + +00:22.360 --> 00:22.400 +559 - 00:22.360 + +00:22.400 --> 00:22.440 +560 - 00:22.400 + +00:22.440 --> 00:22.480 +561 - 00:22.440 + +00:22.480 --> 00:22.520 +562 - 00:22.480 + +00:22.520 --> 00:22.560 +563 - 00:22.520 + +00:22.560 --> 00:22.600 +564 - 00:22.560 + +00:22.600 --> 00:22.640 +565 - 00:22.600 + +00:22.640 --> 00:22.680 +566 - 00:22.640 + +00:22.680 --> 00:22.720 +567 - 00:22.680 + +00:22.720 --> 00:22.760 +568 - 00:22.720 + +00:22.760 --> 00:22.800 +569 - 00:22.760 + +00:22.800 --> 00:22.840 +570 - 00:22.800 + +00:22.840 --> 00:22.880 +571 - 00:22.840 + +00:22.880 --> 00:22.920 +572 - 00:22.880 + +00:22.920 --> 00:22.960 +573 - 00:22.920 + +00:22.960 --> 00:23.000 +574 - 00:22.960 + +00:23.000 --> 00:23.040 +575 - 00:23.000 + +00:23.040 --> 00:23.080 +576 - 00:23.040 + +00:23.080 --> 00:23.120 +577 - 00:23.080 + +00:23.120 --> 00:23.160 +578 - 00:23.120 + +00:23.160 --> 00:23.200 +579 - 00:23.160 + +00:23.200 --> 00:23.240 +580 - 00:23.200 + +00:23.240 --> 00:23.280 +581 - 00:23.240 + +00:23.280 --> 00:23.320 +582 - 00:23.280 + +00:23.320 --> 00:23.360 +583 - 00:23.320 + +00:23.360 --> 00:23.400 +584 - 00:23.360 + +00:23.400 --> 00:23.440 +585 - 00:23.400 + +00:23.440 --> 00:23.480 +586 - 00:23.440 + +00:23.480 --> 00:23.520 +587 - 00:23.480 + +00:23.520 --> 00:23.560 +588 - 00:23.520 + +00:23.560 --> 00:23.600 +589 - 00:23.560 + +00:23.600 --> 00:23.640 +590 - 00:23.600 + +00:23.640 --> 00:23.680 +591 - 00:23.640 + +00:23.680 --> 00:23.720 +592 - 00:23.680 + +00:23.720 --> 00:23.760 +593 - 00:23.720 + +00:23.760 --> 00:23.800 +594 - 00:23.760 + +00:23.800 --> 00:23.840 +595 - 00:23.800 + +00:23.840 --> 00:23.880 +596 - 00:23.840 + +00:23.880 --> 00:23.920 +597 - 00:23.880 + +00:23.920 --> 00:23.960 +598 - 00:23.920 + +00:23.960 --> 00:24.000 +599 - 00:23.960 + +00:24.000 --> 00:24.040 +600 - 00:24.000 + +00:24.040 --> 00:24.080 +601 - 00:24.040 + +00:24.080 --> 00:24.120 +602 - 00:24.080 + +00:24.120 --> 00:24.160 +603 - 00:24.120 + +00:24.160 --> 00:24.200 +604 - 00:24.160 + +00:24.200 --> 00:24.240 +605 - 00:24.200 + +00:24.240 --> 00:24.280 +606 - 00:24.240 + +00:24.280 --> 00:24.320 +607 - 00:24.280 + +00:24.320 --> 00:24.360 +608 - 00:24.320 + +00:24.360 --> 00:24.400 +609 - 00:24.360 + +00:24.400 --> 00:24.440 +610 - 00:24.400 + +00:24.440 --> 00:24.480 +611 - 00:24.440 + +00:24.480 --> 00:24.520 +612 - 00:24.480 + +00:24.520 --> 00:24.560 +613 - 00:24.520 + +00:24.560 --> 00:24.600 +614 - 00:24.560 + +00:24.600 --> 00:24.640 +615 - 00:24.600 + +00:24.640 --> 00:24.680 +616 - 00:24.640 + +00:24.680 --> 00:24.720 +617 - 00:24.680 + +00:24.720 --> 00:24.760 +618 - 00:24.720 + +00:24.760 --> 00:24.800 +619 - 00:24.760 + +00:24.800 --> 00:24.840 +620 - 00:24.800 + +00:24.840 --> 00:24.880 +621 - 00:24.840 + +00:24.880 --> 00:24.920 +622 - 00:24.880 + +00:24.920 --> 00:24.960 +623 - 00:24.920 + +00:24.960 --> 00:25.000 +624 - 00:24.960 + +00:25.000 --> 00:25.040 +625 - 00:25.000 + +00:25.040 --> 00:25.080 +626 - 00:25.040 + +00:25.080 --> 00:25.120 +627 - 00:25.080 + +00:25.120 --> 00:25.160 +628 - 00:25.120 + +00:25.160 --> 00:25.200 +629 - 00:25.160 + +00:25.200 --> 00:25.240 +630 - 00:25.200 + +00:25.240 --> 00:25.280 +631 - 00:25.240 + +00:25.280 --> 00:25.320 +632 - 00:25.280 + +00:25.320 --> 00:25.360 +633 - 00:25.320 + +00:25.360 --> 00:25.400 +634 - 00:25.360 + +00:25.400 --> 00:25.440 +635 - 00:25.400 + +00:25.440 --> 00:25.480 +636 - 00:25.440 + +00:25.480 --> 00:25.520 +637 - 00:25.480 + +00:25.520 --> 00:25.560 +638 - 00:25.520 + +00:25.560 --> 00:25.600 +639 - 00:25.560 + +00:25.600 --> 00:25.640 +640 - 00:25.600 + +00:25.640 --> 00:25.680 +641 - 00:25.640 + +00:25.680 --> 00:25.720 +642 - 00:25.680 + +00:25.720 --> 00:25.760 +643 - 00:25.720 + +00:25.760 --> 00:25.800 +644 - 00:25.760 + +00:25.800 --> 00:25.840 +645 - 00:25.800 + +00:25.840 --> 00:25.880 +646 - 00:25.840 + +00:25.880 --> 00:25.920 +647 - 00:25.880 + +00:25.920 --> 00:25.960 +648 - 00:25.920 + +00:25.960 --> 00:26.000 +649 - 00:25.960 + +00:26.000 --> 00:26.040 +650 - 00:26.000 + +00:26.040 --> 00:26.080 +651 - 00:26.040 + +00:26.080 --> 00:26.120 +652 - 00:26.080 + +00:26.120 --> 00:26.160 +653 - 00:26.120 + +00:26.160 --> 00:26.200 +654 - 00:26.160 + +00:26.200 --> 00:26.240 +655 - 00:26.200 + +00:26.240 --> 00:26.280 +656 - 00:26.240 + +00:26.280 --> 00:26.320 +657 - 00:26.280 + +00:26.320 --> 00:26.360 +658 - 00:26.320 + +00:26.360 --> 00:26.400 +659 - 00:26.360 + +00:26.400 --> 00:26.440 +660 - 00:26.400 + +00:26.440 --> 00:26.480 +661 - 00:26.440 + +00:26.480 --> 00:26.520 +662 - 00:26.480 + +00:26.520 --> 00:26.560 +663 - 00:26.520 + +00:26.560 --> 00:26.600 +664 - 00:26.560 + +00:26.600 --> 00:26.640 +665 - 00:26.600 + +00:26.640 --> 00:26.680 +666 - 00:26.640 + +00:26.680 --> 00:26.720 +667 - 00:26.680 + +00:26.720 --> 00:26.760 +668 - 00:26.720 + +00:26.760 --> 00:26.800 +669 - 00:26.760 + +00:26.800 --> 00:26.840 +670 - 00:26.800 + +00:26.840 --> 00:26.880 +671 - 00:26.840 + +00:26.880 --> 00:26.920 +672 - 00:26.880 + +00:26.920 --> 00:26.960 +673 - 00:26.920 + +00:26.960 --> 00:27.000 +674 - 00:26.960 + +00:27.000 --> 00:27.040 +675 - 00:27.000 + +00:27.040 --> 00:27.080 +676 - 00:27.040 + +00:27.080 --> 00:27.120 +677 - 00:27.080 + +00:27.120 --> 00:27.160 +678 - 00:27.120 + +00:27.160 --> 00:27.200 +679 - 00:27.160 + +00:27.200 --> 00:27.240 +680 - 00:27.200 + +00:27.240 --> 00:27.280 +681 - 00:27.240 + +00:27.280 --> 00:27.320 +682 - 00:27.280 + +00:27.320 --> 00:27.360 +683 - 00:27.320 + +00:27.360 --> 00:27.400 +684 - 00:27.360 + +00:27.400 --> 00:27.440 +685 - 00:27.400 + +00:27.440 --> 00:27.480 +686 - 00:27.440 + +00:27.480 --> 00:27.520 +687 - 00:27.480 + +00:27.520 --> 00:27.560 +688 - 00:27.520 + +00:27.560 --> 00:27.600 +689 - 00:27.560 + +00:27.600 --> 00:27.640 +690 - 00:27.600 + +00:27.640 --> 00:27.680 +691 - 00:27.640 + +00:27.680 --> 00:27.720 +692 - 00:27.680 + +00:27.720 --> 00:27.760 +693 - 00:27.720 + +00:27.760 --> 00:27.800 +694 - 00:27.760 + +00:27.800 --> 00:27.840 +695 - 00:27.800 + +00:27.840 --> 00:27.880 +696 - 00:27.840 + +00:27.880 --> 00:27.920 +697 - 00:27.880 + +00:27.920 --> 00:27.960 +698 - 00:27.920 + +00:27.960 --> 00:28.000 +699 - 00:27.960 + +00:28.000 --> 00:28.040 +700 - 00:28.000 + +00:28.040 --> 00:28.080 +701 - 00:28.040 + +00:28.080 --> 00:28.120 +702 - 00:28.080 + +00:28.120 --> 00:28.160 +703 - 00:28.120 + +00:28.160 --> 00:28.200 +704 - 00:28.160 + +00:28.200 --> 00:28.240 +705 - 00:28.200 + +00:28.240 --> 00:28.280 +706 - 00:28.240 + +00:28.280 --> 00:28.320 +707 - 00:28.280 + +00:28.320 --> 00:28.360 +708 - 00:28.320 + +00:28.360 --> 00:28.400 +709 - 00:28.360 + +00:28.400 --> 00:28.440 +710 - 00:28.400 + +00:28.440 --> 00:28.480 +711 - 00:28.440 + +00:28.480 --> 00:28.520 +712 - 00:28.480 + +00:28.520 --> 00:28.560 +713 - 00:28.520 + +00:28.560 --> 00:28.600 +714 - 00:28.560 + +00:28.600 --> 00:28.640 +715 - 00:28.600 + +00:28.640 --> 00:28.680 +716 - 00:28.640 + +00:28.680 --> 00:28.720 +717 - 00:28.680 + +00:28.720 --> 00:28.760 +718 - 00:28.720 + +00:28.760 --> 00:28.800 +719 - 00:28.760 + +00:28.800 --> 00:28.840 +720 - 00:28.800 + +00:28.840 --> 00:28.880 +721 - 00:28.840 + +00:28.880 --> 00:28.920 +722 - 00:28.880 + +00:28.920 --> 00:28.960 +723 - 00:28.920 + +00:28.960 --> 00:29.000 +724 - 00:28.960 + +00:29.000 --> 00:29.040 +725 - 00:29.000 + +00:29.040 --> 00:29.080 +726 - 00:29.040 + +00:29.080 --> 00:29.120 +727 - 00:29.080 + +00:29.120 --> 00:29.160 +728 - 00:29.120 + +00:29.160 --> 00:29.200 +729 - 00:29.160 + +00:29.200 --> 00:29.240 +730 - 00:29.200 + +00:29.240 --> 00:29.280 +731 - 00:29.240 + +00:29.280 --> 00:29.320 +732 - 00:29.280 + +00:29.320 --> 00:29.360 +733 - 00:29.320 + +00:29.360 --> 00:29.400 +734 - 00:29.360 + +00:29.400 --> 00:29.440 +735 - 00:29.400 + +00:29.440 --> 00:29.480 +736 - 00:29.440 + +00:29.480 --> 00:29.520 +737 - 00:29.480 + +00:29.520 --> 00:29.560 +738 - 00:29.520 + +00:29.560 --> 00:29.600 +739 - 00:29.560 + +00:29.600 --> 00:29.640 +740 - 00:29.600 + +00:29.640 --> 00:29.680 +741 - 00:29.640 + +00:29.680 --> 00:29.720 +742 - 00:29.680 + +00:29.720 --> 00:29.760 +743 - 00:29.720 + +00:29.760 --> 00:29.800 +744 - 00:29.760 + +00:29.800 --> 00:29.840 +745 - 00:29.800 + +00:29.840 --> 00:29.880 +746 - 00:29.840 + +00:29.880 --> 00:29.920 +747 - 00:29.880 + +00:29.920 --> 00:29.960 +748 - 00:29.920 + +00:29.960 --> 00:30.000 +749 - 00:29.960 + +00:30.000 --> 00:30.040 +750 - 00:30.000 + +00:30.040 --> 00:30.080 +751 - 00:30.040 + +00:30.080 --> 00:30.120 +752 - 00:30.080 + +00:30.120 --> 00:30.160 +753 - 00:30.120 + +00:30.160 --> 00:30.200 +754 - 00:30.160 + +00:30.200 --> 00:30.240 +755 - 00:30.200 + +00:30.240 --> 00:30.280 +756 - 00:30.240 + +00:30.280 --> 00:30.320 +757 - 00:30.280 + +00:30.320 --> 00:30.360 +758 - 00:30.320 + +00:30.360 --> 00:30.400 +759 - 00:30.360 + +00:30.400 --> 00:30.440 +760 - 00:30.400 + +00:30.440 --> 00:30.480 +761 - 00:30.440 + +00:30.480 --> 00:30.520 +762 - 00:30.480 + +00:30.520 --> 00:30.560 +763 - 00:30.520 + +00:30.560 --> 00:30.600 +764 - 00:30.560 + +00:30.600 --> 00:30.640 +765 - 00:30.600 + +00:30.640 --> 00:30.680 +766 - 00:30.640 + +00:30.680 --> 00:30.720 +767 - 00:30.680 + +00:30.720 --> 00:30.760 +768 - 00:30.720 + +00:30.760 --> 00:30.800 +769 - 00:30.760 + +00:30.800 --> 00:30.840 +770 - 00:30.800 + +00:30.840 --> 00:30.880 +771 - 00:30.840 + +00:30.880 --> 00:30.920 +772 - 00:30.880 + +00:30.920 --> 00:30.960 +773 - 00:30.920 + +00:30.960 --> 00:31.000 +774 - 00:30.960 + +00:31.000 --> 00:31.040 +775 - 00:31.000 + +00:31.040 --> 00:31.080 +776 - 00:31.040 + +00:31.080 --> 00:31.120 +777 - 00:31.080 + +00:31.120 --> 00:31.160 +778 - 00:31.120 + +00:31.160 --> 00:31.200 +779 - 00:31.160 + +00:31.200 --> 00:31.240 +780 - 00:31.200 + +00:31.240 --> 00:31.280 +781 - 00:31.240 + +00:31.280 --> 00:31.320 +782 - 00:31.280 + +00:31.320 --> 00:31.360 +783 - 00:31.320 + +00:31.360 --> 00:31.400 +784 - 00:31.360 + +00:31.400 --> 00:31.440 +785 - 00:31.400 + +00:31.440 --> 00:31.480 +786 - 00:31.440 + +00:31.480 --> 00:31.520 +787 - 00:31.480 + +00:31.520 --> 00:31.560 +788 - 00:31.520 + +00:31.560 --> 00:31.600 +789 - 00:31.560 + +00:31.600 --> 00:31.640 +790 - 00:31.600 + +00:31.640 --> 00:31.680 +791 - 00:31.640 + +00:31.680 --> 00:31.720 +792 - 00:31.680 + +00:31.720 --> 00:31.760 +793 - 00:31.720 + +00:31.760 --> 00:31.800 +794 - 00:31.760 + +00:31.800 --> 00:31.840 +795 - 00:31.800 + +00:31.840 --> 00:31.880 +796 - 00:31.840 + +00:31.880 --> 00:31.920 +797 - 00:31.880 + +00:31.920 --> 00:31.960 +798 - 00:31.920 + +00:31.960 --> 00:32.000 +799 - 00:31.960 + +00:32.000 --> 00:32.040 +800 - 00:32.000 + +00:32.040 --> 00:32.080 +801 - 00:32.040 + +00:32.080 --> 00:32.120 +802 - 00:32.080 + +00:32.120 --> 00:32.160 +803 - 00:32.120 + +00:32.160 --> 00:32.200 +804 - 00:32.160 + +00:32.200 --> 00:32.240 +805 - 00:32.200 + +00:32.240 --> 00:32.280 +806 - 00:32.240 + +00:32.280 --> 00:32.320 +807 - 00:32.280 + +00:32.320 --> 00:32.360 +808 - 00:32.320 + +00:32.360 --> 00:32.400 +809 - 00:32.360 + +00:32.400 --> 00:32.440 +810 - 00:32.400 + +00:32.440 --> 00:32.480 +811 - 00:32.440 + +00:32.480 --> 00:32.520 +812 - 00:32.480 + +00:32.520 --> 00:32.560 +813 - 00:32.520 + +00:32.560 --> 00:32.600 +814 - 00:32.560 + +00:32.600 --> 00:32.640 +815 - 00:32.600 + +00:32.640 --> 00:32.680 +816 - 00:32.640 + +00:32.680 --> 00:32.720 +817 - 00:32.680 + +00:32.720 --> 00:32.760 +818 - 00:32.720 + +00:32.760 --> 00:32.800 +819 - 00:32.760 + +00:32.800 --> 00:32.840 +820 - 00:32.800 + +00:32.840 --> 00:32.880 +821 - 00:32.840 + +00:32.880 --> 00:32.920 +822 - 00:32.880 + +00:32.920 --> 00:32.960 +823 - 00:32.920 + +00:32.960 --> 00:33.000 +824 - 00:32.960 + +00:33.000 --> 00:33.040 +825 - 00:33.000 + +00:33.040 --> 00:33.080 +826 - 00:33.040 + +00:33.080 --> 00:33.120 +827 - 00:33.080 + +00:33.120 --> 00:33.160 +828 - 00:33.120 + +00:33.160 --> 00:33.200 +829 - 00:33.160 + +00:33.200 --> 00:33.240 +830 - 00:33.200 + +00:33.240 --> 00:33.280 +831 - 00:33.240 + +00:33.280 --> 00:33.320 +832 - 00:33.280 + +00:33.320 --> 00:33.360 +833 - 00:33.320 + +00:33.360 --> 00:33.400 +834 - 00:33.360 + +00:33.400 --> 00:33.440 +835 - 00:33.400 + +00:33.440 --> 00:33.480 +836 - 00:33.440 + +00:33.480 --> 00:33.520 +837 - 00:33.480 + +00:33.520 --> 00:33.560 +838 - 00:33.520 + +00:33.560 --> 00:33.600 +839 - 00:33.560 + +00:33.600 --> 00:33.640 +840 - 00:33.600 + +00:33.640 --> 00:33.680 +841 - 00:33.640 + +00:33.680 --> 00:33.720 +842 - 00:33.680 + +00:33.720 --> 00:33.760 +843 - 00:33.720 + +00:33.760 --> 00:33.800 +844 - 00:33.760 + +00:33.800 --> 00:33.840 +845 - 00:33.800 + +00:33.840 --> 00:33.880 +846 - 00:33.840 + +00:33.880 --> 00:33.920 +847 - 00:33.880 + +00:33.920 --> 00:33.960 +848 - 00:33.920 + +00:33.960 --> 00:34.000 +849 - 00:33.960 + +00:34.000 --> 00:34.040 +850 - 00:34.000 + +00:34.040 --> 00:34.080 +851 - 00:34.040 + +00:34.080 --> 00:34.120 +852 - 00:34.080 + +00:34.120 --> 00:34.160 +853 - 00:34.120 + +00:34.160 --> 00:34.200 +854 - 00:34.160 + +00:34.200 --> 00:34.240 +855 - 00:34.200 + +00:34.240 --> 00:34.280 +856 - 00:34.240 + +00:34.280 --> 00:34.320 +857 - 00:34.280 + +00:34.320 --> 00:34.360 +858 - 00:34.320 + +00:34.360 --> 00:34.400 +859 - 00:34.360 + +00:34.400 --> 00:34.440 +860 - 00:34.400 + +00:34.440 --> 00:34.480 +861 - 00:34.440 + +00:34.480 --> 00:34.520 +862 - 00:34.480 + +00:34.520 --> 00:34.560 +863 - 00:34.520 + +00:34.560 --> 00:34.600 +864 - 00:34.560 + +00:34.600 --> 00:34.640 +865 - 00:34.600 + +00:34.640 --> 00:34.680 +866 - 00:34.640 + +00:34.680 --> 00:34.720 +867 - 00:34.680 + +00:34.720 --> 00:34.760 +868 - 00:34.720 + +00:34.760 --> 00:34.800 +869 - 00:34.760 + +00:34.800 --> 00:34.840 +870 - 00:34.800 + +00:34.840 --> 00:34.880 +871 - 00:34.840 + +00:34.880 --> 00:34.920 +872 - 00:34.880 + +00:34.920 --> 00:34.960 +873 - 00:34.920 + +00:34.960 --> 00:35.000 +874 - 00:34.960 + +00:35.000 --> 00:35.040 +875 - 00:35.000 + +00:35.040 --> 00:35.080 +876 - 00:35.040 + +00:35.080 --> 00:35.120 +877 - 00:35.080 + +00:35.120 --> 00:35.160 +878 - 00:35.120 + +00:35.160 --> 00:35.200 +879 - 00:35.160 + +00:35.200 --> 00:35.240 +880 - 00:35.200 + +00:35.240 --> 00:35.280 +881 - 00:35.240 + +00:35.280 --> 00:35.320 +882 - 00:35.280 + +00:35.320 --> 00:35.360 +883 - 00:35.320 + +00:35.360 --> 00:35.400 +884 - 00:35.360 + +00:35.400 --> 00:35.440 +885 - 00:35.400 + +00:35.440 --> 00:35.480 +886 - 00:35.440 + +00:35.480 --> 00:35.520 +887 - 00:35.480 + +00:35.520 --> 00:35.560 +888 - 00:35.520 + +00:35.560 --> 00:35.600 +889 - 00:35.560 + +00:35.600 --> 00:35.640 +890 - 00:35.600 + +00:35.640 --> 00:35.680 +891 - 00:35.640 + +00:35.680 --> 00:35.720 +892 - 00:35.680 + +00:35.720 --> 00:35.760 +893 - 00:35.720 + +00:35.760 --> 00:35.800 +894 - 00:35.760 + +00:35.800 --> 00:35.840 +895 - 00:35.800 + +00:35.840 --> 00:35.880 +896 - 00:35.840 + +00:35.880 --> 00:35.920 +897 - 00:35.880 + +00:35.920 --> 00:35.960 +898 - 00:35.920 + +00:35.960 --> 00:36.000 +899 - 00:35.960 + +00:36.000 --> 00:36.040 +900 - 00:36.000 + +00:36.040 --> 00:36.080 +901 - 00:36.040 + +00:36.080 --> 00:36.120 +902 - 00:36.080 + +00:36.120 --> 00:36.160 +903 - 00:36.120 + +00:36.160 --> 00:36.200 +904 - 00:36.160 + +00:36.200 --> 00:36.240 +905 - 00:36.200 + +00:36.240 --> 00:36.280 +906 - 00:36.240 + +00:36.280 --> 00:36.320 +907 - 00:36.280 + +00:36.320 --> 00:36.360 +908 - 00:36.320 + +00:36.360 --> 00:36.400 +909 - 00:36.360 + +00:36.400 --> 00:36.440 +910 - 00:36.400 + +00:36.440 --> 00:36.480 +911 - 00:36.440 + +00:36.480 --> 00:36.520 +912 - 00:36.480 + +00:36.520 --> 00:36.560 +913 - 00:36.520 + +00:36.560 --> 00:36.600 +914 - 00:36.560 + +00:36.600 --> 00:36.640 +915 - 00:36.600 + +00:36.640 --> 00:36.680 +916 - 00:36.640 + +00:36.680 --> 00:36.720 +917 - 00:36.680 + +00:36.720 --> 00:36.760 +918 - 00:36.720 + +00:36.760 --> 00:36.800 +919 - 00:36.760 + +00:36.800 --> 00:36.840 +920 - 00:36.800 + +00:36.840 --> 00:36.880 +921 - 00:36.840 + +00:36.880 --> 00:36.920 +922 - 00:36.880 + +00:36.920 --> 00:36.960 +923 - 00:36.920 + +00:36.960 --> 00:37.000 +924 - 00:36.960 + +00:37.000 --> 00:37.040 +925 - 00:37.000 + +00:37.040 --> 00:37.080 +926 - 00:37.040 + +00:37.080 --> 00:37.120 +927 - 00:37.080 + +00:37.120 --> 00:37.160 +928 - 00:37.120 + +00:37.160 --> 00:37.200 +929 - 00:37.160 + +00:37.200 --> 00:37.240 +930 - 00:37.200 + +00:37.240 --> 00:37.280 +931 - 00:37.240 + +00:37.280 --> 00:37.320 +932 - 00:37.280 + +00:37.320 --> 00:37.360 +933 - 00:37.320 + +00:37.360 --> 00:37.400 +934 - 00:37.360 + +00:37.400 --> 00:37.440 +935 - 00:37.400 + +00:37.440 --> 00:37.480 +936 - 00:37.440 + +00:37.480 --> 00:37.520 +937 - 00:37.480 + +00:37.520 --> 00:37.560 +938 - 00:37.520 + +00:37.560 --> 00:37.600 +939 - 00:37.560 + +00:37.600 --> 00:37.640 +940 - 00:37.600 + +00:37.640 --> 00:37.680 +941 - 00:37.640 + +00:37.680 --> 00:37.720 +942 - 00:37.680 + +00:37.720 --> 00:37.760 +943 - 00:37.720 + +00:37.760 --> 00:37.800 +944 - 00:37.760 + +00:37.800 --> 00:37.840 +945 - 00:37.800 + +00:37.840 --> 00:37.880 +946 - 00:37.840 + +00:37.880 --> 00:37.920 +947 - 00:37.880 + +00:37.920 --> 00:37.960 +948 - 00:37.920 + +00:37.960 --> 00:38.000 +949 - 00:37.960 + +00:38.000 --> 00:38.040 +950 - 00:38.000 + +00:38.040 --> 00:38.080 +951 - 00:38.040 + +00:38.080 --> 00:38.120 +952 - 00:38.080 + +00:38.120 --> 00:38.160 +953 - 00:38.120 + +00:38.160 --> 00:38.200 +954 - 00:38.160 + +00:38.200 --> 00:38.240 +955 - 00:38.200 + +00:38.240 --> 00:38.280 +956 - 00:38.240 + +00:38.280 --> 00:38.320 +957 - 00:38.280 + +00:38.320 --> 00:38.360 +958 - 00:38.320 + +00:38.360 --> 00:38.400 +959 - 00:38.360 + +00:38.400 --> 00:38.440 +960 - 00:38.400 + +00:38.440 --> 00:38.480 +961 - 00:38.440 + +00:38.480 --> 00:38.520 +962 - 00:38.480 + +00:38.520 --> 00:38.560 +963 - 00:38.520 + +00:38.560 --> 00:38.600 +964 - 00:38.560 + +00:38.600 --> 00:38.640 +965 - 00:38.600 + +00:38.640 --> 00:38.680 +966 - 00:38.640 + +00:38.680 --> 00:38.720 +967 - 00:38.680 + +00:38.720 --> 00:38.760 +968 - 00:38.720 + +00:38.760 --> 00:38.800 +969 - 00:38.760 + +00:38.800 --> 00:38.840 +970 - 00:38.800 + +00:38.840 --> 00:38.880 +971 - 00:38.840 + +00:38.880 --> 00:38.920 +972 - 00:38.880 + +00:38.920 --> 00:38.960 +973 - 00:38.920 + +00:38.960 --> 00:39.000 +974 - 00:38.960 + +00:39.000 --> 00:39.040 +975 - 00:39.000 + +00:39.040 --> 00:39.080 +976 - 00:39.040 + +00:39.080 --> 00:39.120 +977 - 00:39.080 + +00:39.120 --> 00:39.160 +978 - 00:39.120 + +00:39.160 --> 00:39.200 +979 - 00:39.160 + +00:39.200 --> 00:39.240 +980 - 00:39.200 + +00:39.240 --> 00:39.280 +981 - 00:39.240 + +00:39.280 --> 00:39.320 +982 - 00:39.280 + +00:39.320 --> 00:39.360 +983 - 00:39.320 + +00:39.360 --> 00:39.400 +984 - 00:39.360 + +00:39.400 --> 00:39.440 +985 - 00:39.400 + +00:39.440 --> 00:39.480 +986 - 00:39.440 + +00:39.480 --> 00:39.520 +987 - 00:39.480 + +00:39.520 --> 00:39.560 +988 - 00:39.520 + +00:39.560 --> 00:39.600 +989 - 00:39.560 + +00:39.600 --> 00:39.640 +990 - 00:39.600 + +00:39.640 --> 00:39.680 +991 - 00:39.640 + +00:39.680 --> 00:39.720 +992 - 00:39.680 + +00:39.720 --> 00:39.760 +993 - 00:39.720 + +00:39.760 --> 00:39.800 +994 - 00:39.760 + +00:39.800 --> 00:39.840 +995 - 00:39.800 + +00:39.840 --> 00:39.880 +996 - 00:39.840 + +00:39.880 --> 00:39.920 +997 - 00:39.880 + +00:39.920 --> 00:39.960 +998 - 00:39.920 + +00:39.960 --> 00:40.000 +999 - 00:39.960 + +00:40.000 --> 00:40.040 +1000 - 00:40.000 + +00:40.040 --> 00:40.080 +1001 - 00:40.040 + +00:40.080 --> 00:40.120 +1002 - 00:40.080 + +00:40.120 --> 00:40.160 +1003 - 00:40.120 + +00:40.160 --> 00:40.200 +1004 - 00:40.160 + +00:40.200 --> 00:40.240 +1005 - 00:40.200 + +00:40.240 --> 00:40.280 +1006 - 00:40.240 + +00:40.280 --> 00:40.320 +1007 - 00:40.280 + +00:40.320 --> 00:40.360 +1008 - 00:40.320 + +00:40.360 --> 00:40.400 +1009 - 00:40.360 + +00:40.400 --> 00:40.440 +1010 - 00:40.400 + +00:40.440 --> 00:40.480 +1011 - 00:40.440 + +00:40.480 --> 00:40.520 +1012 - 00:40.480 + +00:40.520 --> 00:40.560 +1013 - 00:40.520 + +00:40.560 --> 00:40.600 +1014 - 00:40.560 + +00:40.600 --> 00:40.640 +1015 - 00:40.600 + +00:40.640 --> 00:40.680 +1016 - 00:40.640 + +00:40.680 --> 00:40.720 +1017 - 00:40.680 + +00:40.720 --> 00:40.760 +1018 - 00:40.720 + +00:40.760 --> 00:40.800 +1019 - 00:40.760 + +00:40.800 --> 00:40.840 +1020 - 00:40.800 + +00:40.840 --> 00:40.880 +1021 - 00:40.840 + +00:40.880 --> 00:40.920 +1022 - 00:40.880 + +00:40.920 --> 00:40.960 +1023 - 00:40.920 + +00:40.960 --> 00:41.000 +1024 - 00:40.960 + +00:41.000 --> 00:41.040 +1025 - 00:41.000 + +00:41.040 --> 00:41.080 +1026 - 00:41.040 + +00:41.080 --> 00:41.120 +1027 - 00:41.080 + +00:41.120 --> 00:41.160 +1028 - 00:41.120 + +00:41.160 --> 00:41.200 +1029 - 00:41.160 + +00:41.200 --> 00:41.240 +1030 - 00:41.200 + +00:41.240 --> 00:41.280 +1031 - 00:41.240 + +00:41.280 --> 00:41.320 +1032 - 00:41.280 + +00:41.320 --> 00:41.360 +1033 - 00:41.320 + +00:41.360 --> 00:41.400 +1034 - 00:41.360 + +00:41.400 --> 00:41.440 +1035 - 00:41.400 + +00:41.440 --> 00:41.480 +1036 - 00:41.440 + +00:41.480 --> 00:41.520 +1037 - 00:41.480 + +00:41.520 --> 00:41.560 +1038 - 00:41.520 + +00:41.560 --> 00:41.600 +1039 - 00:41.560 + +00:41.600 --> 00:41.640 +1040 - 00:41.600 + +00:41.640 --> 00:41.680 +1041 - 00:41.640 + +00:41.680 --> 00:41.720 +1042 - 00:41.680 + +00:41.720 --> 00:41.760 +1043 - 00:41.720 + +00:41.760 --> 00:41.800 +1044 - 00:41.760 + +00:41.800 --> 00:41.840 +1045 - 00:41.800 + +00:41.840 --> 00:41.880 +1046 - 00:41.840 + +00:41.880 --> 00:41.920 +1047 - 00:41.880 + +00:41.920 --> 00:41.960 +1048 - 00:41.920 + +00:41.960 --> 00:42.000 +1049 - 00:41.960 + +00:42.000 --> 00:42.040 +1050 - 00:42.000 + +00:42.040 --> 00:42.080 +1051 - 00:42.040 + +00:42.080 --> 00:42.120 +1052 - 00:42.080 + +00:42.120 --> 00:42.160 +1053 - 00:42.120 + +00:42.160 --> 00:42.200 +1054 - 00:42.160 + +00:42.200 --> 00:42.240 +1055 - 00:42.200 + +00:42.240 --> 00:42.280 +1056 - 00:42.240 + +00:42.280 --> 00:42.320 +1057 - 00:42.280 + +00:42.320 --> 00:42.360 +1058 - 00:42.320 + +00:42.360 --> 00:42.400 +1059 - 00:42.360 + +00:42.400 --> 00:42.440 +1060 - 00:42.400 + +00:42.440 --> 00:42.480 +1061 - 00:42.440 + +00:42.480 --> 00:42.520 +1062 - 00:42.480 + +00:42.520 --> 00:42.560 +1063 - 00:42.520 + +00:42.560 --> 00:42.600 +1064 - 00:42.560 + +00:42.600 --> 00:42.640 +1065 - 00:42.600 + +00:42.640 --> 00:42.680 +1066 - 00:42.640 + +00:42.680 --> 00:42.720 +1067 - 00:42.680 + +00:42.720 --> 00:42.760 +1068 - 00:42.720 + +00:42.760 --> 00:42.800 +1069 - 00:42.760 + +00:42.800 --> 00:42.840 +1070 - 00:42.800 + +00:42.840 --> 00:42.880 +1071 - 00:42.840 + +00:42.880 --> 00:42.920 +1072 - 00:42.880 + +00:42.920 --> 00:42.960 +1073 - 00:42.920 + +00:42.960 --> 00:43.000 +1074 - 00:42.960 + +00:43.000 --> 00:43.040 +1075 - 00:43.000 + +00:43.040 --> 00:43.080 +1076 - 00:43.040 + +00:43.080 --> 00:43.120 +1077 - 00:43.080 + +00:43.120 --> 00:43.160 +1078 - 00:43.120 + +00:43.160 --> 00:43.200 +1079 - 00:43.160 + +00:43.200 --> 00:43.240 +1080 - 00:43.200 + +00:43.240 --> 00:43.280 +1081 - 00:43.240 + +00:43.280 --> 00:43.320 +1082 - 00:43.280 + +00:43.320 --> 00:43.360 +1083 - 00:43.320 + +00:43.360 --> 00:43.400 +1084 - 00:43.360 + +00:43.400 --> 00:43.440 +1085 - 00:43.400 + +00:43.440 --> 00:43.480 +1086 - 00:43.440 + +00:43.480 --> 00:43.520 +1087 - 00:43.480 + +00:43.520 --> 00:43.560 +1088 - 00:43.520 + +00:43.560 --> 00:43.600 +1089 - 00:43.560 + +00:43.600 --> 00:43.640 +1090 - 00:43.600 + +00:43.640 --> 00:43.680 +1091 - 00:43.640 + +00:43.680 --> 00:43.720 +1092 - 00:43.680 + +00:43.720 --> 00:43.760 +1093 - 00:43.720 + +00:43.760 --> 00:43.800 +1094 - 00:43.760 + +00:43.800 --> 00:43.840 +1095 - 00:43.800 + +00:43.840 --> 00:43.880 +1096 - 00:43.840 + +00:43.880 --> 00:43.920 +1097 - 00:43.880 + +00:43.920 --> 00:43.960 +1098 - 00:43.920 + +00:43.960 --> 00:44.000 +1099 - 00:43.960 + +00:44.000 --> 00:44.040 +1100 - 00:44.000 + +00:44.040 --> 00:44.080 +1101 - 00:44.040 + +00:44.080 --> 00:44.120 +1102 - 00:44.080 + +00:44.120 --> 00:44.160 +1103 - 00:44.120 + +00:44.160 --> 00:44.200 +1104 - 00:44.160 + +00:44.200 --> 00:44.240 +1105 - 00:44.200 + +00:44.240 --> 00:44.280 +1106 - 00:44.240 + +00:44.280 --> 00:44.320 +1107 - 00:44.280 + +00:44.320 --> 00:44.360 +1108 - 00:44.320 + +00:44.360 --> 00:44.400 +1109 - 00:44.360 + +00:44.400 --> 00:44.440 +1110 - 00:44.400 + +00:44.440 --> 00:44.480 +1111 - 00:44.440 + +00:44.480 --> 00:44.520 +1112 - 00:44.480 + +00:44.520 --> 00:44.560 +1113 - 00:44.520 + +00:44.560 --> 00:44.600 +1114 - 00:44.560 + +00:44.600 --> 00:44.640 +1115 - 00:44.600 + +00:44.640 --> 00:44.680 +1116 - 00:44.640 + +00:44.680 --> 00:44.720 +1117 - 00:44.680 + +00:44.720 --> 00:44.760 +1118 - 00:44.720 + +00:44.760 --> 00:44.800 +1119 - 00:44.760 + +00:44.800 --> 00:44.840 +1120 - 00:44.800 + +00:44.840 --> 00:44.880 +1121 - 00:44.840 + +00:44.880 --> 00:44.920 +1122 - 00:44.880 + +00:44.920 --> 00:44.960 +1123 - 00:44.920 + +00:44.960 --> 00:45.000 +1124 - 00:44.960 + +00:45.000 --> 00:45.040 +1125 - 00:45.000 + +00:45.040 --> 00:45.080 +1126 - 00:45.040 + +00:45.080 --> 00:45.120 +1127 - 00:45.080 + +00:45.120 --> 00:45.160 +1128 - 00:45.120 + +00:45.160 --> 00:45.200 +1129 - 00:45.160 + +00:45.200 --> 00:45.240 +1130 - 00:45.200 + +00:45.240 --> 00:45.280 +1131 - 00:45.240 + +00:45.280 --> 00:45.320 +1132 - 00:45.280 + +00:45.320 --> 00:45.360 +1133 - 00:45.320 + +00:45.360 --> 00:45.400 +1134 - 00:45.360 + +00:45.400 --> 00:45.440 +1135 - 00:45.400 + +00:45.440 --> 00:45.480 +1136 - 00:45.440 + +00:45.480 --> 00:45.520 +1137 - 00:45.480 + +00:45.520 --> 00:45.560 +1138 - 00:45.520 + +00:45.560 --> 00:45.600 +1139 - 00:45.560 + +00:45.600 --> 00:45.640 +1140 - 00:45.600 + +00:45.640 --> 00:45.680 +1141 - 00:45.640 + +00:45.680 --> 00:45.720 +1142 - 00:45.680 + +00:45.720 --> 00:45.760 +1143 - 00:45.720 + +00:45.760 --> 00:45.800 +1144 - 00:45.760 + +00:45.800 --> 00:45.840 +1145 - 00:45.800 + +00:45.840 --> 00:45.880 +1146 - 00:45.840 + +00:45.880 --> 00:45.920 +1147 - 00:45.880 + +00:45.920 --> 00:45.960 +1148 - 00:45.920 + +00:45.960 --> 00:46.000 +1149 - 00:45.960 + +00:46.000 --> 00:46.040 +1150 - 00:46.000 + +00:46.040 --> 00:46.080 +1151 - 00:46.040 + +00:46.080 --> 00:46.120 +1152 - 00:46.080 + +00:46.120 --> 00:46.160 +1153 - 00:46.120 + +00:46.160 --> 00:46.200 +1154 - 00:46.160 + +00:46.200 --> 00:46.240 +1155 - 00:46.200 + +00:46.240 --> 00:46.280 +1156 - 00:46.240 + +00:46.280 --> 00:46.320 +1157 - 00:46.280 + +00:46.320 --> 00:46.360 +1158 - 00:46.320 + +00:46.360 --> 00:46.400 +1159 - 00:46.360 + +00:46.400 --> 00:46.440 +1160 - 00:46.400 + +00:46.440 --> 00:46.480 +1161 - 00:46.440 + +00:46.480 --> 00:46.520 +1162 - 00:46.480 + +00:46.520 --> 00:46.560 +1163 - 00:46.520 + +00:46.560 --> 00:46.600 +1164 - 00:46.560 + +00:46.600 --> 00:46.640 +1165 - 00:46.600 + +00:46.640 --> 00:46.680 +1166 - 00:46.640 + +00:46.680 --> 00:46.720 +1167 - 00:46.680 + +00:46.720 --> 00:46.760 +1168 - 00:46.720 + +00:46.760 --> 00:46.800 +1169 - 00:46.760 + +00:46.800 --> 00:46.840 +1170 - 00:46.800 + +00:46.840 --> 00:46.880 +1171 - 00:46.840 + +00:46.880 --> 00:46.920 +1172 - 00:46.880 + +00:46.920 --> 00:46.960 +1173 - 00:46.920 + +00:46.960 --> 00:47.000 +1174 - 00:46.960 + +00:47.000 --> 00:47.040 +1175 - 00:47.000 + +00:47.040 --> 00:47.080 +1176 - 00:47.040 + +00:47.080 --> 00:47.120 +1177 - 00:47.080 + +00:47.120 --> 00:47.160 +1178 - 00:47.120 + +00:47.160 --> 00:47.200 +1179 - 00:47.160 + +00:47.200 --> 00:47.240 +1180 - 00:47.200 + +00:47.240 --> 00:47.280 +1181 - 00:47.240 + +00:47.280 --> 00:47.320 +1182 - 00:47.280 + +00:47.320 --> 00:47.360 +1183 - 00:47.320 + +00:47.360 --> 00:47.400 +1184 - 00:47.360 + +00:47.400 --> 00:47.440 +1185 - 00:47.400 + +00:47.440 --> 00:47.480 +1186 - 00:47.440 + +00:47.480 --> 00:47.520 +1187 - 00:47.480 + +00:47.520 --> 00:47.560 +1188 - 00:47.520 + +00:47.560 --> 00:47.600 +1189 - 00:47.560 + +00:47.600 --> 00:47.640 +1190 - 00:47.600 + +00:47.640 --> 00:47.680 +1191 - 00:47.640 + +00:47.680 --> 00:47.720 +1192 - 00:47.680 + +00:47.720 --> 00:47.760 +1193 - 00:47.720 + +00:47.760 --> 00:47.800 +1194 - 00:47.760 + +00:47.800 --> 00:47.840 +1195 - 00:47.800 + +00:47.840 --> 00:47.880 +1196 - 00:47.840 + +00:47.880 --> 00:47.920 +1197 - 00:47.880 + +00:47.920 --> 00:47.960 +1198 - 00:47.920 + +00:47.960 --> 00:48.000 +1199 - 00:47.960 + +00:48.000 --> 00:48.040 +1200 - 00:48.000 + +00:48.040 --> 00:48.080 +1201 - 00:48.040 + +00:48.080 --> 00:48.120 +1202 - 00:48.080 + +00:48.120 --> 00:48.160 +1203 - 00:48.120 + +00:48.160 --> 00:48.200 +1204 - 00:48.160 + +00:48.200 --> 00:48.240 +1205 - 00:48.200 + +00:48.240 --> 00:48.280 +1206 - 00:48.240 + +00:48.280 --> 00:48.320 +1207 - 00:48.280 + +00:48.320 --> 00:48.360 +1208 - 00:48.320 + +00:48.360 --> 00:48.400 +1209 - 00:48.360 + +00:48.400 --> 00:48.440 +1210 - 00:48.400 + +00:48.440 --> 00:48.480 +1211 - 00:48.440 + +00:48.480 --> 00:48.520 +1212 - 00:48.480 + +00:48.520 --> 00:48.560 +1213 - 00:48.520 + +00:48.560 --> 00:48.600 +1214 - 00:48.560 + +00:48.600 --> 00:48.640 +1215 - 00:48.600 + +00:48.640 --> 00:48.680 +1216 - 00:48.640 + +00:48.680 --> 00:48.720 +1217 - 00:48.680 + +00:48.720 --> 00:48.760 +1218 - 00:48.720 + +00:48.760 --> 00:48.800 +1219 - 00:48.760 + +00:48.800 --> 00:48.840 +1220 - 00:48.800 + +00:48.840 --> 00:48.880 +1221 - 00:48.840 + +00:48.880 --> 00:48.920 +1222 - 00:48.880 + +00:48.920 --> 00:48.960 +1223 - 00:48.920 + +00:48.960 --> 00:49.000 +1224 - 00:48.960 + +00:49.000 --> 00:49.040 +1225 - 00:49.000 + +00:49.040 --> 00:49.080 +1226 - 00:49.040 + +00:49.080 --> 00:49.120 +1227 - 00:49.080 + +00:49.120 --> 00:49.160 +1228 - 00:49.120 + +00:49.160 --> 00:49.200 +1229 - 00:49.160 + +00:49.200 --> 00:49.240 +1230 - 00:49.200 + +00:49.240 --> 00:49.280 +1231 - 00:49.240 + +00:49.280 --> 00:49.320 +1232 - 00:49.280 + +00:49.320 --> 00:49.360 +1233 - 00:49.320 + +00:49.360 --> 00:49.400 +1234 - 00:49.360 + +00:49.400 --> 00:49.440 +1235 - 00:49.400 + +00:49.440 --> 00:49.480 +1236 - 00:49.440 + +00:49.480 --> 00:49.520 +1237 - 00:49.480 + +00:49.520 --> 00:49.560 +1238 - 00:49.520 + +00:49.560 --> 00:49.600 +1239 - 00:49.560 + +00:49.600 --> 00:49.640 +1240 - 00:49.600 + +00:49.640 --> 00:49.680 +1241 - 00:49.640 + +00:49.680 --> 00:49.720 +1242 - 00:49.680 + +00:49.720 --> 00:49.760 +1243 - 00:49.720 + +00:49.760 --> 00:49.800 +1244 - 00:49.760 + +00:49.800 --> 00:49.840 +1245 - 00:49.800 + +00:49.840 --> 00:49.880 +1246 - 00:49.840 + +00:49.880 --> 00:49.920 +1247 - 00:49.880 + +00:49.920 --> 00:49.960 +1248 - 00:49.920 + +00:49.960 --> 00:50.000 +1249 - 00:49.960 + +00:50.000 --> 00:50.040 +1250 - 00:50.000 + +00:50.040 --> 00:50.080 +1251 - 00:50.040 + +00:50.080 --> 00:50.120 +1252 - 00:50.080 + +00:50.120 --> 00:50.160 +1253 - 00:50.120 + +00:50.160 --> 00:50.200 +1254 - 00:50.160 + +00:50.200 --> 00:50.240 +1255 - 00:50.200 + +00:50.240 --> 00:50.280 +1256 - 00:50.240 + +00:50.280 --> 00:50.320 +1257 - 00:50.280 + +00:50.320 --> 00:50.360 +1258 - 00:50.320 + +00:50.360 --> 00:50.400 +1259 - 00:50.360 + +00:50.400 --> 00:50.440 +1260 - 00:50.400 + +00:50.440 --> 00:50.480 +1261 - 00:50.440 + +00:50.480 --> 00:50.520 +1262 - 00:50.480 + +00:50.520 --> 00:50.560 +1263 - 00:50.520 + +00:50.560 --> 00:50.600 +1264 - 00:50.560 + +00:50.600 --> 00:50.640 +1265 - 00:50.600 + +00:50.640 --> 00:50.680 +1266 - 00:50.640 + +00:50.680 --> 00:50.720 +1267 - 00:50.680 + +00:50.720 --> 00:50.760 +1268 - 00:50.720 + +00:50.760 --> 00:50.800 +1269 - 00:50.760 + +00:50.800 --> 00:50.840 +1270 - 00:50.800 + +00:50.840 --> 00:50.880 +1271 - 00:50.840 + +00:50.880 --> 00:50.920 +1272 - 00:50.880 + +00:50.920 --> 00:50.960 +1273 - 00:50.920 + +00:50.960 --> 00:51.000 +1274 - 00:50.960 + +00:51.000 --> 00:51.040 +1275 - 00:51.000 + +00:51.040 --> 00:51.080 +1276 - 00:51.040 + +00:51.080 --> 00:51.120 +1277 - 00:51.080 + +00:51.120 --> 00:51.160 +1278 - 00:51.120 + +00:51.160 --> 00:51.200 +1279 - 00:51.160 + +00:51.200 --> 00:51.240 +1280 - 00:51.200 + +00:51.240 --> 00:51.280 +1281 - 00:51.240 + +00:51.280 --> 00:51.320 +1282 - 00:51.280 + +00:51.320 --> 00:51.360 +1283 - 00:51.320 + +00:51.360 --> 00:51.400 +1284 - 00:51.360 + +00:51.400 --> 00:51.440 +1285 - 00:51.400 + +00:51.440 --> 00:51.480 +1286 - 00:51.440 + +00:51.480 --> 00:51.520 +1287 - 00:51.480 + +00:51.520 --> 00:51.560 +1288 - 00:51.520 + +00:51.560 --> 00:51.600 +1289 - 00:51.560 + +00:51.600 --> 00:51.640 +1290 - 00:51.600 + +00:51.640 --> 00:51.680 +1291 - 00:51.640 + +00:51.680 --> 00:51.720 +1292 - 00:51.680 + +00:51.720 --> 00:51.760 +1293 - 00:51.720 + +00:51.760 --> 00:51.800 +1294 - 00:51.760 + +00:51.800 --> 00:51.840 +1295 - 00:51.800 + +00:51.840 --> 00:51.880 +1296 - 00:51.840 + +00:51.880 --> 00:51.920 +1297 - 00:51.880 + +00:51.920 --> 00:51.960 +1298 - 00:51.920 + +00:51.960 --> 00:52.000 +1299 - 00:51.960 + +00:52.000 --> 00:52.040 +1300 - 00:52.000 + +00:52.040 --> 00:52.080 +1301 - 00:52.040 + +00:52.080 --> 00:52.120 +1302 - 00:52.080 + +00:52.120 --> 00:52.160 +1303 - 00:52.120 + +00:52.160 --> 00:52.200 +1304 - 00:52.160 + +00:52.200 --> 00:52.240 +1305 - 00:52.200 + +00:52.240 --> 00:52.280 +1306 - 00:52.240 + +00:52.280 --> 00:52.320 +1307 - 00:52.280 + +00:52.320 --> 00:52.360 +1308 - 00:52.320 + +00:52.360 --> 00:52.400 +1309 - 00:52.360 + +00:52.400 --> 00:52.440 +1310 - 00:52.400 + +00:52.440 --> 00:52.480 +1311 - 00:52.440 + +00:52.480 --> 00:52.520 +1312 - 00:52.480 + +00:52.520 --> 00:52.560 +1313 - 00:52.520 + +00:52.560 --> 00:52.600 +1314 - 00:52.560 + +00:52.600 --> 00:52.640 +1315 - 00:52.600 + +00:52.640 --> 00:52.680 +1316 - 00:52.640 + +00:52.680 --> 00:52.720 +1317 - 00:52.680 + +00:52.720 --> 00:52.760 +1318 - 00:52.720 + +00:52.760 --> 00:52.800 +1319 - 00:52.760 + +00:52.800 --> 00:52.840 +1320 - 00:52.800 + +00:52.840 --> 00:52.880 +1321 - 00:52.840 + +00:52.880 --> 00:52.920 +1322 - 00:52.880 + +00:52.920 --> 00:52.960 +1323 - 00:52.920 + +00:52.960 --> 00:53.000 +1324 - 00:52.960 + +00:53.000 --> 00:53.040 +1325 - 00:53.000 + +00:53.040 --> 00:53.080 +1326 - 00:53.040 + +00:53.080 --> 00:53.120 +1327 - 00:53.080 + +00:53.120 --> 00:53.160 +1328 - 00:53.120 + +00:53.160 --> 00:53.200 +1329 - 00:53.160 + +00:53.200 --> 00:53.240 +1330 - 00:53.200 + +00:53.240 --> 00:53.280 +1331 - 00:53.240 + +00:53.280 --> 00:53.320 +1332 - 00:53.280 + +00:53.320 --> 00:53.360 +1333 - 00:53.320 + +00:53.360 --> 00:53.400 +1334 - 00:53.360 + +00:53.400 --> 00:53.440 +1335 - 00:53.400 + +00:53.440 --> 00:53.480 +1336 - 00:53.440 + +00:53.480 --> 00:53.520 +1337 - 00:53.480 + +00:53.520 --> 00:53.560 +1338 - 00:53.520 + +00:53.560 --> 00:53.600 +1339 - 00:53.560 + +00:53.600 --> 00:53.640 +1340 - 00:53.600 + +00:53.640 --> 00:53.680 +1341 - 00:53.640 + +00:53.680 --> 00:53.720 +1342 - 00:53.680 + +00:53.720 --> 00:53.760 +1343 - 00:53.720 + +00:53.760 --> 00:53.800 +1344 - 00:53.760 + +00:53.800 --> 00:53.840 +1345 - 00:53.800 + +00:53.840 --> 00:53.880 +1346 - 00:53.840 + +00:53.880 --> 00:53.920 +1347 - 00:53.880 + +00:53.920 --> 00:53.960 +1348 - 00:53.920 + +00:53.960 --> 00:54.000 +1349 - 00:53.960 + +00:54.000 --> 00:54.040 +1350 - 00:54.000 + +00:54.040 --> 00:54.080 +1351 - 00:54.040 + +00:54.080 --> 00:54.120 +1352 - 00:54.080 + +00:54.120 --> 00:54.160 +1353 - 00:54.120 + +00:54.160 --> 00:54.200 +1354 - 00:54.160 + +00:54.200 --> 00:54.240 +1355 - 00:54.200 + +00:54.240 --> 00:54.280 +1356 - 00:54.240 + +00:54.280 --> 00:54.320 +1357 - 00:54.280 + +00:54.320 --> 00:54.360 +1358 - 00:54.320 + +00:54.360 --> 00:54.400 +1359 - 00:54.360 + +00:54.400 --> 00:54.440 +1360 - 00:54.400 + +00:54.440 --> 00:54.480 +1361 - 00:54.440 + +00:54.480 --> 00:54.520 +1362 - 00:54.480 + +00:54.520 --> 00:54.560 +1363 - 00:54.520 + +00:54.560 --> 00:54.600 +1364 - 00:54.560 + +00:54.600 --> 00:54.640 +1365 - 00:54.600 + +00:54.640 --> 00:54.680 +1366 - 00:54.640 + +00:54.680 --> 00:54.720 +1367 - 00:54.680 + +00:54.720 --> 00:54.760 +1368 - 00:54.720 + +00:54.760 --> 00:54.800 +1369 - 00:54.760 + +00:54.800 --> 00:54.840 +1370 - 00:54.800 + +00:54.840 --> 00:54.880 +1371 - 00:54.840 + +00:54.880 --> 00:54.920 +1372 - 00:54.880 + +00:54.920 --> 00:54.960 +1373 - 00:54.920 + +00:54.960 --> 00:55.000 +1374 - 00:54.960 + +00:55.000 --> 00:55.040 +1375 - 00:55.000 + +00:55.040 --> 00:55.080 +1376 - 00:55.040 + +00:55.080 --> 00:55.120 +1377 - 00:55.080 + +00:55.120 --> 00:55.160 +1378 - 00:55.120 + +00:55.160 --> 00:55.200 +1379 - 00:55.160 + +00:55.200 --> 00:55.240 +1380 - 00:55.200 + +00:55.240 --> 00:55.280 +1381 - 00:55.240 + +00:55.280 --> 00:55.320 +1382 - 00:55.280 + +00:55.320 --> 00:55.360 +1383 - 00:55.320 + +00:55.360 --> 00:55.400 +1384 - 00:55.360 + +00:55.400 --> 00:55.440 +1385 - 00:55.400 + +00:55.440 --> 00:55.480 +1386 - 00:55.440 + +00:55.480 --> 00:55.520 +1387 - 00:55.480 + +00:55.520 --> 00:55.560 +1388 - 00:55.520 + +00:55.560 --> 00:55.600 +1389 - 00:55.560 + +00:55.600 --> 00:55.640 +1390 - 00:55.600 + +00:55.640 --> 00:55.680 +1391 - 00:55.640 + +00:55.680 --> 00:55.720 +1392 - 00:55.680 + +00:55.720 --> 00:55.760 +1393 - 00:55.720 + +00:55.760 --> 00:55.800 +1394 - 00:55.760 + +00:55.800 --> 00:55.840 +1395 - 00:55.800 + +00:55.840 --> 00:55.880 +1396 - 00:55.840 + +00:55.880 --> 00:55.920 +1397 - 00:55.880 + +00:55.920 --> 00:55.960 +1398 - 00:55.920 + +00:55.960 --> 00:56.000 +1399 - 00:55.960 + +00:56.000 --> 00:56.040 +1400 - 00:56.000 + +00:56.040 --> 00:56.080 +1401 - 00:56.040 + +00:56.080 --> 00:56.120 +1402 - 00:56.080 + +00:56.120 --> 00:56.160 +1403 - 00:56.120 + +00:56.160 --> 00:56.200 +1404 - 00:56.160 + +00:56.200 --> 00:56.240 +1405 - 00:56.200 + +00:56.240 --> 00:56.280 +1406 - 00:56.240 + +00:56.280 --> 00:56.320 +1407 - 00:56.280 + +00:56.320 --> 00:56.360 +1408 - 00:56.320 + +00:56.360 --> 00:56.400 +1409 - 00:56.360 + +00:56.400 --> 00:56.440 +1410 - 00:56.400 + +00:56.440 --> 00:56.480 +1411 - 00:56.440 + +00:56.480 --> 00:56.520 +1412 - 00:56.480 + +00:56.520 --> 00:56.560 +1413 - 00:56.520 + +00:56.560 --> 00:56.600 +1414 - 00:56.560 + +00:56.600 --> 00:56.640 +1415 - 00:56.600 + +00:56.640 --> 00:56.680 +1416 - 00:56.640 + +00:56.680 --> 00:56.720 +1417 - 00:56.680 + +00:56.720 --> 00:56.760 +1418 - 00:56.720 + +00:56.760 --> 00:56.800 +1419 - 00:56.760 + +00:56.800 --> 00:56.840 +1420 - 00:56.800 + +00:56.840 --> 00:56.880 +1421 - 00:56.840 + +00:56.880 --> 00:56.920 +1422 - 00:56.880 + +00:56.920 --> 00:56.960 +1423 - 00:56.920 + +00:56.960 --> 00:57.000 +1424 - 00:56.960 + +00:57.000 --> 00:57.040 +1425 - 00:57.000 + +00:57.040 --> 00:57.080 +1426 - 00:57.040 + +00:57.080 --> 00:57.120 +1427 - 00:57.080 + +00:57.120 --> 00:57.160 +1428 - 00:57.120 + +00:57.160 --> 00:57.200 +1429 - 00:57.160 + +00:57.200 --> 00:57.240 +1430 - 00:57.200 + +00:57.240 --> 00:57.280 +1431 - 00:57.240 + +00:57.280 --> 00:57.320 +1432 - 00:57.280 + +00:57.320 --> 00:57.360 +1433 - 00:57.320 + +00:57.360 --> 00:57.400 +1434 - 00:57.360 + +00:57.400 --> 00:57.440 +1435 - 00:57.400 + +00:57.440 --> 00:57.480 +1436 - 00:57.440 + +00:57.480 --> 00:57.520 +1437 - 00:57.480 + +00:57.520 --> 00:57.560 +1438 - 00:57.520 + +00:57.560 --> 00:57.600 +1439 - 00:57.560 + +00:57.600 --> 00:57.640 +1440 - 00:57.600 + +00:57.640 --> 00:57.680 +1441 - 00:57.640 + +00:57.680 --> 00:57.720 +1442 - 00:57.680 + +00:57.720 --> 00:57.760 +1443 - 00:57.720 + +00:57.760 --> 00:57.800 +1444 - 00:57.760 + +00:57.800 --> 00:57.840 +1445 - 00:57.800 + +00:57.840 --> 00:57.880 +1446 - 00:57.840 + +00:57.880 --> 00:57.920 +1447 - 00:57.880 + +00:57.920 --> 00:57.960 +1448 - 00:57.920 + +00:57.960 --> 00:58.000 +1449 - 00:57.960 + +00:58.000 --> 00:58.040 +1450 - 00:58.000 + +00:58.040 --> 00:58.080 +1451 - 00:58.040 + +00:58.080 --> 00:58.120 +1452 - 00:58.080 + +00:58.120 --> 00:58.160 +1453 - 00:58.120 + +00:58.160 --> 00:58.200 +1454 - 00:58.160 + +00:58.200 --> 00:58.240 +1455 - 00:58.200 + +00:58.240 --> 00:58.280 +1456 - 00:58.240 + +00:58.280 --> 00:58.320 +1457 - 00:58.280 + +00:58.320 --> 00:58.360 +1458 - 00:58.320 + +00:58.360 --> 00:58.400 +1459 - 00:58.360 + +00:58.400 --> 00:58.440 +1460 - 00:58.400 + +00:58.440 --> 00:58.480 +1461 - 00:58.440 + +00:58.480 --> 00:58.520 +1462 - 00:58.480 + +00:58.520 --> 00:58.560 +1463 - 00:58.520 + +00:58.560 --> 00:58.600 +1464 - 00:58.560 + +00:58.600 --> 00:58.640 +1465 - 00:58.600 + +00:58.640 --> 00:58.680 +1466 - 00:58.640 + +00:58.680 --> 00:58.720 +1467 - 00:58.680 + +00:58.720 --> 00:58.760 +1468 - 00:58.720 + +00:58.760 --> 00:58.800 +1469 - 00:58.760 + +00:58.800 --> 00:58.840 +1470 - 00:58.800 + +00:58.840 --> 00:58.880 +1471 - 00:58.840 + +00:58.880 --> 00:58.920 +1472 - 00:58.880 + +00:58.920 --> 00:58.960 +1473 - 00:58.920 + +00:58.960 --> 00:59.000 +1474 - 00:58.960 + +00:59.000 --> 00:59.040 +1475 - 00:59.000 + +00:59.040 --> 00:59.080 +1476 - 00:59.040 + +00:59.080 --> 00:59.120 +1477 - 00:59.080 + +00:59.120 --> 00:59.160 +1478 - 00:59.120 + +00:59.160 --> 00:59.200 +1479 - 00:59.160 + +00:59.200 --> 00:59.240 +1480 - 00:59.200 + +00:59.240 --> 00:59.280 +1481 - 00:59.240 + +00:59.280 --> 00:59.320 +1482 - 00:59.280 + +00:59.320 --> 00:59.360 +1483 - 00:59.320 + +00:59.360 --> 00:59.400 +1484 - 00:59.360 + +00:59.400 --> 00:59.440 +1485 - 00:59.400 + +00:59.440 --> 00:59.480 +1486 - 00:59.440 + +00:59.480 --> 00:59.520 +1487 - 00:59.480 + +00:59.520 --> 00:59.560 +1488 - 00:59.520 + +00:59.560 --> 00:59.600 +1489 - 00:59.560 + +00:59.600 --> 00:59.640 +1490 - 00:59.600 + +00:59.640 --> 00:59.680 +1491 - 00:59.640 + +00:59.680 --> 00:59.720 +1492 - 00:59.680 + +00:59.720 --> 00:59.760 +1493 - 00:59.720 + +00:59.760 --> 00:59.800 +1494 - 00:59.760 + +00:59.800 --> 00:59.840 +1495 - 00:59.800 + +00:59.840 --> 00:59.880 +1496 - 00:59.840 + +00:59.880 --> 00:59.920 +1497 - 00:59.880 + +00:59.920 --> 00:59.960 +1498 - 00:59.920 + +00:59.960 --> 01:00.000 +1499 - 00:59.960 + diff --git a/regression_tests/webvtt/simple.vtt b/regression_tests/webvtt/simple.vtt index d8bb9fc..908017d 100644 --- a/regression_tests/webvtt/simple.vtt +++ b/regression_tests/webvtt/simple.vtt @@ -1,32 +1,32 @@ -WEBVTT - -00:00.000 --> 00:02.000 -Hello, this is a first sample - -00:02.000 --> 00:04.000 -And now a second sample -on two lines - -00:04.000 --> 00:06.000 -And now with a <i>italic</i> text - -00:06.000 --> 00:08.000 -Or <b>bold</b> text - -00:08.000 --> 00:10.000 -Or <u>underlined</u> text - -00:10.000 --> 00:12.000 -<v Jean>What is it for?<v Cyril>I don't care... - -00:12.000 --> 00:14.000 -Some text <00:13.000>and some later text - -00:14.000 --> 00:16.000 -<c.myClass>Classed text</c> - -00:16.000 --> 00:18.000 -<lang fr>En français</lang> - -00:18.000 --> 00:20.000 +WEBVTT + +00:00.000 --> 00:02.000 +Hello, this is a first sample + +00:02.000 --> 00:04.000 +And now a second sample +on two lines + +00:04.000 --> 00:06.000 +And now with a <i>italic</i> text + +00:06.000 --> 00:08.000 +Or <b>bold</b> text + +00:08.000 --> 00:10.000 +Or <u>underlined</u> text + +00:10.000 --> 00:12.000 +<v Jean>What is it for?<v Cyril>I don't care... + +00:12.000 --> 00:14.000 +Some text <00:13.000>and some later text + +00:14.000 --> 00:16.000 +<c.myClass>Classed text</c> + +00:16.000 --> 00:18.000 +<lang fr>En français</lang> + +00:18.000 --> 00:20.000 And also <b><i>bold and italic</i></b> nested \ No newline at end of file diff --git a/regression_tests/xmlin4/anim.swf b/regression_tests/xmlin4/anim.swf new file mode 100644 index 0000000000000000000000000000000000000000..438ad043ada70b91f80db1e9a8cdf4936830c87a GIT binary patch literal 6913 zcmV+c8~)@&S5pZfGXMa1+Lf7kR1;U<fTLAJeZgHTi1ic26_hGbNkLE$MOG0I!lJB6 zhMTBJP$E!8z^Xu%#Y#j_WG6u+GXY{itAa&Qwj?^2rD|Q{psgjgAo@*H`kwck!a2hq z^AEq7$vMyS+?&k6q8WTo)45Ee&7DuPn>LX~qir7h`Sa%mx?^apq0t!fkF?LUsgraW z2B-0k)SvwLO+V9;bvBJ5N8@QGx?}(6RPx%-+6!p3Y0JkMrEDcQ4k2Pj=w4c)&e*ZE zv9!gyU;O*dldscUIemf~FY7ler%fpMg7(+#zo30V-hP?xxWCVzt-bwkwEwyN=C+O; z)9nvC#E+O7$A^D?!Z_ME+D6?q<SFC-=c>Ox<-b>rPjRF%f@zwDByf5LTx5amN{+a( z<<XCXL`TNDk98~n<@PY>ET-59@WRgVDb;sn`ybL@eGMM6V4XsGPR2vxdK|3kQ-!uh z{G<(F#$J3alq6QLH(R$ocP=bvxMXSaOo6=zo^=tmTE)3!rZ}coR>a(;N547;u$JN- zo6%|>a`1v`wOstI&_AAD6GQAJaCjH3h)1j&l+LE*8-!lJVxrx^Lxx{OP_vsHQ*Os3 zP_$F#yhL->1uQ*>Z(bqcy0XqEwNw*%rv>rG^!^5dI1TSEmc}u;w;H;ZHP>Vq?km>( zyc5XEArg%Jr~;rHkI<7;!|>lU_u1gwL%5<Ia}`D;b05BSu8hz7i{E&Xn+<L3gz@At zjy%2~57OF%F|-A`I#i0#(H1d*dJz-IB6KMip{p%o;;4$4I8?+W8cW}I;TKuQzx{U+ z6Br?5=ywu{jOlQt1s0MJ@tBT}?UIBE*r{|yE~wZH!%kz5*MZlmos0czCNm?w`LC`3 zJOo~UAU#*ciwx`W8mvz>w4KLKl!EC1U)wG@lFMFW(xx;jL}V_rvE1dvW;gu%9Mr;? zb7H>2gD7(_^mfu*nGHgg;P-9O;&5d51?4-rm?rRx=SyP<K;Z2U(A)&X<i66#xvWO! zb(LQF7`VytoPFrRyBwpW_Sf>Fnb7H_Cd-vravrx`BMA#+oxjjhW16>bAU=fNe}^D4 z-~&_X(Qxj)=Ut9^H4?%8W!Pg+LS6y)g=0-mL1Hg{%~bNpkoBJb;1zKmhih(Nfx?Jf z{-ag?m7l-;yNF367BQJh5tFq={D*oG{~?Reqg;fZwg~-E6`?;=#1tB9-npw2Od^IU zLZ2BrhTb$DoShEoYp?@?h(GE0*K$dNAtyznyZ|a~AU6ejwS+r1uG8MCW;r}C8+$D# z@ICNWqcrC%FVdyQtGQkzw1NCYl$g%KziyTsN@uUpX+ygTCo`QDnhVQ-jVpdC6J0!q z6Qi$K(_GpBy-xAPnZ%yOc*90CBN*A5rMxZ|eJf<f)6sr{)r&W`qUp(qPPd}VzszUA z^Ea#{2)NecnbGKM$k9t}Zz2j63@0|0*-9+V!#8e_1R<=9hL#%tyfcFM#q|Cr(0dlP zu9GH3b2~qE`C8Td4)>R0PrQiwN*K+<a5YHP!QVKe8yIW}z4bMbhr<oGF(fylk^d+V zT#X+pV#<g`Or=u9RBaK{s24GfEMhw4BBpDLm@%p%W(*ZElg3*9$Yv7eHq5uiEI}Ae zb1xAHr$ftC*f9Z^W`gg}K^H?r4|{l?kZgqeld(Qy?xcXu1A{e=!ULHabve-)0B_Yx z3(|OzW<6oC^&&$XoS(Rcm>!Co-Ig3mU@z=#%M=wf4LE0L&KD6Ix8q6asL>S89!<x4 zQE8IU^RA{m69g>6>lo;%U}R~ka<5!O6ZppStNMx1xA^T=G$D=C`&=OcrTvVZ@99NP z!S)~VbOEa0!|oHeml+ji%C^7eXL^7|`8dN?5+q=q>TapY$=g2=A4c!LN4yonR)#b+ znfq*Z7bmvXf)Tlb{&W}dBMJrku<j2)tPkhKqBTs;0jwP%@;jmJZA?%U(Zhd~3$A`1 z`qr2^ViB{b6fsL%#BAzC%qEMNL%E1K+9JLjRS{nf6)~5_TL19AK7GwFd&E3J*bVyq z@gQ$1v|ELpiUu2I<7ZOPL|MdtG`JyweFG0BV1qNb3%xosnrliK2RbxwRuEl2@QzGc zAmAnF^n^LrpOV?m<tLgGQ}^Iz^^$#&Yy)LmVr)UFz^Q{SECk;;;zv)S)4t%iKkvAi zQmVuBoQ##F6F$axEdxEsL};l>8&P?lz$czxIRN&&#p@MlWEw}=tBB1hjbZLwgB6AV z$6NTxBk0(->}Oc}N#{Z@!|ez^V<%x;h%>fHe3MzHKDCr|<wXkO!!!df;B6jM*h^E> zxP*1riJaOfS!9{!7hiA-gGUZwy`KSQ0-bWOxiaK{rsEAL?1tMKvE-tN&q<GZK-E8c z#M}{!FrZR|fwl-k>O~lmMa-jI#5`>gMx!diXsC$!G?v4c0n-}h3{!-$F#NivB@tYj z3Y|=`^E}|LkN+5pjTc1R<3j_Y))F3$l}?<@{hHn>5!JksMeU@&DFr=Vu&GK~g7A)N zdO`>5%NaHg`H8EDsR8&(sRV?xCt+<-Rs|e}lLtThGO*l&A5KPfKXc6QcjWt*6f$;B zrk749yo~Xy>rfVx^Das8E~k8fa92FNVt@#Ehf5V`_*o9ttFV%n8VEhAG?zn(Esc0` zg5=W&cC)gbnNmm>Y+s={qa=(=@pY~e-?Oa5*)7>ddFcc3OEd#5#JfvS;VjL{<q}?9 zwav9zhLLYH&md^5g$c3Phsi)mho|J2&p?C)U-^b8?SZa$v9o1hP7?kVsQPD*m_K3> zUr{OID{T=As28z-EaLwt7x91EA{LISh=pVk=Hw~HG?u6L>sg-t!xXVx#=4HRC4#~! zaK{R)oCnxCaI8NT$^a)do#zPodexZjPCLDtrGiLz&C3FybcWRzrAJ(O%f;PjY~2cG zY?kJ;88Ox$pIIZZLRh7Bt*HOyNrG)N>6s?PDn~plP0}@m**M@fg?>>;IIP7p{L!^# zoFirm^TE=5f#+?$NEa|C;<e+^=mE})Iz_HtnUTQr5WnOd;RbP`2wkzAV;$D<O%Cq~ za%ciu-rK%Cr$7lE%Qa^ng0DpQI&X<r5i612lI@(gQxIRQ8E7Nk6+)GVG^>KA$L*5o z)hY!CMA&mb;wQOkx=yt@zxx+Z(+ojA_8<@>b>rQ7=wTVhQq%qiaajW$KK|W<@rXSv zqSC`6Z4Zm7_pq4k!Gv-TCfXjBjH-tvWDl#!Q<l<L!QL@nD!Pa1!Cc0^uIU&@lud!V zmSNT5;P@x_wH0>Tkh`7V{R2^Nq0+lw{g(eMk9e>d7N$w}tl+-pcF!EV_L?b}MgOA= zeDH?-RT4df<yhC!2QHluZrRCCD+b0+xLc+K{fd3U1gq$)i500u#U?Vhd;I)N!f`2{ zy&e5V!1-ROuyroI2))MA%Z~z|k9g&;DDy6-C`>UQl+I&%&@}}Sz(Ik3mn-@x=j9_& zlbO31PCR;MC$SX6x3eWNH(83fR>$Ux3g)Ke{G%S=V-ft-L)uiv3k~b$5ZAmI{5P66 zOrWTNxdN%#XFpcVV+WN^0K7LSwG;r1j&q4Ck73{gtf~rlr{Za`l7F^`r6cCBj7kp6 zv^gxNp2Ko7hZU4_SfR~f<*0I4N#<Zio?=R4?K`VGFZ9P@a##;J*EPy<fBnkZy$rh( z4Dx#6epBfp$eX0;Ijc^3;OB)uW2h{8yJi~I77O{OHE$OYPn}>(j<j+!?@U%tqH}$z z%tnD7TSn-6;7cz`_Apql!`c?*T)s2l*h)W}hlC9<!+pD?%DxL7(+7(aneIPfmroN; zM)-Mi)W((bJy&5PD$Nsk*7HjSfX93MB19SaobdS_IbFpAOm_<`kEM=X$1Jgg4a)no z(H44UH!!Ke?Rk=zcGm5zR)*e1RJN&%f5a1fDuaZN^uCNouKJUv*Sv($A`Rh3D6YYR zcyWZ){vdVA3cqEwKfA+2W!MV@)M=oL73Oak!JsSu1foBnXaC<Zn2s2O8I>5!v@xur z9>Xd!hSii~Sgno0d{i-*lQF2s@z*p~yfW*nzJg(5*f_A~26k&ANHc;a?%3|T5x+ji z?fg-;5X|CtiNUQPc)nG-N6Iry?S7F`@5->ffPKdRM*DHMF3C^%?5DFkJmn=PWS$;; z@j@bqfwzRBl6>U2Ms>urVu386P9uv3`=8)lm1sT#nQf+!$xAVT2S;;h2l34XJk(rr zX*=t8e(O?E-W3@4So6USJV}F<OQe>;+(jDL<cviLI0U_|i@0zLn&)8KgCnBnKNJ&J zdTjo-_VtL?)=;swMr&;?b!%%$YZjEPS!k`%M`evZWNjUdm7+8;PW)~dYYv9NWB7L_ zf^<W;+7&xc52oG6GmNl_OprnEDI*#K;H5@sXg<%F+x<bW-bHAeLqA?k%!|NX+9mQd zc2jT1tk@Dq#?I;dvOFSS1KzL)%@ZQ5Zq*o5@wd?58ms;QBA(&xD4MpJ(`&5|43^Rd zb|9L(4q`(-zK0>n4rFx}wk{paYZb=j(?4tl&(a}kF5MK(wVDn4b1;n|LSP*|M1CV= z<YR&15k+PXKM|F=yZ^SfZbWPAsaRXDwYGt}wGE^-OUl+PwbmG;vc?#)_6?17ewJj( zcreV<yo+JT5v=Jr_`v{vvmHAw1sgEDoxqMmZaV$(GNQ=`7RsgIByY`@9vykTGqe?A z$1Mm07Vg+6K?Urq_uHSD7XKvkn1+>HAbi&0*O=(>bi_uftTYl`moe)!=m&!J9B-^a z1+JX?E{c^_B~qq)x#ofjtSiEq_L4Kvtd54(x&C=qnQ^~hADW2gKfoF*smn>OvvsFs zm()ub(Tl0}fTAX7UxY>TA{yzB0`;y24z0CsMzm%{#hR7Ynl*K6)}*zKl&x*lTC*9I zHJc%8wlr3$=ceVEZo{lKPe#}nezPvfoeS;kvGWyR&jmO`F4bl7&d{F}5zRYcX_fSl zfXC49(E;_q(AJlK{A*%v5N;=zh{D;~h3yiecpGEKRIDfm>|Bdq^+XS*A-eaKy9Y%y znQxrt>K{bV3tT2c5hkZFjC{N;SqI%jnj9anwjB3#m870z-P5%EDbKq)5ciz^M>BYl z3uX3F-&}5JSSMm6RT+Y}*rOn#ycs%|VQGSh57v+B^{##%T5Gl=TH8d$+9s{F&D5=J zCau{~wq~cbW<M%x_CwaT&{)+w+stOI9mbj;Bm4-zWdd>eOXy^aNs7RcBp93`O@@0< z(|=hETHK(xNO}a}ZF=4_TdzKXX}e34d<A^zhuc(23cT4z<JymjitfnVr(gw!gqt~D z=#H`yI6pTiX@li9vR$7vR}K<>FY(G7sCO_YF0P|Ir?{HwD%J=gFt5bjy(LHUS+`AE z`t|avWN|OBKU%=c%kYM?G)T&gP3jbaYHuO;9R@={WefDK!15Eok}dcYqpJELYg<ON z=0L@ogVx$s>ejZB*0xc$woPlzaa7hENoz`Syq(5s$k=UO@Z~T&WH6IGhToP9N@v4e z8?jqLP{M`z&U=lB+cxlr6shwnZd+XUEN8jnz~L-xPz=WV<MU97Pav!RLR+X_K?&1& z8kUns*jVDH*yu_b=MY_CJ6QT7^ty?O#{&P4IQk3?EaT+rEA&JqzD)NjdfroDS&y@$ zB(;!jk<{AXbxFb4T!I~SCq7<=&zz;DMLfN*t}>%qFIl7++HeH>JO?PlAh5y=naDwY zM;|Es4LWH4mbQIFX--t6IccRiQ<vsUN^_ws%|$ECbyU(^Nofjl>_%gCw7;`h`*9d) z90A9cuGAsKvtS4V>qrNWyx>!#eTM2Y@3}FvyF&bB-w6)3Yx;_b_dDSq6_ROzERML< z(<r|LZkw*jGzR9j%C25%iss^%z<vduwGCY#$@yNau<0uOS?2jkQ~D?2uEukILRUp{ z=;96|Jzj{KH-(+}sZA!joF#KuiJedpdS&=z4{2`^FDI<KcJNvjBifYzx{GM3Q<<1l z@8|ctAZnEmslo21f%pKt-U{6~^wQ96L}%_)oVjbA?V#>#2kFd%vNI2@vz?=Iwv%+$ zPL4fktfw>L*5B$GW_#QxL~hU@CIQI|$X$oMNd|vzsYcMoa50i|-~#c`7S^4VW-j4z z!g}lm>rXIjXY!Ml5Hp-`db%XhkiAJCeGpX@DY|RL^CE1Q;wS9UMF?kiVaL1X(gnhu z@${m8;PeJhZ$=FT9Q_8Vq_0{ix*Ut_A(qzT_E8c}538WC<*rd)=0N-kP5&<9jRZFH zq%m)~w?EbH?YoyIw(Hva3e-P@QT15QSy04<Upb@y{BzKAL}Ol5jCpB|c~dv$O&Z%p z+1M_vF`rQx^C6A3kYisO>(?3o`Nr<%FstmK5ZKaTB2hCP9$X_HGq|@+{e6WW+W!(& zc{a#+{C9cag&pinlPZ?*o&>bmHD6>i>`r5+E`hIXm6^{`Zd3(ZRHnzBg~XiY&^~q8 z<`h3+?$}H(I6^oL;_0tYLm6j@b%(wY52z!VOh<!<PRdeiNhLk4hnRZ}UmPVd>tQV} z?78b-hYbkC{P*3+%`g0`W7Jz!n*wSwq8iJ@M)JL@iEA%lR2SBx0!2Unt;=^rT}&#v zm|9(a)OGohy8J2Y^4IDL7?rL7QdcuM4y3U@?>N7)qi7gi@iOiWdiQuxKTV}uSDkFp zXfNi(Mk<lwM*pmsw;NO`&*iSzhdiRs4)&jv=ozwn=eN!@4b4R?-}^2xXqPA}ldu&Q zRj#5YE1o`bIFO^8+F>Iq&J()V(=QHyO>dP0F4995H8N2_PQ-G=XS462?AEPHzRA^h z*zq1PNsdp9lK%FVhd%Ef7>wD2G|upU+5e_lwIi-}mc_j)u@$jzKayAkKE%NuAPpQ^ zT7e_F+D*mPZmp|5)Lrc%T?J8g6{K|)JStbgq^m}9971F3omsv)<is$WVG{mxf=bt= zI>h463h_2kq^mkF-QU9Cjj3v1(zTU+&v_Nhl*9AYy#s-&0h<<!?_$dnnnV56YoU)O zyKS}dVi;N)b;UuHtp}Qsz23~${+>z7kMldGbn#@!p+;s-3=C7Y>tJ)D$}2?9&a9V+ z?HZpF-=;>TwMnHLnsB7zjZy4H<mr@v8iV)SR7bfoiG`|2T#$0W3^|wVSB^hbt7ars z`}bWRdQ%lLqNPwOmO{0b!l+vcBQ1qfwiK?l#2S?)){rGOjcs_kddn}|VOCTM{`3pg z0+*W2=-nmaeJKa-BZUe6$7+dU)e-KslTj~2D}wzGL!|d<pvw0~t#WZgr3lSH%5NHl z&r#b{_<CA)ELNiWXpzNLb5V&ENJjP=GxK7)VwF!Duuc?(qSO@RH^e*MR~XZ#QYMM3 zGNOLSEk7?0E<mOk?^=(4YEV7dQnv#o&Q{nFhnA`9UHxSSYN+zosoh}lpj8~uwZ8^A z-Q&j_db!LV(GrJ>C63k-LfsNVT8f}-DMD)rjLH%qEnOtXTpD{>>lViY?!&C5i~;Tq zevgj&DAUgaf3`@qA)vM#?F1Dw<T1I#`%O@DQZj1}i!=Y~gT4#VB4faLs1B)OhGci; zC_mP9Ea>`chl{6Q{8JrY#Jm;*{ge%bXnNn}%<?z>p+6IP<hB<5*S40Uk*|(=dQ$w0 zC~66k>+M&T{p5*if*0(ulEx1`L2*aq&!fVhr{%wwI{&>S|9zDC@6+<%KPvwFN&Y$H zIFiO*KUL{6&SDt;=M5eoQ_T#k8P|7jo%pEUfp$b94bU<8O`<{@>QehY3d)U%U?arj zg%6h9vRZjA3@z!qVk^2R;!Z;NYnUzBJ%^R*LMg*S(kx2SLsqI?J$xq_G&?DGSXZ7# zk0n<8Vimhk{m3|go&C;D6?UOE3vIa}4)foqQKz)~ts43si5!vr0V?bdXxT?mXCFnf z=Tm0S*Rqcu75nHR_6KR~Ep8$18FPo(q4F)CC8$<=)%+6GYA&v6=DVruas%uwe_y4N zr`9!F3?k)*An2TW;a#7^+WX6uiPn;rXvqfAq1cG6YSt>ITMUd<J`iKfK2f{K%bEQa zu@CoY!tb^#x9}??qY^SJ-pFIake-bJ*_OX~t77iU*7YfW5?@G(l&Xc$uVQH5IXEKw zLsZxw(z1`C&OU}@FQCj`pk;q}RO}Cv?9Y?qSXxl=#-`$pcm9pO)Zo=Pm77cL&Avy= z#E(;=Q;|C-1CC{DmZ)xf)u}B$`j;;xg1nIV6+U+T_ZBJl=}R1<E}M%sICGNKyNrE* zj#0%bs~XV5QALkLCMm3aYDT=z$?PT{rKPyi!Xlxdf-sGJjXYxp+_n7OPnD{X{b|wJ zD!$(wbx>W><Nr_gu_L07qk=w8i$0z@`gjukx0KO;t3`igROpY8==YQ3qqLyg){|~q z>;4;krSH=u)ykw=ohXHa__h4dL!?_3D7E~tMrn^#t+dGZ6#1G)=ph^j=J$AKzY@k_ zbJ0?{Xch=7MvPbNV)YL?sOkc)by#$liP5eDYt)%H{o;q-I3FDmXaW_W30k1Xr~^Gl z0!^e0G*JsQX;eUyhJYs1f*xPn^!S?1zkycAygH`Z$(7khb#JIxXd2UwJg*46UHhY% z(jwq$33}dMG)>Mvq4r|<wq&agD=V@jc;BVF<y}N5K#aV1Ir@I`P&J9=eDs-Ita0X} z>aqv_Ei`#VpvS2IJ+1}%9d)4Jkw8yS26{pZ^yH|3o+N<+a(s#wG-w$!XnFA8K<j<q zj&C318@$o!^(#@%dRfI)y|`9n(#c(y4P2ugMeI;#vx_2{h;>A5|G`%u_rJNF&h`RJ z9WEDJB*-fWf?->v`@72eoVtC!<!<QzcIXGjsS#PGP+^&(WtmEyWh%)sjWWwLEz9pm z#qxWS<yLZhnig!ZUS_bq`rj-YvR_YB?QM`xwD{mt?${hQ9oZW0d&5#0txUJBT4(WH zNrl|`P%l!G@9#47{C|2xOlPQII-|vuP90M^i7A6JrVK5n%u!*=Br(~M<1AV*9eYp5 z-u)X>b1gE%xscszWxe9Ez2t|ijOMoDY_Io@KCkG+LeHY6-(PTrl6LQ*RhdO1qS5{z H`fB1#(6^Z< literal 0 HcmV?d00001 diff --git a/regression_tests/xmlin4/ebu-ttd_sample.ttml b/regression_tests/xmlin4/ebu-ttd_sample.ttml new file mode 100644 index 0000000..0f5d7ec --- /dev/null +++ b/regression_tests/xmlin4/ebu-ttd_sample.ttml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<tt xmlns:ttp="http://www.w3.org/ns/ttml#parameter" + xmlns:tts="http://www.w3.org/ns/ttml#styling" + ttp:timeBase="media" + ttp:cellResolution="50 30" + xml:lang="de" xmlns="http://www.w3.org/ns/ttml"> + <head> + <styling> + <style xml:id="defaultStyle" tts:fontFamily="Verdana, Arial, Tiresias" + tts:fontSize="160%" + tts:lineHeight="125%" + tts:color="#ffffff" + tts:backgroundColor="#000000c2" + tts:textAlign="center"/> + </styling> + <layout> + <region xml:id="bottom" tts:origin="10% 10%" tts:extent="80% 80%" + tts:displayAlign="after"/> + </layout> + </head> + <body> + <div style="defaultStyle"> + <p begin="00:00:00.000" end="00:00:01.400" region="bottom" xml:id="sub1">00:00:00.000<br/>00:00:01.400</p> + <p begin="00:00:02.120" end="00:00:03.800" region="bottom" xml:id="sub2">00:00:02.120<br/>00:00:03.800</p> + <p begin="00:00:22.720" end="00:00:25.840" region="bottom" xml:id="sub3">00:00:22.720<br/>00:00:25.840</p> + <p begin="00:00:26.080" end="00:00:29.120" region="bottom" xml:id="sub4">00:00:26.080<br/>00:00:29.120</p> + <p begin="00:00:29.120" end="00:00:30.640" region="bottom" xml:id="sub5">00:00:29.120<br/>00:00:30.640</p> + <p begin="00:00:30.960" end="00:00:33.200" region="bottom" xml:id="sub6">00:00:30.960<br/>00:00:33.200</p> + <p begin="00:00:33.200" end="00:00:36.320" region="bottom" xml:id="sub7">00:00:33.200<br/>00:00:36.320</p> + <p begin="00:00:36.320" end="00:00:40.040" region="bottom" xml:id="sub8">00:00:36.320<br/>00:00:40.040</p> + <p begin="00:00:40.040" end="00:00:43.520" region="bottom" xml:id="sub9">00:00:40.040<br/>00:00:43.520</p> + <p begin="00:00:43.520" end="00:00:46.920" region="bottom" xml:id="sub10">00:00:43.520<br/>00:00:46.920</p> + <p begin="00:00:46.920" end="00:00:51.040" region="bottom" xml:id="sub11">00:00:46.920<br/>00:00:51.040</p> + <p begin="00:00:51.080" end="00:00:54.160" region="bottom" xml:id="sub12">00:00:51.080<br/>00:00:54.160</p> + <p begin="00:00:54.480" end="00:00:58.240" region="bottom" xml:id="sub13">00:00:54.480<br/>00:00:58.240</p> + </div> + </body> +</tt> + diff --git a/regression_tests/xmlin4/first.xml b/regression_tests/xmlin4/first.xml new file mode 100644 index 0000000..76a90cf --- /dev/null +++ b/regression_tests/xmlin4/first.xml @@ -0,0 +1,3 @@ +<gpac xmlns="http://www.gpac.io/xml"> + This is some text in first.xml +</gpac> \ No newline at end of file diff --git a/regression_tests/xmlin4/input.txt b/regression_tests/xmlin4/input.txt new file mode 100644 index 0000000..b520ab5 --- /dev/null +++ b/regression_tests/xmlin4/input.txt @@ -0,0 +1,13 @@ +This is a test file containing some text. + +1st paragraph +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse vehicula suscipit ligula, quis dignissim ipsum auctor quis. Vestibulum condimentum pharetra quam, id aliquet libero euismod quis. Sed sollicitudin ullamcorper arcu, sit amet maximus tortor gravida vel. Duis in dolor in lorem consectetur eleifend. Donec ac suscipit ante. Praesent pharetra vestibulum felis et aliquet. In hac habitasse platea dictumst. Vestibulum orci urna, auctor vel tempus vitae, mattis at enim. Donec porttitor sollicitudin ex, vitae congue dolor dapibus sit amet. Integer vitae quam a erat dignissim eleifend. Aliquam sagittis leo ut leo luctus pulvinar. Fusce ut porta eros, eget bibendum justo. Mauris nunc quam, ullamcorper in hendrerit et, tristique elementum erat. Vivamus convallis pellentesque dignissim. + +2nd paragraph +Vivamus sed euismod ligula, non tempus sapien. Ut iaculis arcu quis cursus placerat. Phasellus vitae ipsum justo. Curabitur pretium nulla ut lorem pulvinar, quis lobortis augue congue. Donec mattis placerat elit, non tincidunt nunc bibendum et. Sed fermentum urna sit amet quam ultrices gravida. Suspendisse vulputate nisl enim. Duis euismod luctus enim vel dapibus. Vestibulum at elementum diam. Mauris commodo pharetra bibendum. + +3rd paragraph +Ut eget quam mauris. Cras tincidunt tincidunt est, id dapibus massa gravida gravida. Mauris sed congue nisl, quis dignissim orci. Proin ac fringilla orci. Morbi malesuada elit id arcu ullamcorper efficitur. Etiam eget leo arcu. Donec vestibulum diam odio, ac porta libero bibendum pharetra. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed vel ullamcorper dui. Donec vel blandit mauris. Nunc eleifend maximus tristique. + +4th paragraph +Praesent turpis lorem, maximus ut luctus eget, sodales ut enim. Ut malesuada mollis efficitur. In mi urna, laoreet sit amet imperdiet quis, fermentum sed ipsum. Sed enim augue, dignissim at sollicitudin non, consectetur sit amet elit. Donec lobortis leo sapien, non cursus nisl ullamcorper eu. Proin id massa porta, mollis dui non, rhoncus ipsum. Cras eu est a eros dictum tincidunt nec nec turpis. Quisque nec arcu a ex blandit semper ac et libero. Sed at augue sed tellus congue imperdiet eu id ex. Fusce ac accumsan augue. diff --git a/regression_tests/xmlin4/input.xml b/regression_tests/xmlin4/input.xml new file mode 100644 index 0000000..07f56c9 --- /dev/null +++ b/regression_tests/xmlin4/input.xml @@ -0,0 +1,5 @@ +<gpac xmlns="http://www.gpac.io/xml"> + <p id='elt1'>This is some text in a first element</p> + <p id='elt2'>This is some text in a second element</p> + <p id='elt3'>This is some text in a third element</p> +</gpac> \ No newline at end of file diff --git a/regression_tests/xmlin4/last.xml b/regression_tests/xmlin4/last.xml new file mode 100644 index 0000000..98e35a0 --- /dev/null +++ b/regression_tests/xmlin4/last.xml @@ -0,0 +1,3 @@ +<gpac xmlns="http://www.gpac.io/xml"> + This is some text in last.xml +</gpac> \ No newline at end of file diff --git a/regression_tests/xmlin4/meta-mett-no-mime.nhml b/regression_tests/xmlin4/meta-mett-no-mime.nhml new file mode 100644 index 0000000..b954e1f --- /dev/null +++ b/regression_tests/xmlin4/meta-mett-no-mime.nhml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="meta" mediaSubType="mett" text_encoding="utf-8" baseMediaFile="input.txt"> + <NHNTSample DTS="0" dataLength="45" isRAP="yes" /> + <NHNTSample DTS="1000" dataLength="820" /> + <NHNTSample DTS="2000" dataLength="449" /> + <NHNTSample DTS="3000" dataLength="487" isRAP="yes" /> + <NHNTSample DTS="4000" dataLength="542" /> +</NHNTStream> diff --git a/regression_tests/xmlin4/meta-mett-xml-header.nhml b/regression_tests/xmlin4/meta-mett-xml-header.nhml new file mode 100644 index 0000000..8f948e3 --- /dev/null +++ b/regression_tests/xmlin4/meta-mett-xml-header.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="meta" mediaSubType="mett" mime_type="text/plain" xmlHeaderEnd="elt1.start" text_encoding="utf-8" baseMediaFile="input.xml" > +<NHNTSample DTS="0" isRAP="yes" xmlFrom="elt1.start" xmlTo="elt2.start"/> +<NHNTSample DTS="10000" isRAP="no" xmlFrom="elt2.start" xmlTo="elt3.start"/> +<NHNTSample DTS="20000" isRAP="no" xmlFrom="elt3.start" xmlTo="doc.end"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/meta-mett-xml.nhml b/regression_tests/xmlin4/meta-mett-xml.nhml new file mode 100644 index 0000000..86a455d --- /dev/null +++ b/regression_tests/xmlin4/meta-mett-xml.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="meta" mediaSubType="mett" mime_type="text/plain" text_encoding="utf-8" baseMediaFile="input.xml" > +<NHNTSample DTS="0" isRAP="yes" xmlFrom="doc.start" xmlTo="elt1.end"/> +<NHNTSample DTS="10000" isRAP="no" xmlFrom="elt2.start" xmlTo="elt2.end"/> +<NHNTSample DTS="20000" isRAP="no" xmlFrom="elt3.start" xmlTo="doc.end"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/meta-mett.nhml b/regression_tests/xmlin4/meta-mett.nhml new file mode 100644 index 0000000..99ad854 --- /dev/null +++ b/regression_tests/xmlin4/meta-mett.nhml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="meta" mediaSubType="mett" mime_type="text/plain" text_encoding="utf-8" baseMediaFile="input.txt" > + <NHNTSample DTS="0" dataLength="45" isRAP="yes" /> + <NHNTSample DTS="1000" dataLength="820" /> + <NHNTSample DTS="2000" dataLength="449" /> + <NHNTSample DTS="3000" dataLength="487" isRAP="yes" /> + <NHNTSample DTS="4000" dataLength="542" /> +</NHNTStream> diff --git a/regression_tests/xmlin4/meta-metx-no-namespace.nhml b/regression_tests/xmlin4/meta-metx-no-namespace.nhml new file mode 100644 index 0000000..1d7dfc8 --- /dev/null +++ b/regression_tests/xmlin4/meta-metx-no-namespace.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="meta" mediaSubType="metx"> +<NHNTSample DTS="0" isRAP="yes" mediaFile="first.xml"/> +<NHNTSample DTS="10000" isRAP="yes" mediaFile="second.xml"/> +<NHNTSample DTS="20000" isRAP="yes" mediaFile="last.xml" duration="10000"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/meta-metx.nhml b/regression_tests/xmlin4/meta-metx.nhml new file mode 100644 index 0000000..f2992e0 --- /dev/null +++ b/regression_tests/xmlin4/meta-metx.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="meta" mediaSubType="metx" text_encoding="utf-8" xml_namespace="http://www.gpac.io/dummy_namespace" xml_schema_location="http://example.org/a.xsd"> +<NHNTSample DTS="0" isRAP="yes" mediaFile="first.xml"/> +<NHNTSample DTS="10000" isRAP="yes" mediaFile="second.xml"/> +<NHNTSample DTS="20000" isRAP="yes" mediaFile="last.xml" duration="10000"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/run_one_test.sh b/regression_tests/xmlin4/run_one_test.sh new file mode 100644 index 0000000..7c2635c --- /dev/null +++ b/regression_tests/xmlin4/run_one_test.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +echo -e "*************** Running basic test for "$1 + +echo -e "\nTesting import" +MP4Box -add $1.nhml -new $1.mp4 + +echo -e "\nTesting info dump" +MP4Box -info $1.mp4 + +echo -e "\nTesting entire track extraction" +MP4Box -raw 1 $1.mp4 + +echo -e "\nTesting sample by sample extraction" +MP4Box -raws 1 $1.mp4 + +echo -e "\nTesting nhml export" +MP4Box -nhml 1 $1.mp4 + +echo -e "\nTesting nhml re-import" +MP4Box -add $1_track1.nhml -new $1_track1.mp4 diff --git a/regression_tests/xmlin4/run_tests.sh b/regression_tests/xmlin4/run_tests.sh new file mode 100644 index 0000000..584c6eb --- /dev/null +++ b/regression_tests/xmlin4/run_tests.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +echo -e "*************** Running text tests ..." + +echo -e "\nTesting simple 'metx'" +./run_one_test.sh meta-metx + +echo -e "\nTesting 'metx' import when namespace is not given, shoud fail" +MP4Box -add meta-metx-no-namespace.nhml -new meta-metx-no-namespace.mp4 + +echo -e "\nTesting simple 'mett'" +./run_one_test.sh meta-mett + +echo -e "\nTesting 'mett' when no mime type is provided, should default to text/plain" +./run_one_test.sh meta-mett-no-mime + +echo -e "\nTesting 'mett' with an XML document" +./run_one_test.sh meta-mett-xml + +echo -e "\nTesting 'mett' with an XML document and a header" +./run_one_test.sh meta-mett-xml-header + +echo -e "\nTesting 'stpp' import" +./run_one_test.sh subt-stpp + +echo -e "\nTesting 'stpp' import when namespace is not provided, should fail" +MP4Box -add subt-stpp-no-namespace.nhml -new subt-stpp-no-namespace.mp4 + +echo -e "\nTesting 'sbtt' import" +./run_one_test.sh subt-sbtt + +echo -e "\nTesting 'sbtt' import without mime, default to text/plain" +./run_one_test.sh subt-sbtt-no-mime + +echo -e "\nTesting simple 'stxt' import" +./run_one_test.sh text-stxt + +echo -e "\nTesting 'stxt' import without mime, default to text/plain" +./run_one_test.sh text-stxt-no-mime + +echo -e "\nTesting 'stxt' import with header" +./run_one_test.sh text-stxt-header + +echo -e "\n**************** Testing SWF conversion as SVG and import as 'stxt' stream " +MP4Box -add anim.swf:fmt=svg -new text-stxt-svg.mp4 +MP4Box -info text-stxt-svg.mp4 +MP4Box -raw 1 text-stxt-svg.mp4 +MP4Box -raws 1 text-stxt-svg.mp4 + +#MP4Box -mp4 anim.swf + +echo -e "\n**************** Testing TTML import as 'stpp' stream " +MP4Box -add ebu-ttd_sample.ttml -new subt-stpp-ttml.mp4 +MP4Box -info subt-stpp-ttml.mp4 +MP4Box -raw 1 subt-stpp-ttml.mp4 +MP4Box -raws 1 subt-stpp-ttml.mp4 + +echo -e "\n**************** Generating file with all text variants text-all.mp4 " +MP4Box -add meta-mett.mp4 -add meta-mett-xml.mp4 -add meta-mett-xml-header.mp4 -add meta-metx.mp4 -add subt-sbtt.mp4 -add subt-stpp.mp4 -add subt-stpp-ttml.mp4 -add text-stxt.mp4 -add text-stxt-header.mp4 -add text-stxt-svg.mp4 -new text-all.mp4 \ No newline at end of file diff --git a/regression_tests/xmlin4/second.xml b/regression_tests/xmlin4/second.xml new file mode 100644 index 0000000..0f17671 --- /dev/null +++ b/regression_tests/xmlin4/second.xml @@ -0,0 +1,3 @@ +<gpac xmlns="http://www.gpac.io/xml"> + This is some text in second.xml +</gpac> \ No newline at end of file diff --git a/regression_tests/xmlin4/subt-sbtt-no-mime.nhml b/regression_tests/xmlin4/subt-sbtt-no-mime.nhml new file mode 100644 index 0000000..025b5d9 --- /dev/null +++ b/regression_tests/xmlin4/subt-sbtt-no-mime.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="subt" mediaSubType="sbtt"> +<NHNTSample DTS="0" isRAP="yes" mediaFile="first.xml"/> +<NHNTSample DTS="10000" isRAP="yes" mediaFile="second.xml"/> +<NHNTSample DTS="20000" isRAP="yes" mediaFile="last.xml" duration="10000"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/subt-sbtt.nhml b/regression_tests/xmlin4/subt-sbtt.nhml new file mode 100644 index 0000000..1c6e900 --- /dev/null +++ b/regression_tests/xmlin4/subt-sbtt.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="subt" mediaSubType="sbtt" mime_type="text/plain" text_encoding="utf-8"> +<NHNTSample DTS="0" isRAP="yes" mediaFile="first.xml"/> +<NHNTSample DTS="10000" isRAP="yes" mediaFile="second.xml"/> +<NHNTSample DTS="20000" isRAP="yes" mediaFile="last.xml" duration="10000"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/subt-stpp-no-namespace.nhml b/regression_tests/xmlin4/subt-stpp-no-namespace.nhml new file mode 100644 index 0000000..b414445 --- /dev/null +++ b/regression_tests/xmlin4/subt-stpp-no-namespace.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="subt" mediaSubType="stpp"> +<NHNTSample DTS="0" isRAP="yes" mediaFile="first.xml"/> +<NHNTSample DTS="10000" isRAP="yes" mediaFile="second.xml"/> +<NHNTSample DTS="20000" isRAP="yes" mediaFile="last.xml" duration="10000"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/subt-stpp.nhml b/regression_tests/xmlin4/subt-stpp.nhml new file mode 100644 index 0000000..b8f1c17 --- /dev/null +++ b/regression_tests/xmlin4/subt-stpp.nhml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="subt" mediaSubType="stpp" xml_namespace="http://www.gpac.io/dummy_namespace" xml_schema_location="http://example.org/a.xsd" trackID="1"> +<NHNTSample DTS="0" isRAP="yes" mediaFile="first.xml"/> +<NHNTSample DTS="10000" isRAP="yes" mediaFile="second.xml"/> +<NHNTSample DTS="20000" isRAP="yes" mediaFile="last.xml" duration="10000"/> +</NHNTStream> diff --git a/regression_tests/xmlin4/text-stxt-header.nhml b/regression_tests/xmlin4/text-stxt-header.nhml new file mode 100644 index 0000000..04ed182 --- /dev/null +++ b/regression_tests/xmlin4/text-stxt-header.nhml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="text" mediaSubType="stxt" mime_type="text/plain" headerEnd="45" text_encoding="utf-8" baseMediaFile="input.txt" > + <NHNTSample DTS="0" dataLength="820" isRAP="yes" /> + <NHNTSample DTS="1000" dataLength="449" /> + <NHNTSample DTS="2000" dataLength="487" isRAP="yes" /> + <NHNTSample DTS="3000" dataLength="542" /> +</NHNTStream> diff --git a/regression_tests/xmlin4/text-stxt-no-mime.nhml b/regression_tests/xmlin4/text-stxt-no-mime.nhml new file mode 100644 index 0000000..732be45 --- /dev/null +++ b/regression_tests/xmlin4/text-stxt-no-mime.nhml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="text" mediaSubType="stxt" text_encoding="utf-8" baseMediaFile="input.txt" > + <NHNTSample DTS="0" dataLength="45" isRAP="yes" /> + <NHNTSample DTS="1000" dataLength="820" /> + <NHNTSample DTS="2000" dataLength="449" /> + <NHNTSample DTS="3000" dataLength="487" isRAP="yes" /> + <NHNTSample DTS="4000" dataLength="542" /> +</NHNTStream> diff --git a/regression_tests/xmlin4/text-stxt.nhml b/regression_tests/xmlin4/text-stxt.nhml new file mode 100644 index 0000000..793b81d --- /dev/null +++ b/regression_tests/xmlin4/text-stxt.nhml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<NHNTStream version="1.0" timeScale="1000" mediaType="text" mediaSubType="stxt" mime_type="text/plain" text_encoding="utf-8" baseMediaFile="input.txt" > + <NHNTSample DTS="0" dataLength="45" isRAP="yes" /> + <NHNTSample DTS="1000" dataLength="820" /> + <NHNTSample DTS="2000" dataLength="449" /> + <NHNTSample DTS="3000" dataLength="487" isRAP="yes" /> + <NHNTSample DTS="4000" dataLength="542" /> +</NHNTStream> diff --git a/src/Makefile b/src/Makefile index a259298..ba9d9ab 100644 --- a/src/Makefile +++ b/src/Makefile @@ -15,13 +15,13 @@ LDFLAGS+=-pg endif ## libgpac objects gathering: src/utils -LIBGPAC_UTILS=utils/os_divers.o utils/list.o utils/bitstream.o utils/error.o utils/alloc.o utils/url.o utils/configfile.o +LIBGPAC_UTILS=utils/os_divers.o utils/os_file.o utils/list.o utils/bitstream.o utils/error.o utils/alloc.o utils/url.o utils/configfile.o ifeq ($(DISABLE_CORE_TOOLS), no) -LIBGPAC_UTILS+=utils/sha1.o utils/base_encoding.o utils/os_net.o utils/os_thread.o utils/os_config_init.o utils/cache.o utils/downloader.o utils/xml_parser.o utils/utf.o utils/token.o +LIBGPAC_UTILS+=utils/sha1.o utils/base_encoding.o utils/os_net.o utils/os_thread.o utils/os_config_init.o utils/cache.o utils/downloader.o utils/xml_parser.o utils/utf.o utils/token.o utils/color.o endif ifeq ($(DISABLE_PLAYER), no) -LIBGPAC_UTILS+=utils/color.o utils/os_module.o utils/math.o utils/path2d.o utils/path2d_stroker.o utils/module.o utils/uni_bidi.o utils/ringbuffer.o utils/unicode.o utils/map.o +LIBGPAC_UTILS+=utils/os_module.o utils/math.o utils/path2d.o utils/path2d_stroker.o utils/module.o utils/uni_bidi.o utils/ringbuffer.o utils/unicode.o utils/map.o endif ## libgpac objects gathering: src/ietf @@ -140,11 +140,10 @@ endif ifeq ($(DISABLE_PLAYER), no) LIBGPAC_MEDIATOOLS+=media_tools/html5_media.o media_tools/html5_mse.o -ifeq ($(DISABLE_TTXT), no) -LIBGPAC_MEDIATOOLS+=media_tools/webvtt.o -endif endif +LIBGPAC_MEDIATOOLS+=media_tools/webvtt.o + ## libgpac objects gathering: src/scene_manager LIBGPAC_SCENEMANAGER= @@ -271,6 +270,9 @@ endif OBJS+=../modules/timedtext/timedtext_dec.o ../modules/timedtext/timedtext_in.o OBJS+=../modules/validator/validator.o OBJS+=../modules/raw_out/raw_video.o +ifeq ($(DISABLE_TTXT), no) +OBJS+=../modules/vtt_in/vtt_in.o ../modules/vtt_in/vtt_dec.o +endif OBJS+=../modules/img_in/img_dec.o ../modules/img_in/img_in.o ../modules/img_in/bmp_dec.o ../modules/img_in/png_dec.o ../modules/img_in/jpeg_dec.o ifneq ($(CONFIG_JP2), no) @@ -557,9 +559,9 @@ endif ##libgpac library output -LIB=libgpac.$(DYN_LIB_SUFFIX) +LIB=libgpac$(DYN_LIB_SUFFIX) ifeq ($(CONFIG_WIN32),yes) -#LDFLAGS+=-export-symbols libgpac.def +LDFLAGS+=-Wl,-out-implib=../bin/gcc/libgpac.dll.a else ifeq ($(CONFIG_DARWIN),yes) LDFLAGS+=-dynamiclib -install_name $(prefix)/lib/$(LIB) @@ -606,19 +608,29 @@ compositor: $(LIBGPAC_COMPOSITOR) ../bin/gcc/$(LIB): $(LIBGPAC_UTILS) $(LIBGPAC_IETF) $(LIBGPAC_BIFS) $(LIBGPAC_ODF) $(LIBGPAC_LASER) $(LIBGPAC_ISOM) $(LIBGPAC_SCENEMANAGER) $(LIBGPAC_TERMINAL) compositor scenegraph media_tools mcrypt $(OBJS) @echo "OBJS $(OBJS)" @echo "LIBS $(EXTRALIBS)" + ifeq ($(CONFIG_DARWIN),yes) + $(LIBTOOL) -s -o ../bin/gcc/libgpac_static.a $(OBJS) $(RANLIB) ../bin/gcc/libgpac_static.a +ifneq ($(STATICBUILD),yes) $(CC) $(SHFLAGS) $(LD_SONAME) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) +endif + else + $(AR) cr ../bin/gcc/libgpac_static.a $(OBJS) $(RANLIB) ../bin/gcc/libgpac_static.a - $(CC) $(SHFLAGS) $(LD_SONAME) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) -ifeq (,$(findstring yes, $(CONFIG_WIN32))) +ifneq ($(STATICBUILD),yes) + $(CC) $(SHFLAGS) $(LD_SONAME) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) mv $@ $@.$(VERSION_SONAME) ln -sf $(notdir $@).$(VERSION_SONAME) $@.$(VERSION_MAJOR) ln -sf $(notdir $@).$(VERSION_SONAME) $@ endif + +endif +ifeq ($(shell fgrep "Libs.private:" ../gpac.pc),) + @echo "Libs.private: $(EXTRALIBS)" >> ../gpac.pc endif dep: diff --git a/src/bifs/bifs_codec.c b/src/bifs/bifs_codec.c index 5a80e93..9191c2c 100644 --- a/src/bifs/bifs_codec.c +++ b/src/bifs/bifs_codec.c @@ -39,19 +39,19 @@ static GF_Err ParseConfig(GF_BitStream *bs, BIFSStreamInfo *info, u32 version) info->config.elementaryMasks = NULL ; if (version==2) { - info->config.Use3DMeshCoding = gf_bs_read_int(bs, 1); - info->config.UsePredictiveMFField = gf_bs_read_int(bs, 1); + info->config.Use3DMeshCoding = (Bool)gf_bs_read_int(bs, 1); + info->config.UsePredictiveMFField = (Bool)gf_bs_read_int(bs, 1); } info->config.NodeIDBits = gf_bs_read_int(bs, 5); info->config.RouteIDBits = gf_bs_read_int(bs, 5); if (version==2) { info->config.ProtoIDBits = gf_bs_read_int(bs, 5); } - cmd_stream = gf_bs_read_int(bs, 1); + cmd_stream = (Bool)gf_bs_read_int(bs, 1); if (cmd_stream) { - info->config.PixelMetrics = gf_bs_read_int(bs, 1); - hasSize = gf_bs_read_int(bs, 1); + info->config.PixelMetrics = (Bool)gf_bs_read_int(bs, 1); + hasSize = (Bool)gf_bs_read_int(bs, 1); if (hasSize) { info->config.Width = gf_bs_read_int(bs, 16); info->config.Height = gf_bs_read_int(bs, 16); @@ -61,7 +61,7 @@ static GF_Err ParseConfig(GF_BitStream *bs, BIFSStreamInfo *info, u32 version) if (gf_bs_get_size(bs) != gf_bs_get_position(bs)) return GF_ODF_INVALID_DESCRIPTOR; return GF_OK; } else { - info->config.BAnimRAP = gf_bs_read_int(bs, 1); + info->config.BAnimRAP = (Bool)gf_bs_read_int(bs, 1); info->config.elementaryMasks = gf_list_new(); while (1) { /*u32 node_id = */gf_bs_read_int(bs, info->config.NodeIDBits); @@ -99,8 +99,8 @@ GF_BifsDecoder *gf_bifs_decoder_new(GF_SceneGraph *scenegraph, Bool command_dec) tmp->scenegraph = scenegraph; tmp->command_buffers = gf_list_new(); if (command_dec) { - tmp->dec_memory_mode = 1; - tmp->force_keep_qp = 1; + tmp->dec_memory_mode = GF_TRUE; + tmp->force_keep_qp = GF_TRUE; } tmp->current_graph = NULL; return tmp; @@ -132,7 +132,7 @@ GF_Err gf_bifs_decoder_configure_stream(GF_BifsDecoder * codec, u16 ESID, char * /* Hack for T-DMB non compliant streams */ GF_SAFEALLOC(pInfo, BIFSStreamInfo); pInfo->ESID = ESID; - pInfo->config.PixelMetrics = 1; + pInfo->config.PixelMetrics = GF_TRUE; pInfo->config.version = (objectTypeIndication==2) ? 1 : 2; assert( codec ); assert( codec->streamInfo ); @@ -181,7 +181,7 @@ GF_Err gf_bifs_decoder_configure_stream(GF_BifsDecoder * codec, u16 ESID, char * GF_EXPORT void gf_bifs_decoder_ignore_size_info(GF_BifsDecoder *codec) { - if (codec) codec->ignore_size = 1; + if (codec) codec->ignore_size = GF_TRUE; } @@ -327,6 +327,7 @@ void gf_bifs_encoder_del(GF_BifsEncoder *codec) } gf_list_del(codec->streamInfo); gf_list_del(codec->encoded_nodes); + if (codec->src_url) gf_free(codec->src_url); // gf_mx_del(codec->mx); gf_free(codec); } @@ -468,6 +469,17 @@ u8 gf_bifs_encoder_get_version(GF_BifsEncoder *codec, u16 ESID) // gf_mx_v(codec->mx); return ret; } + +GF_EXPORT +GF_Err gf_bifs_encoder_set_source_url(GF_BifsEncoder *codec, const char *src_url) +{ + if (!codec) return GF_BAD_PARAM; + if (codec->src_url) gf_free(codec->src_url); + codec->src_url = gf_strdup(src_url); + return GF_OK; +} + + #endif /*GPAC_DISABLE_BIFS_ENC*/ diff --git a/src/bifs/bifs_node_tables.c b/src/bifs/bifs_node_tables.c index 4f75ca7..4148547 100644 --- a/src/bifs/bifs_node_tables.c +++ b/src/bifs/bifs_node_tables.c @@ -1146,84 +1146,6 @@ u32 gf_bifs_get_node_type(u32 NDT_Tag, u32 NodeTag, u32 Version) return 0; } } -u32 GetChildrenNDT(GF_Node *node) -{ - if (!node) return 0; - switch (gf_node_get_tag(node)) { - case TAG_MPEG4_Anchor: - return NDT_SF3DNode; - case TAG_MPEG4_AudioBuffer: - return NDT_SFAudioNode; - case TAG_MPEG4_AudioDelay: - return NDT_SFAudioNode; - case TAG_MPEG4_AudioFX: - return NDT_SFAudioNode; - case TAG_MPEG4_AudioMix: - return NDT_SFAudioNode; - case TAG_MPEG4_AudioSource: - return NDT_SFAudioNode; - case TAG_MPEG4_AudioSwitch: - return NDT_SFAudioNode; - case TAG_MPEG4_Billboard: - return NDT_SF3DNode; - case TAG_MPEG4_Collision: - return NDT_SF3DNode; - case TAG_MPEG4_CompositeTexture2D: - return NDT_SF2DNode; - case TAG_MPEG4_CompositeTexture3D: - return NDT_SF3DNode; - case TAG_MPEG4_Form: - return NDT_SF2DNode; - case TAG_MPEG4_Group: - return NDT_SF3DNode; - case TAG_MPEG4_Layer2D: - return NDT_SF2DNode; - case TAG_MPEG4_Layer3D: - return NDT_SF3DNode; - case TAG_MPEG4_Layout: - return NDT_SF2DNode; - case TAG_MPEG4_OrderedGroup: - return NDT_SF3DNode; - case TAG_MPEG4_Transform: - return NDT_SF3DNode; - case TAG_MPEG4_Transform2D: - return NDT_SF2DNode; - case TAG_MPEG4_TemporalTransform: - return NDT_SF3DNode; - case TAG_MPEG4_TemporalGroup: - return NDT_SFTemporalNode; - case TAG_MPEG4_FFD: - return NDT_SF3DNode; - case TAG_MPEG4_SBBone: - return NDT_SF3DNode; - case TAG_MPEG4_SBSegment: - return NDT_SF3DNode; - case TAG_MPEG4_SBSite: - return NDT_SF3DNode; - case TAG_MPEG4_Clipper2D: - return NDT_SF2DNode; - case TAG_MPEG4_ColorTransform: - return NDT_SF3DNode; - case TAG_MPEG4_PathLayout: - return NDT_SF2DNode; - case TAG_MPEG4_TransformMatrix2D: - return NDT_SF2DNode; - case TAG_MPEG4_AdvancedAudioBuffer: - return NDT_SFAudioNode; - case TAG_MPEG4_AudioChannelConfig: - return NDT_SFAudioNode; - case TAG_MPEG4_Transform3DAudio: - return NDT_SF3DNode; - case TAG_MPEG4_FootPrintSetNode: - return NDT_SFGeometryNode; - case TAG_MPEG4_Shadow: - return NDT_SF3DNode; - case TAG_MPEG4_SpacePartition: - return NDT_SF3DNode; - default: - return 0; - } -} diff --git a/src/bifs/com_dec.c b/src/bifs/com_dec.c index 73ef756..30a3da4 100644 --- a/src/bifs/com_dec.c +++ b/src/bifs/com_dec.c @@ -180,7 +180,7 @@ static GF_Err BD_XReplace(GF_BifsDecoder * codec, GF_BitStream *bs) memcpy(&sffield, &targetField, sizeof(GF_FieldInfo)); sffield.fieldType = sftype; sffield.far_ptr = slot_ptr; - gf_bifs_dec_sf_field(codec, bs, target, &sffield, 0); + gf_bifs_dec_sf_field(codec, bs, target, &sffield, GF_FALSE); } } gf_bifs_check_field_change(target, &targetField); @@ -215,7 +215,7 @@ static GF_Err BD_XReplace(GF_BifsDecoder * codec, GF_BitStream *bs) list = * ((GF_ChildNodeItem **) targetField.far_ptr); prev=NULL; while (list) { - cur = gf_malloc(sizeof(GF_ChildNodeItem)); + cur = (GF_ChildNodeItem*)gf_malloc(sizeof(GF_ChildNodeItem)); cur->next = NULL; cur->node = list->node; if (prev) { @@ -228,7 +228,7 @@ static GF_Err BD_XReplace(GF_BifsDecoder * codec, GF_BitStream *bs) list = list->next; } } else { - e = gf_bifs_dec_field(codec, bs, target, &targetField, 0); + e = gf_bifs_dec_field(codec, bs, target, &targetField, GF_FALSE); if (e) return e; } if (previous) @@ -246,7 +246,7 @@ static GF_Err BD_XReplace(GF_BifsDecoder * codec, GF_BitStream *bs) if (fromField.fieldType == targetField.fieldType) gf_sg_vrml_field_clone(targetField.far_ptr, fromField.far_ptr, targetField.fieldType, codec->current_graph); } else { - e = gf_bifs_dec_field(codec, bs, target, &targetField, 0); + e = gf_bifs_dec_field(codec, bs, target, &targetField, GF_FALSE); } break; } @@ -333,7 +333,7 @@ static GF_Err BD_DecMultipleIndexReplace(GF_BifsDecoder * codec, GF_BitStream *b e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & sffield.far_ptr, pos); if (e) return e; - e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, 0); + e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, GF_FALSE); if (e) break; count--; } @@ -353,9 +353,9 @@ static GF_Err BD_DecMultipleReplace(GF_BifsDecoder * codec, GF_BitStream *bs) flag = gf_bs_read_int(bs, 1); if (flag) { - e = gf_bifs_dec_node_mask(codec, bs, node, 0); + e = gf_bifs_dec_node_mask(codec, bs, node, GF_FALSE); } else { - e = gf_bifs_dec_node_list(codec, bs, node, 0); + e = gf_bifs_dec_node_list(codec, bs, node, GF_FALSE); } return e; } @@ -393,7 +393,7 @@ static GF_Err BD_DecNodeDeleteEx(GF_BifsDecoder * codec, GF_BitStream *bs) NodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); node = gf_sg_find_node(codec->current_graph, NodeID); if (!node) return GF_NON_COMPLIANT_BITSTREAM; - return gf_node_replace(node, NULL, 1); + return gf_node_replace(node, NULL, GF_TRUE); } #ifdef GPAC_UNUSED_FUNC @@ -642,7 +642,7 @@ static GF_Err BD_DecIndexInsert(GF_BifsDecoder * codec, GF_BitStream *bs) e = gf_sg_vrml_mf_insert(field.far_ptr, field.fieldType, & sffield.far_ptr, pos); } if (e) return e; - e = gf_bifs_dec_sf_field(codec, bs, def, &sffield, 0); + e = gf_bifs_dec_sf_field(codec, bs, def, &sffield, GF_FALSE); if (!e) gf_bifs_check_field_change(def, &field); } return e; @@ -663,7 +663,7 @@ static GF_Err BD_DecInsert(GF_BifsDecoder * codec, GF_BitStream *bs) case 2: return BD_DecIndexInsert(codec, bs); case 3: - return gf_bifs_dec_route(codec, bs, 1); + return gf_bifs_dec_route(codec, bs, GF_TRUE); default: return GF_NON_COMPLIANT_BITSTREAM; } @@ -740,7 +740,7 @@ static GF_Err BD_DecDelete(GF_BifsDecoder * codec, GF_BitStream *bs) if (!n) return GF_OK; #endif /*this is a delete of a DEF node, remove ALL INSTANCES*/ - return gf_node_replace(n, NULL, 0); + return gf_node_replace(n, NULL, GF_FALSE); case 2: return BD_DecIndexDelete(codec, bs); case 3: @@ -770,7 +770,7 @@ static GF_Err BD_DecNodeReplace(GF_BifsDecoder * codec, GF_BitStream *bs) new_node = gf_bifs_dec_node(codec, bs, NDT_SFWorldNode); if (!new_node && codec->LastError) return codec->LastError; - e = gf_node_replace(node, new_node, 0); + e = gf_node_replace(node, new_node, GF_FALSE); return e; } @@ -809,9 +809,9 @@ static GF_Err BD_DecFieldReplace(GF_BifsDecoder * codec, GF_BitStream *bs) } /*parse the field*/ - codec->is_com_dec = 1; - e = gf_bifs_dec_field(codec, bs, node, &field, 0); - codec->is_com_dec = 0; + codec->is_com_dec = GF_TRUE; + e = gf_bifs_dec_field(codec, bs, node, &field, GF_FALSE); + codec->is_com_dec = GF_FALSE; /*remove prev nodes*/ if (field.fieldType == GF_SG_VRML_SFNODE) { if (prev_node) e = gf_node_unregister(prev_node, node); @@ -887,7 +887,7 @@ static GF_Err BD_DecIndexValueReplace(GF_BifsDecoder * codec, GF_BitStream *bs) e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & sffield.far_ptr, pos); if (e) return e; - e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, 0); + e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, GF_FALSE); if (!e) gf_bifs_check_field_change(node, &field); } @@ -1018,7 +1018,7 @@ GF_Err gf_bifs_dec_proto_list(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List sprintf(name, "Proto%d", numProtos); } /*create a proto in the current graph*/ - proto = gf_sg_proto_new(codec->current_graph, ID, name, proto_list ? 1 : 0); + proto = gf_sg_proto_new(codec->current_graph, ID, name, proto_list ? GF_TRUE : GF_FALSE); if (proto_list) gf_list_add(proto_list, proto); /*during parsing, this proto is the current active one - all nodes/proto defined/declared @@ -1049,7 +1049,7 @@ GF_Err gf_bifs_dec_proto_list(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List case GF_SG_EVENT_FIELD: /*parse default value except nodes ...*/ if (gf_sg_vrml_is_sf_field(field_type)) { - e = gf_bifs_dec_sf_field(codec, bs, NULL, &field, 0); + e = gf_bifs_dec_sf_field(codec, bs, NULL, &field, GF_FALSE); } else { f = 0; if (codec->info->config.UsePredictiveMFField) { @@ -1139,7 +1139,7 @@ GF_Err gf_bifs_dec_proto_list(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List if (flag) { /*list route*/ while (flag) { - e = gf_bifs_dec_route(codec, bs, 0); + e = gf_bifs_dec_route(codec, bs, GF_FALSE); if (e) goto exit; flag = gf_bs_read_int(bs, 1); } @@ -1148,7 +1148,7 @@ GF_Err gf_bifs_dec_proto_list(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List i = gf_bs_read_int(bs, 5); NbRoutes = gf_bs_read_int(bs, i); for (i=0; i<NbRoutes; i++) { - e = gf_bifs_dec_route(codec, bs, 0); + e = gf_bifs_dec_route(codec, bs, GF_FALSE); if (e) goto exit; } } @@ -1193,12 +1193,12 @@ GF_Err gf_bifs_dec_proto_list(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List qp_min_value = gf_sg_vrml_field_pointer_new(qpsftype); field.name = "QPMinValue"; field.far_ptr = qp_min_value; - gf_bifs_dec_sf_field(codec, bs, NULL, &field, 0); + gf_bifs_dec_sf_field(codec, bs, NULL, &field, GF_FALSE); qp_max_value = gf_sg_vrml_field_pointer_new(qpsftype); field.name = "QPMaxValue"; field.far_ptr = qp_max_value; - gf_bifs_dec_sf_field(codec, bs, NULL, &field, 0); + gf_bifs_dec_sf_field(codec, bs, NULL, &field, GF_FALSE); } /*and store*/ @@ -1297,7 +1297,7 @@ GF_Err BD_DecSceneReplace(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List *pro /*reserved*/ i = gf_bs_read_int(bs, 6); - codec->UseName = gf_bs_read_int(bs, 1); + codec->UseName = (Bool)gf_bs_read_int(bs, 1); /*parse PROTOS*/ e = gf_bifs_dec_proto_list(codec, bs, proto_list); if (e) goto exit; @@ -1325,7 +1325,7 @@ GF_Err BD_DecSceneReplace(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List *pro if (flag) { /*list*/ while (flag) { - e = gf_bifs_dec_route(codec, bs, 0); + e = gf_bifs_dec_route(codec, bs, GF_FALSE); if (e) goto exit; flag = gf_bs_read_int(bs, 1); } @@ -1334,7 +1334,7 @@ GF_Err BD_DecSceneReplace(GF_BifsDecoder * codec, GF_BitStream *bs, GF_List *pro i = gf_bs_read_int(bs, 5); nbR = gf_bs_read_int(bs, i); for (i=0; i<nbR; i++) { - e = gf_bifs_dec_route(codec, bs, 0); + e = gf_bifs_dec_route(codec, bs, GF_FALSE); if (e) goto exit; } } @@ -1372,7 +1372,7 @@ GF_Err gf_bifs_dec_command(GF_BifsDecoder * codec, GF_BitStream *bs) } while (gf_list_count(codec->QPs)) { - gf_bifs_dec_qp_remove(codec, 1); + gf_bifs_dec_qp_remove(codec, GF_TRUE); } gf_bifs_flush_command_list(codec); diff --git a/src/bifs/com_enc.c b/src/bifs/com_enc.c index 52ff239..28696ad 100644 --- a/src/bifs/com_enc.c +++ b/src/bifs/com_enc.c @@ -183,10 +183,10 @@ static GF_Err BE_MultipleReplace(GF_BifsEncoder * codec, GF_Command *com, GF_Bit gf_bs_write_int(bs, gf_node_get_id(com->node)-1, codec->info->config.NodeIDBits); count = gf_list_count(com->command_fields); - use_list = 1; + use_list = GF_TRUE; numFields = gf_node_get_num_fields_in_mode(com->node, GF_SG_FIELD_CODING_DEF); nbBits = gf_get_bit_size(numFields - 1); - if (count < 1+count*(1+nbBits)) use_list = 0; + if (count < 1+count*(1+nbBits)) use_list = GF_FALSE; GF_BIFS_WRITE_INT(codec, bs, use_list ? 0 : 1, 1, "isMask", NULL); for (i=0; i<numFields; i++) { @@ -251,9 +251,9 @@ static GF_Err BE_GlobalQuantizer(GF_BifsEncoder * codec, GF_Command *com, GF_Bit static GF_Err BE_EncProtoDelete(GF_BifsEncoder * codec, GF_Command *com, GF_BitStream *bs) { u32 nbBits, i; - Bool use_list = 0; + Bool use_list = GF_FALSE; nbBits = gf_get_bit_size(com->del_proto_list_size); - if (nbBits+5>com->del_proto_list_size) use_list = 1; + if (nbBits+5>com->del_proto_list_size) use_list = GF_TRUE; GF_BIFS_WRITE_INT(codec, bs, use_list, 1, "isList", NULL); if (!use_list) { GF_BIFS_WRITE_INT(codec, bs, nbBits, 5, "len", NULL); @@ -435,11 +435,11 @@ GF_Err BE_FieldReplace(GF_BifsEncoder *codec, GF_Command *com, GF_BitStream *bs) field.far_ptr = inf->field_ptr; /* Warning: To be changed when proper solution is found */ - if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFSCRIPT) codec->is_encoding_command = 1; + if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFSCRIPT) codec->is_encoding_command = GF_TRUE; e = gf_bifs_enc_field(codec, bs, com->node, &field); - codec->is_encoding_command = 0; + codec->is_encoding_command = GF_FALSE; return e; } @@ -902,7 +902,7 @@ GF_Err gf_bifs_enc_commands(GF_BifsEncoder *codec, GF_List *comList, GF_BitStrea case GF_SG_ROUTE_REPLACE: GF_BIFS_WRITE_INT(codec, bs, 2, 2, "Replace", NULL); GF_BIFS_WRITE_INT(codec, bs, 3, 2, "Route", NULL); - e = BE_RouteReplace(codec, com, bs, 0); + e = BE_RouteReplace(codec, com, bs, GF_FALSE); break; case GF_SG_NODE_INSERT: GF_BIFS_WRITE_INT(codec, bs, 0, 2, "Insert", NULL); @@ -917,7 +917,7 @@ GF_Err gf_bifs_enc_commands(GF_BifsEncoder *codec, GF_List *comList, GF_BitStrea case GF_SG_ROUTE_INSERT: GF_BIFS_WRITE_INT(codec, bs, 0, 2, "Insert", NULL); GF_BIFS_WRITE_INT(codec, bs, 3, 2, "Route", NULL); - e = BE_RouteReplace(codec, com, bs, 1); + e = BE_RouteReplace(codec, com, bs, GF_TRUE); break; case GF_SG_NODE_DELETE: GF_BIFS_WRITE_INT(codec, bs, 1, 2, "Delete", NULL); @@ -944,7 +944,7 @@ GF_Err gf_bifs_enc_commands(GF_BifsEncoder *codec, GF_List *comList, GF_BitStrea GF_BIFS_WRITE_INT(codec, bs, (i+1==count) ? 0 : 1, 1, "moreCommands", NULL); } - while (gf_list_count(codec->QPs)) gf_bifs_enc_qp_remove(codec, 1); + while (gf_list_count(codec->QPs)) gf_bifs_enc_qp_remove(codec, GF_TRUE); return e; } diff --git a/src/bifs/conditional.c b/src/bifs/conditional.c index 95f19e5..723ed47 100644 --- a/src/bifs/conditional.c +++ b/src/bifs/conditional.c @@ -173,7 +173,7 @@ void BIFS_SetupConditionalClone(GF_Node *node, GF_Node *orig) /*and clone all commands*/ i=0; while ((ori_com = (GF_Command*)gf_list_enum(c_orig->buffer.commandList, &i))) { - GF_Command *dest_com = gf_sg_vrml_command_clone(ori_com, gf_node_get_graph(node), 1); + GF_Command *dest_com = gf_sg_vrml_command_clone(ori_com, gf_node_get_graph(node), GF_TRUE); if (dest_com) gf_list_add(c_dest->buffer.commandList, dest_com); } #endif diff --git a/src/bifs/field_decode.c b/src/bifs/field_decode.c index 63c62ae..2e2f507 100644 --- a/src/bifs/field_decode.c +++ b/src/bifs/field_decode.c @@ -127,13 +127,13 @@ GF_Err gf_bifs_dec_sf_field(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *n M_CacheTexture *ct = (M_CacheTexture *) node; ct->data_len = length; if (ct->data) gf_free(ct->data); - ct->data = gf_malloc(sizeof(char)*length); + ct->data = (u8*)gf_malloc(sizeof(char)*length); gf_bs_read_data(bs, (char*)ct->data, length); } else if (node && (node->sgprivate->tag==TAG_MPEG4_BitWrapper) ) { M_BitWrapper *bw = (M_BitWrapper*) node; if (bw->buffer.buffer) gf_free(bw->buffer.buffer); bw->buffer_len = length; - bw->buffer.buffer = gf_malloc(sizeof(char)*length); + bw->buffer.buffer = (char*)gf_malloc(sizeof(char)*length); gf_bs_read_data(bs, (char*)bw->buffer.buffer, length); } else { if ( ((SFString *)field->far_ptr)->buffer ) gf_free( ((SFString *)field->far_ptr)->buffer); @@ -296,7 +296,7 @@ GF_Err BD_DecMFFieldList(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node e = GF_OK;; if (field->fieldType != GF_SG_VRML_MFNODE) { e = gf_sg_vrml_mf_append(field->far_ptr, field->fieldType, & sffield.far_ptr); - e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, 0); + e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, GF_FALSE); } else { new_node = gf_bifs_dec_node(codec, bs, field->NDTtype); //append @@ -310,13 +310,13 @@ GF_Err BD_DecMFFieldList(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node if (gf_node_get_tag(new_node) == TAG_MPEG4_QuantizationParameter) { qp_local = ((M_QuantizationParameter *)new_node)->isLocal; //we have a QP in the same scope, remove previous - if (qp_on) gf_bifs_dec_qp_remove(codec, 0); + if (qp_on) gf_bifs_dec_qp_remove(codec, GF_FALSE); e = gf_bifs_dec_qp_set(codec, new_node); if (e) return e; qp_on = 1; if (qp_local) qp_local = 2; if (codec->force_keep_qp) { - e = gf_node_list_add_child_last( field->far_ptr, new_node, &last); + e = gf_node_list_add_child_last(field->far_ptr, new_node, &last); } else { gf_node_register(new_node, NULL); gf_node_unregister(new_node, node); @@ -395,7 +395,7 @@ GF_Err BD_DecMFFieldVec(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node, for (i=0; i<nbFields; i++) { e = gf_sg_vrml_mf_get_item(field->far_ptr, field->fieldType, & sffield.far_ptr, i); if (e) return e; - e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, 0); + e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, GF_FALSE); } } else { last = NULL; @@ -412,7 +412,7 @@ GF_Err BD_DecMFFieldVec(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node, /*we have a QP in the same scope, remove previous NB: we assume this is the right behaviour, the spec doesn't say whether QP is cumulative or not*/ - if (qp_on) gf_bifs_dec_qp_remove(codec, 0); + if (qp_on) gf_bifs_dec_qp_remove(codec, GF_FALSE); e = gf_bifs_dec_qp_set(codec, new_node); if (e) return e; @@ -450,7 +450,7 @@ GF_Err BD_DecMFFieldVec(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node, } } /*finally delete the QP if any (local or not) as we get out of this node*/ - if (qp_on) gf_bifs_dec_qp_remove(codec, 1); + if (qp_on) gf_bifs_dec_qp_remove(codec, GF_TRUE); return GF_OK; } @@ -584,7 +584,7 @@ GF_Err gf_bifs_dec_node_list(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node * if (e) return e; e = gf_node_get_field(node, field_all, &field); if (e) return e; - e = gf_bifs_dec_field(codec, bs, node, &field, 0); + e = gf_bifs_dec_field(codec, bs, node, &field, GF_FALSE); if (e) return e; flag = gf_bs_read_int(bs, 1); @@ -622,7 +622,7 @@ GF_Err gf_bifs_dec_node_mask(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node * else { e = gf_node_get_field(node, i, &field); if (e) return e; - e = gf_bifs_dec_field(codec, bs, node, &field, 0); + e = gf_bifs_dec_field(codec, bs, node, &field, GF_FALSE); } if (e) return e; } @@ -636,7 +636,7 @@ GF_Err gf_bifs_dec_node_mask(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node * gf_bifs_get_field_index(node, i, GF_SG_FIELD_CODING_DEF, &index); e = gf_node_get_field(node, index, &field); if (e) return e; - e = gf_bifs_dec_field(codec, bs, node, &field, 0); + e = gf_bifs_dec_field(codec, bs, node, &field, GF_FALSE); if (e) return e; if (is_proto) gf_sg_proto_mark_field_loaded(node, &field); @@ -728,17 +728,17 @@ GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) case TAG_MPEG4_Coordinate: { u32 nbCoord = ((M_Coordinate *)new_node)->point.count; - gf_bifs_dec_qp14_enter(codec, 1); + gf_bifs_dec_qp14_enter(codec, GF_TRUE); gf_bifs_dec_qp14_set_length(codec, nbCoord); - gf_bifs_dec_qp14_enter(codec, 0); + gf_bifs_dec_qp14_enter(codec, GF_FALSE); } break; case TAG_MPEG4_Coordinate2D: { u32 nbCoord = ((M_Coordinate2D *)new_node)->point.count; - gf_bifs_dec_qp14_enter(codec, 1); + gf_bifs_dec_qp14_enter(codec, GF_TRUE); gf_bifs_dec_qp14_set_length(codec, nbCoord); - gf_bifs_dec_qp14_enter(codec, 0); + gf_bifs_dec_qp14_enter(codec, GF_FALSE); } break; } @@ -815,7 +815,7 @@ GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) } new_node = NULL; - skip_init = 0; + skip_init = GF_FALSE; /*don't check node IDs duplicate since VRML may use them...*/ #if 0 @@ -845,7 +845,7 @@ GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) if (!new_node) { if (proto) { - skip_init = 1; + skip_init = GF_TRUE; /*create proto interface*/ new_node = gf_sg_proto_create_instance(codec->current_graph, proto); } else { @@ -873,7 +873,7 @@ GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) /*update default time fields except in proto parsing*/ if (!codec->pCurrentProto) UpdateTimeNode(codec, new_node); /*nodes are only init outside protos */ - else skip_init = 1; + else skip_init = GF_TRUE; /*if coords were not stored for QP14 before coding this node, reset QP14 it when leaving*/ reset_qp14 = !codec->coord_stored; @@ -884,13 +884,13 @@ GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: - gf_bifs_dec_qp14_enter(codec, 1); + gf_bifs_dec_qp14_enter(codec, GF_TRUE); } if (gf_bs_read_int(bs, 1)) { - e = gf_bifs_dec_node_mask(codec, bs, new_node, proto ? 1 : 0); + e = gf_bifs_dec_node_mask(codec, bs, new_node, proto ? GF_TRUE : GF_FALSE); } else { - e = gf_bifs_dec_node_list(codec, bs, new_node, proto ? 1 : 0); + e = gf_bifs_dec_node_list(codec, bs, new_node, proto ? GF_TRUE : GF_FALSE); } if (codec->coord_stored && reset_qp14) gf_bifs_dec_qp14_reset(codec); @@ -910,7 +910,7 @@ GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: - gf_bifs_dec_qp14_enter(codec, 0); + gf_bifs_dec_qp14_enter(codec, GF_FALSE); break; case TAG_MPEG4_Script: /*load script if in main graph (useless to load in proto declaration)*/ diff --git a/src/bifs/field_encode.c b/src/bifs/field_encode.c index 227fe80..e14c9b4 100644 --- a/src/bifs/field_encode.c +++ b/src/bifs/field_encode.c @@ -27,6 +27,7 @@ #include <gpac/internal/bifs_dev.h> #include <gpac/internal/bifs_tables.h> +#include <gpac/network.h> #include "quant.h" #include "script.h" @@ -94,14 +95,23 @@ GF_Err gf_bifs_enc_sf_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *no if (node && (node->sgprivate->tag==TAG_MPEG4_CacheTexture) && (field->fieldIndex<=2)) { u32 size, val; char buf[4096]; - FILE *f = gf_f64_open(((SFString*)field->far_ptr)->buffer, "rb"); - if (!f) return GF_URL_ERROR; - gf_f64_seek(f, 0, SEEK_END); - size = (u32) gf_f64_tell(f); + char *res_src = NULL; + const char *src = ((SFString*)field->far_ptr)->buffer; + FILE *f; + if (codec->src_url) res_src = gf_url_concatenate(codec->src_url, src); + + f = gf_fopen(res_src ? res_src : src, "rb"); + if (!f) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[BIFS] Cannot open source file %s for encoding CacheTexture\n", res_src ? res_src : src)); + return GF_URL_ERROR; + } + if (res_src) gf_free(res_src); + gf_fseek(f, 0, SEEK_END); + size = (u32) gf_ftell(f); val = gf_get_bit_size(size); GF_BIFS_WRITE_INT(codec, bs, val, 5, "nbBits", NULL); GF_BIFS_WRITE_INT(codec, bs, size, val, "length", NULL); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_SET); while (size) { u32 read = (u32) fread(buf, 1, 4096, f); gf_bs_write_data(bs, buf, read); @@ -252,9 +262,9 @@ GF_Err gf_bifs_enc_mf_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *no } /*do we work in list or vector*/ - use_list = 0; + use_list = GF_FALSE; nbBits = gf_get_bit_size(nbF); - if (nbBits + 5 > nbF + 1) use_list = 1; + if (nbBits + 5 > nbF + 1) use_list = GF_TRUE; GF_BIFS_WRITE_INT(codec, bs, use_list, 1, "isList", NULL); if (!use_list) { @@ -268,7 +278,7 @@ GF_Err gf_bifs_enc_mf_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *no sffield.NDTtype = field->NDTtype; initial_qp = qp_on = qp_local = 0; - initial_qp = codec->ActiveQP ? 1 : 0; + initial_qp = codec->ActiveQP ? GF_TRUE : GF_FALSE; for (i=0; i<nbF; i++) { if (use_list) GF_BIFS_WRITE_INT(codec, bs, 0, 1, "end", NULL); @@ -283,10 +293,10 @@ GF_Err gf_bifs_enc_mf_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *no /*activate QP*/ if (list->node->sgprivate->tag == TAG_MPEG4_QuantizationParameter) { qp_local = ((M_QuantizationParameter *)list->node)->isLocal; - if (qp_on) gf_bifs_enc_qp_remove(codec, 0); + if (qp_on) gf_bifs_enc_qp_remove(codec, GF_FALSE); e = gf_bifs_enc_qp_set(codec, list->node); if (e) return e; - qp_on = 1; + qp_on = GF_TRUE; if (qp_local) qp_local = 2; } list = list->next; @@ -298,7 +308,7 @@ GF_Err gf_bifs_enc_mf_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *no if (qp_local == 2) qp_local -= 1; else { gf_bifs_enc_qp_remove(codec, initial_qp); - qp_local = qp_on = 0; + qp_local = qp_on = GF_FALSE; } } } @@ -363,10 +373,9 @@ GF_Err EncNodeFields(GF_BifsEncoder * codec, GF_BitStream *bs, GF_Node *node) GF_Err e; s32 *enc_fields; u32 numBitsALL, numBitsDEF, allInd, count, i, nbBitsProto, nbFinal; - Bool use_list, nodeIsFDP = 0; + Bool use_list, nodeIsFDP = GF_FALSE; GF_FieldInfo field, clone_field; - e = GF_OK; if (codec->encoding_proto) { @@ -458,19 +467,19 @@ GF_Err EncNodeFields(GF_BifsEncoder * codec, GF_BitStream *bs, GF_Node *node) } if (clone) gf_node_unregister(clone, NULL); - use_list = 1; + use_list = GF_TRUE; /* patch for FDP node : */ /* cannot use default field sorting due to spec "mistake", so use list to imply inversion between field 2 and field 3 of FDP*/ if (node->sgprivate->tag == TAG_MPEG4_FDP) { s32 s4SwapValue = enc_fields[2]; enc_fields[2] = enc_fields[3]; enc_fields[3] = s4SwapValue; - nodeIsFDP = 1; - use_list = 1; + nodeIsFDP = GF_TRUE; + use_list = GF_TRUE; } /*number of bits in mask node is count*1, in list node is 1+nbFinal*(1+numBitsDEF) */ else if (count < 1+nbFinal*(1+numBitsDEF)) - use_list = 0; + use_list = GF_FALSE; GF_BIFS_WRITE_INT(codec, bs, use_list ? 0 : 1, 1, "isMask", NULL); @@ -536,13 +545,13 @@ exit: Bool BE_NodeIsUSE(GF_BifsEncoder * codec, GF_Node *node) { u32 i, count; - if (!node || !gf_node_get_id(node) ) return 0; + if (!node || !gf_node_get_id(node) ) return GF_FALSE; count = gf_list_count(codec->encoded_nodes); for (i=0; i<count; i++) { - if (gf_list_get(codec->encoded_nodes, i) == node) return 1; + if (gf_list_get(codec->encoded_nodes, i) == node) return GF_TRUE; } gf_list_add(codec->encoded_nodes, node); - return 0; + return GF_FALSE; } GF_Err gf_bifs_enc_node(GF_BifsEncoder * codec, GF_Node *node, u32 NDT_Tag, GF_BitStream *bs, GF_Node *parent_node) @@ -577,17 +586,17 @@ GF_Err gf_bifs_enc_node(GF_BifsEncoder * codec, GF_Node *node, u32 NDT_Tag, GF_B case TAG_MPEG4_Coordinate: { u32 nbCoord = ((M_Coordinate *)new_node)->point.count; - gf_bifs_enc_qp14_enter(codec, 1); + gf_bifs_enc_qp14_enter(codec, GF_TRUE); gf_bifs_enc_qp14_set_length(codec, nbCoord); - gf_bifs_enc_qp14_enter(codec, 0); + gf_bifs_enc_qp14_enter(codec, GF_FALSE); } break; case TAG_MPEG4_Coordinate2D: { u32 nbCoord = ((M_Coordinate2D *)new_node)->point.count; - gf_bifs_enc_qp14_enter(codec, 1); + gf_bifs_enc_qp14_enter(codec, GF_TRUE); gf_bifs_enc_qp14_set_length(codec, nbCoord); - gf_bifs_enc_qp14_enter(codec, 0); + gf_bifs_enc_qp14_enter(codec, GF_FALSE); } break; } @@ -637,7 +646,7 @@ GF_Err gf_bifs_enc_node(GF_BifsEncoder * codec, GF_Node *node, u32 NDT_Tag, GF_B switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: - gf_bifs_enc_qp14_enter(codec, 1); + gf_bifs_enc_qp14_enter(codec, GF_TRUE); } e = EncNodeFields(codec, bs, node); @@ -649,7 +658,7 @@ GF_Err gf_bifs_enc_node(GF_BifsEncoder * codec, GF_Node *node, u32 NDT_Tag, GF_B switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: - gf_bifs_enc_qp14_enter(codec, 0); + gf_bifs_enc_qp14_enter(codec, GF_FALSE); break; } return GF_OK; diff --git a/src/bifs/memory_decoder.c b/src/bifs/memory_decoder.c index edd1b57..008e743 100644 --- a/src/bifs/memory_decoder.c +++ b/src/bifs/memory_decoder.c @@ -80,7 +80,7 @@ static GF_Err BM_ParseMultipleIndexedReplace(GF_BifsDecoder *codec, GF_BitStream gf_node_register(inf->new_node, NULL); } else { field.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType); - e = gf_bifs_dec_sf_field(codec, bs, node, &field, 1); + e = gf_bifs_dec_sf_field(codec, bs, node, &field, GF_TRUE); if (e) goto err; } count--; @@ -127,7 +127,7 @@ static GF_Err BM_ParseMultipleReplace(GF_BifsDecoder *codec, GF_BitStream *bs, G } else { field.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType); } - e = gf_bifs_dec_field(codec, bs, node, &field, 1); + e = gf_bifs_dec_field(codec, bs, node, &field, GF_TRUE); if (e) goto exit; } } else { @@ -149,7 +149,7 @@ static GF_Err BM_ParseMultipleReplace(GF_BifsDecoder *codec, GF_BitStream *bs, G } else { field.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType); } - e = gf_bifs_dec_field(codec, bs, node, &field, 1); + e = gf_bifs_dec_field(codec, bs, node, &field, GF_TRUE); if (e) goto exit; flag = gf_bs_read_int(bs, 1); } @@ -343,7 +343,7 @@ static GF_Err BM_XReplace(GF_BifsDecoder *codec, GF_BitStream *bs, GF_List *com_ } else { decfield.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType); } - e = gf_bifs_dec_sf_field(codec, bs, target, &decfield, 1); + e = gf_bifs_dec_sf_field(codec, bs, target, &decfield, GF_TRUE); if (e) return e; gf_list_add(com_list, com); @@ -512,7 +512,7 @@ GF_Err BM_ParseIndexInsert(GF_BifsDecoder *codec, GF_BitStream *bs, GF_List *com inf->fieldIndex = field_ind; inf->fieldType = sffield.fieldType; sffield.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(sffield.fieldType); - codec->LastError = gf_bifs_dec_sf_field(codec, bs, def, &sffield, 1); + codec->LastError = gf_bifs_dec_sf_field(codec, bs, def, &sffield, GF_TRUE); gf_list_add(com_list, com); } return codec->LastError; @@ -724,7 +724,7 @@ GF_Err BM_ParseFieldReplace(GF_BifsDecoder *codec, GF_BitStream *bs, GF_List *co field.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(field.fieldType); } /*parse the field*/ - codec->LastError = gf_bifs_dec_field(codec, bs, node, &field, 1); + codec->LastError = gf_bifs_dec_field(codec, bs, node, &field, GF_TRUE); gf_list_add(com_list, com); return codec->LastError; @@ -784,7 +784,7 @@ GF_Err BM_ParseIndexValueReplace(GF_BifsDecoder *codec, GF_BitStream *bs, GF_Lis sffield.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); inf->fieldType = sffield.fieldType; sffield.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(sffield.fieldType); - codec->LastError = gf_bifs_dec_sf_field(codec, bs, node, &sffield, 1); + codec->LastError = gf_bifs_dec_sf_field(codec, bs, node, &sffield, GF_TRUE); } gf_list_add(com_list, com); return codec->LastError; @@ -918,7 +918,7 @@ GF_Err BM_ParseCommand(GF_BifsDecoder *codec, GF_BitStream *bs, GF_List *com_lis } while (gf_list_count(codec->QPs)) { - gf_bifs_dec_qp_remove(codec, 1); + gf_bifs_dec_qp_remove(codec, GF_TRUE); } return GF_OK; } diff --git a/src/bifs/quantize.c b/src/bifs/quantize.c index cd61ea9..5034a08 100644 --- a/src/bifs/quantize.c +++ b/src/bifs/quantize.c @@ -64,17 +64,17 @@ u32 gf_bifs_enc_qp14_get_bits(GF_BifsEncoder *codec) void gf_bifs_enc_qp14_enter(GF_BifsEncoder *codec, Bool Enter) { if (!codec->ActiveQP) return; - if (Enter) codec->storing_coord = 1; + if (Enter) codec->storing_coord = GF_TRUE; else { - if (codec->storing_coord) codec->coord_stored = 1; - codec->storing_coord = 0; + if (codec->storing_coord) codec->coord_stored = GF_TRUE; + codec->storing_coord = GF_FALSE; } } void gf_bifs_enc_qp14_reset(GF_BifsEncoder *codec) { - codec->coord_stored = 0; - codec->storing_coord = 0; + codec->coord_stored = GF_FALSE; + codec->storing_coord = GF_FALSE; codec->NumCoord = 0; } diff --git a/src/bifs/script_enc.c b/src/bifs/script_enc.c index 2c7323d..daa9c97 100644 --- a/src/bifs/script_enc.c +++ b/src/bifs/script_enc.c @@ -67,9 +67,9 @@ static GF_Err EncScriptFields(ScriptEnc *sc_enc) GF_FieldInfo info; nbFields = gf_node_get_num_fields_in_mode(sc_enc->script, GF_SG_FIELD_CODING_ALL) - 3; - use_list = 1; + use_list = GF_TRUE; nbBits = gf_get_bit_size(nbFields); - if (nbFields+1 > 4 + gf_get_bit_size(nbFields)) use_list = 0; + if (nbFields+1 > 4 + gf_get_bit_size(nbFields)) use_list = GF_FALSE; if (!nbFields) { GF_BIFS_WRITE_INT(sc_enc->codec, sc_enc->bs, 1, 1, "Script::isList", NULL); GF_BIFS_WRITE_INT(sc_enc->codec, sc_enc->bs, 1, 1, "end", NULL); @@ -293,7 +293,7 @@ const char* sc_keywords [] = Bool SFE_GetNumber(ScriptEnc *sc_enc) { u32 i = 0; - Bool exp = 0; + Bool exp = GF_FALSE; while ( isdigit(sc_enc->cur_buf[i]) || (toupper(sc_enc->cur_buf[i])=='X') || ((toupper(sc_enc->cur_buf[i]) >='A') && (toupper(sc_enc->cur_buf[i])<='F')) @@ -302,24 +302,24 @@ Bool SFE_GetNumber(ScriptEnc *sc_enc) || (exp && (sc_enc->cur_buf[i] == '-')) ) { sc_enc->token[i] = sc_enc->cur_buf[i]; - if (tolower(sc_enc->cur_buf[i])=='e') exp = 1; + if (tolower(sc_enc->cur_buf[i])=='e') exp = GF_TRUE; i++; if (!sc_enc->cur_buf[i]) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[bifs] Script encoding: Invalid number syntax (%s)\n", sc_enc->cur_buf)); sc_enc->err = GF_BAD_PARAM; - return 0; + return GF_FALSE; } } sc_enc->token[i] = 0; sc_enc->cur_buf += i; sc_enc->token_code = TOK_NUMBER; - return 1; + return GF_TRUE; } Bool SFE_NextToken(ScriptEnc *sc_enc) { u32 i; - if (sc_enc->err) return 0; + if (sc_enc->err) return GF_FALSE; while (strchr(" \t\r\n", sc_enc->cur_buf[0])) { if (sc_enc->cur_buf[0]=='\n') sc_enc->cur_line ++; sc_enc->cur_buf++; @@ -331,7 +331,7 @@ Bool SFE_NextToken(ScriptEnc *sc_enc) if (!sc_enc->cur_buf[0] || !sc_enc->cur_buf[1]) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[bifs] Script encoding: cannot find closing comment */\n")); sc_enc->err = GF_BAD_PARAM; - return 0; + return GF_FALSE; } } sc_enc->cur_buf+=2; @@ -351,13 +351,13 @@ Bool SFE_NextToken(ScriptEnc *sc_enc) for (i=0; i<NUMBER_OF_KEYWORD; i++) { if (!strcmp(sc_enc->token, sc_keywords[i])) { sc_enc->token_code = i; - return 1; + return GF_TRUE; } } if (!stricmp(sc_enc->token, "TRUE") || !stricmp(sc_enc->token, "FALSE") ) { sc_enc->token_code = TOK_BOOLEAN; } - return 1; + return GF_TRUE; } /*get a number*/ if (isdigit(sc_enc->cur_buf[i])) return SFE_GetNumber(sc_enc); @@ -366,10 +366,10 @@ Bool SFE_NextToken(ScriptEnc *sc_enc) || ((sc_enc->cur_buf[i]=='\\') && (sc_enc->cur_buf[i+1]=='\"')) ) { char end; - Bool skip_last = 0; + Bool skip_last = GF_FALSE; end = sc_enc->cur_buf[i]; if (sc_enc->cur_buf[i]=='\\') { - skip_last = 1; + skip_last = GF_TRUE; sc_enc->cur_buf++; } while (sc_enc->cur_buf[i+1] != end) { @@ -380,14 +380,14 @@ Bool SFE_NextToken(ScriptEnc *sc_enc) sc_enc->cur_buf += i+2; if (skip_last) sc_enc->cur_buf++; sc_enc->token_code = TOK_STRING; - return 1; + return GF_TRUE; } /*all other codes*/ switch (sc_enc->cur_buf[i]) { case '.': if (isdigit(sc_enc->cur_buf[i+1])) { SFE_GetNumber(sc_enc); - return 1; + return GF_TRUE; } else { sc_enc->token_code = TOK_PERIOD; } @@ -402,6 +402,11 @@ Bool SFE_NextToken(ScriptEnc *sc_enc) break; case '=': if (sc_enc->cur_buf[i+1]=='=') { + if (sc_enc->cur_buf[i+2]=='=') { + GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[BIFSEnc] JavaScript token '===' not supported by standard\n")); + sc_enc->err = GF_NOT_SUPPORTED; + return GF_FALSE; + } sc_enc->token_code = TOK_EQ; sc_enc->cur_buf ++; } else { @@ -560,19 +565,19 @@ Bool SFE_NextToken(ScriptEnc *sc_enc) default: GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[bifs] Script encoding: Unrecognized symbol %c\n", sc_enc->cur_buf[i])); sc_enc->err = GF_BAD_PARAM; - return 0; + return GF_FALSE; } sc_enc->cur_buf ++; - return 1; + return GF_TRUE; } Bool SFE_CheckToken(ScriptEnc *sc_enc, u32 token) { if (sc_enc->token_code != token) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[bifs] Script encoding: Bad token (expecting \"%s\" got \"%s\")\n", tok_names[token] , tok_names[sc_enc->token_code])); - return 0; + return GF_FALSE; } - return 1; + return GF_TRUE; } void SFE_PutIdentifier(ScriptEnc *sc_enc, char *id) @@ -671,7 +676,7 @@ u32 SFE_LoadExpression(ScriptEnc *sc_enc, u32 *expr_sep) goto break_loop; } - if (sc_enc->token_code==TOK_VAR) is_var = 1; + if (sc_enc->token_code==TOK_VAR) is_var = GF_TRUE; if (!is_var || (sc_enc->token_code!=TOK_COMMA)) { sc_enc->expr_toks[sc_enc->expr_toks_len] = sc_enc->token_code; sc_enc->expr_toks_len++; @@ -703,6 +708,8 @@ u32 SFE_LoadExpression(ScriptEnc *sc_enc, u32 *expr_sep) } while ( (sc_enc->token_code != close_code) || count); } SFE_NextToken(sc_enc); + + if (sc_enc->err) break; } break_loop: @@ -766,10 +773,10 @@ void SFE_CompoundExpression(ScriptEnc *sc_enc, u32 start, u32 end, u32 isPar) nbExp = SFE_ScanExpression(sc_enc, start, end, expr_sep); } - SFE_Expression(sc_enc, expr_sep[0], expr_sep[1], 0); + SFE_Expression(sc_enc, expr_sep[0], expr_sep[1], GF_FALSE); for (i=1; i<nbExp; i++) { SFE_WRITE_INT(sc_enc, 1, 1, isPar ? "hasParam" : "hasExpression", NULL); - SFE_Expression(sc_enc, expr_sep[i]+1, expr_sep[i+1], 0); + SFE_Expression(sc_enc, expr_sep[i]+1, expr_sep[i+1], GF_FALSE); } SFE_WRITE_INT(sc_enc, 0, 1, isPar ? "hasParam" : "hasExpression", NULL); } @@ -914,7 +921,7 @@ void SFE_SwitchStatement(ScriptEnc *sc_enc) buf_bck = sc_enc->cur_buf; tok_bck = sc_enc->token_code; prev_emu = sc_enc->emul; - sc_enc->emul = 1; + sc_enc->emul = GF_TRUE; SFE_NextToken(sc_enc); while (sc_enc->token_code == TOK_CASE) { @@ -1594,8 +1601,8 @@ skip_token: case ET_OR: case ET_LAND: case ET_LOR: - SFE_Expression(sc_enc, start, finalPos, 0); - SFE_Expression(sc_enc, finalPos+1, end, 0); + SFE_Expression(sc_enc, start, finalPos, GF_FALSE); + SFE_Expression(sc_enc, finalPos+1, end, GF_FALSE); break; case ET_ASSIGN: case ET_PLUSEQ: @@ -1610,13 +1617,13 @@ skip_token: case ET_XOREQ: case ET_OREQ: { - u32 ret = SFE_Expression(sc_enc, start, finalPos, 0); + u32 ret = SFE_Expression(sc_enc, start, finalPos, GF_FALSE); if ( ret != ET_IDENTIFIER && ret != ET_OBJECT_MEMBER_ACCESS && ret != ET_ARRAY_DEREFERENCE ) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[bifs] Script encoding: LeftVariable expected, %s returned\n", expr_name[ret])); sc_enc->err = GF_BAD_PARAM; return expr; } - SFE_Expression(sc_enc, finalPos+1, end, 0); + SFE_Expression(sc_enc, finalPos+1, end, GF_FALSE); } break; @@ -1664,14 +1671,14 @@ skip_token: case ET_DECREMENT: case ET_NOT: case ET_ONESCOMP: - SFE_Expression(sc_enc, finalPos+1, end, 0); + SFE_Expression(sc_enc, finalPos+1, end, GF_FALSE); break; case ET_CURVED_EXPR: SFE_CompoundExpression(sc_enc, finalPos+1, end-1, 0); break; case ET_POST_INCREMENT : case ET_POST_DECREMENT : - SFE_Expression(sc_enc, start, finalPos, 0); + SFE_Expression(sc_enc, start, finalPos, GF_FALSE); break; case ET_FUNCTION_CALL: SFE_FunctionCall(sc_enc, start, end); @@ -1731,7 +1738,7 @@ void SFE_ObjectMemberAccess(ScriptEnc *sc_enc, u32 start, u32 op, u32 end) u32 curTok; char *str; - SFE_Expression(sc_enc, start, op, 1); + SFE_Expression(sc_enc, start, op, GF_TRUE); curTok = sc_enc->expr_toks[op]; CHECK_TOK(TOK_PERIOD); curTok = sc_enc->expr_toks[end-1]; @@ -1747,7 +1754,7 @@ void SFE_ObjectMethodCall(ScriptEnc *sc_enc, u32 start, u32 op, u32 end) u32 curTok; char *str; - SFE_Expression(sc_enc, start, op, 0); + SFE_Expression(sc_enc, start, op, GF_FALSE); curTok = sc_enc->expr_toks[op]; CHECK_TOK(TOK_PERIOD); curTok = sc_enc->expr_toks[op+1]; @@ -1767,7 +1774,7 @@ void SFE_ArrayDereference(ScriptEnc *sc_enc, u32 start, u32 op, u32 end) { u32 curTok; - SFE_Expression(sc_enc, start, op, 0); + SFE_Expression(sc_enc, start, op, GF_FALSE); curTok = sc_enc->expr_toks[op]; CHECK_TOK(TOK_LEFT_BRACKET); SFE_CompoundExpression(sc_enc, op+1, end-1, 0); @@ -1799,15 +1806,15 @@ void SFE_ConditionTest(ScriptEnc *sc_enc, u32 start, u32 op, u32 end) { u32 curTok; - SFE_Expression(sc_enc, start, op, 0); + SFE_Expression(sc_enc, start, op, GF_FALSE); curTok = sc_enc->expr_toks[op]; CHECK_TOK(TOK_CONDTEST); start = op+1; op = MoveToToken(sc_enc, TOK_CONDSEP, op, end-1); - SFE_Expression(sc_enc, start, op, 0); + SFE_Expression(sc_enc, start, op, GF_FALSE); curTok = sc_enc->expr_toks[op]; CHECK_TOK(TOK_CONDSEP); - SFE_Expression(sc_enc, op+1, end, 0); + SFE_Expression(sc_enc, op+1, end, GF_FALSE); } void SFE_Params(ScriptEnc *sc_enc, u32 start, u32 end) diff --git a/src/bifs/unquantize.c b/src/bifs/unquantize.c index ce8b628..8a10283 100644 --- a/src/bifs/unquantize.c +++ b/src/bifs/unquantize.c @@ -27,6 +27,7 @@ #ifndef GPAC_DISABLE_BIFS +#include <math.h> u32 gf_bifs_dec_qp14_get_bits(GF_BifsDecoder *codec) { diff --git a/src/compositor/audio_input.c b/src/compositor/audio_input.c index 7e2ae29..b40d8b2 100644 --- a/src/compositor/audio_input.c +++ b/src/compositor/audio_input.c @@ -30,6 +30,9 @@ /*diff time in ms to consider an audio frame too late and drop it - we should try to dynamically figure this out since the drift may be high on TS for example, where PTS-PCR>500ms is quite common*/ #define MAX_RESYNC_TIME 1000 +//if drift between audio object time and clock varies more is than this value (in ms) between two drift computation, clock is adjusted. We don't adjust for lower values otherwise we would +//introduce oscillations in the clock and non-smooth playback +#define MIN_DRIFT_ADJUST 75 struct __audiofilteritem { @@ -55,22 +58,32 @@ static char *gf_audio_input_fetch_frame(void *callback, u32 *size, u32 audio_del u32 obj_time, ts; s32 drift; Fixed speed; + Bool done; GF_AudioInput *ai = (GF_AudioInput *) callback; /*even if the stream is signaled as finished we must check it, because it may have been restarted by a mediaControl*/ if (!ai->stream) return NULL; - frame = gf_mo_fetch_data(ai->stream, 0, &ai->stream_finished, &ts, size, NULL, NULL); + done = ai->stream_finished; + frame = gf_mo_fetch_data(ai->stream, ai->compositor->audio_renderer->step_mode ? GF_MO_FETCH_PAUSED : GF_MO_FETCH, &ai->stream_finished, &ts, size, NULL, NULL); /*invalidate scene on end of stream to refresh audio graph*/ - if (ai->stream_finished) gf_sc_invalidate(ai->compositor, NULL); + if (done != ai->stream_finished) { + gf_sc_invalidate(ai->compositor, NULL); + } /*no more data or not enough data, reset syncro drift*/ if (!frame) { - GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] No data in audio object (eos %d)\n", ai->stream_finished)); + if (!ai->stream_finished) { + GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] No data in audio object\n")); + } gf_mo_adjust_clock(ai->stream, 0); *size = 0; return NULL; } - ai->need_release = 1; + ai->need_release = GF_TRUE; + + //step mode, return the frame without sync check + if (ai->compositor->audio_renderer->step_mode) + return frame; speed = gf_mo_get_current_speed(ai->stream); @@ -87,7 +100,7 @@ static char *gf_audio_input_fetch_frame(void *callback, u32 *size, u32 audio_del /*too early (silence insertions), skip*/ if (drift < 0) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] audio too early of %d (CTS %u at OTB %u with audio delay %d ms)\n", drift + audio_delay_ms, ts, obj_time, audio_delay_ms)); - ai->need_release = 0; + ai->need_release = GF_FALSE; gf_mo_release_data(ai->stream, 0, -1); *size = 0; return NULL; @@ -95,16 +108,21 @@ static char *gf_audio_input_fetch_frame(void *callback, u32 *size, u32 audio_del #endif /*adjust drift*/ if (audio_delay_ms) { - s32 resync_delay = FIX2INT(speed * MAX_RESYNC_TIME); + s32 resync_delay = speed > 0 ? FIX2INT(speed * MAX_RESYNC_TIME) : FIX2INT(-speed * MAX_RESYNC_TIME); /*CU is way too late, discard and fetch a new one - this usually happen when media speed is more than 1*/ if (drift>resync_delay) { GF_LOG(GF_LOG_INFO, GF_LOG_AUDIO, ("[Audio Input] Audio data too late obj time %d - CTS %d - drift %d ms - resync forced\n", obj_time - audio_delay_ms, ts, drift)); gf_mo_release_data(ai->stream, *size, 2); - ai->need_release = 0; + ai->need_release = GF_FALSE; return gf_audio_input_fetch_frame(callback, size, audio_delay_ms); } - GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[Audio Input] Audio clock: delay %d - obj time %d - CTS %d - adjust drift %d\n", audio_delay_ms, obj_time - audio_delay_ms, ts, drift)); - gf_mo_adjust_clock(ai->stream, drift); + resync_delay = gf_mo_get_clock_drift(ai->stream) - drift; + if (resync_delay < 0) resync_delay = -resync_delay; + + if (resync_delay > MIN_DRIFT_ADJUST) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[Audio Input] Audio clock: delay %d - obj time %d - audio delay %d - CTS %d - adjust drift %d\n", audio_delay_ms, obj_time, audio_delay_ms, ts, drift)); + gf_mo_adjust_clock(ai->stream, drift); + } } return frame; } @@ -114,7 +132,7 @@ static void gf_audio_input_release_frame(void *callback, u32 nb_bytes) GF_AudioInput *ai = (GF_AudioInput *) callback; if (!ai->stream) return; gf_mo_release_data(ai->stream, nb_bytes, 1); - ai->need_release = 0; + ai->need_release = GF_FALSE; } static Fixed gf_audio_input_get_speed(void *callback) @@ -130,36 +148,37 @@ static Bool gf_audio_input_get_volume(void *callback, Fixed *vol) return ai->snd->GetChannelVolume(ai->snd->owner, vol); } else { vol[0] = vol[1] = vol[2] = vol[3] = vol[4] = vol[5] = ai->intensity; - return (ai->intensity==FIX_ONE) ? 0 : 1; + return (ai->intensity==FIX_ONE) ? GF_FALSE : GF_TRUE; } } static Bool gf_audio_input_is_muted(void *callback) { GF_AudioInput *ai = (GF_AudioInput *) callback; - if (!ai->stream) return 1; + if (!ai->stream) return GF_TRUE; if (ai->is_muted) - return 1; + return GF_TRUE; return gf_mo_is_muted(ai->stream); } static Bool gf_audio_input_get_config(GF_AudioInterface *aifc, Bool for_recf) { GF_AudioInput *ai = (GF_AudioInput *) aifc->callback; - if (!ai->stream) return 0; + if (!ai->stream) return GF_FALSE; /*watchout for object reuse*/ - if (aifc->samplerate && (gf_mo_get_flags(ai->stream) & GF_MO_IS_INIT)) return 1; - if (!for_recf) - return 0; + if (aifc->samplerate && (gf_mo_get_flags(ai->stream) & GF_MO_IS_INIT)) return GF_TRUE; gf_mo_get_audio_info(ai->stream, &aifc->samplerate, &aifc->bps , &aifc->chan, &aifc->ch_cfg); + if (!for_recf) + return aifc->samplerate ? GF_TRUE : GF_FALSE; + if (aifc->samplerate * aifc->chan * aifc->bps && ((aifc->chan<=2) || aifc->ch_cfg)) { - gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, 1); - return 1; + gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, GF_TRUE); + return GF_TRUE; } - gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, 0); - return 0; + gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, GF_FALSE); + return GF_FALSE; } GF_EXPORT @@ -198,16 +217,16 @@ GF_Err gf_sc_audio_open(GF_AudioInput *ai, MFURL *url, Double clipBegin, Double if (ai->is_open) return GF_BAD_PARAM; /*get media object*/ - ai->stream = gf_mo_register(ai->owner, url, lock_timeline, 0); + ai->stream = gf_mo_register(ai->owner, url, lock_timeline, GF_FALSE); /*bad URL*/ if (!ai->stream) return GF_NOT_SUPPORTED; /*request play*/ - gf_mo_play(ai->stream, clipBegin, clipEnd, 0); + gf_mo_play(ai->stream, clipBegin, clipEnd, GF_FALSE); - ai->stream_finished = 0; + ai->stream_finished = GF_FALSE; ai->is_open = 1; - gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, 0); + gf_mo_set_flag(ai->stream, GF_MO_IS_INIT, GF_FALSE); if (ai->filter) gf_af_del(ai->filter); ai->filter = NULL; @@ -228,7 +247,7 @@ void gf_sc_audio_stop(GF_AudioInput *ai) if (!ai->is_open) return; /*we must make sure audio mixer is not using the stream otherwise we may leave it dirty (with unrelease frame)*/ - gf_mixer_lock(ai->compositor->audio_renderer->mixer, 1); + gf_mixer_lock(ai->compositor->audio_renderer->mixer, GF_TRUE); assert(!ai->need_release); @@ -240,7 +259,7 @@ void gf_sc_audio_stop(GF_AudioInput *ai) if (ai->filter) gf_af_del(ai->filter); ai->filter = NULL; - gf_mixer_lock(ai->compositor->audio_renderer->mixer, 0); + gf_mixer_lock(ai->compositor->audio_renderer->mixer, GF_FALSE); } @@ -249,8 +268,8 @@ void gf_sc_audio_restart(GF_AudioInput *ai) { if (!ai->is_open) return; if (ai->need_release) gf_mo_release_data(ai->stream, 0xFFFFFFFF, 2); - ai->need_release = 0; - ai->stream_finished = 0; + ai->need_release = GF_FALSE; + ai->stream_finished = GF_FALSE; if (ai->filter) gf_af_reset(ai->filter); gf_mo_restart(ai->stream); } @@ -284,21 +303,21 @@ void gf_sc_audio_register(GF_AudioInput *ai, GF_TraverseState *tr_state) if (ai->register_with_parent) return; if (ai->register_with_renderer) { gf_sc_ar_remove_src(ai->compositor->audio_renderer, aifce); - ai->register_with_renderer = 0; + ai->register_with_renderer = GF_FALSE; } tr_state->audio_parent->add_source(tr_state->audio_parent, ai); - ai->register_with_parent = 1; + ai->register_with_parent = GF_TRUE; ai->snd = tr_state->sound_holder; } else if (!ai->register_with_renderer) { if (ai->register_with_parent) { - ai->register_with_parent = 0; + ai->register_with_parent = GF_FALSE; /*if used in a parent audio group, do a complete traverse to rebuild the group*/ gf_sc_invalidate(ai->compositor, NULL); } gf_sc_ar_add_src(ai->compositor->audio_renderer, aifce); - ai->register_with_renderer = 1; + ai->register_with_renderer = GF_TRUE; ai->snd = tr_state->sound_holder; } } @@ -310,7 +329,7 @@ void gf_sc_audio_unregister(GF_AudioInput *ai) if (ai->filter) aifce = &ai->filter->input; if (ai->register_with_renderer) { - ai->register_with_renderer = 0; + ai->register_with_renderer = GF_FALSE; gf_sc_ar_remove_src(ai->compositor->audio_renderer, aifce); } else { /*if used in a parent audio group, do a complete traverse to rebuild the group*/ @@ -378,8 +397,8 @@ static Bool gf_af_get_config(GF_AudioInterface *ai, Bool for_reconf) GF_AudioFilterItem *af = (GF_AudioFilterItem *)ai->callback; Bool res = af->src->GetConfig(af->src, for_reconf); - if (!res) return 0; - if (!for_reconf) return 1; + if (!res) return GF_FALSE; + if (!for_reconf) return GF_TRUE; af->input.bps = af->src->bps; @@ -391,9 +410,9 @@ static Bool gf_af_get_config(GF_AudioInterface *ai, Bool for_reconf) if (gf_afc_setup(&af->filter_chain, af->input.bps, af->input.samplerate, af->src->chan, af->src->ch_cfg, &af->input.chan, &af->input.ch_cfg)!=GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUDIO, ("[Audio Input] Failed to configure audio filter chain\n")); - return 0; + return GF_FALSE; } - return 1; + return GF_TRUE; } GF_AudioFilterItem *gf_af_new(GF_Compositor *compositor, GF_AudioInterface *src, char *filter_name) diff --git a/src/compositor/audio_mixer.c b/src/compositor/audio_mixer.c index 18b29b8..2379e60 100644 --- a/src/compositor/audio_mixer.c +++ b/src/compositor/audio_mixer.c @@ -249,6 +249,13 @@ Bool gf_mixer_reconfig(GF_AudioMixer *am) gf_mixer_lock(am, 0); return 0; } + + if (am->ar && am->ar->config_forced) { + am->must_reconfig=0; + gf_mixer_lock(am, 0); + return 0; + } + numInit = 0; max_sample_rate = am->sample_rate; max_channels = am->nb_channels; @@ -330,6 +337,7 @@ Bool gf_mixer_reconfig(GF_AudioMixer *am) } if (numInit == count) am->must_reconfig = 0; + if (am->ar) cfg_changed = 1; gf_mixer_lock(am, 0); return cfg_changed; @@ -563,13 +571,15 @@ u32 gf_mixer_get_output(GF_AudioMixer *am, void *buffer, u32 buffer_size, u32 de s32 *out_mix, nb_act_src; char *data, *ptr; + //reset buffer whatever the state of the mixer is + memset(buffer, 0, buffer_size); + /*the config has changed we don't write to output since settings change*/ if (gf_mixer_reconfig(am)) return 0; gf_mixer_lock(am, 1); count = gf_list_count(am->sources); if (!count) { - memset(buffer, 0, buffer_size); gf_mixer_lock(am, 0); return 0; } @@ -583,7 +593,6 @@ u32 gf_mixer_get_output(GF_AudioMixer *am, void *buffer, u32 buffer_size, u32 de if (am->ar) { am->must_reconfig = 1; gf_mixer_reconfig(am); - memset(buffer, 0, buffer_size); gf_mixer_lock(am, 0); return 0; } @@ -610,9 +619,7 @@ single_source_mix: if (!data || !size) break; /*don't copy more than possible*/ if (size > buffer_size) size = buffer_size; - if (is_muted) { - memset(ptr, 0, size); - } else { + if (!is_muted) { memcpy(ptr, data, size); } buffer_size -= size; @@ -627,7 +634,6 @@ single_source_mix: if (!data) { GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioMixer] not enough input data (%d still to fill)\n", buffer_size)); } - memset(ptr, 0, buffer_size); } gf_mixer_lock(am, 0); return (in_size - buffer_size); @@ -702,7 +708,6 @@ do_mix: } } if (!nb_act_src) { - memset(buffer, 0, sizeof(char)*buffer_size); gf_mixer_lock(am, 0); return 0; } @@ -723,9 +728,9 @@ do_mix: in->out_samples_to_write = 0; continue; } - if (in->out_samples_to_write>in->out_samples_written) { - gf_mixer_fetch_input(am, in, delay + 8000 * i / am->bits_per_sample / am->sample_rate / am->nb_channels); - if (in->out_samples_to_write>in->out_samples_written) nb_to_fill++; + if (in->out_samples_to_write > in->out_samples_written) { + gf_mixer_fetch_input(am, in, delay /*+ 8000 * i / am->bits_per_sample / am->sample_rate / am->nb_channels*/ ); + if (in->out_samples_to_write > in->out_samples_written) nb_to_fill++; } } /*release - this is done in 2 steps in case 2 audio object use the same source...*/ @@ -736,6 +741,8 @@ do_mix: in->in_bytes_used = 0; } if (!nb_to_fill) break; + //only resync on the first fill + delay=0; } /*step 3, mix the final buffer*/ memset(am->output, 0, sizeof(s32) * buffer_size); @@ -757,7 +764,6 @@ do_mix: } if (!nb_written) { - memset(buffer, 0, sizeof(char)*buffer_size); gf_mixer_lock(am, 0); return 0; } @@ -791,8 +797,6 @@ do_mix: } nb_written *= am->nb_channels*am->bits_per_sample/8; - if (buffer_size > nb_written) - memset((char *)buffer + nb_written, 0, sizeof(char)*(buffer_size-nb_written)); gf_mixer_lock(am, 0); return nb_written; diff --git a/src/compositor/audio_render.c b/src/compositor/audio_render.c index 1b19202..2f1acf5 100644 --- a/src/compositor/audio_render.c +++ b/src/compositor/audio_render.c @@ -178,7 +178,7 @@ u32 gf_afc_process(GF_AudioFilterChain *afc, u32 nb_bytes) entry->nb_bytes -= entry->in_block_size; processed += entry->in_block_size; } - /*move remaining data at the begining of the buffer*/ + /*move remaining data at the beginning of the buffer*/ if (processed && entry->nb_bytes) memmove(entry->in_block, entry->in_block+processed, entry->nb_bytes); @@ -277,6 +277,10 @@ static GF_Err gf_ar_setup_output_format(GF_AudioRenderer *ar) ar->audio_out->SetVolume(ar->audio_out, ar->volume); ar->audio_out->SetPan(ar->audio_out, ar->pan); + ar->time_at_last_config = ar->current_time; + ar->bytes_requested = 0; + ar->bytes_per_second = freq * nb_chan * nb_bits / 8; + if (ar->audio_listeners) { u32 k=0; GF_AudioListener *l; @@ -287,6 +291,27 @@ static GF_Err gf_ar_setup_output_format(GF_AudioRenderer *ar) return GF_OK; } +static void gf_ar_pause(GF_AudioRenderer *ar, Bool DoFreeze, Bool for_reconfig, Bool reset_hw_buffer) +{ + gf_mixer_lock(ar->mixer, 1); + if (DoFreeze) { + if (!ar->Frozen) { + ar->freeze_time = gf_sys_clock_high_res(); + if (!for_reconfig && ar->audio_out && ar->audio_out->Play) ar->audio_out->Play(ar->audio_out, 0); + ar->Frozen = 1; + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[Audio] pausing master clock - time "LLD" (sys time "LLD")\n", ar->freeze_time, gf_sys_clock_high_res())); + } + } else { + if (ar->Frozen) { + if (!for_reconfig && ar->audio_out && ar->audio_out->Play) ar->audio_out->Play(ar->audio_out, reset_hw_buffer ? 2 : 1); + ar->Frozen = 0; + ar->start_time += gf_sys_clock_high_res() - ar->freeze_time; + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[Audio] resuming master clock - new time "LLD" (sys time "LLD") \n", ar->start_time, gf_sys_clock_high_res())); + } + } + gf_mixer_lock(ar->mixer, 0); +} + static u32 gf_ar_fill_output(void *ptr, char *buffer, u32 buffer_size) { @@ -295,6 +320,13 @@ static u32 gf_ar_fill_output(void *ptr, char *buffer, u32 buffer_size) if (!ar->need_reconfig) { u32 delay_ms = ar->disable_resync ? 0 : ar->audio_delay; + if (ar->Frozen) { + memset(buffer, 0, buffer_size); + return buffer_size; + } + + gf_mixer_lock(ar->mixer, 1); + if (ar->filter_chain.enable_filters) { char *ptr = buffer; u32 res = buffer_size; @@ -330,18 +362,57 @@ static u32 gf_ar_fill_output(void *ptr, char *buffer, u32 buffer_size) } else { written = gf_mixer_get_output(ar->mixer, buffer, buffer_size, delay_ms); } - if (ar->audio_listeners) { - u32 k=0; - GF_AudioListener *l; - while ((l = gf_list_enum(ar->audio_listeners, &k))) { - l->on_audio_frame(l->udta, buffer, written, gf_sc_ar_get_clock(ar), delay_ms); + gf_mixer_lock(ar->mixer, 0); + + //done with one sim step, go back in pause + if (ar->step_mode) { + ar->step_mode = 0; + gf_ar_pause(ar, 1, 0, 0); + } + + if (!ar->need_reconfig) { + if (ar->audio_listeners) { + u32 k=0; + GF_AudioListener *l; + while ((l = gf_list_enum(ar->audio_listeners, &k))) { + l->on_audio_frame(l->udta, buffer, buffer_size, gf_sc_ar_get_clock(ar), delay_ms); + } } + + ar->bytes_requested += buffer_size; + ar->current_time = ar->time_at_last_config + (u32) (ar->bytes_requested * 1000 / ar->bytes_per_second); } - return written; + //always return buffer size (eg requested input size to be filled), since the clock is always increased by buffer_size (cf above line) + return buffer_size; } return 0; } +void gf_sc_flush_next_audio(GF_Compositor *compositor) +{ + if (!compositor->audio_renderer->audio_out) + return; + + gf_mixer_lock(compositor->audio_renderer->mixer, 1); + compositor->audio_renderer->step_mode = 1; + //resume for one frame + if (compositor->audio_renderer->Frozen) { + gf_ar_pause(compositor->audio_renderer, 0, 0, 0); + } + gf_mixer_lock(compositor->audio_renderer->mixer, 0); +} + +Bool gf_sc_check_audio_pending(GF_Compositor *compositor) +{ + Bool res = 0; + gf_mixer_lock(compositor->audio_renderer->mixer, 1); + if (compositor->audio_renderer->step_mode) + res = 1; + gf_mixer_lock(compositor->audio_renderer->mixer, 0); + + return res; +} + u32 gf_ar_proc(void *p) { GF_AudioRenderer *ar = (GF_AudioRenderer *) p; @@ -356,21 +427,14 @@ u32 gf_ar_proc(void *p) gf_mixer_lock(ar->mixer, 0); while (ar->audio_th_state == 1) { - //GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Audio simulation step\n")); - - /*THIS IS NEEDED FOR SYMBIAN - if no yield here, the audio module always grabs the - main mixer mutex and it takes forever before it can be grabed by another thread, - for instance when reconfiguring scene*/ -// gf_sleep(1); - - gf_mixer_lock(ar->mixer, 1); - if (ar->Frozen || gf_mixer_empty(ar->mixer) ) { - gf_mixer_lock(ar->mixer, 0); - gf_sleep(33); - } else { + //do mix even if mixer is empty, otherwise we will push the same buffer over and over to the sound card +/* + if (ar->Frozen ) { + gf_sleep(0); + } else +*/ { if (ar->need_reconfig) gf_sc_ar_reconfig(ar); ar->audio_out->WriteAudio(ar->audio_out); - gf_mixer_lock(ar->mixer, 0); } } GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Exiting audio thread\n")); @@ -478,11 +542,16 @@ GF_AudioRenderer *gf_sc_ar_load(GF_User *user) } } } - if (!ar->audio_out) gf_cfg_set_key(user->config, "Audio", "DriverName", "No Audio Output Available"); + if (!ar->audio_out) { + gf_cfg_set_key(user->config, "Audio", "DriverName", "No Audio Output Available"); + } else { + if (user->init_flags & GF_TERM_USE_AUDIO_HW_CLOCK) + ar->clock_use_audio_out = GF_TRUE; + } } - /*init compositor timer*/ - ar->startTime = gf_sys_clock(); + ar->start_time = gf_sys_clock_high_res(); + ar->current_time = 0; return ar; } @@ -492,7 +561,7 @@ void gf_sc_ar_del(GF_AudioRenderer *ar) GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Destroying compositor\n")); /*resume if paused (might cause deadlock otherwise)*/ - if (ar->Frozen) gf_sc_ar_control(ar, 1); + if (ar->Frozen) gf_sc_ar_control(ar, GF_SC_AR_RESUME); /*stop and shutdown*/ if (ar->audio_out) { /*kill audio thread*/ @@ -528,28 +597,9 @@ void gf_sc_ar_reset(GF_AudioRenderer *ar) gf_mixer_remove_all(ar->mixer); } -static void gf_ar_freeze_intern(GF_AudioRenderer *ar, Bool DoFreeze, Bool for_reconfig, Bool reset_hw_buffer) -{ - gf_mixer_lock(ar->mixer, 1); - if (DoFreeze) { - if (!ar->Frozen) { - ar->FreezeTime = gf_sys_clock(); - if (!for_reconfig && ar->audio_out && ar->audio_out->Play) ar->audio_out->Play(ar->audio_out, 0); - ar->Frozen = 1; - } - } else { - if (ar->Frozen) { - if (!for_reconfig && ar->audio_out && ar->audio_out->Play) ar->audio_out->Play(ar->audio_out, reset_hw_buffer ? 2 : 1); - ar->Frozen = 0; - ar->startTime += gf_sys_clock() - ar->FreezeTime; - } - } - gf_mixer_lock(ar->mixer, 0); -} - void gf_sc_ar_control(GF_AudioRenderer *ar, u32 PauseType) { - gf_ar_freeze_intern(ar, !PauseType, 0, (PauseType==2) ? 1 : 0); + gf_ar_pause(ar, (PauseType==GF_SC_AR_PAUSE), 0, (PauseType==GF_SC_AR_RESET_HW_AND_PLAY) ? 1 : 0); } void gf_sc_ar_set_volume(GF_AudioRenderer *ar, u32 Volume) @@ -623,10 +673,10 @@ void gf_sc_ar_reconfig(GF_AudioRenderer *ar) /*lock mixer*/ gf_mixer_lock(ar->mixer, 1); - gf_ar_freeze_intern(ar, 1, 1, 0); + gf_ar_pause(ar, 1, 1, 0); ar->need_reconfig = 0; gf_ar_setup_output_format(ar); - gf_ar_freeze_intern(ar, 0, 1, 0); + gf_ar_pause(ar, 0, 1, 0); /*unlock mixer*/ gf_mixer_lock(ar->mixer, 0); @@ -640,8 +690,13 @@ u32 gf_sc_ar_get_delay(GF_AudioRenderer *ar) u32 gf_sc_ar_get_clock(GF_AudioRenderer *ar) { - if (ar->Frozen) return ar->FreezeTime - ar->startTime; - return gf_sys_clock() - ar->startTime; + if (ar->clock_use_audio_out) return ar->current_time; + + if (ar->Frozen) { + return (u32) ((ar->freeze_time - ar->start_time) / 1000); + } + + return (u32) ((gf_sys_clock_high_res() - ar->start_time) / 1000); } GF_EXPORT @@ -655,10 +710,10 @@ void gf_sc_reload_audio_filters(GF_Compositor *compositor) gf_afc_unload(&ar->filter_chain); gf_afc_load(&ar->filter_chain, ar->user, (char*)gf_cfg_get_key(ar->user->config, "Audio", "Filter")); - gf_ar_freeze_intern(ar, 1, 1, 0); + gf_ar_pause(ar, 1, 1, 0); ar->need_reconfig = 0; gf_ar_setup_output_format(ar); - gf_ar_freeze_intern(ar, 0, 1, 0); + gf_ar_pause(ar, 0, 1, 0); gf_mixer_lock(ar->mixer, 0); } diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 85e1ca8..2d0e859 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -38,13 +38,9 @@ #define SC_DEF_WIDTH 320 #define SC_DEF_HEIGHT 240 - -void gf_sc_simulation_tick(GF_Compositor *compositor); - - void gf_sc_next_frame_state(GF_Compositor *compositor, u32 state) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Forcing frame redraw state: %d\n", state)); +// GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Forcing frame redraw state: %d\n", state)); compositor->frame_draw_type = state; if (state==GF_SC_DRAW_FLUSH) compositor->skip_flush = 2; @@ -60,8 +56,12 @@ static void gf_sc_set_fullscreen(GF_Compositor *compositor) /*move to FS*/ compositor->fullscreen = !compositor->fullscreen; - gf_sc_ar_control(compositor->audio_renderer, 0); + //gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE); + //in windows (and other?) we may get blocked by SetWindowPos in the fullscreen method until another window thread dispatches a resize event, + //which would try to grab the compositor mutex and thus deadlock us + //to avoid this, unlock the compositor just for the SetFullscreen + gf_mx_v(compositor->mx); if (compositor->fullscreen && (compositor->scene_width>=compositor->scene_height) #ifndef GPAC_DISABLE_3D && !compositor->visual->type_3d @@ -71,8 +71,9 @@ static void gf_sc_set_fullscreen(GF_Compositor *compositor) } else { e = compositor->video_out->SetFullScreen(compositor->video_out, compositor->fullscreen, &compositor->display_width, &compositor->display_height); } + gf_mx_p(compositor->mx); - gf_sc_ar_control(compositor->audio_renderer, 1); + //gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME); if (e) { GF_Event evt; @@ -131,18 +132,23 @@ static void gf_sc_reconfig_task(GF_Compositor *compositor) if (compositor->msg_type & GF_SR_CFG_SET_SIZE) { u32 fs_width, fs_height; Bool restore_fs = compositor->fullscreen; - compositor->msg_type &= ~GF_SR_CFG_SET_SIZE; GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Changing display size to %d x %d\n", compositor->new_width, compositor->new_height)); fs_width = fs_height = 0; if (restore_fs) { - fs_width = compositor->display_width; - fs_height = compositor->display_height; + if ((compositor->new_width>compositor->display_width) || (compositor->new_height>compositor->display_height)) { + u32 w = compositor->display_width; + compositor->display_width = compositor->display_height; + compositor->display_height = w; + compositor->recompute_ar = 1; + } + fs_width = compositor->display_width; + fs_height = compositor->display_height; } evt.type = GF_EVENT_SIZE; evt.size.width = compositor->new_width; evt.size.height = compositor->new_height; - compositor->new_width = compositor->new_height = 0; + /*send resize event*/ if (!(compositor->msg_type & GF_SR_CFG_WINDOWSIZE_NOTIF)) { compositor->video_out->ProcessEvent(compositor->video_out, &evt); @@ -153,7 +159,7 @@ static void gf_sc_reconfig_task(GF_Compositor *compositor) if ((compositor->display_width != fs_width) || (compositor->display_height != fs_height)) { compositor->display_width = fs_width; compositor->display_height = fs_height; - compositor->recompute_ar = 1; + compositor->recompute_ar = 1; } } else { compositor->display_width = evt.size.width; @@ -162,7 +168,9 @@ static void gf_sc_reconfig_task(GF_Compositor *compositor) gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); } notif_size=1; - + compositor->new_width = compositor->new_height = 0; + compositor->msg_type &= ~GF_SR_CFG_SET_SIZE; + GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Display size changed to %d x %d\n", compositor->new_width, compositor->new_height)); } /*aspect ratio modif*/ if (compositor->msg_type & GF_SR_CFG_AR) { @@ -212,15 +220,20 @@ static void gf_sc_reconfig_task(GF_Compositor *compositor) } GF_EXPORT -Bool gf_sc_draw_frame(GF_Compositor *compositor, u32 *ms_till_next) +Bool gf_sc_draw_frame(GF_Compositor *compositor, Bool no_flush, s32 *ms_till_next) { - gf_sc_simulation_tick(compositor); + if (no_flush) + compositor->skip_flush=1; + gf_sc_render_frame(compositor); + if (ms_till_next) { - if ((s32) compositor->next_frame_delay == -1) + if ( compositor->ms_until_next_frame == GF_INT_MAX) *ms_till_next = compositor->frame_duration; - else - *ms_till_next = MIN(compositor->next_frame_delay, compositor->frame_duration); + else + *ms_till_next = compositor->ms_until_next_frame; } + //next frame is late, we should redraw + if (compositor->ms_until_next_frame < 0) return 1; if (compositor->frame_draw_type) return 1; if (compositor->fonts_pending) return 1; return GF_FALSE; @@ -279,6 +292,9 @@ static GF_Err gf_sc_load(GF_Compositor *compositor) compositor->visual = visual_new(compositor); compositor->visual->GetSurfaceAccess = compositor_2d_get_video_access; compositor->visual->ReleaseSurfaceAccess = compositor_2d_release_video_access; + compositor->visual->CheckAttached = compositor_2d_check_attached; + compositor->visual->ClearSurface = compositor_2d_clear_surface; + if (compositor->video_out->FlushRectangles) compositor->visual->direct_flush = GF_TRUE; @@ -475,13 +491,8 @@ static u32 gf_sc_proc(void *par) compositor->video_th_state = GF_COMPOSITOR_THREAD_RUN; while (compositor->video_th_state == GF_COMPOSITOR_THREAD_RUN) { - if (compositor->is_hidden==1) { - if (!compositor->bench_mode) { - compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer); - } - gf_sleep(compositor->frame_duration); - } else - gf_sc_simulation_tick(compositor); + //simulation tick is self-regulating. Call it regardless of the visibility status + gf_sc_render_frame(compositor); } #ifndef GPAC_DISABLE_3D @@ -551,10 +562,13 @@ GF_Compositor *gf_sc_new(GF_User *user, Bool self_threaded, GF_Terminal *term) if ((tmp->user->init_flags & GF_TERM_NO_REGULATION) || !tmp->VisualThread) tmp->no_regulation = GF_TRUE; - /*set default size if owning output*/ +#if 1 + /*set default size if owning output*/ if (!tmp->user->os_window_handler) { gf_sc_set_size(tmp, SC_DEF_WIDTH, SC_DEF_HEIGHT); } +#endif + /*try to load GL extensions*/ #ifndef GPAC_DISABLE_3D gf_sc_load_opengl_extensions(tmp, GF_FALSE); @@ -622,6 +636,8 @@ void gf_sc_del(GF_Compositor *compositor) #ifndef GPAC_DISABLE_3D if (compositor->unit_bbox) mesh_free(compositor->unit_bbox); + + if (compositor->screen_buffer) gf_free(compositor->screen_buffer); #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unloading visual compositor module\n")); @@ -698,29 +714,20 @@ static void gf_sc_set_play_state(GF_Compositor *compositor, u32 PlayState) /*step mode*/ if (PlayState==GF_STATE_STEP_PAUSE) { compositor->step_mode = 1; - if (!compositor->paused) - gf_term_set_option(compositor->term, GF_OPT_PLAY_STATE, GF_STATE_PAUSED); - else { - u32 dur = compositor->frame_duration; - u32 i, count = gf_list_count(compositor->textures); - for (i=0; i<count; i++) { - GF_TextureHandler *txh = (GF_TextureHandler *) gf_list_get(compositor->textures, i); - if (txh->stream) { - u32 d = gf_mo_get_min_frame_dur(txh->stream); - if (d && d<dur) dur = d; - } - } - gf_term_step_clocks(compositor->term, dur); - } + gf_sc_flush_next_audio(compositor); + compositor->paused = 1; } else { compositor->step_mode = 0; - if (compositor->audio_renderer) gf_sc_ar_control(compositor->audio_renderer, (compositor->paused && (PlayState==0xFF)) ? 2 : compositor->paused); + if (compositor->audio_renderer) gf_sc_ar_control(compositor->audio_renderer, (compositor->paused && (PlayState==0xFF)) ? GF_SC_AR_RESET_HW_AND_PLAY : (compositor->paused ? GF_SC_AR_RESUME : GF_SC_AR_PAUSE) ); compositor->paused = (PlayState==GF_STATE_PAUSED) ? 1 : 0; } } u32 gf_sc_get_clock(GF_Compositor *compositor) { + if (!compositor->bench_mode) { + return gf_sc_ar_get_clock(compositor->audio_renderer); + } return compositor->scene_sampled_clock; } @@ -1064,6 +1071,10 @@ GF_EXPORT GF_Err gf_sc_set_size(GF_Compositor *compositor, u32 NewWidth, u32 NewHeight) { Bool lock_ok; + + if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight)) + return GF_OK; + if (!NewWidth || !NewHeight) { compositor->override_size_flags &= ~2; compositor->msg_type |= GF_SR_CFG_AR; @@ -1076,6 +1087,7 @@ GF_Err gf_sc_set_size(GF_Compositor *compositor, u32 NewWidth, u32 NewHeight) compositor->new_width = NewWidth; compositor->new_height = NewHeight; compositor->msg_type |= GF_SR_CFG_SET_SIZE; + assert(compositor->new_width); /*if same size only request for video setup */ compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF; @@ -1216,18 +1228,28 @@ void gf_sc_reload_config(GF_Compositor *compositor) #ifndef GPAC_DISABLE_3D sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "OpenGLMode"); - compositor->force_opengl_2d = (sOpt && !strcmp(sOpt, "always")) ? 1 : 0; - if (!sOpt) { - compositor->recompute_ar = 1; - compositor->autoconfig_opengl = 1; + + if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) { + if (sOpt && strcmp(sOpt, "disable")) { + GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] OpenGL mode %s requested but no opengl-capable output - disabling openGL\n", sOpt)); + } + compositor->force_opengl_2d = 0; + compositor->autoconfig_opengl = 0; + compositor->hybrid_opengl = 0; } else { - compositor->hybrid_opengl = !strcmp(sOpt, "hybrid") ? 1 : 0; + compositor->force_opengl_2d = (sOpt && !strcmp(sOpt, "always")) ? 1 : 0; + if (!sOpt) { + compositor->recompute_ar = 1; + compositor->autoconfig_opengl = 1; + } else { + compositor->hybrid_opengl = !strcmp(sOpt, "hybrid") ? 1 : 0; #ifdef OPENGL_RASTER - compositor->opengl_raster = !strcmp(sOpt, "raster") ? 1 : 0; - if (compositor->opengl_raster) compositor->traverse_state->immediate_draw = GF_TRUE; + compositor->opengl_raster = !strcmp(sOpt, "raster") ? 1 : 0; + if (compositor->opengl_raster) compositor->traverse_state->immediate_draw = GF_TRUE; #endif + } } - + sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "EnablePBO"); if (!sOpt) gf_cfg_set_key(compositor->user->config, "Compositor", "EnablePBO", "no"); compositor->enable_pbo = (sOpt && !strcmp(sOpt, "yes")) ? 1 : 0; @@ -1244,7 +1266,7 @@ void gf_sc_reload_config(GF_Compositor *compositor) /*currently: - no support for npow2 textures, and no support for DrawPixels */ -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "EmulatePOW2"); compositor->emul_pow2 = (sOpt && !stricmp(sOpt, "yes") ) ? 1 : 0; #else @@ -1376,7 +1398,7 @@ void gf_sc_reload_config(GF_Compositor *compositor) compositor->display_depth = -1; } #endif - + if (!compositor->video_out->view_distance) { sOpt = gf_cfg_get_key(compositor->user->config, "Compositor", "ViewDistance"); compositor->video_out->view_distance = FLT2FIX( sOpt ? (Float) atof(sOpt) : 50.0f ); @@ -1478,6 +1500,13 @@ GF_Err gf_sc_set_option(GF_Compositor *compositor, u32 type, u32 value) compositor->freeze_display = value; gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); break; + case GF_OPT_FORCE_AUDIO_CONFIG: + if (value) { + compositor->audio_renderer->config_forced++; + } else if (compositor->audio_renderer->config_forced) { + compositor->audio_renderer->config_forced --; + } + break; case GF_OPT_RELOAD_CONFIG: gf_sc_reload_config(compositor); gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); @@ -1638,6 +1667,7 @@ GF_Err gf_sc_set_option(GF_Compositor *compositor, u32 type, u32 value) return e; } +GF_EXPORT Bool gf_sc_is_over(GF_Compositor *compositor, GF_SceneGraph *scene_graph) { u32 i, count; @@ -1908,6 +1938,9 @@ GF_Node *gf_sc_pick_node(GF_Compositor *compositor, s32 X, s32 Y) static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node) { + Bool force_pause = compositor->audio_renderer->Frozen ? 0 : 1; + + force_pause = GF_FALSE; #ifndef GPAC_DISABLE_LOG compositor->visual_config_time = 0; @@ -1920,8 +1953,9 @@ static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node) time = gf_sys_clock(); } #endif + if (force_pause) + gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE); - gf_sc_ar_control(compositor->audio_renderer, 0); #ifndef GPAC_DISABLE_3D if (compositor->autoconfig_opengl) { compositor->visual->type_3d = 1; @@ -1930,8 +1964,8 @@ static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node) compositor_3d_set_aspect_ratio(compositor); gf_sc_load_opengl_extensions(compositor, compositor->visual->type_3d); if (compositor->autoconfig_opengl) { -#ifndef GPAC_USE_OGL_ES - visual_3d_init_yuv_shader(compositor->visual); +#ifndef GPAC_USE_GLES1X + visual_3d_init_shaders(compositor->visual); #endif compositor->autoconfig_opengl = 0; compositor->visual->type_3d = 0; @@ -1954,8 +1988,8 @@ static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node) #ifndef GPAC_DISABLE_3D if (compositor->hybrid_opengl) { gf_sc_load_opengl_extensions(compositor, GF_TRUE); -#ifndef GPAC_USE_OGL_ES - visual_3d_init_yuv_shader(compositor->visual); +#ifndef GPAC_USE_GLES1X + visual_3d_init_shaders(compositor->visual); #endif if (!compositor->visual->hybgl_drawn.list) { ra_init(&compositor->visual->hybgl_drawn); @@ -1964,7 +1998,8 @@ static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node) #endif } - gf_sc_ar_control(compositor->audio_renderer, 1); + if (force_pause ) + gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME); #ifndef GPAC_DISABLE_LOG if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) { @@ -2110,6 +2145,8 @@ static void gf_sc_draw_scene(GF_Compositor *compositor) if (!top_node && !compositor->visual->last_had_back && !compositor->visual->cur_context) { //GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Scene has no root node, nothing to draw\n")); + //nothing to draw, skip flush + compositor->skip_flush = 1; return; } @@ -2170,8 +2207,20 @@ static void compositor_release_textures(GF_Compositor *compositor, Bool frame_dr } } +void gf_sc_flush_video(GF_Compositor *compositor) +{ + GF_Window rc; -void gf_sc_simulation_tick(GF_Compositor *compositor) + //release compositor in case we have vsync + gf_sc_lock(compositor, 0); + rc.x = rc.y = 0; + rc.w = compositor->display_width; + rc.h = compositor->display_height; + compositor->video_out->Flush(compositor->video_out, &rc); + gf_sc_lock(compositor, 1); +} + +void gf_sc_render_frame(GF_Compositor *compositor) { #ifndef GPAC_DISABLE_SCENEGRAPH GF_SceneGraph *sg; @@ -2185,6 +2234,7 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) /*lock compositor for the whole cycle*/ gf_sc_lock(compositor, 1); + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Entering render_frame \n")); in_time = gf_sys_clock(); @@ -2216,6 +2266,7 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) gf_sleep(compositor->bench_mode ? 2 : compositor->frame_duration); } compositor->force_bench_frame=0; + compositor->frame_draw_type = 0; return; } @@ -2268,8 +2319,8 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) //first update all natural textures to figure out timing - compositor->frame_delay = (u32) -1; - compositor->next_frame_delay = (u32) -1; + compositor->frame_delay = 0; + compositor->ms_until_next_frame = GF_INT_MAX; frame_duration = compositor->frame_duration; #ifndef GPAC_DISABLE_LOG @@ -2376,10 +2427,13 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) #endif gf_sg_activate_routes(compositor->scene); + +#ifndef GPAC_DISABLE_SCENEGRAPH i = 0; while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) { gf_sg_activate_routes(sg); } +#endif #ifndef GPAC_DISABLE_LOG route_time = gf_sys_clock() - route_time; @@ -2439,7 +2493,8 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) compositor->frame_draw_type=GF_SC_DRAW_FRAME; } - if (compositor->is_hidden) { + //if hidden and no listener, do not draw the scene + if (compositor->is_hidden && !compositor->video_listeners) { compositor->frame_draw_type = 0; } @@ -2447,7 +2502,6 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) /*if invalidated, draw*/ if (compositor->frame_draw_type) { - GF_Window rc; Bool textures_released = 0; #ifndef GPAC_DISABLE_LOG @@ -2494,14 +2548,7 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) } if (compositor->skip_flush!=1) { - - //release compositor in case we have vsync - gf_sc_lock(compositor, 0); - rc.x = rc.y = 0; - rc.w = compositor->display_width; - rc.h = compositor->display_height; - compositor->video_out->Flush(compositor->video_out, &rc); - gf_sc_lock(compositor, 1); + gf_sc_flush_video(compositor); } else { compositor->skip_flush = 0; } @@ -2590,22 +2637,28 @@ void gf_sc_simulation_tick(GF_Compositor *compositor) } //we have a pending frame, return asap - we could sleep until frames matures but this give weird regulation - if (compositor->next_frame_delay != (u32) -1) { - if (compositor->next_frame_delay>end_time) compositor->next_frame_delay-=end_time; - else compositor->next_frame_delay=0; + if (compositor->ms_until_next_frame != GF_INT_MAX) { + compositor->ms_until_next_frame -= end_time; + + if (compositor->ms_until_next_frame<=0) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame already due (%d ms late) - not going to sleep\n", - compositor->ms_until_next_frame)); + compositor->ms_until_next_frame=0; + return; + } - compositor->next_frame_delay = MIN(compositor->next_frame_delay, 2*frame_duration); - if (compositor->next_frame_delay>2) { - u32 diff=0; + compositor->ms_until_next_frame = MIN(compositor->ms_until_next_frame, (s32) frame_duration ); + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame due in %d ms\n", compositor->ms_until_next_frame)); + if (compositor->ms_until_next_frame > 2) { + u64 start = gf_sys_clock_high_res(); + u64 diff=0; + u64 wait_for = 1000 * (u64) compositor->ms_until_next_frame; while (! compositor->msg_type && ! compositor->video_frame_pending) { gf_sleep(1); - diff = gf_sys_clock() - in_time; - if (diff >= (u32) compositor->next_frame_delay) + diff = gf_sys_clock_high_res() - start; + if (diff >= wait_for) break; } - GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept %d ms until next frame due in %d ms\n", diff, compositor->next_frame_delay)); - } else { - GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame due in %d ms - not going to sleep\n", compositor->next_frame_delay)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept %d ms until next frame (msg type %d - frame pending %d)\n", diff/1000, compositor->msg_type, compositor->video_frame_pending)); } return; } @@ -2683,13 +2736,14 @@ void gf_sc_traverse_subscene_ex(GF_Compositor *compositor, GF_Node *inline_paren of bindable stacks and gives us free 2D/3D integration*/ if (tag==TAG_MPEG4_OrderedGroup) { new_tag = TAG_MPEG4_Layer2D; - } else if ((tag==TAG_MPEG4_Group) + } else if (tag==TAG_MPEG4_Group) { + new_tag = TAG_MPEG4_Layer3D; + } #ifndef GPAC_DISABLE_X3D - || (tag==TAG_X3D_Group) + else if (tag==TAG_X3D_Group) { + new_tag = TAG_MPEG4_Layer3D; + } #endif - ) { - new_tag = TAG_MPEG4_Layer3D; - } } #if !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_3D) /*if the inlined root node is a 3D one except Layer3D and we are not in a 3D context, insert @@ -2853,7 +2907,13 @@ static Bool gf_sc_on_event_ex(GF_Compositor *compositor , GF_Event *event, Bool return GF_FALSE; } switch (event->type) { + case GF_EVENT_SHOWHIDE: + case GF_EVENT_SET_CAPTION: case GF_EVENT_MOVE: + compositor->video_out->ProcessEvent(compositor->video_out, event); + break; + + case GF_EVENT_MOVE_NOTIF: case GF_EVENT_REFRESH: if (!compositor->frame_draw_type) { /*when refreshing the window in 3D or with overlays we redraw the scene */ @@ -2899,6 +2959,7 @@ static Bool gf_sc_on_event_ex(GF_Compositor *compositor , GF_Event *event, Bool } else { /*remove pending resize notif*/ compositor->msg_type &= ~GF_SR_CFG_SET_SIZE; + compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF; } if (lock_ok) gf_sc_lock(compositor, GF_FALSE); } @@ -2949,14 +3010,10 @@ static Bool gf_sc_on_event_ex(GF_Compositor *compositor , GF_Event *event, Bool return gf_sc_handle_event_intern(compositor, event, from_user); /*switch fullscreen off!!!*/ - case GF_EVENT_SHOWHIDE: + case GF_EVENT_SHOWHIDE_NOTIF: compositor->is_hidden = event->show.show_type ? GF_FALSE : GF_TRUE; break; - case GF_EVENT_SET_CAPTION: - compositor->video_out->ProcessEvent(compositor->video_out, event); - break; - case GF_EVENT_MOUSEMOVE: event->mouse.button = 0; case GF_EVENT_MOUSEDOWN: @@ -2996,6 +3053,10 @@ Bool gf_sc_user_event(GF_Compositor *compositor, GF_Event *event) case GF_EVENT_SET_CAPTION: compositor->video_out->ProcessEvent(compositor->video_out, event); return GF_FALSE; + +// case GF_EVENT_SET_CAPTION: +// gf_sc_queue_event(compositor, event); +// return GF_FALSE; default: return gf_sc_on_event_ex(compositor, event, GF_TRUE); } @@ -3327,6 +3388,27 @@ void gf_sc_set_video_pending_frame(GF_Compositor *compositor) compositor->video_frame_pending = GF_TRUE; } +void gf_sc_queue_event(GF_Compositor *compositor, GF_Event *evt) +{ + u32 i, count; + GF_QueuedEvent *qev; + gf_mx_p(compositor->evq_mx); + + count = gf_list_count(compositor->event_queue); + for (i=0; i<count; i++) { + qev = gf_list_get(compositor->event_queue, i); + if (!qev->node && (qev->evt.type==evt->type)) { + qev->evt = *evt; + gf_mx_v(compositor->evq_mx); + return; + } + } + GF_SAFEALLOC(qev, GF_QueuedEvent); + qev->evt = *evt; + gf_list_add(compositor->event_queue, qev); + gf_mx_v(compositor->evq_mx); +} + void gf_sc_queue_dom_event(GF_Compositor *compositor, GF_Node *node, GF_DOM_Event *evt) { u32 i, count; diff --git a/src/compositor/compositor_2d.c b/src/compositor/compositor_2d.c index f0830e1..269f6cf 100644 --- a/src/compositor/compositor_2d.c +++ b/src/compositor/compositor_2d.c @@ -37,7 +37,7 @@ static void c2d_gl_fill_no_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color color) { return; -#if defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_GLES1X) GLfloat line[4]; line[0] = FIX2FLT(x); @@ -65,7 +65,7 @@ static void c2d_gl_fill_no_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Colo static void c2d_gl_fill_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color color, u8 alpha) { return; -#if defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_GLES1X) GLfloat line[4]; line[0] = FIX2FLT(x); @@ -96,7 +96,7 @@ static void c2d_gl_fill_alpha(void *cbk, u32 x, u32 y, u32 run_h_len, GF_Color c static void c2d_gl_fill_rect(void *cbk, u32 x, u32 y, u32 width, u32 height, GF_Color color) { return; -#if defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_GLES1X) GLfloat line[8]; line[0] = FIX2FLT(x); @@ -191,8 +191,8 @@ void compositor_2d_hybgl_flush_video(GF_Compositor *compositor, GF_IRect *area) a_tr_state.camera = &compositor->visual->camera; gf_mx_init(a_tr_state.model_matrix); - visual_3d_set_state(compositor->visual, V3D_STATE_LIGHT, 0); - visual_3d_enable_antialias(compositor->visual, 0); + visual_3d_set_state(compositor->visual, V3D_STATE_LIGHT, GF_FALSE); + visual_3d_enable_antialias(compositor->visual, GF_FALSE); gf_sc_texture_set_blend_mode(compositor->hybgl_txh, TX_MODULATE); visual_3d_set_material_2d_argb(compositor->visual, 0xFFFFFFFF); a_tr_state.mesh_num_textures = gf_sc_texture_enable(compositor->hybgl_txh, NULL); @@ -206,7 +206,7 @@ void compositor_2d_hybgl_flush_video(GF_Compositor *compositor, GF_IRect *area) orig.x = INT2FIX(area->x); orig.y = INT2FIX(area->y); - mesh_new_rectangle(compositor->hybgl_mesh, size, &orig, 1); + mesh_new_rectangle(compositor->hybgl_mesh, size, &orig, GF_TRUE); orig.x = INT2FIX(area->x) + INT2FIX(compositor->vp_width)/2; orig.y = INT2FIX(compositor->vp_height)/2 - INT2FIX(area->y) + INT2FIX(area->height); @@ -237,7 +237,7 @@ void compositor_2d_hybgl_flush_video(GF_Compositor *compositor, GF_IRect *area) SFVec2f size; size.x = INT2FIX(compositor->vp_width); size.y = INT2FIX(compositor->vp_height); - mesh_new_rectangle(compositor->hybgl_mesh, size, NULL, 1); + mesh_new_rectangle(compositor->hybgl_mesh, size, NULL, GF_TRUE); } } @@ -256,21 +256,21 @@ exit: compositor->visual->nb_objects_on_canvas_since_last_ogl_flush = 0; } -Bool c2d_gl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key) +Bool c2d_gl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx) { u8 alpha = GF_COL_A(ctx->aspect.fill_color); - if (ctx->transform.m[1] || ctx->transform.m[3]) return 0; + if (ctx->transform.m[1] || ctx->transform.m[3]) return GF_FALSE; - visual_3d_set_state(visual, V3D_STATE_LIGHT, 0); - visual_3d_enable_antialias(visual, 0); + visual_3d_set_state(visual, V3D_STATE_LIGHT, GF_FALSE); + visual_3d_enable_antialias(visual, GF_FALSE); if (alpha && (alpha != 0xFF)) { visual_3d_set_material_2d_argb(visual, ctx->aspect.fill_color); gf_sc_texture_set_blend_mode(ctx->aspect.fill_texture, TX_MODULATE); } else if (gf_sc_texture_is_transparent(ctx->aspect.fill_texture)) { gf_sc_texture_set_blend_mode(ctx->aspect.fill_texture, TX_REPLACE); } else { - visual_3d_set_state(visual, V3D_STATE_BLEND, 0); + visual_3d_set_state(visual, V3D_STATE_BLEND, GF_FALSE); } #ifndef GPAC_DISABLE_VRML /*ignore texture transform for bitmap*/ @@ -285,37 +285,43 @@ Bool c2d_gl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, Dr orig.y = INT2FIX(visual->compositor->vp_height)/2 - ctx->bi->unclip.y + ctx->bi->unclip.height; } mesh = new_mesh(); - mesh_new_rectangle(mesh, size, &orig, 1); + mesh_new_rectangle(mesh, size, &orig, GF_TRUE); visual_3d_mesh_paint(tr_state, mesh); mesh_free(mesh); gf_sc_texture_disable(ctx->aspect.fill_texture); tr_state->mesh_num_textures = 0; - return 1; + return GF_TRUE; } #endif - return 0; + return GF_FALSE; } -Bool compositor_2d_hybgl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key) +Bool compositor_2d_hybgl_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx) { + GF_Node *txtrans = NULL; //for anything but background use regular routines - if (!(ctx->flags & CTX_IS_BACKGROUND)) return 0; + if (!(ctx->flags & CTX_IS_BACKGROUND)) return GF_FALSE; + +#ifndef GPAC_DISABLE_VRML + if (tr_state->appear ) txtrans = ((M_Appearance *)tr_state->appear)->textureTransform; +#endif /*ignore texture transform for bitmap*/ - tr_state->mesh_num_textures = gf_sc_texture_enable(ctx->aspect.fill_texture, tr_state->appear ? ((M_Appearance *)tr_state->appear)->textureTransform : NULL); + tr_state->mesh_num_textures = gf_sc_texture_enable(ctx->aspect.fill_texture, txtrans); + if (tr_state->mesh_num_textures) { SFVec2f size, orig; size.x = ctx->bi->unclip.width; size.y = ctx->bi->unclip.height; orig.x = ctx->bi->unclip.x ; orig.y = ctx->bi->unclip.y; - mesh_new_rectangle(visual->compositor->hybgl_mesh_background, size, &orig, 0); + mesh_new_rectangle(visual->compositor->hybgl_mesh_background, size, &orig, GF_FALSE); visual_3d_mesh_paint(tr_state, visual->compositor->hybgl_mesh_background); gf_sc_texture_disable(ctx->aspect.fill_texture); tr_state->mesh_num_textures = 0; } - return 1; + return GF_TRUE; } #endif @@ -345,9 +351,8 @@ void compositor_2d_reset_gl_auto(GF_Compositor *compositor) static GF_Err compositor_2d_setup_opengl(GF_VisualManager *visual) { - Fixed hh, hw; GF_Compositor *compositor = visual->compositor; - visual->is_attached = 1; + visual->is_attached = GF_TRUE; visual_3d_setup(visual); visual->compositor->traverse_state->camera = &visual->camera; @@ -360,7 +365,7 @@ static GF_Err compositor_2d_setup_opengl(GF_VisualManager *visual) glLineWidth(1.0f); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X glDisable(GL_POLYGON_SMOOTH); #endif glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); @@ -378,106 +383,114 @@ static GF_Err compositor_2d_setup_opengl(GF_VisualManager *visual) glEnable(GL_LINE_SMOOTH); } - hw = INT2FIX(compositor->vp_width)/2; - hh = INT2FIX(compositor->vp_height)/2; - gf_mx_ortho(&visual->camera.projection, -hw, hw, -hh, hh, 50, -50); + visual->camera.width = INT2FIX(compositor->vp_width); + visual->camera.height = INT2FIX(compositor->vp_height); + visual->camera.up.y = FIX_ONE; + visual->camera.end_zoom = FIX_ONE; + visual->camera.position.z = INT2FIX(1000); + visual->camera.flags = CAM_IS_DIRTY; + camera_update(&visual->camera, NULL, visual->center_coords); visual_3d_projection_matrix_modified(visual); - gf_mx_init(visual->camera.modelview); - #ifdef OPENGL_RASTER if (compositor->opengl_raster) { - gf_mx_add_scale(&visual->camera.modelview, 1, -1, 1); - gf_mx_add_translation(&visual->camera.modelview, -hw, -hh, 0); + gf_mx_add_scale(&visual->camera.modelview, FIX_ONE, -FIX_ONE, FIX_ONE); + gf_mx_add_translation(&visual->camera.modelview, -visual->camera.width/2, -visual->camera.height/2, 0); } #endif return GF_OK; } #endif -GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) +#ifdef OPENGL_RASTER +static GF_Err c2d_video_access_opengl_raster(GF_VisualManager *visual) { GF_Err e; GF_Compositor *compositor = visual->compositor; + GF_RasterCallback callbacks; - if (!visual->raster_surface) return GF_BAD_PARAM; + callbacks.cbk = visual; + callbacks.fill_run_alpha = c2d_gl_fill_alpha; + callbacks.fill_run_no_alpha = c2d_gl_fill_no_alpha; + callbacks.fill_rect = c2d_gl_fill_rect; -#ifdef OPENGL_RASTER - if (compositor->opengl_raster && compositor->rasterizer->surface_attach_to_callbacks) { - GF_RasterCallback callbacks; - callbacks.cbk = visual; - callbacks.fill_run_alpha = c2d_gl_fill_alpha; - callbacks.fill_run_no_alpha = c2d_gl_fill_no_alpha; - callbacks.fill_rect = c2d_gl_fill_rect; - - visual->DrawBitmap = c2d_gl_draw_bitmap; + visual->DrawBitmap = c2d_gl_draw_bitmap; - e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &callbacks, compositor->vp_width, compositor->vp_height); - if (e) return e; + e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &callbacks, compositor->vp_width, compositor->vp_height); + if (e) return e; - return compositor_2d_setup_opengl(visual); - } + return compositor_2d_setup_opengl(visual); +} #endif #ifndef GPAC_DISABLE_3D - if (compositor->hybrid_opengl) { - if (!compositor->hybgl_txh) { - GF_SAFEALLOC(compositor->hybgl_txh, GF_TextureHandler); - if (!compositor->hybgl_txh) return GF_IO_ERR; - compositor->hybgl_txh->compositor = compositor; - } +static GF_Err c2d_video_access_hybrid_opengl(GF_VisualManager *visual) +{ + GF_Err e; + GF_Compositor *compositor = visual->compositor; - if ((compositor->hybgl_txh->width != compositor->vp_width) || (compositor->hybgl_txh->height != compositor->vp_height)) { - SFVec2f size; - compositor->hybgl_txh->data = gf_realloc(compositor->hybgl_txh->data, 4*compositor->vp_width*compositor->vp_height); + if (!compositor->hybgl_txh) { + GF_SAFEALLOC(compositor->hybgl_txh, GF_TextureHandler); + if (!compositor->hybgl_txh) return GF_IO_ERR; + compositor->hybgl_txh->compositor = compositor; + } - if (compositor->hybgl_txh->tx_io) - gf_sc_texture_release(compositor->hybgl_txh); + if ((compositor->hybgl_txh->width != compositor->vp_width) || (compositor->hybgl_txh->height != compositor->vp_height)) { + SFVec2f size; + compositor->hybgl_txh->data = (char*)gf_realloc(compositor->hybgl_txh->data, 4*compositor->vp_width*compositor->vp_height); - compositor->hybgl_txh->width = compositor->vp_width; - compositor->hybgl_txh->height = compositor->vp_height; - compositor->hybgl_txh->stride = 4*compositor->vp_width; - compositor->hybgl_txh->pixelformat = GF_PIXEL_RGBA; - compositor->hybgl_txh->transparent = 1; - compositor->hybgl_txh->flags = GF_SR_TEXTURE_PRIVATE_MEDIA | GF_SR_TEXTURE_NO_GL_FLIP; + if (compositor->hybgl_txh->tx_io) + gf_sc_texture_release(compositor->hybgl_txh); - memset(compositor->hybgl_txh->data, 0, 4*compositor->hybgl_txh->width*compositor->hybgl_txh->height); - gf_sc_texture_allocate(compositor->hybgl_txh); - gf_sc_texture_set_data(compositor->hybgl_txh); + compositor->hybgl_txh->width = compositor->vp_width; + compositor->hybgl_txh->height = compositor->vp_height; + compositor->hybgl_txh->stride = 4*compositor->vp_width; + compositor->hybgl_txh->pixelformat = GF_PIXEL_RGBA; + compositor->hybgl_txh->transparent = GF_TRUE; + compositor->hybgl_txh->flags = GF_SR_TEXTURE_PRIVATE_MEDIA | GF_SR_TEXTURE_NO_GL_FLIP; - if (!compositor->hybgl_mesh) - compositor->hybgl_mesh = new_mesh(); + memset(compositor->hybgl_txh->data, 0, 4*compositor->hybgl_txh->width*compositor->hybgl_txh->height); + gf_sc_texture_allocate(compositor->hybgl_txh); + gf_sc_texture_set_data(compositor->hybgl_txh); - if (!compositor->hybgl_mesh_background) - compositor->hybgl_mesh_background = new_mesh(); + if (!compositor->hybgl_mesh) + compositor->hybgl_mesh = new_mesh(); - size.x = INT2FIX(compositor->vp_width); - size.y = INT2FIX(compositor->vp_height); - mesh_new_rectangle(compositor->hybgl_mesh, size, NULL, 1); - mesh_new_rectangle(compositor->hybgl_mesh_background, size, NULL, 0); - } - if (!compositor->hybgl_txh->data) return GF_IO_ERR; - - if (visual->compositor->traverse_state->immediate_draw) - memset(compositor->hybgl_txh->data, 0, 4*compositor->hybgl_txh->width*compositor->hybgl_txh->height); - - e = compositor->rasterizer->surface_attach_to_buffer(visual->raster_surface, compositor->hybgl_txh->data, - compositor->hybgl_txh->width, - compositor->hybgl_txh->height, - 0, - compositor->hybgl_txh->width * 4, - (GF_PixelFormat) GF_PIXEL_RGBA); - if (e) return e; - e = compositor_2d_setup_opengl(visual); - if (e) return e; - visual->ClearSurface = compositor_2d_hybgl_clear_surface; - visual->DrawBitmap = compositor_2d_hybgl_draw_bitmap; - return GF_OK; + if (!compositor->hybgl_mesh_background) + compositor->hybgl_mesh_background = new_mesh(); + + size.x = INT2FIX(compositor->vp_width); + size.y = INT2FIX(compositor->vp_height); + mesh_new_rectangle(compositor->hybgl_mesh, size, NULL, GF_TRUE); + mesh_new_rectangle(compositor->hybgl_mesh_background, size, NULL, GF_FALSE); } + if (!compositor->hybgl_txh->data) return GF_IO_ERR; + + if (visual->compositor->traverse_state->immediate_draw) + memset(compositor->hybgl_txh->data, 0, 4*compositor->hybgl_txh->width*compositor->hybgl_txh->height); + + e = compositor->rasterizer->surface_attach_to_buffer(visual->raster_surface, compositor->hybgl_txh->data, + compositor->hybgl_txh->width, + compositor->hybgl_txh->height, + 0, + compositor->hybgl_txh->width * 4, + (GF_PixelFormat) GF_PIXEL_RGBA); + if (e) return e; + e = compositor_2d_setup_opengl(visual); + if (e) return e; + visual->ClearSurface = compositor_2d_hybgl_clear_surface; + visual->DrawBitmap = compositor_2d_hybgl_draw_bitmap; + return GF_OK; +} #endif - compositor->hw_locked = 0; +static GF_Err c2d_get_video_access_normal(GF_VisualManager *visual) +{ + GF_Err e; + GF_Compositor *compositor = visual->compositor; + + compositor->hw_locked = GF_FALSE; e = GF_IO_ERR; /*try from video memory handle (WIN32) if supported*/ @@ -485,15 +498,15 @@ GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) && compositor->rasterizer->surface_attach_to_device && compositor->video_out->LockOSContext ) { - compositor->hw_context = compositor->video_out->LockOSContext(compositor->video_out, 1); + compositor->hw_context = compositor->video_out->LockOSContext(compositor->video_out, GF_TRUE); if (compositor->hw_context) { e = compositor->rasterizer->surface_attach_to_device(visual->raster_surface, compositor->hw_context, compositor->vp_width, compositor->vp_height); if (!e) { - visual->is_attached = 1; + visual->is_attached = GF_TRUE; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface handle attached to raster\n")); return GF_OK; } - compositor->video_out->LockOSContext(compositor->video_out, 0); + compositor->video_out->LockOSContext(compositor->video_out, GF_FALSE); GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface handle to raster: %s\n", gf_error_to_string(e) )); } } @@ -501,7 +514,7 @@ GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) if (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_LINE_BLIT) { e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &compositor->raster_callbacks, compositor->vp_width, compositor->vp_height); if (!e) { - visual->is_attached = 1; + visual->is_attached = GF_TRUE; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface callbacks attached to raster\n")); return GF_OK; } @@ -510,9 +523,9 @@ GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) e = GF_NOT_SUPPORTED; - e = compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 1); + e = compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, GF_TRUE); if (e==GF_OK) { - compositor->hw_locked = 1; + compositor->hw_locked = GF_TRUE; e = compositor->rasterizer->surface_attach_to_buffer(visual->raster_surface, compositor->hw_surface.video_buffer, compositor->hw_surface.width, @@ -521,26 +534,98 @@ GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) compositor->hw_surface.pitch_y, (GF_PixelFormat) compositor->hw_surface.pixel_format); if (!e) { - visual->is_attached = 1; + visual->is_attached = GF_TRUE; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface memory attached to raster - w=%d h=%d pitch_x=%d pitch_y=%d\n", compositor->hw_surface.width, compositor->hw_surface.height, compositor->hw_surface.pitch_x, compositor->hw_surface.pitch_y)); return GF_OK; } GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface memory to raster: %s\n", gf_error_to_string(e) )); - compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0); + compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, GF_FALSE); } - compositor->hw_locked = 0; - visual->is_attached = 0; + compositor->hw_locked = GF_FALSE; + visual->is_attached = GF_FALSE; /*if using BlitTexture, return OK to still be able to blit images*/ if (compositor->video_out->BlitTexture) e = GF_OK; return e; } +GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) +{ + GF_Compositor *compositor = visual->compositor; + + if (!visual->raster_surface) return GF_BAD_PARAM; + +#ifdef OPENGL_RASTER + if (compositor->opengl_raster && compositor->rasterizer->surface_attach_to_callbacks) { + return c2d_video_access_opengl_raster(visual); + } +#endif + +#ifndef GPAC_DISABLE_3D + if (compositor->hybrid_opengl) { + return c2d_video_access_hybrid_opengl(visual); + } +#endif + //do nothing until asked to really attach + return GF_OK; +} + +Bool compositor_2d_check_attached(GF_VisualManager *visual) +{ + if (!visual->is_attached) { + c2d_get_video_access_normal(visual); + } + + return visual->is_attached; +} + +void compositor_2d_clear_surface(GF_VisualManager *visual, GF_IRect *rc, u32 BackColor, Bool offscreen_clear) +{ + //visual not attached on main (direct video) visual, use texture bliting + if (!visual->is_attached && visual->compositor->video_out->Blit && (visual->compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGB)) { + char data[12]; + GF_Err e; + GF_VideoSurface video_src; + GF_Window src_wnd, dst_wnd; + data[0] = data[3] = data[6] = data[9] = GF_COL_R(BackColor); + data[1] = data[4] = data[7] = data[10] = GF_COL_G(BackColor); + data[2] = data[5] = data[8] = data[11] = GF_COL_B(BackColor); + + memset(&video_src, 0, sizeof(GF_VideoSurface)); + video_src.height = 2; + video_src.width = 2; + video_src.pitch_x = 0; + video_src.pitch_y = 6; + video_src.pixel_format = GF_PIXEL_RGB_24; + video_src.video_buffer = data; + + src_wnd.x = src_wnd.y = 0; + src_wnd.w = src_wnd.h = 1; + if (rc) { + dst_wnd.x = rc->x; + dst_wnd.y = rc->y; + dst_wnd.w = rc->width; + dst_wnd.h = rc->height; + } else { + dst_wnd.x = dst_wnd.y = 0; + dst_wnd.w = visual->width; + dst_wnd.h = visual->height; + } + + e = visual->compositor->video_out->Blit(visual->compositor->video_out, &video_src, &src_wnd, &dst_wnd, 0); + if (e==GF_OK) return; + } + + visual_2d_clear_surface(visual, rc, BackColor, offscreen_clear); +} + + + void compositor_2d_release_video_access(GF_VisualManager *visual) { GF_Compositor *compositor = visual->compositor; if (visual->is_attached) { compositor->rasterizer->surface_detach(visual->raster_surface); - visual->is_attached = 0; + visual->is_attached = GF_FALSE; } #ifndef GPAC_DISABLE_3D @@ -551,11 +636,11 @@ void compositor_2d_release_video_access(GF_VisualManager *visual) #endif //GPAC_DISABLE_3D if (compositor->hw_context) { - compositor->video_out->LockOSContext(compositor->video_out, 0); + compositor->video_out->LockOSContext(compositor->video_out, GF_FALSE); compositor->hw_context = NULL; } else if (compositor->hw_locked) { - compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0); - compositor->hw_locked = 0; + compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, GF_FALSE); + compositor->hw_locked = GF_FALSE; } } @@ -601,7 +686,7 @@ Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler * h_scale = final.height / txh->height; if ((w_scale != FIX_ONE) || (h_scale!=FIX_ONE)) { - if (has_scale) *has_scale = 1; + if (has_scale) *has_scale = GF_TRUE; } if (visual->offscreen) { @@ -629,12 +714,12 @@ Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler * if (clipped_final.x<0) { clipped_final.width += clipped_final.x; clipped_final.x = 0; - if (clipped_final.width <= 0) return 0; + if (clipped_final.width <= 0) return GF_FALSE; } if (clipped_final.y<0) { clipped_final.height += clipped_final.y; clipped_final.y = 0; - if (clipped_final.height <= 0) return 0; + if (clipped_final.height <= 0) return GF_FALSE; } if (clipped_final.x + clipped_final.width > (s32) output_width) { clipped_final.width = output_width - clipped_final.x; @@ -646,7 +731,7 @@ Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler * } /*needed in direct drawing since clipping is not performed*/ if (clipped_final.width<=0 || clipped_final.height <=0) - return 0; + return GF_FALSE; if (clipped_final.width-1>= FIX2INT(final.width) ) clipped_final.width = FIX2INT(final.width); if (clipped_final.height-1>= FIX2INT(final.height) ) clipped_final.height = FIX2INT(final.height); @@ -657,7 +742,7 @@ Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler * dst->w = (u32) clipped_final.width; dst->h = (u32) clipped_final.height; - if (!dst->w || !dst->h) return 0; + if (!dst->w || !dst->h) return GF_FALSE; #ifdef GPAC_FIXED_POINT #define ROUND_FIX(_v) \ @@ -678,38 +763,45 @@ Bool compositor_texture_rectangles(GF_VisualManager *visual, GF_TextureHandler * if (ABS(tmp) > FIX_EPSILON) use_blit = 0; #endif - use_blit = 1; - /*compute SRC window*/ - tmp = gf_divfix(INT2FIX(clipped_final.x) - final.x, w_scale); - if (tmp<0) tmp=0; - CEILING(src->x); + use_blit = GF_TRUE; - tmp = gf_divfix(INT2FIX(clipped_final.y) - final.y, h_scale); - if (tmp<0) tmp=0; - CEILING(src->y); + if (txh->data && !txh->size && (txh->width==2) && (txh->height==2) ) { + src->x = src->y = 0; + src->w = 1; + src->h = 1; + } else { + /*compute SRC window*/ + tmp = gf_divfix(INT2FIX(clipped_final.x) - final.x, w_scale); + if (tmp<0) tmp=0; + CEILING(src->x); - tmp = gf_divfix(INT2FIX(clip->width), w_scale); - ROUND_FIX(src->w); + tmp = gf_divfix(INT2FIX(clipped_final.y) - final.y, h_scale); + if (tmp<0) tmp=0; + CEILING(src->y); - tmp = gf_divfix(INT2FIX(clip->height), h_scale); - ROUND_FIX(src->h); + tmp = gf_divfix(INT2FIX(clip->width), w_scale); + ROUND_FIX(src->w); + + tmp = gf_divfix(INT2FIX(clip->height), h_scale); + ROUND_FIX(src->h); -#undef ROUND_FIX - if (src->w>txh->width) src->w=txh->width; - if (src->h>txh->height) src->h=txh->height; + if (src->w>txh->width) src->w=txh->width; + if (src->h>txh->height) src->h=txh->height; - if (!src->w || !src->h) return GF_FALSE; + if (!src->w || !src->h) return GF_FALSE; - /*make sure we lie in src bounds*/ - if (src->x + src->w>txh->width) src->w = txh->width - src->x; - if (src->y + src->h>txh->height) src->h = txh->height - src->y; + /*make sure we lie in src bounds*/ + if (src->x + src->w>txh->width) src->w = txh->width - src->x; + if (src->y + src->h>txh->height) src->h = txh->height - src->y; + } +#undef ROUND_FIX if (disable_blit) *disable_blit = use_blit ? GF_FALSE : GF_TRUE; return GF_TRUE; } -static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHandler *txh, DrawableContext *ctx, GF_IRect *clip, GF_Rect *unclip, u8 alpha, GF_ColorKey *col_key, GF_TraverseState *tr_state, Bool force_soft_blt) +static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHandler *txh, DrawableContext *ctx, GF_IRect *clip, GF_Rect *unclip, u8 alpha, GF_TraverseState *tr_state, Bool force_soft_blt) { GF_VideoSurface video_src; GF_Err e; @@ -761,9 +853,13 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan case GF_PIXEL_RGBD: // case GF_PIXEL_RGB_555: // case GF_PIXEL_RGB_565: - if (hw_caps & GF_VIDEO_HW_HAS_RGB) - use_soft_stretch = GF_FALSE; - break; + if ((alpha==0xFF) && (hw_caps & GF_VIDEO_HW_HAS_RGB)) { + use_soft_stretch = GF_FALSE; + } + else if ((alpha!=0xFF) && (hw_caps & GF_VIDEO_HW_HAS_RGBA)) { + use_soft_stretch = GF_FALSE; + } + break; case GF_PIXEL_ARGB: case GF_PIXEL_RGBA: case GF_PIXEL_RGBAS: @@ -786,7 +882,7 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan } /*disable based on settings*/ if (!visual->compositor->enable_yuv_hw - || (ctx->col_mat || (alpha!=0xFF) || !visual->compositor->video_out->Blit) + || (ctx->col_mat || !visual->compositor->video_out->Blit) ) { use_soft_stretch = GF_TRUE; overlay_type = 0; @@ -796,7 +892,7 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan } /*disable HW color keying - not compatible with MPEG-4 MaterialKey*/ - if (col_key) { + if (tr_state->col_key) { use_soft_stretch = GF_TRUE; overlay_type = 0; } @@ -813,8 +909,8 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan } /*OK we can overlay this video - if full display, don't flush*/ if (overlay_type==1) { - if (dst_wnd.w==visual->compositor->display_width) flush_video = 0; - else if (dst_wnd.h==visual->compositor->display_height) flush_video = 0; + if (dst_wnd.w==visual->compositor->display_width) flush_video = GF_FALSE; + else if (dst_wnd.h==visual->compositor->display_height) flush_video = GF_FALSE; else flush_video = visual->has_modif; } /*if no color keying, we cannot queue the overlay*/ @@ -842,6 +938,7 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan video_src.u_ptr = (char *) txh->pU; video_src.v_ptr = (char *) txh->pV; } + video_src.global_alpha = alpha; //overlay queing if (overlay_type==2) { @@ -871,7 +968,7 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan o_rc.width = dst_wnd.w; o_rc.height = dst_wnd.h; - visual->ClearSurface(visual, &o_rc, visual->compositor->video_out->overlay_color_key, 0); + visual->ClearSurface(visual, &o_rc, visual->compositor->video_out->overlay_color_key, GF_FALSE); visual->has_overlays = GF_TRUE; /*mark drawable as overlay*/ ctx->drawable->flags |= DRAWABLE_IS_OVERLAY; @@ -960,7 +1057,7 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan e = visual->compositor->video_out->LockBackBuffer(visual->compositor->video_out, &backbuffer, GF_TRUE); if (!e) { u32 push_time = gf_sys_clock(); - gf_stretch_bits(&backbuffer, &video_src, &dst_wnd, &src_wnd, alpha, 0, col_key, ctx->col_mat); + gf_stretch_bits(&backbuffer, &video_src, &dst_wnd, &src_wnd, alpha, GF_FALSE, tr_state->col_key, ctx->col_mat); #ifndef GPAC_DISABLE_LOG log_blit_times(txh, push_time); #endif @@ -985,32 +1082,32 @@ static Bool compositor_2d_draw_bitmap_ex(GF_VisualManager *visual, GF_TextureHan -Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key) +Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx) { u8 alpha = 0xFF; - if (!ctx->aspect.fill_texture) return 1; - /*check if texture is ready*/ - if (!ctx->aspect.fill_texture->data) return 0; - if (ctx->transform.m[0]<0) return 0; + if (!ctx->aspect.fill_texture) return GF_TRUE; + /*check if texture is ready - if not pretend we drew it*/ + if (!ctx->aspect.fill_texture->data) return GF_TRUE; + if (ctx->transform.m[0]<0) return GF_FALSE; /*check if the <0 value is due to a flip in he scene description or due to bifs<->svg... context switching*/ if (ctx->transform.m[4]<0) { - if (!(ctx->flags & CTX_FLIPED_COORDS)) return 0; + if (!(ctx->flags & CTX_FLIPED_COORDS)) return GF_FALSE; } else { - if (ctx->flags & CTX_FLIPED_COORDS) return 0; + if (ctx->flags & CTX_FLIPED_COORDS) return GF_FALSE; } - if (ctx->transform.m[1] || ctx->transform.m[3]) return 0; + if (ctx->transform.m[1] || ctx->transform.m[3]) return GF_FALSE; #ifndef GPAC_DISABLE_VRML if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform) - return 0; + return GF_FALSE; #endif alpha = GF_COL_A(ctx->aspect.fill_color); /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/ if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color); - if (!alpha) return 1; + if (!alpha) return GF_TRUE; switch (ctx->aspect.fill_texture->pixelformat) { case GF_PIXEL_ALPHAGREY: @@ -1051,7 +1148,7 @@ Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_st /*direct drawing, no clippers */ if (tr_state->immediate_draw) { if (visual->compositor->video_out->BlitTexture) { - if (! visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, col_key + if (! visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, tr_state->col_key #ifdef GF_SR_USE_DEPTH , ctx->depth_offset, ctx->depth_gain #else @@ -1060,7 +1157,7 @@ Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_st )) return GF_FALSE; } else { - if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &ctx->bi->clip, &ctx->bi->unclip, alpha, col_key, tr_state, 0)) + if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &ctx->bi->clip, &ctx->bi->unclip, alpha, tr_state, GF_FALSE)) return GF_FALSE; } } @@ -1077,29 +1174,29 @@ Bool compositor_2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_st gf_irect_intersect(&clip, &tr_state->visual->to_redraw.list[i].rect); if (clip.width && clip.height) { if (visual->compositor->video_out->BlitTexture) { - if (!visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, col_key + if (!visual->compositor->video_out->BlitTexture(visual->compositor->video_out, ctx->aspect.fill_texture, &ctx->transform, &ctx->bi->clip, alpha, tr_state->col_key #ifdef GF_SR_USE_DEPTH , ctx->depth_offset, ctx->depth_gain #else , 0, 0 #endif )) - return 0; - } else if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &clip, &ctx->bi->unclip, alpha, col_key, tr_state, 0)) { - return 0; + return GF_FALSE; + } else if (!compositor_2d_draw_bitmap_ex(visual, ctx->aspect.fill_texture, ctx, &clip, &ctx->bi->unclip, alpha, tr_state, GF_FALSE)) { + return GF_FALSE; } } } } ctx->aspect.fill_texture->flags |= GF_SR_TEXTURE_USED; - return 1; + return GF_TRUE; } GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor) { u32 old_vp_width, old_vp_height; - Bool changed = 0; + Bool changed = GF_FALSE; Double ratio; GF_Event evt; GF_Err e; @@ -1114,7 +1211,7 @@ GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor) old_vp_height = compositor->vp_height; /*force complete clean*/ - compositor->traverse_state->invalidate_all = 1; + compositor->traverse_state->invalidate_all = GF_TRUE; if (!compositor->has_size_info && !(compositor->override_size_flags & 2) ) { compositor->output_width = compositor->display_width; @@ -1201,30 +1298,30 @@ GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor) evt.setup.height = compositor->vp_height; evt.setup.opengl_mode = 0; /*copy over settings*/ - evt.setup.system_memory = compositor->video_memory ? 0 : 1; - if (compositor->request_video_memory) evt.setup.system_memory = 0; - compositor->request_video_memory = 0; + evt.setup.system_memory = compositor->video_memory ? GF_FALSE : GF_TRUE; + if (compositor->request_video_memory) evt.setup.system_memory = GF_FALSE; + compositor->request_video_memory = GF_FALSE; #ifdef OPENGL_RASTER if (compositor->opengl_raster) { evt.setup.opengl_mode = 1; - evt.setup.system_memory = 0; - evt.setup.back_buffer = 1; + evt.setup.system_memory = GF_FALSE; + evt.setup.back_buffer = GF_TRUE; } #endif #ifndef GPAC_DISABLE_3D if (compositor->hybrid_opengl) { evt.setup.opengl_mode = 1; - evt.setup.system_memory = 0; - evt.setup.back_buffer = 1; + evt.setup.system_memory = GF_FALSE; + evt.setup.back_buffer = GF_TRUE; } #endif - if (compositor->was_system_memory != evt.setup.system_memory) changed = 1; - else if (old_vp_width != compositor->vp_width) changed=1; - else if (old_vp_height != compositor->vp_height) changed=1; - else if (compositor->is_opengl != evt.setup.opengl_mode) changed=1; + if (compositor->was_system_memory != evt.setup.system_memory) changed = GF_TRUE; + else if (old_vp_width != compositor->vp_width) changed = GF_TRUE; + else if (old_vp_height != compositor->vp_height) changed = GF_TRUE; + else if (compositor->is_opengl != evt.setup.opengl_mode) changed = GF_TRUE; if (changed) { @@ -1236,7 +1333,7 @@ GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor) if (e) { #ifndef GPAC_DISABLE_3D if (!compositor->hybrid_opengl) { - compositor->hybrid_opengl=1; + compositor->hybrid_opengl = GF_TRUE; GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Failed to configure 2D output (%s) - retrying in OpenGL mode\n", gf_error_to_string(e) )); return compositor_2d_set_aspect_ratio(compositor); } @@ -1260,7 +1357,8 @@ GF_Err compositor_2d_set_aspect_ratio(GF_Compositor *compositor) compositor->traverse_state->vp_size.x = INT2FIX(compositor->output_width); compositor->traverse_state->vp_size.y = INT2FIX(compositor->output_height); } - + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Reconfigured display size %d x %d done\n", evt.setup.width, evt.setup.height)); + /*set scale factor*/ compositor_set_ar_scale(compositor, scaleX, scaleY); return GF_OK; @@ -1323,7 +1421,7 @@ void compositor_2d_set_user_transform(GF_Compositor *compositor, Fixed zoom, Fix Fixed ratio; Fixed old_tx, old_ty, old_z; - gf_sc_lock(compositor, 1); + gf_sc_lock(compositor, GF_TRUE); old_tx = tx; old_ty = ty; old_z = compositor->zoom; @@ -1337,7 +1435,7 @@ void compositor_2d_set_user_transform(GF_Compositor *compositor, Fixed zoom, Fix compositor->trans_x = gf_mulfix(compositor->trans_x, ratio); compositor->trans_y = gf_mulfix(compositor->trans_y, ratio); compositor->zoom = zoom; - compositor->zoom_changed = 1; + compositor->zoom_changed = GF_TRUE; /*recenter visual*/ if (!compositor->visual->center_coords) { @@ -1377,12 +1475,12 @@ void compositor_2d_set_user_transform(GF_Compositor *compositor, Fixed zoom, Fix gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); - compositor->traverse_state->invalidate_all = 1; + compositor->traverse_state->invalidate_all = GF_TRUE; /*for zoom&pan, send the event right away. For resize/scroll, wait for the frame to be drawn before sending it otherwise viewport info of SVG nodes won't be correct*/ - if (!is_resize) compositor_send_resize_event(compositor, NULL, old_z, old_tx, old_ty, 0); - gf_sc_lock(compositor, 0); + if (!is_resize) compositor_send_resize_event(compositor, NULL, old_z, old_tx, old_ty, GF_FALSE); + gf_sc_lock(compositor, GF_FALSE); } @@ -1434,7 +1532,7 @@ GF_Rect compositor_2d_update_clipper(GF_TraverseState *tr_state, GF_Rect this_cl } if (for_layer) { tr_state->layer_clipper = clip; - tr_state->has_layer_clip = 1; + tr_state->has_layer_clip = GF_TRUE; #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_mx_copy(tr_state->layer_matrix, tr_state->model_matrix); @@ -1454,7 +1552,7 @@ GF_Rect compositor_2d_update_clipper(GF_TraverseState *tr_state, GF_Rect this_cl gf_mx2d_apply_rect(&tr_state->transform, &tr_state->clipper); - tr_state->has_clip = 1; + tr_state->has_clip = GF_TRUE; } return clip; } @@ -1466,7 +1564,7 @@ Bool visual_2d_overlaps_overlay(GF_VisualManager *visual, DrawableContext *ctx, u32 res = 0; GF_OverlayStack *ol; GF_Compositor *compositor = visual->compositor; - if (compositor->visual != visual) return 0; + if (compositor->visual != visual) return GF_FALSE; ol = visual->overlays; while (ol) { @@ -1499,7 +1597,7 @@ Bool visual_2d_overlaps_overlay(GF_VisualManager *visual, DrawableContext *ctx, ra_union_rect(&ol->ra, &clip); ol = ol->next; } - return res ? 1 : 0; + return res ? GF_TRUE : GF_FALSE; } void visual_2d_flush_overlay_areas(GF_VisualManager *visual, GF_TraverseState *tr_state) @@ -1514,7 +1612,7 @@ void visual_2d_flush_overlay_areas(GF_VisualManager *visual, GF_TraverseState *t ol = visual->overlays; while (ol) { u32 i; - Bool needs_draw = 1; + Bool needs_draw = GF_TRUE; GF_IRect the_clip, vid_clip; ra_refresh(&ol->ra); @@ -1533,9 +1631,9 @@ void visual_2d_flush_overlay_areas(GF_VisualManager *visual, GF_TraverseState *t if ((ctx->flags & CTX_IS_TRANSPARENT) || !gf_irect_inside(&prev_clip, &the_clip)) { vid_clip = ol->ra.list[i].rect; gf_irect_intersect(&vid_clip, &ol->ctx->bi->clip); - compositor_2d_draw_bitmap_ex(visual, ol->ctx->aspect.fill_texture, ol->ctx, &vid_clip, &ol->ctx->bi->unclip, 0xFF, NULL, tr_state, 1); + compositor_2d_draw_bitmap_ex(visual, ol->ctx->aspect.fill_texture, ol->ctx, &vid_clip, &ol->ctx->bi->unclip, 0xFF, tr_state, GF_TRUE); } - needs_draw = 0; + needs_draw = GF_FALSE; } gf_irect_intersect(&ctx->bi->clip, &the_clip); tr_state->ctx = ctx; diff --git a/src/compositor/drawable.c b/src/compositor/drawable.c index 23bf49d..fe801d2 100644 --- a/src/compositor/drawable.c +++ b/src/compositor/drawable.c @@ -645,64 +645,11 @@ static Bool check_transparent_skip(DrawableContext *ctx, Bool skipFill) } -#ifndef GPAC_DISABLE_VRML - -DrawableContext *drawable_init_context_mpeg4(Drawable *drawable, GF_TraverseState *tr_state) +static void check_texture_dirty(DrawableContext *ctx, Drawable *drawable, GF_TraverseState *tr_state) { - DrawableContext *ctx; - Bool skipFill; - GF_Node *appear; #ifndef GPAC_DISABLE_3D Bool texture_ready=0; #endif - assert(tr_state->visual); - - /*switched-off geometry nodes are not drawn*/ - if (tr_state->switched_off) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Drawable is switched off - skipping\n")); - return NULL; - } - - //Get a empty context from the current visual - ctx = visual_2d_get_drawable_context(tr_state->visual); - if (!ctx) return NULL; - - ctx->drawable = drawable; - - appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear; - - /*usually set by colorTransform or changes in OrderedGroup*/ - if (tr_state->invalidate_all) - ctx->flags |= CTX_APP_DIRTY; - - ctx->aspect.fill_texture = NULL; - if (appear) { - ctx->appear = appear; - if (gf_node_dirty_get(appear)) - ctx->flags |= CTX_APP_DIRTY; - } - /*todo cliper*/ - - /*FIXME - only needed for texture*/ - if (!tr_state->color_mat.identity) { - GF_SAFEALLOC(ctx->col_mat, GF_ColorMatrix); - gf_cmx_copy(ctx->col_mat, &tr_state->color_mat); - } - - /*IndexedLineSet2D and PointSet2D ignores fill flag and texturing*/ - skipFill = 0; - ctx->aspect.fill_texture = NULL; - switch (gf_node_get_tag(ctx->drawable->node) ) { -#ifndef GPAC_DISABLE_VRML - case TAG_MPEG4_IndexedLineSet2D: - skipFill = 1; - break; -#endif - default: - break; - } - - ctx->flags |= drawable_get_aspect_2d_mpeg4(drawable->node, &ctx->aspect, tr_state); /*Update texture info - draw even if texture not created (this may happen if the media is removed)*/ if (ctx->aspect.fill_texture) { @@ -751,12 +698,71 @@ DrawableContext *drawable_init_context_mpeg4(Drawable *drawable, GF_TraverseStat } #endif } - + #ifndef GPAC_DISABLE_3D //from now on, we won't clear the canvas when updating this texture (unless transparent, cf above) if (texture_ready) drawable->flags |= DRAWABLE_HYBGL_INIT; #endif +} + +#ifndef GPAC_DISABLE_VRML + +DrawableContext *drawable_init_context_mpeg4(Drawable *drawable, GF_TraverseState *tr_state) +{ + DrawableContext *ctx; + Bool skipFill; + GF_Node *appear; + assert(tr_state->visual); + + /*switched-off geometry nodes are not drawn*/ + if (tr_state->switched_off) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Drawable is switched off - skipping\n")); + return NULL; + } + + //Get a empty context from the current visual + ctx = visual_2d_get_drawable_context(tr_state->visual); + if (!ctx) return NULL; + + ctx->drawable = drawable; + + appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear; + + /*usually set by colorTransform or changes in OrderedGroup*/ + if (tr_state->invalidate_all) + ctx->flags |= CTX_APP_DIRTY; + + ctx->aspect.fill_texture = NULL; + if (appear) { + ctx->appear = appear; + if (gf_node_dirty_get(appear)) + ctx->flags |= CTX_APP_DIRTY; + } + /*todo cliper*/ + + /*FIXME - only needed for texture*/ + if (!tr_state->color_mat.identity) { + GF_SAFEALLOC(ctx->col_mat, GF_ColorMatrix); + gf_cmx_copy(ctx->col_mat, &tr_state->color_mat); + } + + /*IndexedLineSet2D and PointSet2D ignores fill flag and texturing*/ + skipFill = 0; + ctx->aspect.fill_texture = NULL; + switch (gf_node_get_tag(ctx->drawable->node) ) { +#ifndef GPAC_DISABLE_VRML + case TAG_MPEG4_IndexedLineSet2D: + skipFill = 1; + break; +#endif + default: + break; + } + + ctx->flags |= drawable_get_aspect_2d_mpeg4(drawable->node, &ctx->aspect, tr_state); + + check_texture_dirty(ctx, drawable, tr_state); /*not clear in the spec: what happens when a transparent node is in form/layout ?? this may completely break layout of children. We consider the node should be drawn*/ @@ -963,6 +969,8 @@ void drawable_check_focus_highlight(GF_Node *node, GF_TraverseState *tr_state, G GF_Matrix2D cur; GF_Compositor *compositor = tr_state->visual->compositor; + if (compositor->disable_focus_highlight) return; + if (compositor->focus_node!=node) return; /*if key navigator, don't draw a focus highlight*/ if (compositor->keynav_node) return; @@ -1448,10 +1456,12 @@ DrawableContext *drawable_init_context_svg(Drawable *drawable, GF_TraverseState DrawableContext *ctx; assert(tr_state->visual); +#ifndef GPAC_DISABLE_VRML /*setup SVG based on override appearance node */ if (tr_state->override_appearance) { return drawable_init_context_mpeg4(drawable, tr_state); } +#endif /*switched-off geometry nodes are not drawn*/ if (tr_state->switched_off) return NULL; @@ -1508,9 +1518,7 @@ DrawableContext *drawable_init_context_svg(Drawable *drawable, GF_TraverseState } } - /*Update texture info - draw even if texture not created (this may happen if the media is removed)*/ - if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->needs_refresh) - ctx->flags |= CTX_TEXTURE_DIRTY; + check_texture_dirty(ctx, drawable, tr_state); /*we are drawing on a centered coord surface, remember to flip the texture*/ if (tr_state->fliped_coords) diff --git a/src/compositor/events.c b/src/compositor/events.c index 7b16c47..e6f0840 100644 --- a/src/compositor/events.c +++ b/src/compositor/events.c @@ -249,132 +249,132 @@ static Bool load_text_node(GF_Compositor *compositor, u32 cmd_type) } else #endif /*GPAC_DISABLE_VRML*/ - if (compositor->focus_node) { + if (compositor->focus_node) { #ifndef GPAC_DISABLE_SVG - GF_ChildNodeItem *child = ((GF_ParentNode *) compositor->focus_node)->children; + GF_ChildNodeItem *child = ((GF_ParentNode *) compositor->focus_node)->children; + + while (child) { + switch (gf_node_get_tag(child->node)) { + case TAG_DOMText: + break; + default: + child = child->next; + continue; + } + compositor->dom_text_pos++; + if (!cmd_type) res = &((GF_DOMText *)child->node)->textContent; + else if (pos==compositor->dom_text_pos) { + if (append) { + u16 end; + const u16 *srcp; + size_t len; + GF_DOMText *cur, *ntext; + GF_ChildNodeItem *children = ((GF_ParentNode *) compositor->focus_node)->children; + GF_Node *t = gf_node_new(gf_node_get_graph(child->node), TAG_SVG_tbreak); - while (child) { - switch (gf_node_get_tag(child->node)) { - case TAG_DOMText: - break; - default: - child = child->next; - continue; - } - compositor->dom_text_pos++; - if (!cmd_type) res = &((GF_DOMText *)child->node)->textContent; - else if (pos==compositor->dom_text_pos) { - if (append) { - u16 end; - const u16 *srcp; - size_t len; - GF_DOMText *cur, *ntext; - GF_ChildNodeItem *children = ((GF_ParentNode *) compositor->focus_node)->children; - GF_Node *t = gf_node_new(gf_node_get_graph(child->node), TAG_SVG_tbreak); - - gf_node_init(t); - gf_node_register(t, compositor->focus_node); - - pos = gf_node_list_find_child(children, child->node); - - /*we're only inserting a tbreak*/ - if (!compositor->caret_pos) { - gf_node_list_insert_child(&children, t, pos); - res = &((GF_DOMText *)child->node)->textContent; - } else { - gf_node_list_insert_child(&children, t, pos+1); - ntext = (GF_DOMText*) gf_node_new(gf_node_get_graph(child->node), TAG_DOMText); gf_node_init(t); - gf_node_list_insert_child(&children, (GF_Node *)ntext, pos+2); - gf_node_register((GF_Node*)ntext, compositor->focus_node); - - cur = (GF_DOMText*) child->node; - - gf_free(cur->textContent); - end = compositor->sel_buffer[compositor->caret_pos]; - compositor->sel_buffer[compositor->caret_pos] = 0; - len = gf_utf8_wcslen(compositor->sel_buffer); - cur->textContent = gf_malloc(sizeof(char)*(len+1)); - srcp = compositor->sel_buffer; - len = gf_utf8_wcstombs(cur->textContent, len, &srcp); - cur->textContent[len] = 0; - compositor->sel_buffer[compositor->caret_pos] = end; - - if (compositor->caret_pos+1<compositor->sel_buffer_len) { - len = gf_utf8_wcslen(compositor->sel_buffer + compositor->caret_pos + 1); - ntext->textContent = gf_malloc(sizeof(char)*(len+1)); - srcp = compositor->sel_buffer + compositor->caret_pos + 1; - len = gf_utf8_wcstombs(ntext->textContent, len, &srcp); - ntext->textContent[len] = 0; + gf_node_register(t, compositor->focus_node); + + pos = gf_node_list_find_child(children, child->node); + + /*we're only inserting a tbreak*/ + if (!compositor->caret_pos) { + gf_node_list_insert_child(&children, t, pos); + res = &((GF_DOMText *)child->node)->textContent; } else { - ntext->textContent = gf_strdup(""); + gf_node_list_insert_child(&children, t, pos+1); + ntext = (GF_DOMText*) gf_node_new(gf_node_get_graph(child->node), TAG_DOMText); + gf_node_init(t); + gf_node_list_insert_child(&children, (GF_Node *)ntext, pos+2); + gf_node_register((GF_Node*)ntext, compositor->focus_node); + + cur = (GF_DOMText*) child->node; + + gf_free(cur->textContent); + end = compositor->sel_buffer[compositor->caret_pos]; + compositor->sel_buffer[compositor->caret_pos] = 0; + len = gf_utf8_wcslen(compositor->sel_buffer); + cur->textContent = gf_malloc(sizeof(char)*(len+1)); + srcp = compositor->sel_buffer; + len = gf_utf8_wcstombs(cur->textContent, len, &srcp); + cur->textContent[len] = 0; + compositor->sel_buffer[compositor->caret_pos] = end; + + if (compositor->caret_pos+1<compositor->sel_buffer_len) { + len = gf_utf8_wcslen(compositor->sel_buffer + compositor->caret_pos + 1); + ntext->textContent = gf_malloc(sizeof(char)*(len+1)); + srcp = compositor->sel_buffer + compositor->caret_pos + 1; + len = gf_utf8_wcstombs(ntext->textContent, len, &srcp); + ntext->textContent[len] = 0; + } else { + ntext->textContent = gf_strdup(""); + } + res = &ntext->textContent; + compositor->dom_text_pos ++; + compositor->edited_text = NULL; } - res = &ntext->textContent; - compositor->dom_text_pos ++; - compositor->edited_text = NULL; - } - } else { - if (delete_cr && child->next) { - GF_Node *tbreak = child->next->node; - GF_ChildNodeItem *children = ((GF_ParentNode *) compositor->focus_node)->children; - gf_node_list_del_child(&children, tbreak); - gf_node_unregister(tbreak, compositor->focus_node); - if (child->next && (gf_node_get_tag(child->next->node)==TAG_DOMText) ) { - GF_DOMText *n1 = (GF_DOMText *)child->node; - GF_DOMText *n2 = (GF_DOMText *)child->next->node; - - if (compositor->edited_text) { - flush_text_node_edit(compositor, 1); - } - if (!n1->textContent) n1->textContent = gf_strdup(""); - caret_pos = (u32) strlen(n1->textContent); - if (n2->textContent) { - n1->textContent = gf_realloc(n1->textContent, sizeof(char)*(strlen(n1->textContent)+strlen(n2->textContent)+1)); - strcat(n1->textContent, n2->textContent); + } else { + if (delete_cr && child->next) { + GF_Node *tbreak = child->next->node; + GF_ChildNodeItem *children = ((GF_ParentNode *) compositor->focus_node)->children; + gf_node_list_del_child(&children, tbreak); + gf_node_unregister(tbreak, compositor->focus_node); + if (child->next && (gf_node_get_tag(child->next->node)==TAG_DOMText) ) { + GF_DOMText *n1 = (GF_DOMText *)child->node; + GF_DOMText *n2 = (GF_DOMText *)child->next->node; + + if (compositor->edited_text) { + flush_text_node_edit(compositor, 1); + } + if (!n1->textContent) n1->textContent = gf_strdup(""); + caret_pos = (u32) strlen(n1->textContent); + if (n2->textContent) { + n1->textContent = gf_realloc(n1->textContent, sizeof(char)*(strlen(n1->textContent)+strlen(n2->textContent)+1)); + strcat(n1->textContent, n2->textContent); + } + gf_node_list_del_child(&children, (GF_Node*)n2); + gf_node_unregister((GF_Node*)n2, compositor->focus_node); + compositor->edited_text = NULL; } - gf_node_list_del_child(&children, (GF_Node*)n2); - gf_node_unregister((GF_Node*)n2, compositor->focus_node); - compositor->edited_text = NULL; } + res = &((GF_DOMText *)child->node)->textContent; } - res = &((GF_DOMText *)child->node)->textContent; - } - /* if (1) { - GF_ChildNodeItem *child = ((GF_ParentNode *) compositor->focus_node)->children; - fprintf(stderr, "Dumping text tree:\n"); - while (child) { - switch (gf_node_get_tag(child->node)) { - case TAG_SVG_tbreak: fprintf(stderr, "\ttbreak\n"); break; - case TAG_DOMText: fprintf(stderr, "\ttext: %s\n", ((GF_DOMText *)child->node)->textContent); break; + /* if (1) { + GF_ChildNodeItem *child = ((GF_ParentNode *) compositor->focus_node)->children; + fprintf(stderr, "Dumping text tree:\n"); + while (child) { + switch (gf_node_get_tag(child->node)) { + case TAG_SVG_tbreak: fprintf(stderr, "\ttbreak\n"); break; + case TAG_DOMText: fprintf(stderr, "\ttext: %s\n", ((GF_DOMText *)child->node)->textContent); break; + } + child = child->next; } - child = child->next; } - } - */ - break; + */ + break; + } + child = child->next; + continue; + } + /*load of an empty text*/ + if (!res && !cmd_type) { + GF_DOMText *t = gf_dom_add_text_node(compositor->focus_node, gf_strdup("")); + res = &t->textContent; } - child = child->next; - continue; - } - /*load of an empty text*/ - if (!res && !cmd_type) { - GF_DOMText *t = gf_dom_add_text_node(compositor->focus_node, gf_strdup("")); - res = &t->textContent; - } - if (!res) { - compositor->dom_text_pos = prev_pos; - return 0; - } + if (!res) { + compositor->dom_text_pos = prev_pos; + return 0; + } #endif - } + } if (compositor->edited_text) { flush_text_node_edit(compositor, 1); } - if (res && *res) { + if (res && *res && strlen(*res) ) { const char *src = *res; compositor->sel_buffer_alloc = 2 + (u32) strlen(src); compositor->sel_buffer = gf_realloc(compositor->sel_buffer, sizeof(u16)*compositor->sel_buffer_alloc); @@ -416,13 +416,12 @@ static void exec_text_input(GF_Compositor *compositor, GF_Event *event) load_text_node(compositor, 0); return; } else if (event->type==GF_EVENT_TEXTINPUT) { - switch (event->character.unicode_char) { - case '\r': - case '\n': - case '\t': - case '\b': + u32 unicode_char = event->character.unicode_char; + //filter all non-text symbols + if (unicode_char <= 31) { return; - default: + } + { #ifndef GPAC_DISABLE_SVG GF_DOM_Event evt; @@ -433,7 +432,7 @@ static void exec_text_input(GF_Compositor *compositor, GF_Event *event) evt.bubbles = 1; evt.cancelable = 1; evt.type = event->type; - evt.detail = event->character.unicode_char; + evt.detail = unicode_char; target = compositor->focus_node; if (!target) target = gf_sg_get_root_node(compositor->scene); gf_dom_event_fire(target, &evt); @@ -445,13 +444,11 @@ static void exec_text_input(GF_Compositor *compositor, GF_Event *event) compositor->sel_buffer = gf_realloc(compositor->sel_buffer, sizeof(u16)*compositor->sel_buffer_alloc); } memmove(&compositor->sel_buffer[compositor->caret_pos+1], &compositor->sel_buffer[compositor->caret_pos], sizeof(u16)*(compositor->sel_buffer_len-compositor->caret_pos)); - compositor->sel_buffer[compositor->caret_pos] = event->character.unicode_char; + compositor->sel_buffer[compositor->caret_pos] = unicode_char; compositor->sel_buffer_len++; compositor->caret_pos++; compositor->sel_buffer[compositor->sel_buffer_len] = 0; #endif - break; - } } } else if (event->type==GF_EVENT_KEYDOWN) { u32 prev_caret = compositor->caret_pos; @@ -544,11 +541,17 @@ static void exec_text_input(GF_Compositor *compositor, GF_Event *event) flush_text_node_edit(compositor, is_end); } -static void fireTermEvent(GF_Compositor * compositor, u32 eventType) { +static void toggle_keyboard(GF_Compositor * compositor, Bool do_show) +{ + GF_Event evt; + memset(&evt, 0, sizeof(GF_Event)); + evt.type = do_show ? GF_EVENT_TEXT_EDITING_START : GF_EVENT_TEXT_EDITING_END; + + if (compositor->video_out) { + GF_Err e = compositor->video_out->ProcessEvent(compositor->video_out, &evt); + if (e == GF_OK) return; + } if (compositor->term) { - GF_Event evt; - memset(&evt, 0, sizeof(GF_Event)); - evt.type = eventType; gf_term_user_event(compositor->term, &evt); } } @@ -561,7 +564,7 @@ static Bool hit_node_editable(GF_Compositor *compositor, Bool check_focus_node) u32 tag; GF_Node *text = check_focus_node ? compositor->focus_node : compositor->hit_node; if (!text) { - fireTermEvent(compositor, GF_EVENT_TEXT_EDITING_END); + toggle_keyboard(compositor, GF_FALSE); return 0; } if (compositor->hit_node==compositor->focus_node) return compositor->focus_text_type ? 1 : 0; @@ -569,11 +572,12 @@ static Bool hit_node_editable(GF_Compositor *compositor, Bool check_focus_node) tag = gf_node_get_tag(text); #ifndef GPAC_DISABLE_VRML - if ( (tag==TAG_MPEG4_Text) + switch (tag) { + case TAG_MPEG4_Text: #ifndef GPAC_DISABLE_X3D - || (tag==TAG_X3D_Text) + case TAG_X3D_Text: #endif - ) { + { M_FontStyle *fs = (M_FontStyle *) ((M_Text *)text)->fontStyle; if (!fs || !fs->style.buffer) return 0; if (strstr(fs->style.buffer, "editable") || strstr(fs->style.buffer, "EDITABLE")) { @@ -581,12 +585,15 @@ static Bool hit_node_editable(GF_Compositor *compositor, Bool check_focus_node) } else if (strstr(fs->style.buffer, "simple_edit") || strstr(fs->style.buffer, "SIMPLE_EDIT")) { compositor->focus_text_type = 4; } else { - fireTermEvent(compositor, GF_EVENT_TEXT_EDITING_END); + toggle_keyboard(compositor, GF_FALSE); return 0; } compositor->focus_node = text; - fireTermEvent(compositor, compositor->focus_text_type > 2 ? GF_EVENT_TEXT_EDITING_START : GF_EVENT_TEXT_EDITING_END); + toggle_keyboard(compositor, compositor->focus_text_type > 2 ? GF_TRUE : GF_FALSE); return 1; + } + default: + break; } #endif /*GPAC_DISABLE_VRML*/ if (tag <= GF_NODE_FIRST_DOM_NODE_TAG) return 0; @@ -617,7 +624,7 @@ static Bool hit_node_editable(GF_Compositor *compositor, Bool check_focus_node) compositor->focus_uses_dom_events = 1; } compositor->hit_node = NULL; - fireTermEvent(compositor, compositor->focus_text_type > 0 ? GF_EVENT_TEXT_EDITING_START : GF_EVENT_TEXT_EDITING_END); + toggle_keyboard(compositor, compositor->focus_text_type > 0 ? GF_TRUE : GF_FALSE); #endif return 1; } @@ -899,22 +906,25 @@ Bool gf_sc_exec_event_vrml(GF_Compositor *compositor, GF_Event *ev) stype = GF_CURSOR_NORMAL; for (i=0; i<count; i++) { GF_Node *keynav; + Bool check_anchor=0; hs = (GF_SensorHandler*)gf_list_get(compositor->sensors, i); /*try to remove this sensor from the previous sensor list*/ gf_list_del_item(compositor->previous_sensors, hs); - stype = gf_node_get_tag(hs->sensor); + if (gf_node_get_id(hs->sensor)) + stype = gf_node_get_tag(hs->sensor); + keynav = gf_scene_get_keynav(gf_node_get_graph(hs->sensor), hs->sensor); if (keynav) gf_sc_change_key_navigator(compositor, keynav); /*call the sensor LAST, as this may triger a destroy of the scene the sensor is in this is only true for anchors, as other other sensors output events are queued as routes untill next pass*/ res += hs->OnUserEvent(hs, 1, 0, ev, compositor); - if ((stype == TAG_MPEG4_Anchor) + if (stype == TAG_MPEG4_Anchor) check_anchor=1; #ifndef GPAC_DISABLE_X3D - || (stype == TAG_X3D_Anchor) + else if (stype == TAG_X3D_Anchor) check_anchor=1; #endif - ) { + if (check_anchor) { /*subscene with active sensor has been deleted, we cannot continue process the sensors stack*/ if (count != gf_list_count(compositor->sensors)) break; diff --git a/src/compositor/gl_inc.h b/src/compositor/gl_inc.h index 3371f75..d687bcc 100644 --- a/src/compositor/gl_inc.h +++ b/src/compositor/gl_inc.h @@ -33,10 +33,10 @@ #ifndef GPAC_DISABLE_3D #include <gpac/internal/compositor_dev.h> -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #ifndef GPAC_FIXED_POINT -#error "OpenGL ES defined without fixed-point support - unsupported." +//#error "OpenGL ES defined without fixed-point support - unsupported." #endif #ifdef GPAC_ANDROID @@ -105,7 +105,7 @@ extern proc_ ## funname funname; \ #if defined GPAC_USE_TINYGL //no extensions with TinyGL -#elif defined (GPAC_USE_OGL_ES) +#elif defined (GPAC_USE_GLES1X) //no extensions with OpenGL ES #elif defined(WIN32) || defined (GPAC_CONFIG_WIN32) #define LOAD_GL_FUNCS @@ -120,7 +120,7 @@ extern void (*glXGetProcAddress(const GLubyte *procname))( void ); #endif -#if !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_GLES1X) /*redefine all ext needed*/ @@ -471,11 +471,18 @@ GLDECL(void, glUniformMatrix4x2fv, (GLint location, GLsizei count, GLboolean tra GLDECL(void, glUniformMatrix3x4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) ) GLDECL(void, glUniformMatrix4x3fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) ) +#ifndef GPAC_ANDROID +GLDECL(void, glEnableVertexAttribArray, (GLuint index) ) +GLDECL(void, glDisableVertexAttribArray, (GLuint index) ) +GLDECL(void, glVertexAttribPointer, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer) ) +GLDECL(void, glVertexAttribIPointer, (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) ) +GLDECL(GLint, glGetAttribLocation, (GLuint prog, const char *name) ) +#endif #endif //GL_VERSION_2_0 -#endif //GPAC_USE_OGL_ES +#endif //GPAC_USE_GLES1X #endif /*GPAC_DISABLE_3D*/ diff --git a/src/compositor/hardcoded_protos.c b/src/compositor/hardcoded_protos.c index 72ab673..2bc8069 100644 --- a/src/compositor/hardcoded_protos.c +++ b/src/compositor/hardcoded_protos.c @@ -1051,6 +1051,94 @@ void compositor_init_style_group(GF_Compositor *compositor, GF_Node *node) } + +/*TestSensor: tests eventIn/eventOuts for hardcoded proto*/ +typedef struct +{ + BASE_NODE + + Bool onTrigger; + Fixed value; +} TestSensor; + +typedef struct +{ + TestSensor ts; +} TestSensorStack; + +static Bool TestSensor_GetNode(GF_Node *node, TestSensor *ts) +{ + GF_FieldInfo field; + memset(ts, 0, sizeof(TestSensor)); + ts->sgprivate = node->sgprivate; + + if (gf_node_get_field(node, 0, &field) != GF_OK) return 0; + if (field.fieldType != GF_SG_VRML_SFBOOL) return 0; + if (field.eventType != GF_SG_EVENT_IN) return 0; + ts->onTrigger = *(SFBool *)field.far_ptr; + + if (gf_node_get_field(node, 1, &field) != GF_OK) return 0; + if (field.fieldType != GF_SG_VRML_SFFLOAT) return 0; + if (field.eventType != GF_SG_EVENT_EXPOSED_FIELD) return 0; + ts->value = *(SFFloat *)field.far_ptr; + + if (gf_node_get_field(node, 2, &field) != GF_OK) return 0; + if (field.fieldType != GF_SG_VRML_SFFLOAT) return 0; + if (field.eventType != GF_SG_EVENT_OUT) return 0; + + return 1; +} + + +static void TraverseTestSensor(GF_Node *node, void *rs, Bool is_destroy) +{ + TestSensorStack *stack = (TestSensorStack *)gf_node_get_private(node); + + if (is_destroy) { + gf_free(stack); + return; + } +} + +void TestSensor_OnTrigger(GF_Node *node, struct _route *route) +{ + GF_FieldInfo field; + Fixed value; + TestSensorStack *stack = (TestSensorStack *)gf_node_get_private(node); + TestSensor_GetNode(node, &stack->ts); + + if (stack->ts.onTrigger) { + value = stack->ts.value; + } else { + value = 1-stack->ts.value; + } + + gf_node_get_field(node, 2, &field); + *(SFFloat*)field.far_ptr = value; + gf_node_event_out(node, 2); +} + +void compositor_init_test_sensor(GF_Compositor *compositor, GF_Node *node) +{ + TestSensor ts; + if (TestSensor_GetNode(node, &ts)) { + GF_Err e; + TestSensorStack *stack; + GF_SAFEALLOC(stack, TestSensorStack); + gf_node_set_private(node, stack); + gf_node_set_callback_function(node, TraverseTestSensor); + stack->ts = ts; + + e = gf_node_set_proto_eventin_handler(node, 0, TestSensor_OnTrigger); + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to initialize Proto TestSensor callback: %s\n", gf_error_to_string(e) )); + } + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unable to initialize test sensor\n")); + } +} + + /*hardcoded proto loading - this is mainly used for module development and testing...*/ void compositor_init_hardcoded_proto(GF_Compositor *compositor, GF_Node *node) { @@ -1111,6 +1199,10 @@ void compositor_init_hardcoded_proto(GF_Compositor *compositor, GF_Node *node) compositor_init_style_group(compositor, node); return; } + if (!strcmp(url, "urn:inet:gpac:builtin:TestSensor")) { + compositor_init_test_sensor(compositor, node); + return; + } /*check proto modules*/ if (compositor->proto_modules) { diff --git a/src/compositor/mesh.c b/src/compositor/mesh.c index 97ae443..d622311 100644 --- a/src/compositor/mesh.c +++ b/src/compositor/mesh.c @@ -604,7 +604,7 @@ void compute_sphere(Fixed radius, SFVec3f *coords, SFVec2f *texcoords, u32 num_s } } -#define SPHERE_SUBDIV 12 +#define SPHERE_SUBDIV 24 void mesh_new_sphere(GF_Mesh *mesh, Fixed radius, Bool low_res) { u32 i, j, num_steps, npts; diff --git a/src/compositor/mpeg4_audio.c b/src/compositor/mpeg4_audio.c index 72156bb..b709ba6 100644 --- a/src/compositor/mpeg4_audio.c +++ b/src/compositor/mpeg4_audio.c @@ -39,8 +39,8 @@ typedef struct static void audioclip_activate(AudioClipStack *st, M_AudioClip *ac) { - if (gf_sc_audio_open(&st->input, &ac->url, 0, -1, 0) != GF_OK) { - st->failure = 1; + if (gf_sc_audio_open(&st->input, &ac->url, 0, -1, GF_FALSE) != GF_OK) { + st->failure = GF_TRUE; return; } ac->isActive = 1; @@ -57,7 +57,7 @@ static void audioclip_deactivate(AudioClipStack *st, M_AudioClip *ac) ac->isActive = 0; gf_node_event_out((GF_Node *)ac, 7/*"isActive"*/); - st->time_handle.needs_unregister = 1; + st->time_handle.needs_unregister = GF_TRUE; } static void audioclip_traverse(GF_Node *node, void *rs, Bool is_destroy) @@ -91,7 +91,7 @@ static void audioclip_traverse(GF_Node *node, void *rs, Bool is_destroy) if (st->set_duration && st->input.stream) { ac->duration_changed = gf_mo_get_duration(st->input.stream); gf_node_event_out(node, 6/*"duration_changed"*/); - st->set_duration = 0; + st->set_duration = GF_FALSE; } /*store mute flag*/ @@ -102,14 +102,14 @@ static void audioclip_update_time(GF_TimeNode *tn) { Double time; M_AudioClip *ac = (M_AudioClip *)tn->udta; - AudioClipStack *st = (AudioClipStack *)gf_node_get_private(tn->udta); + AudioClipStack *st = (AudioClipStack *)gf_node_get_private((GF_Node*)tn->udta); if (st->failure) return; if (! ac->isActive) { st->start_time = ac->startTime; st->input.speed = ac->pitch; } - time = gf_node_get_scene_time(tn->udta); + time = gf_node_get_scene_time((GF_Node*)tn->udta); if ((time<st->start_time) || (st->start_time<0)) return; if (ac->isActive) { @@ -130,7 +130,7 @@ void compositor_init_audioclip(GF_Compositor *compositor, GF_Node *node) st->time_handle.UpdateTimeNode = audioclip_update_time; st->time_handle.udta = node; - st->set_duration = 1; + st->set_duration = GF_TRUE; gf_node_set_private(node, st); gf_node_set_callback_function(node, audioclip_traverse); @@ -144,13 +144,13 @@ void compositor_audioclip_modified(GF_Node *node) AudioClipStack *st = (AudioClipStack *) gf_node_get_private(node); if (!st) return; - st->failure = 0; + st->failure = GF_FALSE; /*MPEG4 spec is not clear about that , so this is not forbidden*/ if (st->input.is_open) { if (gf_sc_audio_check_url(&st->input, &ac->url)) { gf_sc_audio_stop(&st->input); - gf_sc_audio_open(&st->input, &ac->url, 0, -1, 0); + gf_sc_audio_open(&st->input, &ac->url, 0, -1, GF_FALSE); /*force unregister to resetup audio cfg*/ gf_sc_audio_unregister(&st->input); gf_sc_invalidate(st->input.compositor, NULL); @@ -168,7 +168,7 @@ void compositor_audioclip_modified(GF_Node *node) if (!st->time_handle.is_registered && !st->time_handle.needs_unregister) gf_sc_register_time_node(st->input.compositor, &st->time_handle); else - st->time_handle.needs_unregister = 0; + st->time_handle.needs_unregister = GF_FALSE; } @@ -182,9 +182,9 @@ typedef struct static void audiosource_activate(AudioSourceStack *st, M_AudioSource *as) { - if (gf_sc_audio_open(&st->input, &as->url, 0, -1, 0) != GF_OK) + if (gf_sc_audio_open(&st->input, &as->url, 0, -1, GF_FALSE) != GF_OK) return; - st->is_active = 1; + st->is_active = GF_TRUE; gf_mo_set_speed(st->input.stream, st->input.speed); /*traverse all graph to get parent audio group*/ gf_sc_invalidate(st->input.compositor, NULL); @@ -193,8 +193,8 @@ static void audiosource_activate(AudioSourceStack *st, M_AudioSource *as) static void audiosource_deactivate(AudioSourceStack *st, M_AudioSource *as) { gf_sc_audio_stop(&st->input); - st->is_active = 0; - st->time_handle.needs_unregister = 1; + st->is_active = GF_FALSE; + st->time_handle.needs_unregister = GF_TRUE; } static void audiosource_traverse(GF_Node *node, void *rs, Bool is_destroy) @@ -216,7 +216,7 @@ static void audiosource_traverse(GF_Node *node, void *rs, Bool is_destroy) /*check end of stream*/ if (st->input.stream && st->input.stream_finished) { - if (gf_mo_get_loop(st->input.stream, 0)) { + if (gf_mo_get_loop(st->input.stream, GF_FALSE)) { gf_sc_audio_restart(&st->input); } else if (st->is_active && gf_mo_should_deactivate(st->input.stream)) { /*deactivate*/ @@ -235,13 +235,13 @@ static void audiosource_update_time(GF_TimeNode *tn) { Double time; M_AudioSource *as = (M_AudioSource *)tn->udta; - AudioSourceStack *st = (AudioSourceStack *)gf_node_get_private(tn->udta); + AudioSourceStack *st = (AudioSourceStack *)gf_node_get_private((GF_Node*)tn->udta); if (! st->is_active) { st->start_time = as->startTime; st->input.speed = as->speed; } - time = gf_node_get_scene_time(tn->udta); + time = gf_node_get_scene_time((GF_Node*)tn->udta); if ((time<st->start_time) || (st->start_time<0)) return; if (st->input.input_ifce.GetSpeed(st->input.input_ifce.callback) && st->is_active) { @@ -282,7 +282,7 @@ void compositor_audiosource_modified(GF_Node *node) gf_sc_audio_unregister(&st->input); gf_sc_invalidate(st->input.compositor, NULL); - if (st->is_active) gf_sc_audio_open(&st->input, &as->url, 0, -1, 0); + if (st->is_active) gf_sc_audio_open(&st->input, &as->url, 0, -1, GF_FALSE); } //update state if we're active @@ -295,7 +295,7 @@ void compositor_audiosource_modified(GF_Node *node) if (!st->time_handle.is_registered && !st->time_handle.needs_unregister) gf_sc_register_time_node(st->input.compositor, &st->time_handle); else - st->time_handle.needs_unregister = 0; + st->time_handle.needs_unregister = GF_FALSE; } @@ -354,18 +354,18 @@ static void audiobuffer_traverse(GF_Node *node, void *rs, Bool is_destroy) l = l->next; } - gf_mixer_lock(st->am, 1); + gf_mixer_lock(st->am, GF_TRUE); /*if no new inputs don't change mixer config*/ - update_mixer = gf_list_count(st->new_inputs) ? 1 : 0; + update_mixer = gf_list_count(st->new_inputs) ? GF_TRUE : GF_FALSE; if (gf_mixer_get_src_count(st->am) == gf_list_count(st->new_inputs)) { u32 count = gf_list_count(st->new_inputs); - update_mixer = 0; + update_mixer = GF_FALSE; for (j=0; j<count; j++) { GF_AudioInput *cur = (GF_AudioInput *)gf_list_get(st->new_inputs, j); if (!gf_mixer_is_src_present(st->am, &cur->input_ifce)) { - update_mixer = 1; + update_mixer = GF_TRUE; break; } } @@ -382,7 +382,7 @@ static void audiobuffer_traverse(GF_Node *node, void *rs, Bool is_destroy) if (update_mixer) gf_mixer_add_input(st->am, &src->input_ifce); } - gf_mixer_lock(st->am, 0); + gf_mixer_lock(st->am, GF_FALSE); tr_state->audio_parent = parent; /*Note the audio buffer is ALWAYS registered untill destroyed since buffer filling shall happen even when inactive*/ @@ -401,7 +401,7 @@ static void audiobuffer_activate(AudioBufferStack *st, M_AudioBuffer *ab) gf_node_event_out((GF_Node *)ab, 17/*"isActive"*/); /*rerender all graph to get parent audio group*/ gf_sc_invalidate(st->output.compositor, NULL); - st->done = 0; + st->done = GF_FALSE; st->read_pos = 0; } @@ -409,19 +409,19 @@ static void audiobuffer_deactivate(AudioBufferStack *st, M_AudioBuffer *ab) { ab->isActive = 0; gf_node_event_out((GF_Node *)ab, 17/*"isActive"*/); - st->time_handle.needs_unregister = 1; + st->time_handle.needs_unregister = GF_TRUE; } static void audiobuffer_update_time(GF_TimeNode *tn) { Double time; M_AudioBuffer *ab = (M_AudioBuffer *)tn->udta; - AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private(tn->udta); + AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private((GF_Node*)tn->udta); if (! ab->isActive) { st->start_time = ab->startTime; } - time = gf_node_get_scene_time(tn->udta); + time = gf_node_get_scene_time((GF_Node*)tn->udta); if ((time<st->start_time) || (st->start_time<0)) return; if (ab->isActive) { @@ -449,7 +449,7 @@ static char *audiobuffer_fetch_frame(void *callback, u32 *size, u32 audio_delay_ if (!st->is_init) return NULL; if (!st->buffer) { - st->done = 0; + st->done = GF_FALSE; st->buffer_size = (u32) ceil(FIX2FLT(ab->length) * st->output.input_ifce.bps*st->output.input_ifce.samplerate*st->output.input_ifce.chan/8); blockAlign = gf_mixer_get_block_align(st->am); /*BLOCK ALIGN*/ @@ -492,7 +492,7 @@ static void audiobuffer_release_frame(void *callback, u32 nb_bytes) } else if ( ((M_AudioBuffer*)st->output.owner)->loop) { st->read_pos = 0; } else { - st->done = 1; + st->done = GF_TRUE; } } } @@ -511,7 +511,7 @@ static Bool audiobuffer_get_volume(void *callback, Fixed *vol) return ai->snd->GetChannelVolume(ai->snd->owner, vol); } else { vol[0] = vol[1] = vol[2] = vol[3] = vol[4] = vol[5] = FIX_ONE; - return 0; + return GF_FALSE; } } @@ -533,11 +533,11 @@ static Bool audiobuffer_get_config(GF_AudioInterface *aifc, Bool for_reconf) } gf_mixer_get_config(st->am, &aifc->samplerate, &aifc->chan, &aifc->bps, &aifc->ch_cfg); - st->is_init = (aifc->samplerate && aifc->chan && aifc->bps) ? 1 : 0; + st->is_init = (aifc->samplerate && aifc->chan && aifc->bps) ? GF_TRUE : GF_FALSE; assert(st->is_init); if (!st->is_init) aifc->samplerate = aifc->chan = aifc->bps = aifc->ch_cfg = 0; /*this will force invalidation*/ - return (for_reconf && st->is_init) ? 1 : 0; + return (for_reconf && st->is_init) ? GF_TRUE : GF_FALSE; } return st->is_init; } @@ -580,7 +580,7 @@ void compositor_init_audiobuffer(GF_Compositor *compositor, GF_Node *node) st->time_handle.UpdateTimeNode = audiobuffer_update_time; st->time_handle.udta = node; - st->set_duration = 1; + st->set_duration = GF_TRUE; st->am = gf_mixer_new(NULL); st->new_inputs = gf_list_new(); @@ -605,7 +605,7 @@ void compositor_audiobuffer_modified(GF_Node *node) if (!st->time_handle.is_registered && !st->time_handle.needs_unregister) gf_sc_register_time_node(st->output.compositor, &st->time_handle); else - st->time_handle.needs_unregister = 0; + st->time_handle.needs_unregister = GF_FALSE; } #endif /*GPAC_DISABLE_VRML*/ diff --git a/src/compositor/mpeg4_background2d.c b/src/compositor/mpeg4_background2d.c index b0ec705..359ecc3 100644 --- a/src/compositor/mpeg4_background2d.c +++ b/src/compositor/mpeg4_background2d.c @@ -104,6 +104,7 @@ static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state { Bool clear_all = GF_TRUE; u32 color; + Bool use_texture; Bool is_offscreen = GF_FALSE; Background2DStack *stack; if (!ctx || !ctx->drawable || !ctx->drawable->node) return; @@ -114,9 +115,19 @@ static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state stack->flags &= ~CTX_PATH_FILLED; color = ctx->aspect.fill_color; - if (back_use_texture((M_Background2D *)ctx->drawable->node)) { + use_texture = back_use_texture((M_Background2D *)ctx->drawable->node); + if (!use_texture && !tr_state->visual->is_attached) { + use_texture = 1; + stack->txh.data = stack->col_tx; + stack->txh.width = 2; + stack->txh.height = 2; + stack->txh.stride = 6; + stack->txh.pixelformat = GF_PIXEL_RGB_24; + } - if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL)) { + if (use_texture) { + + if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) { /*set target rect*/ gf_path_reset(stack->drawable->path); gf_path_add_rect_center(stack->drawable->path, @@ -146,7 +157,8 @@ static void DrawBackground2D_2D(DrawableContext *ctx, GF_TraverseState *tr_state if (ctx->flags & CTX_BACKROUND_NOT_LAYER) { color &= 0x00FFFFFF; compositor_2d_hybgl_clear_surface(tr_state->visual, NULL, color, GF_FALSE); - clear_all = GF_FALSE; + is_offscreen = GF_TRUE; + //we may need to clear the canvas for immediate mode } } #endif @@ -336,6 +348,8 @@ static void TraverseBackground2D(GF_Node *node, void *rs, Bool is_destroy) if (!status) return; if (gf_node_dirty_get(node)) { + u32 i; + stack->flags |= CTX_APP_DIRTY; gf_node_dirty_clear(node, 0); @@ -345,6 +359,11 @@ static void TraverseBackground2D(GF_Node *node, void *rs, Bool is_destroy) status->ctx.aspect.fill_color = col; stack->flags |= CTX_APP_DIRTY; } + for (i=0; i<4;i++) { + stack->col_tx[3*i] = FIX2INT(255 * bck->backColor.red); + stack->col_tx[3*i+1] = FIX2INT(255 * bck->backColor.green); + stack->col_tx[3*i+2] = FIX2INT(255 * bck->backColor.blue); + } } if (back_use_texture(bck) ) { @@ -358,7 +377,11 @@ static void TraverseBackground2D(GF_Node *node, void *rs, Bool is_destroy) stack->flags |= CTX_TEXTURE_DIRTY; } } - status->ctx.flags = stack->flags; + if (status->ctx.flags & CTX_BACKROUND_NOT_LAYER) { + status->ctx.flags = stack->flags | CTX_BACKROUND_NOT_LAYER; + } else { + status->ctx.flags = stack->flags; + } if (tr_state->traversing_mode != TRAVERSE_BINDABLE) return; diff --git a/src/compositor/mpeg4_bitmap.c b/src/compositor/mpeg4_bitmap.c index dc65c90..96f378d 100644 --- a/src/compositor/mpeg4_bitmap.c +++ b/src/compositor/mpeg4_bitmap.c @@ -129,7 +129,7 @@ static void draw_bitmap_3d(GF_Node *node, GF_TraverseState *tr_state) static void draw_bitmap_2d(GF_Node *node, GF_TraverseState *tr_state) { - GF_ColorKey *key, keyColor; + GF_ColorKey keyColor; DrawableContext *ctx = tr_state->ctx; BitmapStack *st = (BitmapStack *) gf_node_get_private(node); @@ -138,7 +138,6 @@ static void draw_bitmap_2d(GF_Node *node, GF_TraverseState *tr_state) ctx->transform.m[1] = ctx->transform.m[3] = 0; /*check for material key materialKey*/ - key = NULL; if (ctx->appear) { M_Appearance *app = (M_Appearance *)ctx->appear; if ( app->material && (gf_node_get_tag((GF_Node *)app->material)==TAG_MPEG4_MaterialKey) ) { @@ -150,14 +149,14 @@ static void draw_bitmap_2d(GF_Node *node, GF_TraverseState *tr_state) keyColor.alpha = FIX2INT( (FIX_ONE - mk->transparency) * 255); keyColor.low = FIX2INT(mk->lowThreshold * 255); keyColor.high = FIX2INT(mk->highThreshold * 255); - key = &keyColor; + tr_state->col_key = &keyColor; } } } /*no HW, fall back to the graphics driver*/ - if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, key)) { + if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) { GF_Matrix2D _mat; GF_Rect rc = gf_rect_center(ctx->bi->unclip.width, ctx->bi->unclip.height); gf_mx2d_copy(_mat, ctx->transform); @@ -168,9 +167,8 @@ static void draw_bitmap_2d(GF_Node *node, GF_TraverseState *tr_state) gf_path_add_rect_center(st->graph->path, 0, 0, rc.width, rc.height); ctx->flags |= CTX_NO_ANTIALIAS; visual_2d_texture_path(tr_state->visual, st->graph->path, ctx, tr_state); - return; } - + tr_state->col_key = NULL; } static void TraverseBitmap(GF_Node *node, void *rs, Bool is_destroy) diff --git a/src/compositor/mpeg4_composite.c b/src/compositor/mpeg4_composite.c index 2e96aa7..9e3b57f 100644 --- a/src/compositor/mpeg4_composite.c +++ b/src/compositor/mpeg4_composite.c @@ -53,7 +53,7 @@ typedef struct } CompositeTextureStack; -static Bool composite2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx, GF_ColorKey *col_key) +static Bool composite2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx) { u8 alpha = 0xFF; GF_VideoSurface offscreen_dst, video_src; @@ -103,7 +103,7 @@ static Bool composite2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState * offscreen_dst.pixel_format = st->txh.pixelformat; offscreen_dst.video_buffer = st->txh.data; - gf_stretch_bits(&offscreen_dst, &video_src, &dst_wnd, &src_wnd, alpha, 0, col_key, ctx->col_mat); + gf_stretch_bits(&offscreen_dst, &video_src, &dst_wnd, &src_wnd, alpha, 0, tr_state->col_key, ctx->col_mat); return 1; } @@ -139,6 +139,7 @@ static void composite_traverse(GF_Node *node, void *rs, Bool is_destroy) #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx); #endif + gf_list_del(st->sensors); gf_list_del(st->previous_sensors); @@ -290,7 +291,7 @@ static void composite_update(GF_TextureHandler *txh) #endif /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/ -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X new_pixel_format = GF_PIXEL_RGBA; #endif @@ -575,6 +576,11 @@ void composite_release_video_access(GF_VisualManager *visual) visual->compositor->rasterizer->surface_detach(visual->raster_surface); } +Bool composite_check_visual_attached(GF_VisualManager *visual) +{ + return visual->is_attached; +} + void compositor_init_compositetexture2d(GF_Compositor *compositor, GF_Node *node) { M_CompositeTexture2D *c2d = (M_CompositeTexture2D *)node; @@ -597,8 +603,11 @@ void compositor_init_compositetexture2d(GF_Compositor *compositor, GF_Node *node st->visual->offscreen = node; st->visual->GetSurfaceAccess = composite_get_video_access; st->visual->ReleaseSurfaceAccess = composite_release_video_access; - st->visual->raster_surface = compositor->rasterizer->surface_new(compositor->rasterizer, 1); st->visual->DrawBitmap = composite2d_draw_bitmap; + st->visual->CheckAttached = composite_check_visual_attached; + + st->visual->raster_surface = compositor->rasterizer->surface_new(compositor->rasterizer, 1); + st->first = 1; st->visual->compositor = compositor; @@ -770,22 +779,6 @@ Bool compositor_compositetexture_handle_event(GF_Compositor *compositor, GF_Node gf_mx_copy(compositor->hit_world_to_local, w2l_mx); } - stack->prev_hit_appear = compositor->prev_hit_appear; - - if (prev_appear) { - if (prev_appear->sgprivate->num_instances>1) { - compositor->prev_hit_appear = prev_appear; - compositor->hit_appear = appear; - } else { - compositor->prev_hit_appear = NULL; - compositor->hit_appear = NULL; - } - gf_node_unregister(prev_appear, NULL); - } else { - compositor->prev_hit_appear = prev_appear; - compositor->hit_appear = appear; - } - compositor->hit_world_point = world_pt; compositor->hit_world_ray = ray; compositor->hit_square_dist = dist; @@ -805,6 +798,24 @@ Bool compositor_compositetexture_handle_event(GF_Compositor *compositor, GF_Node #endif gf_free(tr_state); } + + stack->prev_hit_appear = compositor->prev_hit_appear; + + //finally unregister the node, this may destroy the stack ! + if (prev_appear) { + if (prev_appear->sgprivate->num_instances>1) { + compositor->prev_hit_appear = prev_appear; + compositor->hit_appear = appear; + } else { + compositor->prev_hit_appear = NULL; + compositor->hit_appear = NULL; + } + gf_node_unregister(prev_appear, NULL); + } else { + compositor->prev_hit_appear = prev_appear; + compositor->hit_appear = appear; + } + return res; } @@ -838,22 +849,22 @@ void compositor_adjust_scale(GF_Node *node, Fixed *sx, Fixed *sy) Bool compositor_is_composite_texture(GF_Node *appear) { + M_Appearance *ap = NULL; u32 tag; if (!appear) return 0; + tag = gf_node_get_tag(appear); - if ((tag==TAG_MPEG4_Appearance) + if (tag==TAG_MPEG4_Appearance) ap = (M_Appearance *)appear; #ifndef GPAC_DISABLE_X3D - || (tag==TAG_X3D_Appearance) + else if (tag==TAG_X3D_Appearance) ap = (M_Appearance *)appear; #endif - ) { - M_Appearance *ap = (M_Appearance *)appear; - if (!ap->texture) return 0; - switch (gf_node_get_tag(((M_Appearance *)appear)->texture)) { - case TAG_MPEG4_CompositeTexture2D: - case TAG_MPEG4_CompositeTexture3D: - return 1; - } - } + if (!ap) return 0; + if (!ap->texture) return 0; + switch (gf_node_get_tag(((M_Appearance *)appear)->texture)) { + case TAG_MPEG4_CompositeTexture2D: + case TAG_MPEG4_CompositeTexture3D: + return 1; + } return 0; } diff --git a/src/compositor/mpeg4_geometry_2d.c b/src/compositor/mpeg4_geometry_2d.c index 11d9496..debdd65 100644 --- a/src/compositor/mpeg4_geometry_2d.c +++ b/src/compositor/mpeg4_geometry_2d.c @@ -283,7 +283,7 @@ static void compositor_2d_draw_rectangle(GF_TraverseState *tr_state) ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip); gf_irect_intersect(&ctx->bi->clip, &orig_clip); - res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL); + res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx); /*strike path*/ ctx->bi->unclip = orig_unclip; @@ -293,7 +293,7 @@ static void compositor_2d_draw_rectangle(GF_TraverseState *tr_state) visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); } } else { - res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL); + res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx); } /*if failure retry with raster*/ if (res) return; diff --git a/src/compositor/mpeg4_grouping.c b/src/compositor/mpeg4_grouping.c index 158877e..bd07ad1 100644 --- a/src/compositor/mpeg4_grouping.c +++ b/src/compositor/mpeg4_grouping.c @@ -43,7 +43,8 @@ void group_2d_traverse(GF_Node *node, GroupingNode2D *group, GF_TraverseState *t backup = gf_node_dirty_get(node); if (backup & GF_SG_CHILD_DIRTY) { GF_SensorHandler *hsens; - u32 ntag = gf_node_get_tag(node); + Bool check_anchor=0; + u32 ntag = gf_node_get_tag(node); group->flags &= ~GROUP_HAS_SENSORS; if (group->sensors) gf_list_reset(group->sensors); @@ -53,11 +54,11 @@ void group_2d_traverse(GF_Node *node, GroupingNode2D *group, GF_TraverseState *t but still mark the group as empty*/ group->bounds.width = 0; /*special case for anchor which is a parent node acting as a sensor*/ - if ((ntag==TAG_MPEG4_Anchor) + if (ntag==TAG_MPEG4_Anchor) check_anchor=1; #ifndef GPAC_DISABLE_X3D - || (ntag==TAG_X3D_Anchor) + else if (ntag==TAG_X3D_Anchor) check_anchor=1; #endif - ) { + if (check_anchor) { GF_SensorHandler *gf_sc_anchor_get_handler(GF_Node *n); hsens = gf_sc_anchor_get_handler(node); @@ -220,16 +221,17 @@ void group_2d_traverse_with_order(GF_Node *node, GroupingNode2D *group, GF_Trave backup = gf_node_dirty_get(node); if (backup & GF_SG_CHILD_DIRTY) { GF_SensorHandler *hsens; + Bool check_anchor=0; /*never trigger bounds recompute in 2D since we don't cull 2D groups*/ u32 ntag = gf_node_get_tag(node); group->flags &= ~GROUP_HAS_SENSORS; drawable_reset_group_highlight(tr_state, node); /*special case for anchor which is a parent node acting as a sensor*/ - if ((ntag==TAG_MPEG4_Anchor) + if (ntag==TAG_MPEG4_Anchor) check_anchor=1; #ifndef GPAC_DISABLE_X3D - || (ntag==TAG_X3D_Anchor) + else if (ntag==TAG_X3D_Anchor) check_anchor=1; #endif - ) { + if (check_anchor) { GF_SensorHandler *gf_sc_anchor_get_handler(GF_Node *n); hsens = gf_sc_anchor_get_handler(node); @@ -677,15 +679,16 @@ void parent_node_traverse(GF_Node *node, ParentNode2D *group, GF_TraverseState * GF_ChildNodeItem *l; if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) { + Bool check_anchor=0; /*parent groups must recompute their bounds themselves since they modify children layout*/ u32 ntag = gf_node_get_tag(node); group->flags &= ~GROUP_HAS_SENSORS; /*special case for anchor which is a parent node acting as a sensor*/ - if ((ntag==TAG_MPEG4_Anchor) + if (ntag==TAG_MPEG4_Anchor) check_anchor=1; #ifndef GPAC_DISABLE_X3D - || (ntag==TAG_X3D_Anchor) + else if (ntag==TAG_X3D_Anchor) check_anchor=1; #endif - ) { + if (check_anchor) { group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR; } else { l = ((GF_ParentNode *)node)->children; diff --git a/src/compositor/mpeg4_layer_3d.c b/src/compositor/mpeg4_layer_3d.c index f5d1679..aa18f91 100644 --- a/src/compositor/mpeg4_layer_3d.c +++ b/src/compositor/mpeg4_layer_3d.c @@ -160,7 +160,7 @@ u32 layer3d_setup_offscreen(GF_Node *node, Layer3DStack *st, GF_TraverseState *t // new_pixel_format = GF_PIXEL_RGB_24; /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/ -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X new_pixel_format = GF_PIXEL_RGBA; #else /*no support for alpha in offscreen rendering*/ @@ -282,7 +282,7 @@ u32 layer3d_setup_offscreen(GF_Node *node, Layer3DStack *st, GF_TraverseState *t static void layer3d_draw_2d(GF_Node *node, GF_TraverseState *tr_state) { DrawableContext *ctx = tr_state->ctx; - if (tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL)) + if (tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) return; visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); diff --git a/src/compositor/mpeg4_layout.c b/src/compositor/mpeg4_layout.c index 990df3f..cca121f 100644 --- a/src/compositor/mpeg4_layout.c +++ b/src/compositor/mpeg4_layout.c @@ -70,10 +70,6 @@ static LineInfo *new_line_info(LayoutStack *st) gf_list_add(st->lines, li); return li; } -static GFINLINE LineInfo *get_line_info(LayoutStack *st, u32 i) -{ - return (LineInfo *) gf_list_get(st->lines, i); -} enum diff --git a/src/compositor/mpeg4_lighting.c b/src/compositor/mpeg4_lighting.c index 061207b..f2329b8 100644 --- a/src/compositor/mpeg4_lighting.c +++ b/src/compositor/mpeg4_lighting.c @@ -40,7 +40,7 @@ static void TraverseSpotLight(GF_Node *n, void *rs, Bool is_destroy) GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { - Bool *vis = gf_node_get_private(n); + Bool *vis = (Bool*)gf_node_get_private(n); gf_free(vis); return; } @@ -53,19 +53,19 @@ static void TraverseSpotLight(GF_Node *n, void *rs, Bool is_destroy) if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { GF_BBox b; SFVec3f size; - Bool *visible = gf_node_get_private(n); + Bool *visible = (Bool*)gf_node_get_private(n); size.x = size.y = size.z = sl->radius; gf_vec_add(b.max_edge, sl->location, size); gf_vec_diff(b.min_edge, sl->location, size); gf_bbox_refresh(&b); - *visible = visual_3d_node_cull(tr_state, &b, 0); + *visible = visual_3d_node_cull(tr_state, &b, GF_FALSE); /*if visible, disable culling on our parent branch - this is not very efficient but we only store one bound per grouping node, and we don't want the lights to interfere with it*/ - if (*visible) tr_state->disable_cull = 1; + if (*visible) tr_state->disable_cull = GF_TRUE; return; } else if (tr_state->traversing_mode == TRAVERSE_LIGHTING) { - Bool *visible = gf_node_get_private(n); + Bool *visible = (Bool*)gf_node_get_private(n); if (*visible) { visual_3d_add_spot_light(tr_state->visual, sl->ambientIntensity, sl->attenuation, sl->beamWidth, sl->color, sl->cutOffAngle, sl->direction, sl->intensity, sl->location, &tr_state->model_matrix); @@ -77,8 +77,8 @@ static void TraverseSpotLight(GF_Node *n, void *rs, Bool is_destroy) void compositor_init_spot_light(GF_Compositor *compositor, GF_Node *node) { - Bool *vis = gf_malloc(sizeof(Bool)); - *vis = 0; + Bool *vis = (Bool*)gf_malloc(sizeof(Bool)); + *vis = GF_FALSE; gf_node_set_private(node, vis); /*no need for a stck*/ gf_node_set_callback_function(node, TraverseSpotLight); @@ -90,7 +90,7 @@ static void TraversePointLight(GF_Node *n, void *rs, Bool is_destroy) GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { - Bool *vis = gf_node_get_private(n); + Bool *vis = (Bool*)gf_node_get_private(n); gf_free(vis); return; } @@ -103,18 +103,18 @@ static void TraversePointLight(GF_Node *n, void *rs, Bool is_destroy) if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { SFVec3f size; GF_BBox b; - Bool *visible = gf_node_get_private(n); + Bool *visible = (Bool*)gf_node_get_private(n); size.x = size.y = size.z = pl->radius; gf_vec_add(b.max_edge, pl->location, size); gf_vec_diff(b.min_edge, pl->location, size); gf_bbox_refresh(&b); - *visible = visual_3d_node_cull(tr_state, &b, 0); + *visible = visual_3d_node_cull(tr_state, &b, GF_FALSE); /*if visible, disable culling on our parent branch*/ - if (*visible) tr_state->disable_cull = 1; + if (*visible) tr_state->disable_cull = GF_TRUE; return; } else if (tr_state->traversing_mode == TRAVERSE_LIGHTING) { - Bool *visible = gf_node_get_private(n); + Bool *visible = (Bool*)gf_node_get_private(n); if (*visible) { visual_3d_add_point_light(tr_state->visual, pl->ambientIntensity, pl->attenuation, pl->color, pl->intensity, pl->location, &tr_state->model_matrix); @@ -126,8 +126,8 @@ static void TraversePointLight(GF_Node *n, void *rs, Bool is_destroy) void compositor_init_point_light(GF_Compositor *compositor, GF_Node *node) { - Bool *vis = gf_malloc(sizeof(Bool)); - *vis = 0; + Bool *vis = (Bool*)gf_malloc(sizeof(Bool)); + *vis = GF_FALSE; gf_node_set_private(node, vis); /*no need for a stck*/ gf_node_set_callback_function(node, TraversePointLight); @@ -157,15 +157,15 @@ static void TraverseDirectionalLight(GF_Node *n, void *rs, Bool is_destroy) *stack = visual_3d_add_directional_light(tr_state->visual, dl->ambientIntensity, dl->color, dl->intensity, dl->direction, &tr_state->model_matrix); } else { if (*stack) visual_3d_remove_last_light(tr_state->visual); - *stack = 0; + *stack = GF_FALSE; visual_3d_has_inactive_light(tr_state->visual); } } void compositor_init_directional_light(GF_Compositor *compositor, GF_Node *node) { - Bool *stack = gf_malloc(sizeof(Bool)); - *stack = 0; + Bool *stack = (Bool*)gf_malloc(sizeof(Bool)); + *stack = GF_FALSE; gf_node_set_private(node, stack); gf_node_set_callback_function(node, TraverseDirectionalLight); } diff --git a/src/compositor/mpeg4_text.c b/src/compositor/mpeg4_text.c index 752fe7b..a4abaf5 100644 --- a/src/compositor/mpeg4_text.c +++ b/src/compositor/mpeg4_text.c @@ -55,6 +55,7 @@ typedef struct GF_List *spans; GF_Rect bounds; u32 texture_text_flag; + Bool is_dirty; GF_Compositor *compositor; } TextStack; @@ -596,6 +597,7 @@ static void Text_Traverse(GF_Node *n, void *rs, Bool is_destroy) if (!txt->string.count) return; if (tr_state->text_split_mode) { + st->is_dirty = gf_node_dirty_get(n) ? 1 : 0; gf_node_dirty_clear(n, 0); text_clean_paths(tr_state->visual->compositor, st); build_text_split(st, txt, tr_state); @@ -664,6 +666,8 @@ static void Text_Traverse(GF_Node *n, void *rs, Bool is_destroy) ctx->flags |= CTX_APP_DIRTY; } } + } else if (st->is_dirty) { + ctx->flags |= CTX_APP_DIRTY; } if (ctx->sub_path_index) { diff --git a/src/compositor/mpeg4_textures.c b/src/compositor/mpeg4_textures.c index d7d3b77..824fa41 100644 --- a/src/compositor/mpeg4_textures.c +++ b/src/compositor/mpeg4_textures.c @@ -288,47 +288,66 @@ static void imagetexture_update(GF_TextureHandler *txh) u32 out_size; GF_Err e; - /*BT/XMT playback*/ + /*BT/XMT playback: load to memory*/ if (ct->image.buffer) { - e = gf_img_file_dec(ct->image.buffer, (u32 *) &ct->objectTypeIndication, &txh->width, &txh->height, &txh->pixelformat, &txh->data, &out_size); - if (e==GF_OK) { - txh->needs_refresh = 1; - txh->stride = out_size / txh->height; + char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); + char *src_url = gf_url_concatenate(par, ct->image.buffer); + FILE *test = gf_fopen( src_url ? src_url : ct->image.buffer, "rb"); + if (test) { + fseek(test, 0, SEEK_END); + ct->data_len = (u32) gf_ftell(test); + ct->data = gf_malloc(sizeof(char)*ct->data_len); + fseek(test, 0, SEEK_SET); + if (ct->data_len != fread(ct->data, 1, ct->data_len, test)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: IO err\n", src_url ? src_url : ct->image.buffer ) ); + gf_free(ct->data); + ct->data = NULL; + ct->data_len = 0; + } + gf_fclose(test); + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: not found\n", src_url ? src_url : ct->image.buffer ) ); } + ct->image.buffer = NULL; + if (src_url) gf_free(src_url); } + /*BIFS decoded playback*/ - else { - switch (ct->objectTypeIndication) { - case GPAC_OTI_IMAGE_JPEG: - out_size = 0; - e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3); - if (e==GF_BUFFER_TOO_SMALL) { - u32 BPP; - txh->data = gf_malloc(sizeof(char) * out_size); - if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1; - else BPP = 3; - - e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP); - if (e==GF_OK) { - txh->needs_refresh = 1; - txh->stride = out_size / txh->height; - } + switch (ct->objectTypeIndication) { + case GPAC_OTI_IMAGE_JPEG: + out_size = 0; + e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3); + if (e==GF_BUFFER_TOO_SMALL) { + u32 BPP; + txh->data = gf_malloc(sizeof(char) * out_size); + if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1; + else BPP = 3; + + e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP); + if (e==GF_OK) { + gf_sc_texture_allocate(txh); + gf_sc_texture_set_data(txh); + txh->needs_refresh = 1; + txh->stride = out_size / txh->height; } - break; - case GPAC_OTI_IMAGE_PNG: - out_size = 0; - e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size); - if (e==GF_BUFFER_TOO_SMALL) { - txh->data = gf_malloc(sizeof(char) * out_size); - e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size); - if (e==GF_OK) { - txh->needs_refresh = 1; - txh->stride = out_size / txh->height; - } + } + break; + case GPAC_OTI_IMAGE_PNG: + out_size = 0; + e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size); + if (e==GF_BUFFER_TOO_SMALL) { + txh->data = gf_malloc(sizeof(char) * out_size); + e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size); + if (e==GF_OK) { + gf_sc_texture_allocate(txh); + gf_sc_texture_set_data(txh); + txh->needs_refresh = 1; + txh->stride = out_size / txh->height; } - break; } + break; } + #endif // GPAC_DISABLE_AV_PARSERS /*cacheURL is specified, store the image*/ @@ -358,10 +377,10 @@ static void imagetexture_update(GF_TextureHandler *txh) strcat(szExtractName, "_"); strcat(szExtractName, ct->cacheURL.buffer); - cached_texture = gf_f64_open(szExtractName, "wb"); + cached_texture = gf_fopen(szExtractName, "wb"); if (cached_texture) { gf_fwrite(ct->data, 1, ct->data_len, cached_texture); - fclose(cached_texture); + gf_fclose(cached_texture); } /*and write cache info*/ diff --git a/src/compositor/nodes_stacks.h b/src/compositor/nodes_stacks.h index a50f11b..26a056c 100644 --- a/src/compositor/nodes_stacks.h +++ b/src/compositor/nodes_stacks.h @@ -111,6 +111,7 @@ typedef struct Bool hybgl_init; #endif u32 flags; + char col_tx[12]; } Background2DStack; #ifndef GPAC_DISABLE_3D diff --git a/src/compositor/offscreen_cache.c b/src/compositor/offscreen_cache.c index 6588f2b..35faa47 100644 --- a/src/compositor/offscreen_cache.c +++ b/src/compositor/offscreen_cache.c @@ -43,7 +43,7 @@ void group_cache_draw(GroupCache *cache, GF_TraverseState *tr_state) tr_state->ctx->aspect.fill_texture = &cache->txh; -#ifndef GPAC_DISABLE_3D +#if !defined( GPAC_DISABLE_3D) && !defined(GPAC_DISABLE_VRML) if (tr_state->traversing_mode == TRAVERSE_DRAW_3D) { if (!cache->drawable->mesh) { cache->drawable->mesh = new_mesh(); @@ -55,7 +55,7 @@ void group_cache_draw(GroupCache *cache, GF_TraverseState *tr_state) } #endif - if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx, NULL)) { + if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx)) { visual_2d_texture_path(tr_state->visual, cache->drawable->path, tr_state->ctx, tr_state); } tr_state->ctx->aspect.fill_texture = old_txh; diff --git a/src/compositor/svg_filters.c b/src/compositor/svg_filters.c index 2efce58..498e04d 100644 --- a/src/compositor/svg_filters.c +++ b/src/compositor/svg_filters.c @@ -416,7 +416,7 @@ static void svg_traverse_filter(GF_Node *node, void *rs, Bool is_destroy) } if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) { - if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx, NULL)) { + if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx)) { visual_2d_texture_path(tr_state->visual, st->drawable->path, tr_state->ctx, tr_state); } } diff --git a/src/compositor/svg_media.c b/src/compositor/svg_media.c index 3cf4cf7..965fb66 100644 --- a/src/compositor/svg_media.c +++ b/src/compositor/svg_media.c @@ -36,7 +36,7 @@ static void svg_traverse_audio_ex(GF_Node *node, void *rs, Bool is_destroy, SVGP typedef struct { GF_TextureHandler txh; - Drawable *graph; + Drawable *drawable; MFURL txurl; Bool first_frame_fetched; GF_Node *audio; @@ -80,7 +80,7 @@ static Bool svg_video_get_transform_behavior(GF_TraverseState *tr_state, SVGAllA static void SVG_Draw_bitmap(GF_TraverseState *tr_state) { DrawableContext *ctx = tr_state->ctx; - if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL)) { + if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) { visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); } } @@ -93,11 +93,11 @@ static void SVG_Build_Bitmap_Graph(SVG_video_stack *stack, GF_TraverseState *tr_ Fixed rectx, recty, rectwidth, rectheight; SVGAllAttributes atts; SVG_PreserveAspectRatio pAR; - SVG_Element *e = (SVG_Element *)stack->graph->node; + SVG_Element *e = (SVG_Element *)stack->drawable->node; gf_svg_flatten_attributes(e, &atts); - tag = gf_node_get_tag(stack->graph->node); + tag = gf_node_get_tag(stack->drawable->node); switch (tag) { case TAG_SVG_image: case TAG_SVG_video: @@ -201,16 +201,16 @@ static void SVG_Build_Bitmap_Graph(SVG_video_stack *stack, GF_TraverseState *tr_ } - gf_path_get_bounds(stack->graph->path, &rc); - drawable_reset_path(stack->graph); - gf_path_add_rect_center(stack->graph->path, rectx, recty, rectwidth, rectheight); - gf_path_get_bounds(stack->graph->path, &new_rc); + gf_path_get_bounds(stack->drawable->path, &rc); + drawable_reset_path(stack->drawable); + gf_path_add_rect_center(stack->drawable->path, rectx, recty, rectwidth, rectheight); + gf_path_get_bounds(stack->drawable->path, &new_rc); if (!gf_rect_equal(rc, new_rc)) - drawable_mark_modified(stack->graph, tr_state); + drawable_mark_modified(stack->drawable, tr_state); else if (stack->txh.flags & GF_SR_TEXTURE_PRIVATE_MEDIA) - drawable_mark_modified(stack->graph, tr_state); + drawable_mark_modified(stack->drawable, tr_state); - gf_node_dirty_clear(stack->graph->node, GF_SG_SVG_GEOMETRY_DIRTY); + gf_node_dirty_clear(stack->drawable->node, GF_SG_SVG_GEOMETRY_DIRTY); } static void svg_open_texture(SVG_video_stack *stack) @@ -254,7 +254,7 @@ static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) gf_sc_texture_destroy(&stack->txh); gf_sg_mfurl_del(stack->txurl); - drawable_del(stack->graph); + drawable_del(stack->drawable); if (stack->audio) { gf_node_unregister(stack->audio, NULL); } @@ -262,15 +262,24 @@ static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) return; } - /*TRAVERSE_DRAW is NEVER called in 3D mode*/ if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) { SVG_Draw_bitmap(tr_state); return; } else if (tr_state->traversing_mode==TRAVERSE_PICK) { - svg_drawable_pick(node, stack->graph, tr_state); + svg_drawable_pick(node, stack->drawable, tr_state); return; } +#ifndef GPAC_DISABLE_3D + else if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) { + if (!stack->drawable->mesh) { + stack->drawable->mesh = new_mesh(); + mesh_from_path(stack->drawable->mesh, stack->drawable->path); + } + compositor_3d_draw_bitmap(stack->drawable, &tr_state->ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE); + return; + } +#endif /*flatten attributes and apply animations + inheritance*/ gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); @@ -304,7 +313,7 @@ static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { if (!compositor_svg_is_display_off(tr_state->svg_props)) { - gf_path_get_bounds(stack->graph->path, &tr_state->bounds); + gf_path_get_bounds(stack->drawable->path, &tr_state->bounds); compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { @@ -329,12 +338,12 @@ static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); - ctx = drawable_init_context_svg(stack->graph, tr_state); + ctx = drawable_init_context_svg(stack->drawable, tr_state); if (!ctx || !ctx->aspect.fill_texture ) return; if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { - drawable_reset_path(stack->graph); - gf_path_add_rect_center(stack->graph->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height)); + drawable_reset_path(stack->drawable); + gf_path_add_rect_center(stack->drawable->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height)); gf_mx2d_copy(mx_bck, tr_state->transform); restore_mx = GF_TRUE; @@ -362,11 +371,11 @@ static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { - if (!stack->graph->mesh) { - stack->graph->mesh = new_mesh(); - mesh_from_path(stack->graph->mesh, stack->graph->path); + if (!stack->drawable->mesh) { + stack->drawable->mesh = new_mesh(); + mesh_from_path(stack->drawable->mesh, stack->drawable->path); } - compositor_3d_draw_bitmap(stack->graph, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE); + compositor_3d_draw_bitmap(stack->drawable, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE); ctx->drawable = NULL; } else #endif @@ -415,9 +424,9 @@ void compositor_init_svg_image(GF_Compositor *compositor, GF_Node *node) { SVG_video_stack *stack; GF_SAFEALLOC(stack, SVG_video_stack) - stack->graph = drawable_new(); - stack->graph->flags = DRAWABLE_USE_TRAVERSE_DRAW; - stack->graph->node = node; + stack->drawable = drawable_new(); + stack->drawable->flags = DRAWABLE_USE_TRAVERSE_DRAW; + stack->drawable->node = node; gf_sc_texture_setup(&stack->txh, compositor, node); stack->txh.update_texture_fcnt = SVG_Update_image; @@ -494,7 +503,7 @@ static void SVG_Update_video(GF_TextureHandler *txh) } } - /*we have no choice but retraversing the graph until we're inactive since the movie framerate and + /*we have no choice but retraversing the drawable until we're inactive since the movie framerate and the compositor framerate are likely to be different */ if (!txh->stream_finished) if (txh->needs_refresh) @@ -546,9 +555,9 @@ void compositor_init_svg_video(GF_Compositor *compositor, GF_Node *node) { SVG_video_stack *stack; GF_SAFEALLOC(stack, SVG_video_stack) - stack->graph = drawable_new(); - stack->graph->flags = DRAWABLE_USE_TRAVERSE_DRAW; - stack->graph->node = node; + stack->drawable = drawable_new(); + stack->drawable->flags = DRAWABLE_USE_TRAVERSE_DRAW; + stack->drawable->node = node; gf_sc_texture_setup(&stack->txh, compositor, node); stack->txh.update_texture_fcnt = SVG_Update_video; diff --git a/src/compositor/svg_text.c b/src/compositor/svg_text.c index fa6029f..0261cf0 100644 --- a/src/compositor/svg_text.c +++ b/src/compositor/svg_text.c @@ -1501,7 +1501,7 @@ static void svg_traverse_tbreak(GF_Node *node, void *rs, Bool is_destroy) return; svg_text_area_reset_state(tr_state); - /*begining of a line, force a break of current fontSize*/ + /*beginning of a line, force a break of current fontSize*/ if (!tr_state->text_end_x) { if (tr_state->svg_props->line_increment->type != SVG_NUMBER_AUTO) { tr_state->text_end_y += tr_state->svg_props->line_increment->value; diff --git a/src/compositor/texturing.c b/src/compositor/texturing.c index 3bebb9f..5aa9ada 100644 --- a/src/compositor/texturing.c +++ b/src/compositor/texturing.c @@ -172,7 +172,7 @@ static void setup_texture_object(GF_TextureHandler *txh, Bool private_media) break; } } - gf_mo_set_flag(txh->stream, GF_MO_IS_INIT, 1); + gf_mo_set_flag(txh->stream, GF_MO_IS_INIT, GF_TRUE); } } @@ -203,10 +203,12 @@ void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) gf_sc_texture_release(txh); } } - txh->data = gf_mo_fetch_data(txh->stream, !disable_resync, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next); + txh->data = gf_mo_fetch_data(txh->stream, disable_resync ? GF_MO_FETCH : GF_MO_FETCH_RESYNC, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next); if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { needs_reload = 1; + } else if (size && txh->size && (size != txh->size)) { + needs_reload = 1; } if (needs_reload) { @@ -224,7 +226,7 @@ void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) /*if no frame or muted don't draw*/ if (!txh->data || !size) { - GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("|Visual Texture] No output frame available \n")); + GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Visual Texture] No output frame available \n")); /*TODO - check if this is needed */ if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { //txh->needs_refresh = 1; @@ -233,18 +235,23 @@ void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) return; } + if (txh->compositor->frame_delay > ms_until_pres) + txh->compositor->frame_delay = ms_until_pres; + /*if setup and same frame return*/ if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) { gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); txh->needs_release = 0; if (!txh->stream_finished) { - if (ms_until_next>0 && (txh->compositor->next_frame_delay > (u32) ms_until_next)) - txh->compositor->next_frame_delay = ms_until_next; + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual Texture] Same frame fetched (TS %d)\n", ts)); + if (txh->compositor->ms_until_next_frame > ms_until_next) + txh->compositor->ms_until_next_frame = ms_until_next; } return; } txh->needs_release = 1; txh->last_frame_time = ts; + txh->size = size; if (txh->raw_memory) { gf_mo_get_raw_image_planes(txh->stream, (u8 **) &txh->data, (u8 **) &txh->pU, (u8 **) &txh->pV); } @@ -257,10 +264,8 @@ void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) else ms_until_pres -= push_delay; } - if (txh->compositor->frame_delay < ms_until_pres) - txh->compositor->frame_delay = ms_until_pres; - - txh->compositor->next_frame_delay = 1; + if (txh->compositor->ms_until_next_frame > ms_until_next) + txh->compositor->ms_until_next_frame = ms_until_next; if (!txh->tx_io) { setup_texture_object(txh, 0); diff --git a/src/compositor/texturing_gl.c b/src/compositor/texturing_gl.c index 402a979..535bad3 100644 --- a/src/compositor/texturing_gl.c +++ b/src/compositor/texturing_gl.c @@ -33,7 +33,7 @@ # define GLTEXENV glTexEnvi # define GLTEXPARAM glTexParameteri # define TexEnvType u32 -#elif defined (GPAC_USE_OGL_ES) +#elif defined (GPAC_USE_GLES1X) # define GLTEXENV glTexEnvx # define GLTEXPARAM glTexParameterx # define TexEnvType Fixed @@ -138,6 +138,8 @@ void gf_sc_texture_release(GF_TextureHandler *txh) } if (txh->tx_io) { + gf_sc_lock(txh->compositor, 1); + if (txh->tx_io->tx_raster) { txh->compositor->rasterizer->stencil_delete(txh->tx_io->tx_raster); txh->tx_io->tx_raster = NULL; @@ -148,7 +150,9 @@ void gf_sc_texture_release(GF_TextureHandler *txh) } else { gf_list_add(txh->compositor->textures_gc, txh->tx_io); } - txh->tx_io=NULL; + txh->tx_io = NULL; + + gf_sc_lock(txh->compositor, 0); } } @@ -168,7 +172,7 @@ GF_Err gf_sc_texture_set_data(GF_TextureHandler *txh) { txh->tx_io->flags |= TX_NEEDS_RASTER_LOAD | TX_NEEDS_HW_LOAD; -#if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) //PBO mode: start pushing the texture if (txh->tx_io->pbo_id) { u8 *ptr; @@ -269,7 +273,7 @@ void tx_bind_with_mode(GF_TextureHandler *txh, Bool transparent, u32 blend_mode, break; case TX_MODULATE: if (txh->transparent) glEnable(GL_BLEND); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GLTEXENV(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); #else GLTEXENV(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); @@ -298,7 +302,7 @@ void gf_sc_texture_disable(GF_TextureHandler *txh) { if (txh && txh->tx_io) { -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (txh->tx_io->yuv_shader) { glUseProgram(0); txh->compositor->visual->current_texture_glsl_program = 0; @@ -371,7 +375,7 @@ static Bool tx_setup_format(GF_TextureHandler *txh) txh->tx_io->gl_type = GL_TEXTURE_2D; use_rect = tx_can_use_rect_ext(compositor, txh); if (!is_pow2 && use_rect) { -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) txh->tx_io->gl_type = GL_TEXTURE_RECTANGLE_EXT; #endif txh->tx_io->flags = TX_IS_RECT; @@ -411,7 +415,7 @@ static Bool tx_setup_format(GF_TextureHandler *txh) txh->tx_io->gl_format = GL_RGBA; txh->tx_io->nb_comp = 4; break; -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X case GF_PIXEL_ARGB: if (!compositor->gl_caps.bgra_texture) return 0; txh->tx_io->gl_format = GL_BGRA_EXT; @@ -421,7 +425,7 @@ static Bool tx_setup_format(GF_TextureHandler *txh) case GF_PIXEL_YV12: case GF_PIXEL_YV12_10: case GF_PIXEL_NV21: -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (compositor->gl_caps.has_shaders && (is_pow2 || compositor->visual->yuv_rect_glsl_program) ) { use_yuv_shaders = 1; break; @@ -465,7 +469,7 @@ static Bool tx_setup_format(GF_TextureHandler *txh) } tx_id[0] = txh->tx_io->id; -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (use_yuv_shaders && !txh->tx_io->u_id) { glGenTextures(1, &txh->tx_io->u_id); glGenTextures(1, &txh->tx_io->v_id); @@ -495,7 +499,7 @@ static Bool tx_setup_format(GF_TextureHandler *txh) } #endif -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) if (txh->compositor->gl_caps.pbo && txh->compositor->enable_pbo) { u32 size = txh->stride*txh->height; @@ -547,7 +551,7 @@ static Bool tx_setup_format(GF_TextureHandler *txh) glEnable(txh->tx_io->gl_type); glBindTexture(txh->tx_io->gl_type, tx_id[i] ); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GLTEXPARAM(txh->tx_io->gl_type, GL_TEXTURE_WRAP_S, (txh->flags & GF_SR_TEXTURE_REPEAT_S) ? GL_REPEAT : GL_CLAMP_TO_EDGE); GLTEXPARAM(txh->tx_io->gl_type, GL_TEXTURE_WRAP_T, (txh->flags & GF_SR_TEXTURE_REPEAT_T) ? GL_REPEAT : GL_CLAMP_TO_EDGE); if (txh->tx_io->gl_type == GL_TEXTURE_2D) { @@ -582,13 +586,13 @@ static Bool tx_setup_format(GF_TextureHandler *txh) if (txh->tx_io->yuv_shader && (txh->pixelformat==GF_PIXEL_YV12_10)) { //will never happen on GLES for now since we don't have GLES2 support yet ... -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X glPixelStorei(GL_UNPACK_ALIGNMENT, 2); //we use 10 bits but GL will normalise using 16 bits, so we need to multiply the nomralized result by 2^6 glPixelTransferi(GL_RED_SCALE, 64); #endif } else { -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X glPixelTransferi(GL_RED_SCALE, 1); #endif glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -826,7 +830,7 @@ static void do_tex_image_2d(GF_TextureHandler *txh, GLint tx_mode, Bool first_lo needs_stride = (stride!=w*txh->tx_io->nb_comp) ? GF_TRUE : GF_FALSE; } -#if !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_GLES1X) if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); #else @@ -834,7 +838,7 @@ static void do_tex_image_2d(GF_TextureHandler *txh, GLint tx_mode, Bool first_lo if (needs_stride) { #endif -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) if (txh->tx_io->pbo_pushed) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo_id); glTexImage2D(txh->tx_io->gl_type, 0, tx_mode, w, h, 0, txh->tx_io->gl_format, txh->tx_io->gl_dtype, NULL); @@ -848,7 +852,7 @@ static void do_tex_image_2d(GF_TextureHandler *txh, GLint tx_mode, Bool first_lo glTexSubImage2D(txh->tx_io->gl_type, 0, 0, 0, w, h, txh->tx_io->gl_format, txh->tx_io->gl_dtype, data); } -#if !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_GLES1X) if (needs_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); return; @@ -938,7 +942,7 @@ Bool gf_sc_texture_push_image(GF_TextureHandler *txh, Bool generate_mipmaps, Boo w = txh->width; h = txh->height; } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X tx_mode = txh->tx_io->gl_format; #else tx_mode = txh->tx_io->nb_comp; @@ -970,7 +974,7 @@ Bool gf_sc_texture_push_image(GF_TextureHandler *txh, Bool generate_mipmaps, Boo pV = (u8 *) pU + txh->height*txh->stride/4; } -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (txh->pixelformat==GF_PIXEL_YV12_10) { glPixelStorei(GL_UNPACK_ALIGNMENT, 2); //we use 10 bits but GL will normalise using 16 bits, so we need to multiply the nomralized result by 2^6 @@ -1000,7 +1004,7 @@ Bool gf_sc_texture_push_image(GF_TextureHandler *txh, Bool generate_mipmaps, Boo txh->nb_frames ++; txh->upload_time += push_time; -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (txh->pixelformat==GF_PIXEL_YV12_10) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelTransferi(GL_RED_SCALE, 1); @@ -1127,7 +1131,7 @@ void gf_sc_copy_to_stencil(GF_TextureHandler *txh) //glPixelTransferf(GL_DEPTH_SCALE, txh->compositor->OGLDepthGain); //glPixelTransferf(GL_DEPTH_BIAS, txh->compositor->OGLDepthOffset); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X /*obtain depthmap*/ if (!txh->tx_io->depth_data) txh->tx_io->depth_data = (char*)gf_malloc(sizeof(char)*txh->width*txh->height); glReadPixels(0, 0, txh->width, txh->height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, txh->tx_io->depth_data); @@ -1267,7 +1271,7 @@ Bool gf_sc_texture_get_transform(GF_TextureHandler *txh, GF_Node *tx_transform, static Bool gf_sc_texture_enable_matte_texture(GF_Node *n) { GF_TextureHandler *b_surf; -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) GF_TextureHandler *matte_hdl; GF_TextureHandler *a_surf; GF_TextureHandler *alpha_surf; @@ -1285,12 +1289,14 @@ static Bool gf_sc_texture_enable_matte_texture(GF_Node *n) glEnable(GL_BLEND); tx_set_image(b_surf, 0); -#if defined(GPAC_USE_TINYGL) || defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_TINYGL) || defined(GPAC_USE_GLES1X) tx_bind(b_surf); return 1; #else - /*To remove: gcc 4.6 introduces this warning*/ + +#ifdef LOAD_GL_1_3 + /*To remove: gcc 4.6 introduces this warning*/ #if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Waddress" @@ -1303,7 +1309,10 @@ static Bool gf_sc_texture_enable_matte_texture(GF_Node *n) #if __GNUC__ == 4 && __GNUC_MINOR__ == 6 #pragma GCC diagnostic pop #endif - matte_hdl = gf_node_get_private(n); + +#endif + + matte_hdl = gf_node_get_private(n); if (!matte_hdl->tx_io) { gf_sc_texture_allocate(matte_hdl); } @@ -1637,7 +1646,9 @@ u32 gf_sc_texture_enable_ex(GF_TextureHandler *txh, GF_Node *tx_transform, GF_Re compositor_gradient_update(txh); } - tx_set_image(txh, 0); + if (! tx_set_image(txh, 0) ) { + return 0; + } if (bounds && txh->compute_gradient_matrix) { GF_Matrix2D mx2d; @@ -1653,7 +1664,7 @@ u32 gf_sc_texture_enable_ex(GF_TextureHandler *txh, GF_Node *tx_transform, GF_Re txh->flags |= GF_SR_TEXTURE_USED; -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (txh->tx_io->yuv_shader) { GLint loc; /*use our program*/ @@ -1723,14 +1734,16 @@ void gf_sc_texture_set_stencil(GF_TextureHandler *txh, GF_STENCIL stencil) void gf_sc_texture_check_pause_on_first_load(GF_TextureHandler *txh) { + return; + if (txh->stream && txh->tx_io) { switch (txh->tx_io->init_pause_status) { case 0: - gf_sc_ar_control(txh->compositor->audio_renderer, 0); + gf_sc_ar_control(txh->compositor->audio_renderer, GF_SC_AR_PAUSE); txh->tx_io->init_pause_status = 1; break; case 1: - gf_sc_ar_control(txh->compositor->audio_renderer, 1); + gf_sc_ar_control(txh->compositor->audio_renderer, GF_SC_AR_RESUME); txh->tx_io->init_pause_status = 2; break; default: diff --git a/src/compositor/visual_manager.c b/src/compositor/visual_manager.c index fcf634c..0471dc4 100644 --- a/src/compositor/visual_manager.c +++ b/src/compositor/visual_manager.c @@ -30,7 +30,7 @@ #include <gpac/nodes_svg.h> #endif -static Bool visual_draw_bitmap_stub(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx, GF_ColorKey *col_key) +static Bool visual_draw_bitmap_stub(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx) { return 0; } diff --git a/src/compositor/visual_manager.h b/src/compositor/visual_manager.h index ee70873..26a78ba 100644 --- a/src/compositor/visual_manager.h +++ b/src/compositor/visual_manager.h @@ -130,7 +130,9 @@ struct _visual_manager */ void (*ClearSurface)(GF_VisualManager *visual, GF_IRect *rc, u32 BackColor, Bool offscreen_clear); /*draws specified texture as flat bitmap*/ - Bool (*DrawBitmap)(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx, GF_ColorKey *col_key); + Bool (*DrawBitmap)(GF_VisualManager *visual, GF_TraverseState *tr_state, DrawableContext *ctx); + /*checks if the visual is ready for being drawn on. Returns GF_FALSE if no draw operation can be sent*/ + Bool (*CheckAttached)(GF_VisualManager *visual); /*raster surface interface*/ GF_SURFACE raster_surface; @@ -203,12 +205,12 @@ struct _visual_manager GF_SHADERID current_texture_glsl_program; - Bool has_mat_2d; + Bool has_material_2d; SFColorRGBA mat_2d; - Bool has_mat; + Bool has_material; SFColorRGBA materials[4]; - Float shininess; + Fixed shininess; Bool state_light_on, state_blend_on, state_color_on; @@ -227,6 +229,11 @@ struct _visual_manager SFColor fog_color; Fixed fog_density, fog_visibility; + + GF_SHADERID glsl_vertex; + GF_SHADERID glsl_fragment; + GF_SHADERID glsl_program; + #endif #ifdef GF_SR_USE_DEPTH diff --git a/src/compositor/visual_manager_2d.c b/src/compositor/visual_manager_2d.c index b9a8ac7..b0af6cb 100644 --- a/src/compositor/visual_manager_2d.c +++ b/src/compositor/visual_manager_2d.c @@ -519,6 +519,8 @@ static u32 register_context_rect(GF_RectArray *ra, DrawableContext *ctx, u32 ctx static void register_dirty_rect(GF_RectArray *ra, GF_IRect *rc) { + if (!rc->width || !rc->height) return; + /*technically this is correct however the gain is not that big*/ #if 0 @@ -701,7 +703,7 @@ Bool visual_2d_terminate_draw(GF_VisualManager *visual, GF_TraverseState *tr_sta has_changed = 1; tr_state->traversing_mode = TRAVERSE_DRAW_2D; - if (first_opaque && (visual->to_redraw.count==1) && gf_rect_equal(first_opaque->bi->clip, visual->to_redraw.list[0].rect)) { + if (!hyb_force_redraw && first_opaque && (visual->to_redraw.count==1) && gf_rect_equal(first_opaque->bi->clip, visual->to_redraw.list[0].rect)) { visual->has_modif=0; goto skip_background; } @@ -737,7 +739,7 @@ Bool visual_2d_terminate_draw(GF_VisualManager *visual, GF_TraverseState *tr_sta if (visual->to_redraw.list[k].opaque_node_index > 0) continue; #endif rc = visual->to_redraw.list[k].rect; - visual->ClearSurface(visual, &rc, 0, 0); + visual->ClearSurface(visual, &rc, 0, 1); } #ifndef GPAC_DISABLE_3D if (!count && hyb_force_redraw) { diff --git a/src/compositor/visual_manager_2d.h b/src/compositor/visual_manager_2d.h index 77a3c72..538f0ea 100644 --- a/src/compositor/visual_manager_2d.h +++ b/src/compositor/visual_manager_2d.h @@ -63,6 +63,7 @@ typedef struct /*adds rect to list - expand if needed*/ #define ra_add(ra, rc) { \ + assert((rc)->width); \ if ((ra)->count==(ra)->alloc) { \ (ra)->alloc += RA_DEFAULT_STEP; \ (ra)->list = (GF_RectArrayEntry*)gf_realloc((ra)->list, sizeof(GF_RectArrayEntry) * (ra)->alloc); \ diff --git a/src/compositor/visual_manager_2d_draw.c b/src/compositor/visual_manager_2d_draw.c index 024614b..8146cfb 100644 --- a/src/compositor/visual_manager_2d_draw.c +++ b/src/compositor/visual_manager_2d_draw.c @@ -57,7 +57,7 @@ void visual_2d_clear_surface(GF_VisualManager *visual, GF_IRect *rc, u32 BackCol #ifdef SKIP_DRAW return; #endif - if (!visual->is_attached) return; + if (! visual->CheckAttached(visual) ) return; if (!BackColor && !visual->offscreen) { if (!visual->compositor->user || !(visual->compositor->user->init_flags & GF_TERM_WINDOW_TRANSPARENT)) { @@ -290,7 +290,8 @@ void visual_2d_texture_path_text(GF_VisualManager *visual, DrawableContext *txt_ GF_ColorMatrix cmat; GF_Raster2D *raster; - if (!visual->is_attached) return; + if (! visual->CheckAttached(visual) ) return; + raster = visual->compositor->rasterizer; stencil = gf_sc_texture_get_stencil(txh); @@ -452,7 +453,9 @@ void visual_2d_texture_path_extended(GF_VisualManager *visual, GF_Path *path, GF GF_Matrix2D mx_texture; GF_Rect orig_rc; GF_Raster2D *raster; - if (!visual->is_attached) return; + + if (! visual->CheckAttached(visual) ) return; + raster = visual->compositor->rasterizer; if (!txh) txh = ctx->aspect.fill_texture; @@ -580,7 +583,9 @@ void visual_2d_texture_path(GF_VisualManager *visual, GF_Path *path, struct _dra #ifdef SKIP_DRAW return; #endif - if (!visual->is_attached || (ctx->flags & CTX_PATH_FILLED) || !ctx->aspect.fill_texture || visual->compositor->is_hidden) return; + if (! visual->CheckAttached(visual) ) return; + + if ((ctx->flags & CTX_PATH_FILLED) || !ctx->aspect.fill_texture || visual->compositor->is_hidden) return; /*this is ambiguous in the spec, what if the material is filled and the texture is transparent ? let's draw, it's nicer */ @@ -604,7 +609,7 @@ void visual_2d_draw_path_extended(GF_VisualManager *visual, GF_Path *path, Drawa #ifdef SKIP_DRAW return; #endif - if (!visual->is_attached) return; + if (! visual->CheckAttached(visual) ) return; if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) { if (visual->compositor->draw_bvol) draw_clipper(visual, ctx); @@ -697,7 +702,8 @@ void visual_2d_fill_rect(GF_VisualManager *visual, DrawableContext *ctx, GF_Rect return; #endif - if (!visual->is_attached) return; + if (! visual->CheckAttached(visual) ) return; + if (!color && !strike_color) return; if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) { @@ -761,7 +767,9 @@ void visual_2d_fill_irect(GF_VisualManager *visual, GF_IRect *rc, u32 fill, u32 #endif if (!rc) return; - if (!visual->is_attached) return; + + if (! visual->CheckAttached(visual) ) return; + if (!fill && !strike ) return; /*no aa*/ diff --git a/src/compositor/visual_manager_3d.c b/src/compositor/visual_manager_3d.c index 8a48919..f67748e 100644 --- a/src/compositor/visual_manager_3d.c +++ b/src/compositor/visual_manager_3d.c @@ -63,6 +63,8 @@ void drawable3d_check_focus_highlight(GF_Node *node, GF_TraverseState *tr_state, GF_Matrix cur; GF_Compositor *compositor = tr_state->visual->compositor; + if (compositor->disable_focus_highlight) return; + if (compositor->focus_node!=node) return; hlight = compositor->focus_highlight; @@ -868,8 +870,8 @@ Bool visual_3d_draw_frame(GF_VisualManager *visual, GF_Node *root, GF_TraverseSt auto_stereo = 1; } -#ifndef GPAC_USE_OGL_ES - visual_3d_init_yuv_shader(visual); +#ifndef GPAC_USE_GLES1X + visual_3d_init_shaders(visual); #endif for (visual->current_view=0; visual->current_view < visual->nb_views; visual->current_view++) { @@ -1508,12 +1510,14 @@ void visual_3d_set_2d_strike(GF_TraverseState *tr_state, DrawAspect2D *asp) { if (asp->line_texture) { GF_Node *txtrans = NULL; +#ifndef GPAC_DISABLE_VRML if (tr_state->appear && (gf_node_get_tag( ((M_Appearance *)tr_state->appear)->material) == TAG_MPEG4_Material2D) && (gf_node_get_tag(((M_Material2D *) ((M_Appearance *)tr_state->appear)->material)->lineProps) == TAG_MPEG4_XLineProperties) ) { txtrans = ((M_XLineProperties *) ((M_Material2D *) ((M_Appearance *)tr_state->appear)->material)->lineProps)->textureTransform; } +#endif /*We forgot to specify this in the spec ...*/ gf_sc_texture_set_blend_mode(asp->line_texture, TX_REPLACE); @@ -1836,7 +1840,7 @@ void visual_3d_draw(GF_TraverseState *tr_state, GF_Mesh *mesh) visual_3d_mesh_paint(tr_state, mesh); visual_3d_disable_texture(tr_state); -#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_DISABLE_X3D) +#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_DISABLE_X3D) if (tr_state->appear && gf_node_get_tag(tr_state->appear)==TAG_X3D_Appearance) { X_Appearance *ap = (X_Appearance *)tr_state->appear; X_FillProperties *fp = ap->fillProperties ? (X_FillProperties *) ap->fillProperties : NULL; @@ -1870,8 +1874,8 @@ void visual_3d_enable_headlight(GF_VisualManager *visual, Bool bOn, GF_Camera *c void visual_3d_set_material_2d(GF_VisualManager *visual, SFColor col, Fixed alpha) { - visual->has_mat_2d = alpha ? 1 : 0; - if (visual->has_mat_2d) { + visual->has_material_2d = alpha ? 1 : 0; + if (visual->has_material_2d) { visual->mat_2d.red = col.red; visual->mat_2d.green = col.green; visual->mat_2d.blue = col.blue; @@ -1883,8 +1887,8 @@ void visual_3d_set_material_2d(GF_VisualManager *visual, SFColor col, Fixed alph void visual_3d_set_material_2d_argb(GF_VisualManager *visual, u32 col) { u32 a = GF_COL_A(col); - visual->has_mat_2d = a ? 1 : 0; - if (visual->has_mat_2d) { + visual->has_material_2d = a ? 1 : 0; + if (visual->has_material_2d) { visual->mat_2d.red = INT2FIX( GF_COL_R(col) ) / 255; visual->mat_2d.green = INT2FIX( GF_COL_G(col) ) / 255; visual->mat_2d.blue = INT2FIX( GF_COL_B(col) ) / 255; @@ -1948,7 +1952,7 @@ void visual_3d_set_material(GF_VisualManager *visual, u32 material_type, Fixed * visual->materials[material_type].blue = rgba[2]; visual->materials[material_type].alpha = rgba[3]; - visual->has_mat = 1; + visual->has_material = 1; } void visual_3d_set_shininess(GF_VisualManager *visual, Fixed shininess) diff --git a/src/compositor/visual_manager_3d.h b/src/compositor/visual_manager_3d.h index 3ca0323..cd6ac73 100644 --- a/src/compositor/visual_manager_3d.h +++ b/src/compositor/visual_manager_3d.h @@ -296,7 +296,7 @@ void visual_3d_fill_rect(GF_VisualManager *visual, GF_Rect rc, SFColorRGBA color void visual_3d_point_sprite(GF_VisualManager *visual, Drawable *stack, GF_TextureHandler *txh, GF_TraverseState *tr_state); /*non-oglES functions*/ -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X /*X3D hatching*/ void visual_3d_mesh_hatch(GF_TraverseState *tr_state, GF_Mesh *mesh, u32 hatchStyle, SFColor hatchColor); #endif @@ -308,7 +308,7 @@ void visual_3d_draw_bbox(GF_TraverseState *tr_state, GF_BBox *box); GF_Err visual_3d_init_autostereo(GF_VisualManager *visual); void visual_3d_end_auto_stereo_pass(GF_VisualManager *visual); -void visual_3d_init_yuv_shader(GF_VisualManager *visual); +void visual_3d_init_shaders(GF_VisualManager *visual); void visual_3d_reset_graphics(GF_VisualManager *visual); #endif /*GPAC_DISABLE_3D*/ diff --git a/src/compositor/visual_manager_3d_gl.c b/src/compositor/visual_manager_3d_gl.c index bbe3195..9f62c12 100644 --- a/src/compositor/visual_manager_3d_gl.c +++ b/src/compositor/visual_manager_3d_gl.c @@ -36,7 +36,7 @@ # if defined(GPAC_USE_TINYGL) # pragma comment(lib, "TinyGL") -# elif defined(GPAC_USE_OGL_ES) +# elif defined(GPAC_USE_GLES1X) # if 0 # pragma message("Using OpenGL-ES Common Lite Profile") @@ -62,7 +62,7 @@ #undef GL_MAX_CLIP_PLANES #endif -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X #define GL_CLAMP GL_CLAMP_TO_EDGE #endif @@ -137,6 +137,13 @@ GLDECL_STATIC(glUniformMatrix4x2fv); GLDECL_STATIC(glUniformMatrix3x4fv); GLDECL_STATIC(glUniformMatrix4x3fv); +#ifndef GPAC_ANDROID +GLDECL_STATIC(glEnableVertexAttribArray); +GLDECL_STATIC(glDisableVertexAttribArray); +GLDECL_STATIC(glVertexAttribPointer); +GLDECL_STATIC(glVertexAttribIPointer); +GLDECL_STATIC(glGetAttribLocation); +#endif #endif //LOAD_GL_2_0 @@ -180,7 +187,7 @@ void gf_sc_load_opengl_extensions(GF_Compositor *compositor, Bool has_gl_context compositor->gl_caps.vbo = 1; } -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (CHECK_GL_EXT("GL_EXT_texture_rectangle") || CHECK_GL_EXT("GL_NV_texture_rectangle")) { compositor->gl_caps.rect_texture = 1; if (CHECK_GL_EXT("GL_MESA_ycbcr_texture")) compositor->gl_caps.yuv_texture = YCBCR_MESA; @@ -270,6 +277,20 @@ void gf_sc_load_opengl_extensions(GF_Compositor *compositor, Bool has_gl_context GET_GLFUN(glUniformMatrix4x3fv); compositor->gl_caps.has_shaders = 1; + +#ifndef GPAC_ANDROID + GET_GLFUN(glEnableVertexAttribArray); + GET_GLFUN(glDisableVertexAttribArray); + GET_GLFUN(glVertexAttribPointer); + GET_GLFUN(glVertexAttribIPointer); + GET_GLFUN(glGetAttribLocation); + + if (glGetAttribLocation != NULL) { + compositor->shader_only_mode = 0; + } +#endif + + } else { GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] OpenGL shaders not supported\n")); } @@ -290,8 +311,7 @@ void gf_sc_load_opengl_extensions(GF_Compositor *compositor, Bool has_gl_context } -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) - +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) static char *default_glsl_vertex = "\ @@ -481,11 +501,15 @@ Bool visual_3d_compile_shader(GF_SHADERID shader_id, const char *name, const cha GLint blen = 0; GLsizei slen = 0; s32 len; + GLint is_compiled=0; if (!source || !shader_id) return 0; len = (u32) strlen(source); glShaderSource(shader_id, 1, &source, &len); glCompileShader(shader_id); + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &is_compiled); + if (is_compiled == GL_TRUE) return GF_TRUE; + glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH , &blen); if (blen > 1) { char* compiler_log = (char*) gf_malloc(blen); @@ -503,17 +527,17 @@ Bool visual_3d_compile_shader(GF_SHADERID shader_id, const char *name, const cha } static GF_SHADERID visual_3d_shader_from_source_file(const char *src_path, u32 shader_type) { - FILE *src = gf_f64_open(src_path, "rt"); + FILE *src = gf_fopen(src_path, "rt"); GF_SHADERID shader = 0; if (src) { size_t size; char *shader_src; - gf_f64_seek(src, 0, SEEK_END); - size = (size_t) gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_END); + size = (size_t) gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); shader_src = gf_malloc(sizeof(char)*(size+1)); size = fread(shader_src, 1, size, src); - fclose(src); + gf_fclose(src); if (size != (size_t) -1) { shader_src[size]=0; shader = glCreateShader(shader_type); @@ -577,7 +601,7 @@ void visual_3d_init_stereo_shaders(GF_VisualManager *visual) #define DEL_SHADER(_a) if (_a) { glDeleteShader(_a); _a = 0; } #define DEL_PROGRAM(_a) if (_a) { glDeleteProgram(_a); _a = 0; } -void visual_3d_init_yuv_shader(GF_VisualManager *visual) +static void visual_3d_init_yuv_shaders(GF_VisualManager *visual) { u32 i; GLint loc; @@ -675,12 +699,31 @@ void visual_3d_init_yuv_shader(GF_VisualManager *visual) } } } -#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) + +//todo ... +static void visual_3d_init_generic_shaders(GF_VisualManager *visual) +{ + if (visual->glsl_program) return; + +} + +void visual_3d_init_shaders(GF_VisualManager *visual) +{ + if (!visual->compositor->gl_caps.has_shaders) return; + + visual_3d_init_yuv_shaders(visual); + if (visual->compositor->shader_only_mode) { + visual_3d_init_generic_shaders(visual); + } + +} + +#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) void visual_3d_reset_graphics(GF_VisualManager *visual) { -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) DEL_SHADER(visual->base_glsl_vertex); DEL_SHADER(visual->autostereo_glsl_fragment); @@ -698,13 +741,13 @@ void visual_3d_reset_graphics(GF_VisualManager *visual) mesh_free(visual->autostereo_mesh); visual->autostereo_mesh = NULL; } -#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) } GF_Err visual_3d_init_autostereo(GF_VisualManager *visual) { -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) u32 bw, bh; SFVec2f s; if (visual->gl_textures) return GF_OK; @@ -738,19 +781,19 @@ GF_Err visual_3d_init_autostereo(GF_VisualManager *visual) GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual3D] AutoStereo initialized - width %d height %d\n", visual->auto_stereo_width, visual->auto_stereo_height) ); visual_3d_init_stereo_shaders(visual); -#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) return GF_OK; } void visual_3d_end_auto_stereo_pass(GF_VisualManager *visual) { -#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) u32 i; GLint loc; char szTex[100]; Double hw, hh; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GF_Matrix mx; #endif @@ -848,7 +891,7 @@ void visual_3d_end_auto_stereo_pass(GF_VisualManager *visual) glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); -#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_OGL_ES) +#endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) } @@ -873,7 +916,7 @@ static void visual_3d_setup_quality(GF_VisualManager *visual) if (visual->compositor->antiAlias == GF_ANTIALIAS_FULL) { glEnable(GL_LINE_SMOOTH); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (visual->compositor->poly_aa) glEnable(GL_POLYGON_SMOOTH); else @@ -881,7 +924,7 @@ static void visual_3d_setup_quality(GF_VisualManager *visual) #endif } else { glDisable(GL_LINE_SMOOTH); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X glDisable(GL_POLYGON_SMOOTH); #endif } @@ -898,7 +941,7 @@ void visual_3d_setup(GF_VisualManager *visual) glFrontFace(GL_CCW); glCullFace(GL_BACK); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glClearDepthx(FIX_ONE); glLightModelx(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, FLT2FIX(0.2f * 128) ); @@ -946,7 +989,7 @@ void visual_3d_set_background_state(GF_VisualManager *visual, Bool on) glDisable(GL_FOG); glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X glDisable(GL_POLYGON_SMOOTH); #endif glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); @@ -962,7 +1005,7 @@ void visual_3d_enable_antialias(GF_VisualManager *visual, Bool bOn) { if (bOn) { glEnable(GL_LINE_SMOOTH); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X if (visual->compositor->poly_aa) glEnable(GL_POLYGON_SMOOTH); else @@ -970,7 +1013,7 @@ void visual_3d_enable_antialias(GF_VisualManager *visual, Bool bOn) #endif } else { glDisable(GL_LINE_SMOOTH); -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X glDisable(GL_POLYGON_SMOOTH); #endif } @@ -1043,7 +1086,7 @@ static void visual_3d_draw_aabb_node(GF_TraverseState *tr_state, GF_Mesh *mesh, However we must push triangles one by one since primitive order may have been swapped when building the AABB tree*/ for (i=0; i<n->nb_idx; i++) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glDrawElements(prim_type, 3, GL_UNSIGNED_SHORT, &mesh->indices[3*n->indices[i]]); #else glDrawElements(prim_type, 3, GL_UNSIGNED_INT, &mesh->indices[3*n->indices[i]]); @@ -1053,15 +1096,18 @@ static void visual_3d_draw_aabb_node(GF_TraverseState *tr_state, GF_Mesh *mesh, static void visual_3d_matrix_load(GF_VisualManager *visual, Fixed *mat) { +#if defined(GPAC_FIXED_POINT) + Float _mat[16]; + u32 i; +#endif + if (!mat) { glLoadIdentity(); return; } -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) glLoadMatrixx(mat); #elif defined(GPAC_FIXED_POINT) - Float _mat[16]; - u32 i; for (i=0; i<16; i++) _mat[i] = FIX2FLT(mat[i]); glLoadMatrixf(_mat); #else @@ -1071,7 +1117,7 @@ static void visual_3d_matrix_load(GF_VisualManager *visual, Fixed *mat) static void visual_3d_matrix_add(GF_VisualManager *visual, Fixed *mat) { -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) glMultMatrixx(mat); #elif defined(GPAC_FIXED_POINT) u32 i; @@ -1109,7 +1155,7 @@ static void visual_3d_set_clippers(GF_VisualManager *visual, GF_TraverseState *t for (i=0; i<visual->num_clips; i++) { u32 idx = GL_CLIP_PLANE0 + i; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X Fixed g[4]; #else Double g[4]; @@ -1127,7 +1173,7 @@ static void visual_3d_set_clippers(GF_VisualManager *visual, GF_TraverseState *t gf_mx_apply_plane(&mx, &p); } -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) g[0] = p.normal.x; g[1] = p.normal.y; g[2] = p.normal.z; @@ -1138,7 +1184,13 @@ static void visual_3d_set_clippers(GF_VisualManager *visual, GF_TraverseState *t g[1] = FIX2FLT(p.normal.y); g[2] = FIX2FLT(p.normal.z); g[3] = FIX2FLT(p.d); + +#if defined(GPAC_USE_GLES1X) + glClipPlanef(idx, g); +#else glClipPlane(idx, g); +#endif + #endif glEnable(idx); @@ -1176,7 +1228,7 @@ void visual_3d_reset_lights(GF_VisualManager *visual) static void visual_3d_set_lights(GF_VisualManager *visual) { u32 i; -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) Fixed vals[4], exp; #else Float vals[4], intensity, cutOffAngle, beamWidth, ambientIntensity, exp; @@ -1196,7 +1248,7 @@ static void visual_3d_set_lights(GF_VisualManager *visual) switch (li->type) { //directionnal light case 0: -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) vals[0] = -li->direction.x; vals[1] = -li->direction.y; vals[2] = -li->direction.z; @@ -1249,14 +1301,14 @@ static void visual_3d_set_lights(GF_VisualManager *visual) //spot light case 1: -#ifndef GPAC_USE_OGL_ES +#ifndef GPAC_USE_GLES1X ambientIntensity = FIX2FLT(li->ambientIntensity); intensity = FIX2FLT(li->intensity); cutOffAngle = FIX2FLT(li->cutOffAngle); beamWidth = FIX2FLT(li->beamWidth); #endif -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) vals[0] = li->direction.x; vals[1] = li->direction.y; vals[2] = li->direction.z; @@ -1331,7 +1383,7 @@ static void visual_3d_set_lights(GF_VisualManager *visual) //point light case 2: -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) vals[0] = li->position.x; vals[1] = li->position.y; vals[2] = li->position.z; @@ -1394,7 +1446,7 @@ void visual_3d_enable_fog(GF_VisualManager *visual) #ifndef GPAC_USE_TINYGL -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) Fixed vals[4]; glEnable(GL_FOG); if (!visual->fog_type) glFogx(GL_FOG_MODE, GL_LINEAR); @@ -1412,9 +1464,17 @@ void visual_3d_enable_fog(GF_VisualManager *visual) #else Float vals[4]; glEnable(GL_FOG); + +#if defined(GPAC_USE_GLES1X) + if (!visual->fog_type) glFogf(GL_FOG_MODE, GL_LINEAR); + else if (visual->fog_type==1) glFogf(GL_FOG_MODE, GL_EXP); + else if (visual->fog_type==2) glFogf(GL_FOG_MODE, GL_EXP2); +#else if (!visual->fog_type) glFogi(GL_FOG_MODE, GL_LINEAR); else if (visual->fog_type==1) glFogi(GL_FOG_MODE, GL_EXP); else if (visual->fog_type==2) glFogi(GL_FOG_MODE, GL_EXP2); +#endif + glFogf(GL_FOG_DENSITY, FIX2FLT(visual->fog_density)); glFogf(GL_FOG_START, 0); glFogf(GL_FOG_END, FIX2FLT(visual->fog_visibility)); @@ -1431,29 +1491,238 @@ void visual_3d_enable_fog(GF_VisualManager *visual) } +static void visual_3d_do_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) +{ + u32 prim_type; + GF_Matrix mx; + u32 i, p_idx[6]; + GF_Plane fplanes[6]; + + + switch (mesh->mesh_type) { + case MESH_LINESET: + prim_type = GL_LINES; + break; + case MESH_POINTSET: + prim_type = GL_POINTS; + break; + default: + prim_type = GL_TRIANGLES; + break; + } + + /*if inside or no aabb for the mesh draw vertex array*/ + if (tr_state->visual->compositor->disable_gl_cull || (tr_state->cull_flag==CULL_INSIDE) || !mesh->aabb_root || !mesh->aabb_root->pos) { +#ifdef GPAC_USE_GLES1X + glDrawElements(prim_type, mesh->i_count, GL_UNSIGNED_SHORT, mesh->indices); +#else + glDrawElements(prim_type, mesh->i_count, GL_UNSIGNED_INT, mesh->indices); +#endif + + return; + } + + /*otherwise cull aabb against frustum - after some testing it appears (as usual) that there must + be a compromise: we're slowing down the compositor here, however the gain is really appreciable for + large meshes, especially terrains/elevation grids*/ + + /*first get transformed frustum in local space*/ + gf_mx_copy(mx, tr_state->model_matrix); + gf_mx_inverse(&mx); + for (i=0; i<6; i++) { + fplanes[i] = tr_state->camera->planes[i]; + gf_mx_apply_plane(&mx, &fplanes[i]); + p_idx[i] = gf_plane_get_p_vertex_idx(&fplanes[i]); + } + /*then recursively cull & draw AABB tree*/ + visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_idx, mesh->aabb_root->pos); + visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_idx, mesh->aabb_root->neg); +} + +#if !defined(GPAC_ANDROID) && !defined(GPAC_IPHONE) + +static GLint my_glGetUniformLocation(GF_SHADERID glsl_program, const char *uniform_name) +{ + GLint loc = glGetUniformLocation(glsl_program, uniform_name); + if (loc<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[V3D:GLSL] Cannot find uniform \"%s\" in GLSL program\n", uniform_name)); + } + return loc; +} + +static GLint my_glGetAttribLocation(GF_SHADERID glsl_program, const char *attrib_name) +{ + GLint loc = glGetAttribLocation(glsl_program, attrib_name); + if (loc<0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[V3D:GLSL] Cannot find attrib \"%s\" in GLSL program\n", attrib_name)); + } + return loc; +} + +#ifndef GPAC_FIXED_POINT +static void visual_3d_draw_mesh_shader_only(GF_TraverseState *tr_state, GF_Mesh *mesh, void *vertex_buffer_address) +{ + GF_VisualManager *visual = tr_state->visual; + GLint loc; + GF_Matrix mx; + GL_CHECK_ERR + glUseProgram(visual->glsl_program); + GL_CHECK_ERR + + loc = my_glGetUniformLocation(visual->glsl_program, "gfModelViewMatrix"); + if (loc<0) return; + gf_mx_copy(mx, tr_state->camera->modelview); + gf_mx_add_matrix(&mx, &tr_state->model_matrix); + glUniformMatrix4fv(loc, 1, GL_FALSE, mx.m); + GL_CHECK_ERR + + loc = my_glGetUniformLocation(visual->glsl_program, "gfProjectionMatrix"); + if (loc<0) return; + glUniformMatrix4fv(loc, 1, GL_FALSE, tr_state->camera->projection.m); + GL_CHECK_ERR + + loc = my_glGetAttribLocation(visual->glsl_program, "gfVertex"); + if (loc<0) return; + glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex), vertex_buffer_address); + glEnableVertexAttribArray(loc); + GL_CHECK_ERR + + if (visual->has_material_2d) { + loc = my_glGetUniformLocation(visual->glsl_program, "gfEmissionColor"); + if (loc>=0) + glUniform4fv(loc, 1, (GLfloat *) & visual->mat_2d); + + loc = my_glGetUniformLocation(visual->glsl_program, "gfNumLights"); + if (loc>=0) + glUniform1i(loc, 0); + } + + if (visual->has_material) { + loc = my_glGetUniformLocation(visual->glsl_program, "gfAmbientColor"); + if (loc>=0) + glUniform4fv(loc, 1, (GLfloat *) & visual->materials[0] ); + + loc = my_glGetUniformLocation(visual->glsl_program, "gfDiffuseColor"); + if (loc>=0) + glUniform4fv(loc, 1, (GLfloat *) & visual->materials[1] ); + + loc = my_glGetUniformLocation(visual->glsl_program, "gfSpecularColor"); + if (loc>=0) + glUniform4fv(loc, 1, (GLfloat *) & visual->materials[2] ); + + loc = my_glGetUniformLocation(visual->glsl_program, "gfEmissionColor"); + if (loc>=0) + glUniform4fv(loc, 1, (GLfloat *) & visual->materials[3] ); + + loc = my_glGetUniformLocation(visual->glsl_program, "gfShininess"); + if (loc>=0) + glUniform1f(loc, visual->shininess ); + + } + + if (!visual->has_material_2d && visual->num_lights && !mesh->mesh_type) { + GF_Matrix normal_mx; + GF_Vec pt; + GF_LightInfo *li; + Float ambientIntensity, intensity; + Float vals[4]; + + gf_mx_copy(normal_mx, mx); + normal_mx.m[12] = normal_mx.m[13] = normal_mx.m[14] = 0; + gf_mx_inverse(&normal_mx); + normal_mx.m[12] = normal_mx.m[13] = normal_mx.m[14] = 0; + + loc = my_glGetUniformLocation(visual->glsl_program, "gfNormalMatrix"); + //transpose the matrix when uploading + if (loc>=0) + glUniformMatrix4fv(loc, 1, GL_TRUE, normal_mx.m); + GL_CHECK_ERR + + + loc = my_glGetAttribLocation(visual->glsl_program, "gfNormal"); + if (loc>=0) { +#ifdef MESH_USE_FIXED_NORMAL + glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, sizeof(GF_Vertex), ((char *)vertex_buffer_address + MESH_NORMAL_OFFSET) ); +#else + glVertexAttribPointer(loc, 3, GL_BYTE, GL_TRUE, sizeof(GF_Vertex), ((char *)vertex_buffer_address + MESH_NORMAL_OFFSET) ); +#endif + glEnableVertexAttribArray(loc); + } + GL_CHECK_ERR + + loc = my_glGetUniformLocation(visual->glsl_program, "gfNumLights"); + if (loc>=0) + glUniform1i(loc, 1); + + li = &visual->lights[0]; + + //only one light for now + pt = li->direction; + gf_mx_copy(mx, tr_state->camera->modelview); + gf_mx_add_matrix(&mx, &li->light_mx); + gf_mx_apply_vec(&mx, &pt); + gf_vec_norm(&pt); + vals[0] = -FIX2FLT(pt.x); + vals[1] = -FIX2FLT(pt.y); + vals[2] = -FIX2FLT(pt.z); + vals[3] = 0; +// vals[0] = FIX2FLT(pt.x); vals[1] = FIX2FLT(pt.y); vals[2] = FIX2FLT(pt.z); vals[3] = 0; + + loc = my_glGetUniformLocation(visual->glsl_program, "gfLightPosition"); + if (loc>=0) + glUniform4fv(loc, 1, vals); + + ambientIntensity = FIX2FLT(li->ambientIntensity); + intensity = FIX2FLT(li->intensity); + + vals[0] = FIX2FLT(li->color.red)*intensity; + vals[1] = FIX2FLT(li->color.green)*intensity; + vals[2] = FIX2FLT(li->color.blue)*intensity; + vals[3] = 1; + loc = my_glGetUniformLocation(visual->glsl_program, "gfLightDiffuse"); + if (loc>=0) glUniform4fv(loc, 1, vals); + loc = my_glGetUniformLocation(visual->glsl_program, "gfLightSpecular"); + if (loc>=0) glUniform4fv(loc, 1, vals); + + vals[0] = FIX2FLT(li->color.red)*ambientIntensity; + vals[1] = FIX2FLT(li->color.green)*ambientIntensity; + vals[2] = FIX2FLT(li->color.blue)*ambientIntensity; + vals[3] = 1; + loc = my_glGetUniformLocation(visual->glsl_program, "gfLightAmbiant"); + if (loc>=0) glUniform4fv(loc, 1, vals); + + if (visual->compositor->backcull + && (!tr_state->mesh_is_transparent || (visual->compositor->backcull ==GF_BACK_CULL_ALPHA) ) + && (mesh->flags & MESH_IS_SOLID)) { + glEnable(GL_CULL_FACE); + glFrontFace((mesh->flags & MESH_IS_CW) ? GL_CW : GL_CCW); + } else { + glDisable(GL_CULL_FACE); + } + } + + visual_3d_do_draw_mesh(tr_state, mesh); + + GL_CHECK_ERR + glUseProgram(0); +} +#endif //GPAC_FIXED_POINT + +#endif //GPAC_ANDROID + static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) { Bool has_col, has_tx, has_norm; - u32 prim_type; GF_VisualManager *visual = tr_state->visual; GF_Compositor *compositor = tr_state->visual->compositor; void *base_address = NULL; -#if defined(GPAC_FIXED_POINT) && !defined(GPAC_USE_OGL_ES) +#if defined(GPAC_FIXED_POINT) && !defined(GPAC_USE_GLES1X) Float *color_array = NULL; Float fix_scale = 1.0f; fix_scale /= FIX_ONE; #endif has_col = has_tx = has_norm = 0; - GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[V3D] Drawing mesh %p\n", mesh)); - - //set lights before pushing modelview matrix - visual_3d_set_lights(visual); - - visual_3d_update_matrices(tr_state); - - if (visual->has_fog) visual_3d_enable_fog(visual); - if ((compositor->reset_graphics==2) && mesh->vbo) { /*we lost OpenGL context at previous frame, recreate VBO*/ @@ -1461,10 +1730,14 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) } /*rebuild VBO for large ojects only (we basically filter quads out)*/ if ((mesh->v_count>4) && !mesh->vbo && compositor->gl_caps.vbo) { + GL_CHECK_ERR glGenBuffers(1, &mesh->vbo); + GL_CHECK_ERR if (mesh->vbo) { glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + GL_CHECK_ERR glBufferData(GL_ARRAY_BUFFER, mesh->v_count * sizeof(GF_Vertex) , mesh->vertices, (mesh->vbo_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + GL_CHECK_ERR mesh->vbo_dirty = 0; } } @@ -1472,6 +1745,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) if (mesh->vbo) { base_address = NULL; glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + GL_CHECK_ERR } else { base_address = & mesh->vertices[0].pos; } @@ -1481,24 +1755,20 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) mesh->vbo_dirty = 0; } - glEnableClientState(GL_VERTEX_ARRAY); -#if defined(GPAC_USE_OGL_ES) - glVertexPointer(3, GL_FIXED, sizeof(GF_Vertex), base_address); -#elif defined(GPAC_FIXED_POINT) - /*scale modelview matrix*/ - glPushMatrix(); - glScalef(fix_scale, fix_scale, fix_scale); - glVertexPointer(3, GL_INT, sizeof(GF_Vertex), base_address); -#else - glVertexPointer(3, GL_FLOAT, sizeof(GF_Vertex), base_address); +#if !defined(GPAC_ANDROID) && !defined(GPAC_IPHONE) && !defined(GPAC_FIXED_POINT) + if (visual->compositor->shader_only_mode) { + visual_3d_draw_mesh_shader_only(tr_state, mesh, base_address); + return; + } #endif - /*enable states*/ -#if 0 - if (visual->state_light_on) glEnable(GL_LIGHTING); - else glDisable(GL_LIGHTING); -#endif + //set lights before pushing modelview matrix + visual_3d_set_lights(visual); + visual_3d_update_matrices(tr_state); + + /*enable states*/ + if (visual->has_fog) visual_3d_enable_fog(visual); if (visual->state_color_on) glEnable(GL_COLOR_MATERIAL); else glDisable(GL_COLOR_MATERIAL); @@ -1509,14 +1779,27 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) if (visual->num_clips) visual_3d_set_clippers(visual, tr_state); + glEnableClientState(GL_VERTEX_ARRAY); +#if defined(GPAC_USE_GLES1X) + glVertexPointer(3, GL_FIXED, sizeof(GF_Vertex), base_address); +#elif defined(GPAC_FIXED_POINT) + /*scale modelview matrix*/ + glPushMatrix(); + glScalef(fix_scale, fix_scale, fix_scale); + glVertexPointer(3, GL_INT, sizeof(GF_Vertex), base_address); +#else + glVertexPointer(3, GL_FLOAT, sizeof(GF_Vertex), base_address); +#endif + + /* * Enable colors: if mat2d is set, use mat2d and no lighting */ - if (visual->has_mat_2d) { + if (visual->has_material_2d) { glDisable(GL_LIGHTING); -#if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) if (visual->compositor->visual->current_texture_glsl_program) { int loc = glGetUniformLocation(visual->compositor->visual->current_texture_glsl_program, "alpha"); if (loc == -1) { @@ -1536,23 +1819,36 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) glDisable(GL_BLEND); visual_3d_enable_antialias(visual, visual->compositor->antiAlias ? 1 : 0); } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glColor4x( FIX2INT(visual->mat_2d.red * 255), FIX2INT(visual->mat_2d.green * 255), FIX2INT(visual->mat_2d.blue * 255), FIX2INT(visual->mat_2d.alpha * 255)); +#elif defined(GPAC_FIXED_POINT) + glColor4f(FIX2FLT(visual->mat_2d.red), FIX2FLT(visual->mat_2d.green), FIX2FLT(visual->mat_2d.blue), FIX2FLT(visual->mat_2d.alpha)); #else glColor4f(visual->mat_2d.red, visual->mat_2d.green, visual->mat_2d.blue, visual->mat_2d.alpha); #endif } } +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) + else if (visual->compositor->visual->current_texture_glsl_program) { + int loc = glGetUniformLocation(visual->compositor->visual->current_texture_glsl_program, "alpha"); + if (loc == -1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to locate uniform \"alpha\" in YUV shader\n")); + } else { + glUniform1f(loc, 1.0 ); + } + } +#endif + //setup material color - if (visual->has_mat) { + if (visual->has_material) { u32 i; GL_CHECK_ERR for (i=0; i<4; i++) { GLenum mode; Fixed *rgba = (Fixed *) & visual->materials[i]; -#if defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_GLES1X) Fixed *_rgba = (Fixed *) rgba; #elif defined(GPAC_FIXED_POINT) Float _rgba[4]; @@ -1579,14 +1875,14 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) break; } -#ifdef GPAC_USE_OGL_ES +#if defined(GPAC_USE_GLES1X) && defined(GPAC_FIXED_POINT) glMaterialxv(GL_FRONT_AND_BACK, mode, _rgba); #else glMaterialfv(GL_FRONT_AND_BACK, mode, _rgba); #endif GL_CHECK_ERR } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, visual->shininess * 128); #else glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, FIX2FLT(visual->shininess) * 128); @@ -1597,13 +1893,13 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) //otherwise setup mesh color if (!tr_state->mesh_num_textures && (mesh->flags & MESH_HAS_COLOR)) { glEnable(GL_COLOR_MATERIAL); -#if !defined (GPAC_USE_OGL_ES) +#if !defined (GPAC_USE_GLES1X) glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); #endif glEnableClientState(GL_COLOR_ARRAY); has_col = 1; -#if defined (GPAC_USE_OGL_ES) +#if defined (GPAC_USE_GLES1X) if (mesh->flags & MESH_HAS_ALPHA) { glEnable(GL_BLEND); @@ -1683,7 +1979,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) glMatrixMode(GL_MODELVIEW); -#if defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_GLES1X) glTexCoordPointer(2, GL_FIXED, sizeof(GF_Vertex), ((char *)base_address + MESH_TEX_OFFSET)); glEnableClientState(GL_TEXTURE_COORD_ARRAY ); #elif defined(GPAC_FIXED_POINT) @@ -1713,7 +2009,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) } if (mesh->mesh_type) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glNormal3x(0, 0, FIX_ONE); #else glNormal3f(0, 0, 1.0f); @@ -1733,7 +2029,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) glEnableClientState(GL_NORMAL_ARRAY ); #ifdef MESH_USE_FIXED_NORMAL -#if defined(GPAC_USE_OGL_ES) +#if defined(GPAC_USE_GLES1X) normal_type = GL_FIXED; #elif defined(GPAC_FIXED_POINT) normal_type = GL_INT; @@ -1759,48 +2055,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) } } - switch (mesh->mesh_type) { - case MESH_LINESET: - prim_type = GL_LINES; - break; - case MESH_POINTSET: - prim_type = GL_POINTS; - break; - default: - prim_type = GL_TRIANGLES; - break; - } - -#if 1 - /*if inside or no aabb for the mesh draw vertex array*/ - if (compositor->disable_gl_cull || (tr_state->cull_flag==CULL_INSIDE) || !mesh->aabb_root || !mesh->aabb_root->pos) { -#ifdef GPAC_USE_OGL_ES - glDrawElements(prim_type, mesh->i_count, GL_UNSIGNED_SHORT, mesh->indices); -#else - glDrawElements(prim_type, mesh->i_count, GL_UNSIGNED_INT, mesh->indices); -#endif - } else { - /*otherwise cull aabb against frustum - after some testing it appears (as usual) that there must - be a compromise: we're slowing down the compositor here, however the gain is really appreciable for - large meshes, especially terrains/elevation grids*/ - - /*first get transformed frustum in local space*/ - GF_Matrix mx; - u32 i, p_idx[6]; - GF_Plane fplanes[6]; - gf_mx_copy(mx, tr_state->model_matrix); - gf_mx_inverse(&mx); - for (i=0; i<6; i++) { - fplanes[i] = tr_state->camera->planes[i]; - gf_mx_apply_plane(&mx, &fplanes[i]); - p_idx[i] = gf_plane_get_p_vertex_idx(&fplanes[i]); - } - /*then recursively cull & draw AABB tree*/ - visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_idx, mesh->aabb_root->pos); - visual_3d_draw_aabb_node(tr_state, mesh, prim_type, fplanes, p_idx, mesh->aabb_root->neg); - } - -#endif + visual_3d_do_draw_mesh(tr_state, mesh); glDisableClientState(GL_VERTEX_ARRAY); if (has_col) glDisableClientState(GL_COLOR_ARRAY); @@ -1812,7 +2067,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) if (mesh->vbo) glBindBuffer(GL_ARRAY_BUFFER, 0); -#if defined(GPAC_FIXED_POINT) && !defined(GPAC_USE_OGL_ES) +#if defined(GPAC_FIXED_POINT) && !defined(GPAC_USE_GLES1X) if (color_array) gf_free(color_array); if (tr_state->mesh_num_textures && !mesh->mesh_type && !(mesh->flags & MESH_NO_TEXTURE)) { glMatrixMode(GL_TEXTURE); @@ -1830,8 +2085,8 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) //reset all our states if (visual->num_clips) visual_3d_reset_clippers(visual); - visual->has_mat_2d = 0; - visual->has_mat = 0; + visual->has_material_2d = 0; + visual->has_material = 0; visual->state_color_on = 0; if (tr_state->mesh_is_transparent) glDisable(GL_BLEND); tr_state->mesh_is_transparent = 0; @@ -1839,7 +2094,7 @@ static void visual_3d_draw_mesh(GF_TraverseState *tr_state, GF_Mesh *mesh) static void visual_3d_set_debug_color(u32 col) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glColor4x( (col ? GF_COL_R(col) : 255) , (col ? GF_COL_G(col) : 0) , (col ? GF_COL_B(col) : 255), 255); #else glColor4f(col ? GF_COL_R(col)/255.0f : 1, col ? GF_COL_G(col)/255.0f : 0, col ? GF_COL_B(col)/255.0f : 1, 1); @@ -1856,7 +2111,7 @@ static void visual_3d_draw_normals(GF_TraverseState *tr_state, GF_Mesh *mesh) u32 i, j; Fixed scale = mesh->bounds.radius / 4; -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GF_Vec va[2]; u16 indices[2]; glEnableClientState(GL_VERTEX_ARRAY); @@ -1872,7 +2127,7 @@ static void visual_3d_draw_normals(GF_TraverseState *tr_state, GF_Mesh *mesh) MESH_GET_NORMAL(end, mesh->vertices[idx[j]]); end = gf_vec_scale(end, scale); gf_vec_add(end, pt, end); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X va[0] = pt; va[1] = end; indices[0] = 0; @@ -1898,7 +2153,7 @@ static void visual_3d_draw_normals(GF_TraverseState *tr_state, GF_Mesh *mesh) end = gf_vec_scale(end, scale); gf_vec_add(end, pt, end); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X va[0] = pt; va[1] = end; indices[0] = 0; @@ -1914,7 +2169,7 @@ static void visual_3d_draw_normals(GF_TraverseState *tr_state, GF_Mesh *mesh) idx += 3; } } -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glDisableClientState(GL_VERTEX_ARRAY); #endif @@ -1985,6 +2240,7 @@ static void visual_3d_draw_bounds(GF_TraverseState *tr_state, GF_Mesh *mesh) void visual_3d_mesh_paint(GF_TraverseState *tr_state, GF_Mesh *mesh) { Bool mesh_drawn = 0; + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[V3D] Drawing mesh %p\n", mesh)); if (tr_state->visual->compositor->wiremode != GF_WIREFRAME_ONLY) { visual_3d_draw_mesh(tr_state, mesh); mesh_drawn = 1; @@ -2007,7 +2263,7 @@ void visual_3d_mesh_paint(GF_TraverseState *tr_state, GF_Mesh *mesh) glEnableClientState(GL_VERTEX_ARRAY); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glVertexPointer(3, GL_FIXED, sizeof(GF_Vertex), &mesh->vertices[0].pos); glDrawElements(GL_LINES, mesh->i_count, GL_UNSIGNED_SHORT, mesh->indices); #else @@ -2017,9 +2273,11 @@ void visual_3d_mesh_paint(GF_TraverseState *tr_state, GF_Mesh *mesh) glDisableClientState(GL_VERTEX_ARRAY); } if (tr_state->visual->compositor->draw_bvol) visual_3d_draw_bounds(tr_state, mesh); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[V3D] Done drawing mesh %p\n", mesh)); } -#if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) static GLubyte hatch_horiz[] = { @@ -2176,7 +2434,7 @@ void visual_3d_mesh_hatch(GF_TraverseState *tr_state, GF_Mesh *mesh, u32 hatchSt /*only used for ILS/ILS2D or IFS2D outline*/ void visual_3d_mesh_strike(GF_TraverseState *tr_state, GF_Mesh *mesh, Fixed width, Fixed line_scale, u32 dash_style) { -#if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) u16 style; #endif @@ -2187,7 +2445,7 @@ void visual_3d_mesh_strike(GF_TraverseState *tr_state, GF_Mesh *mesh, Fixed widt glLineWidth( FIX2FLT(width)); #endif -#if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) switch (dash_style) { case GF_DASH_STYLE_DASH: @@ -2224,7 +2482,7 @@ void visual_3d_mesh_strike(GF_TraverseState *tr_state, GF_Mesh *mesh, Fixed widt void visual_3d_clear(GF_VisualManager *visual, SFColor color, Fixed alpha) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glClearColorx(color.red, color.green, color.blue, alpha); #else glClearColor(FIX2FLT(color.red), FIX2FLT(color.green), FIX2FLT(color.blue), FIX2FLT(alpha)); @@ -2237,7 +2495,7 @@ void visual_3d_fill_rect(GF_VisualManager *visual, GF_Rect rc, SFColorRGBA color { glDisable(GL_BLEND | GL_LIGHTING | GL_TEXTURE_2D); -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X glNormal3x(0, 0, FIX_ONE); if (color.alpha!=FIX_ONE) glEnable(GL_BLEND); glColor4x(color.red, color.green, color.blue, color.alpha); @@ -2295,21 +2553,28 @@ GF_Err compositor_3d_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurfac u32 hy; #endif //GPAC_USE_TINYGL - fb->width = compositor->vp_width; - fb->height = compositor->vp_height; + fb->width = compositor->display_width; + fb->height = compositor->display_height; /*depthmap-only dump*/ if (depth_dump_mode==1) { - Float *depthp; - Float zFar, zNear; -#ifdef GPAC_USE_OGL_ES + //depth reading not supported on gles <= 1.1 +#ifdef GPAC_USE_GLES1X return GF_NOT_SUPPORTED; #else + Float *depthp; + Float zFar, zNear; fb->pitch_x = 0; fb->pitch_y = compositor->vp_width; - fb->video_buffer = (char*)gf_malloc(sizeof(char)* fb->pitch_y * fb->height); + if (compositor->screen_buffer_alloc_size < fb->pitch_y * fb->height) { + compositor->screen_buffer_alloc_size = fb->pitch_y * fb->height; + compositor->screen_buffer = gf_realloc(compositor->screen_buffer, compositor->screen_buffer_alloc_size); + } + + fb->video_buffer = compositor->screen_buffer; + //read as float depthp = (Float*)gf_malloc(sizeof(Float)* fb->pitch_y * fb->height); fb->pixel_format = GF_PIXEL_GREYSCALE; @@ -2322,8 +2587,8 @@ GF_Err compositor_3d_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurfac glReadPixels(compositor->vp_x, compositor->vp_y, fb->width, fb->height, GL_DEPTH_COMPONENT, GL_FLOAT, depthp); //linearize z buffer, from 0 (zfar) to 1 (znear) - zFar = compositor->visual->camera.z_far; - zNear = compositor->visual->camera.z_near; + zFar = FIX2FLT(compositor->visual->camera.z_far); + zNear = FIX2FLT(compositor->visual->camera.z_near); for (i=0; i<fb->height*fb->width; i++) { Float res = ( (2.0f * zNear) / (zFar + zNear - depthp[i] * (zFar - zNear)) ) ; fb->video_buffer[i] = (u8) ( 255.0 * (1.0 - res)); @@ -2331,26 +2596,30 @@ GF_Err compositor_3d_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurfac gf_free(depthp); -#endif /*GPAC_USE_OGL_ES*/ +#endif /*GPAC_USE_GLES1X*/ } /* RGBDS or RGBD dump*/ else if (depth_dump_mode==2 || depth_dump_mode==3) { -#ifdef GPAC_USE_OGL_ES +#ifdef GPAC_USE_GLES1X GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor]: RGB+Depth format not implemented in OpenGL ES\n")); return GF_NOT_SUPPORTED; #else char *depth_data=NULL; + u32 size; fb->pitch_x = 4; fb->pitch_y = compositor->vp_width*4; /* 4 bytes for each rgbds pixel */ #ifndef GPAC_USE_TINYGL - fb->video_buffer = (char*)gf_malloc(sizeof(char)* fb->pitch_y * fb->height); + size = fb->pitch_y * fb->height; #else - fb->video_buffer = (char*)gf_malloc(sizeof(char)* 2 * fb->pitch_y * fb->height); + size = 2 * fb->pitch_y * fb->height; #endif - - + if (compositor->screen_buffer_alloc_size < size) { + compositor->screen_buffer_alloc_size = size; + compositor->screen_buffer = gf_realloc(compositor->screen_buffer, compositor->screen_buffer_alloc_size); + } + fb->video_buffer = compositor->screen_buffer; #ifndef GPAC_USE_TINYGL @@ -2391,15 +2660,21 @@ GF_Err compositor_3d_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurfac return GF_NOT_SUPPORTED; #endif -#endif /*GPAC_USE_OGL_ES*/ - +#endif /*GPAC_USE_GLES1X*/ } else { /*if (compositor->user && (compositor->user->init_flags & GF_TERM_WINDOW_TRANSPARENT))*/ + u32 size; fb->pitch_x = 4; fb->pitch_y = 4*compositor->vp_width; - fb->video_buffer = (char*)gf_malloc(sizeof(char) * fb->pitch_y * fb->height); + size = fb->pitch_y * fb->height; + if (compositor->screen_buffer_alloc_size < size) { + compositor->screen_buffer_alloc_size = size; + compositor->screen_buffer = gf_realloc(compositor->screen_buffer, compositor->screen_buffer_alloc_size); + } + + fb->video_buffer = compositor->screen_buffer; fb->pixel_format = GF_PIXEL_RGBA; - glReadPixels(compositor->vp_x, compositor->vp_y, fb->width, fb->height, GL_RGBA, GL_UNSIGNED_BYTE, fb->video_buffer); + glReadPixels(0, 0, fb->width, fb->height, GL_RGBA, GL_UNSIGNED_BYTE, fb->video_buffer); /* } else { fb->pitch_x = 3; fb->pitch_y = 3*compositor->vp_width; @@ -2426,14 +2701,13 @@ GF_Err compositor_3d_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurfac GF_Err compositor_3d_release_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer) { - gf_free(framebuffer->video_buffer); framebuffer->video_buffer = 0; return GF_OK; } GF_Err compositor_3d_get_offscreen_buffer(GF_Compositor *compositor, GF_VideoSurface *fb, u32 view_idx, u32 depth_dump_mode) { -#if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) char *tmp; u32 hy, i; /*not implemented yet*/ @@ -2469,7 +2743,7 @@ GF_Err compositor_3d_get_offscreen_buffer(GF_Compositor *compositor, GF_VideoSur void visual_3d_point_sprite(GF_VisualManager *visual, Drawable *stack, GF_TextureHandler *txh, GF_TraverseState *tr_state) { -#if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) +#if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) u32 w, h; u32 pixel_format, stride; u8 *data; @@ -2479,6 +2753,7 @@ void visual_3d_point_sprite(GF_VisualManager *visual, Drawable *stack, GF_Textur Bool in_strip; Float delta = 0; Bool first_pass = 2; + GF_Node *txtrans = NULL; if ((visual->compositor->depth_gl_type==GF_SC_DEPTH_GL_POINTS) && visual->compositor->gl_caps.point_sprite) { Float z; @@ -2695,11 +2970,14 @@ restart: } stack->mesh->vbo_dirty = 1; } - tr_state->mesh_num_textures = gf_sc_texture_enable(txh, ((M_Appearance *)tr_state->appear)->textureTransform); +#ifndef GPAC_DISABLE_VRML + if (tr_state->appear) txtrans = ((M_Appearance *)tr_state->appear)->textureTransform; +#endif + tr_state->mesh_num_textures = gf_sc_texture_enable(txh, txtrans); visual_3d_draw_mesh(tr_state, stack->mesh); visual_3d_disable_texture(tr_state); -#endif //GPAC_USE_OGL_ES +#endif //GPAC_USE_GLES1X } diff --git a/src/export.cpp b/src/export.cpp index 9a8d31a..ab3a8d2 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -16,8 +16,7 @@ * 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 + ** 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. * @@ -42,9 +41,13 @@ #pragma comment (linker, EXPORT_SYMBOL(gpac_features) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sys_init) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sys_close) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sys_set_args) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sys_get_argc) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sys_get_arg) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sleep) ) #pragma comment (linker, EXPORT_SYMBOL(gf_mkdir) ) #pragma comment (linker, EXPORT_SYMBOL(gf_rmdir) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dir_exists) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cleanup_dir) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sys_clock) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sys_clock_high_res) ) @@ -78,9 +81,10 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_temp_file_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_file_modification_time) ) #pragma comment (linker, EXPORT_SYMBOL(gf_fwrite) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_f64_open) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_f64_seek) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_f64_tell) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_fopen) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_fclose) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_fseek) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_ftell) ) #pragma comment (linker, EXPORT_SYMBOL(gf_prompt_has_input) ) #pragma comment (linker, EXPORT_SYMBOL(gf_prompt_get_char) ) #pragma comment (linker, EXPORT_SYMBOL(gf_prompt_set_echo_off) ) @@ -89,6 +93,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_gz_compress_payload) ) #pragma comment (linker, EXPORT_SYMBOL(gf_gz_decompress_payload) ) #endif +#pragma comment (linker, EXPORT_SYMBOL(gf_file_handles_count) ) /* Memory */ #ifdef GPAC_MEMORY_TRACKING @@ -269,6 +274,9 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_utc_time_since_1970) ) #pragma comment (linker, EXPORT_SYMBOL(gf_gettimeofday) ) #pragma comment (linker, EXPORT_SYMBOL(gf_net_get_ntp) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_net_get_ntp_ts) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_net_get_ntp_diff_ms) ) + #pragma comment (linker, EXPORT_SYMBOL(gf_net_get_utc) ) #pragma comment (linker, EXPORT_SYMBOL(gf_net_parse_date) ) #pragma comment (linker, EXPORT_SYMBOL(gf_net_get_timezone) ) @@ -332,6 +340,14 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_utf8_reorder_bidi) ) #endif + +#pragma comment (linker, EXPORT_SYMBOL(gf_lang_get_count) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_lang_find) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_lang_get_name) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_lang_get_2cc) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_lang_get_3cc) ) + + #ifndef GPAC_DISABLE_CORE_TOOLS #pragma comment (linker, EXPORT_SYMBOL(gf_dm_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_new) ) @@ -348,6 +364,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_reset) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_mime_type) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_get_header) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_get_header_sizes_and_times) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_set_data_rate) ) @@ -357,7 +374,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_cache_get_cache_filename) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cache_create_entry) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cache_get_mime_type) ) -#pragma comment (linker, EXPORT_SYMBOL(appendHttpCacheHeaders) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_cache_append_http_headers) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cache_open_write_cache) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cache_set_last_modified_on_server) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cache_set_etag_on_server) ) @@ -373,6 +390,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_set_range) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_setup_from_url) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dm_get_file_memory) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dm_get_global_rate) ) + #pragma comment (linker, EXPORT_SYMBOL(gf_dm_sess_can_be_cached_on_disk) ) @@ -400,6 +419,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_get_attribute) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_set_attribute) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_append_child) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_rem_child) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_node_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_get_root) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_get_error) ) @@ -407,6 +427,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_serialize) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_node_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_parse_string) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_get_root_nodes_count) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_get_root_idx) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_parse_bit_sequence) ) #pragma comment (linker, EXPORT_SYMBOL(gf_xml_dom_detach_root) ) #endif @@ -525,6 +547,9 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_cmx_multiply) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cmx_apply) ) #pragma comment (linker, EXPORT_SYMBOL(gf_cmx_apply_fixed) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_color_parse) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_color_get_name) ) + /*path2d.h exports*/ #pragma comment (linker, EXPORT_SYMBOL(gf_path_new) ) @@ -595,6 +620,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_odf_avc_cfg_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_avc_cfg_new) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_odf_avc_cfg_read) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_odf_avc_cfg_write) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_hevc_cfg_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_hevc_cfg_read) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odf_hevc_cfg_del) ) @@ -625,8 +652,6 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_oci_codec_encode) ) #pragma comment (linker, EXPORT_SYMBOL(gf_oci_codec_decode) ) #pragma comment (linker, EXPORT_SYMBOL(gf_oci_codec_get_event) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_odf_avc_cfg_read) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_odf_avc_cfg_write) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sl_packetize) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sl_get_header_size) ) #endif /*GPAC_MINIMAL_ODF*/ @@ -643,10 +668,13 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_mode) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_file_size) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_moov_first) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_timed_meta_data_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_box_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_box_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_parse_box) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_xml_metadata_description) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_dims_description) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_stxt_get_description) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_xml_subtitle_get_description) ) #ifndef GPAC_DISABLE_ISOM_WRITE #pragma comment (linker, EXPORT_SYMBOL(gf_isom_box_write) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_box_size) ) @@ -692,6 +720,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_sample_padding) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_info) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_flags) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_for_media_time) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_for_movie_time) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_dts) ) @@ -781,7 +810,6 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_media_data_size) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_omadrm_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_is_omadrm_media) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_dims_description) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_track_switch_group_count) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_track_switch_parameter) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_next_alternate_group_id) ) @@ -801,6 +829,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_adobe_protection_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_sample_group_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_tile_info) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_udta_count) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_udta_type) ) #ifndef GPAC_DISABLE_ISOM_WRITE #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_sync_table) ) @@ -831,6 +861,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_track) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_creation_time) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_track_creation_time) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_update_duration) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_track_enabled) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_track_id) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_rewrite_track_dependencies) ) @@ -847,6 +878,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_sample) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_final_name) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_storage_mode) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_force_64bit_chunk_offset) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_storage_mode) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_interleave_time) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_interleave_time) ) @@ -854,20 +886,27 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_media_type) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_media_subtype) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_copyright) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_add_track_kind) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_track_kind) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_track_kind) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_get_track_kind_count) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_watermark) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_edit_segment) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_modify_edit_segment) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_append_edit_segment) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_edit_segments) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_edit_segment) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_update_edit_list_duration) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_media_language) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_handler_name) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_add_user_data) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_add_user_data_boxes) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_user_data) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_user_data_item) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_use_compact_size) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_brand_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_modify_alternate_brand) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_reset_alt_brands) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_sample_padding_bits) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_visual_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_pixel_aspect_ratio) ) @@ -891,6 +930,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_add_desc_to_description) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_new_generic_sample_description) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_change_generic_sample_description) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_update_bitrate) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_sample_description) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_clone_sample_description) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_clone_track) ) @@ -928,6 +968,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_isom_text_add_blink) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_text_set_wrap) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_text_to_sample) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_isom_text_set_display_flags) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_remove_track_protection) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_set_ismacryp_protection) ) #pragma comment (linker, EXPORT_SYMBOL(gf_isom_change_ismacryp_protection) ) @@ -1060,6 +1101,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_service_download_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_service_download_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_service_download_update_stats) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_term_service_command) ) /*mediaobject.h exports*/ #pragma comment (linker, EXPORT_SYMBOL(gf_mo_register) ) @@ -1091,6 +1133,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_mo_get_flags) ) #pragma comment (linker, EXPORT_SYMBOL(gf_mo_set_flag) ) #pragma comment (linker, EXPORT_SYMBOL(gf_mo_get_min_frame_dur) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_mo_get_clock_drift) ) + #ifndef GPAC_DISABLE_SVG #pragma comment (linker, EXPORT_SYMBOL(gf_mo_load_xlink_resource) ) @@ -1236,6 +1280,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_media_import_chapters) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_change_pl) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_nalu_next_start_code_bs) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_media_nalu_payload_end_bs) ) + #pragma comment (linker, EXPORT_SYMBOL(gf_media_avc_rewrite_samples) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_split_svc) ) #pragma comment (linker, EXPORT_SYMBOL(gf_media_merge_svc) ) @@ -1309,10 +1355,12 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_mp3_get_next_header) ) #pragma comment (linker, EXPORT_SYMBOL(gf_mp3_get_next_header_mem) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m4a_get_config) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_m4a_get_channel_cfg) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m4a_write_config) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m4a_write_config_bs) ) #pragma comment (linker, EXPORT_SYMBOL(gf_ac3_parser_bs) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_eac3_parser_bs) ) #pragma comment (linker, EXPORT_SYMBOL(gf_ac3_get_channels) ) #pragma comment (linker, EXPORT_SYMBOL(gf_ac3_get_bitrate) ) #ifndef GPAC_DISABLE_OGG @@ -1446,10 +1494,11 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_bifs_encoder_get_config) ) #pragma comment (linker, EXPORT_SYMBOL(gf_bifs_encoder_get_version) ) #pragma comment (linker, EXPORT_SYMBOL(gf_bifs_encoder_get_rap) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_bifs_encoder_set_source_url) ) #endif #endif /*GPAC_DISABLE_BIFS*/ -#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_SVG) +#if !defined(GPAC_DISABLE_VRML) || !defined(GPAC_DISABLE_X3D) || !defined(GPAC_DISABLE_SVG) /*scenegraph.h exports*/ #pragma comment (linker, EXPORT_SYMBOL(gf_node_get_tag) ) @@ -1480,7 +1529,6 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_node_get_graph) ) #pragma comment (linker, EXPORT_SYMBOL(gf_node_init) ) #pragma comment (linker, EXPORT_SYMBOL(gf_node_get_scene_time) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_node_in_table_by_tag) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_new_subscene) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_set_scene_time_callback) ) @@ -1556,17 +1604,9 @@ #ifdef GPAC_HAS_SPIDERMONKEY -#pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_get_node) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_js_add_root) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_js_add_named_root) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_js_remove_root) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_js_vrml_flush_event_out) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_has_instance) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_sg_lock_javascript) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_sg_try_lock_javascript) ) #ifndef GPAC_DISABLE_SVG -#pragma comment (linker, EXPORT_SYMBOL(dom_js_pre_destroy) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_dom_pre_destroy) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_event_add_listener) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_event_remove_listener) ) #endif @@ -1598,6 +1638,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sg_vrml_field_copy) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_vrml_field_equal) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_route_new) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sg_route_new_to_callback) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_route_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_route_del_by_id) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_route_find) ) @@ -1632,6 +1673,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sg_proto_get_class_name) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_proto_field_is_sftime_offset) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_proto_instance_set_ised) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_node_set_proto_eventin_handler) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_script_field_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_script_field_get_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_script_load) ) @@ -1642,6 +1684,11 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sg_get_next_available_proto_id) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_set_proto_loader) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sg_sfcolor_to_rgba) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_node_in_table_by_tag) ) +#ifdef GPAC_HAS_SPIDERMONKEY +#pragma comment (linker, EXPORT_SYMBOL(gf_js_vrml_flush_event_out) ) +#endif + #ifndef GPAC_DISABLE_X3D #pragma comment (linker, EXPORT_SYMBOL(gf_node_x3d_type_by_class_name) ) @@ -1658,6 +1705,16 @@ #endif //!defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_SVG) +#ifdef GPAC_HAS_SPIDERMONKEY +#pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_get_node) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_js_add_root) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_js_add_named_root) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_js_remove_root) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sg_js_has_instance) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sg_lock_javascript) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sg_try_lock_javascript) ) +#endif + #ifndef GPAC_DISABLE_PLAYER /*terminal.h exports*/ @@ -1698,6 +1755,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_term_get_simulation_frame_rate) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_step_clocks) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_process_flush) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_term_process_flush_video) ) #pragma comment (linker, EXPORT_SYMBOL(gf_service_get_interface) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_get_service_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_get_text_selection) ) @@ -1724,6 +1782,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_term_remove_event_filter) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_lock_media_queue) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_get_current_service_id) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_term_get_clock) ) /*terminal_dev exports*/ #pragma comment (linker, EXPORT_SYMBOL(gf_scene_new) ) @@ -1737,6 +1796,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_scene_force_size) ) #pragma comment (linker, EXPORT_SYMBOL(gf_scene_process_anchor) ) #pragma comment (linker, EXPORT_SYMBOL(gf_scene_disconnect) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_scene_register_associated_media) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_scene_set_addon_layout_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odm_new) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odm_setup_object) ) #pragma comment (linker, EXPORT_SYMBOL(gf_odm_disconnect) ) @@ -1745,8 +1806,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_term_node_callback) ) #pragma comment (linker, EXPORT_SYMBOL(gf_term_message) ) #pragma comment (linker, EXPORT_SYMBOL(gf_clock_time) ) -//for Ivica #pragma comment (linker, EXPORT_SYMBOL(gf_scene_get_media_object_ex) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_scene_resume_live) ) #endif @@ -1768,7 +1829,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sc_get_fps) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_get_screen_buffer) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_release_screen_buffer) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_sc_simulation_tick) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sc_render_frame) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_reset_graphics) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_pick_node) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_get_viewpoint) ) @@ -1782,6 +1843,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_sc_add_audio_listener) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_remove_audio_listener) ) #pragma comment (linker, EXPORT_SYMBOL(gf_sc_focus_switch_ring) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_sc_is_over) ) #ifndef GPAC_DISABLE_SVG #pragma comment (linker, EXPORT_SYMBOL(gf_sc_animation_get_scenegraph) ) @@ -1822,6 +1884,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_demux_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_process_data) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_reset_parsers) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_reset_parsers_for_program) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_es_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_set_pes_framing) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_get_stream_name) ) @@ -1830,6 +1893,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_demux_file) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_pes_get_framing_mode) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_get_sdt_info) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_abort_parsing) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_pause_demux) ) /* carousel.h */ @@ -1865,8 +1930,9 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_mpd_init_from_dom) ) #pragma comment (linker, EXPORT_SYMBOL(gf_mpd_del) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m3u8_to_mpd) ) -#pragma comment (linker, EXPORT_SYMBOL(parse_root_playlist) ) -#pragma comment (linker, EXPORT_SYMBOL(variant_playlist_del) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_m3u8_parse_master_playlist) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_mpd_write_file) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_mpd_resolve_url) ) #pragma comment (linker, EXPORT_SYMBOL(gf_m2ts_demuxer_setup)) @@ -1929,6 +1995,7 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dash_open) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_close) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_url) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_is_m3u8) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_group_count) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_group_udta) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_group_udta) ) @@ -1938,9 +2005,11 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_switch_quality) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_duration) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_time_shift_buffer_depth) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_check_mpd_root_type) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_segment_mime) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_segment_init_url) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_segment_init_keys) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_select) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_groups_set_language) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_in_last_period) ) @@ -1955,14 +2024,13 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_group_done) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_in_period_setup) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_seek) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_playback_start_range) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_start_range) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_segment_switch_forced) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_current_segment_start_time) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_presentation_time_offset) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_video_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_representation_info) ) -#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_buffer_info_buffering) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_buffer_info) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_check_bandwidth) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_resync_to_segment) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_loop_detected) ) @@ -1975,6 +2043,23 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_min_timeout_between_404) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_segment_expiration_threshold) ) #pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_user_buffer) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_speed) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_switching_probe_count) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_period_start) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_period_duration) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_language) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_audio_channels) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_enum_descriptor) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_num_qualities) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_quality_info) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_automatic_switching) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_automatic_switching) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_select_quality) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_group_get_download_rate) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_set_timeshift) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_dash_get_timeshift_buffer_pos) ) + + #endif #ifndef GPAC_DISABLE_ISOM_WRITE diff --git a/src/ietf/rtcp.c b/src/ietf/rtcp.c index cdeccd2..aff7f27 100644 --- a/src/ietf/rtcp.c +++ b/src/ietf/rtcp.c @@ -94,7 +94,7 @@ GF_Err gf_rtp_decode_rtcp(GF_RTPChannel *ch, char *pck, u32 pck_size, Bool *has_ || rtcp_hdr.Padding ) { gf_bs_del(bs); - GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTCP] Corrupted RTCP packet: payload type %d (200 or 201 expected) - Padding %d (0 expected)\n", rtcp_hdr.PayloadType, rtcp_hdr.Padding)); + GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTCP] Corrupted RTCP packet: payload type %d (200 or 201 expected) - Padding %d (0 expected)\n", rtcp_hdr.PayloadType, rtcp_hdr.Padding)); return GF_CORRUPTED_DATA; } first = 0; diff --git a/src/ietf/rtp.c b/src/ietf/rtp.c index 444bafa..cad2be2 100644 --- a/src/ietf/rtp.c +++ b/src/ietf/rtp.c @@ -211,7 +211,7 @@ GF_Err gf_rtp_initialize(GF_RTPChannel *ch, u32 UDPBufferSize, Bool IsSource, u3 if (!IsSource) { port = ch->net_info.port_first; if (!port) port = ch->net_info.client_port_first; - /*if a destination adress was given (rtsd) use it*/ + /*if a destination address was given (rtsd) use it*/ if (!local_ip && ch->net_info.destination) local_ip = ch->net_info.destination; e = gf_sk_bind(ch->rtp, local_ip, ch->net_info.client_port_first, ch->net_info.source, port, GF_SOCK_REUSE_PORT); @@ -254,7 +254,7 @@ GF_Err gf_rtp_initialize(GF_RTPChannel *ch, u32 UDPBufferSize, Bool IsSource, u3 if (!IsSource) { port = ch->net_info.port_last; if (!port) port = ch->net_info.client_port_last; - /*if a destination adress was given (rtsd) use it*/ + /*if a destination address was given (rtsd) use it*/ if (!local_ip && ch->net_info.destination) local_ip = ch->net_info.destination; e = gf_sk_bind(ch->rtcp, local_ip, ch->net_info.client_port_last, ch->net_info.source, port, GF_SOCK_REUSE_PORT); @@ -438,7 +438,7 @@ GF_Err gf_rtp_decode_rtp(GF_RTPChannel *ch, char *pck, u32 pck_size, GF_RTPHeade } if (ch->first_SR && !ch->SenderSSRC && rtp_hdr->SSRC) { ch->SenderSSRC = rtp_hdr->SSRC; - GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] Assigning SSRC %d because none has been signaled\n", ch->SenderSSRC)); + GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTP] Assigning SSRC to %d because none was specified through SDP/RTSP\n", ch->SenderSSRC)); } @@ -459,6 +459,24 @@ GF_Err gf_rtp_decode_rtp(GF_RTPChannel *ch, char *pck, u32 pck_size, GF_RTPHeade ch->num_sn_loops += 1; } + if (ch->last_SR_rtp_time) { + s32 diff_sec = ((s32) rtp_hdr->TimeStamp - (s32) ch->last_SR_rtp_time) / (s32) ch->TimeScale; + u32 sec = ch->last_SR_NTP_sec; + s64 frac = ch->last_SR_NTP_frac; + + frac = (s32) rtp_hdr->TimeStamp - (s32) ch->last_SR_rtp_time - diff_sec*(s32)ch->TimeScale; + frac *= 0xFFFFFFFF; + frac /= ch->TimeScale; + frac += ch->last_SR_NTP_frac; + if (frac>0xFFFFFFFF) { + sec += 1; + frac -= 0xFFFFFFFF; + } + rtp_hdr->recomputed_ntp_ts = sec + diff_sec; + rtp_hdr->recomputed_ntp_ts <<= 32; + rtp_hdr->recomputed_ntp_ts |= frac; + } + ntp = gf_rtp_channel_time(ch); deviance = ntp - rtp_hdr->TimeStamp; delta = deviance - ch->last_deviance; diff --git a/src/ietf/rtp_depacketizer.c b/src/ietf/rtp_depacketizer.c index 802d8db..f54259b 100644 --- a/src/ietf/rtp_depacketizer.c +++ b/src/ietf/rtp_depacketizer.c @@ -524,7 +524,7 @@ static void gf_rtp_parse_ttxt(GF_RTPDepacketizer *rtp, GF_RTPHeader *hdr, char * gf_bs_read_u16(bs);/*complete text sample size, ignored*/ txt_size = size - 10; - /*init - 3GPP/MPEG-4 spliting is IMHO stupid: + /*init - 3GPP/MPEG-4 splitting is IMHO stupid: - nb frag & cur frags are not needed: rtp reordering insures packet are in order, and !!!we assume fragments are sent in order!!! - any other TTU suffices to indicate end of text string (modifiers or != RTP TS) @@ -1009,6 +1009,7 @@ static void gf_rtp_parse_ac3(GF_RTPDepacketizer *rtp, GF_RTPHeader *hdr, char *p if (!ft) { GF_AC3Header hdr; + memset(&hdr, 0, sizeof(GF_AC3Header)); rtp->sl_hdr.accessUnitStartFlag = rtp->sl_hdr.accessUnitEndFlag = 1; while (size) { u32 offset; @@ -1222,7 +1223,7 @@ static GF_Err gf_rtp_payt_setup(GF_RTPDepacketizer *rtp, GF_RTPMap *map, GF_SDPM #ifndef GPAC_DISABLE_AV_PARSERS case GF_RTP_PAYT_LATM: { - u32 AudioMuxVersion, AllStreamsSameTime, numSubFrames, numPrograms, numLayers; + u32 AudioMuxVersion, AllStreamsSameTime, numSubFrames, numPrograms, numLayers, ch_cfg; GF_M4ADecSpecInfo cfg; char *latm_dsi = rtp->sl_map.config; GF_BitStream *bs = gf_bs_new(latm_dsi, rtp->sl_map.configSize, GF_BITSTREAM_READ); @@ -1244,7 +1245,7 @@ static GF_Err gf_rtp_payt_setup(GF_RTPDepacketizer *rtp, GF_RTPMap *map, GF_SDPM } else { cfg.base_sr = GF_M4ASampleRates[cfg.base_sr_index]; } - cfg.nb_chan = gf_bs_read_int(bs, 4); + ch_cfg = gf_bs_read_int(bs, 4); if (cfg.base_object_type==5 || cfg.base_object_type==29) { if (cfg.base_object_type==29) { cfg.has_ps = 1; @@ -1265,7 +1266,8 @@ static GF_Err gf_rtp_payt_setup(GF_RTPDepacketizer *rtp, GF_RTPMap *map, GF_SDPM /*write as regular AAC*/ gf_bs_write_int(bs, cfg.base_object_type, 5); gf_bs_write_int(bs, cfg.base_sr_index, 4); - gf_bs_write_int(bs, cfg.nb_chan, 4); + + gf_bs_write_int(bs, ch_cfg, 4); gf_bs_align(bs); gf_bs_get_content(bs, &rtp->sl_map.config, &rtp->sl_map.configSize); gf_bs_del(bs); @@ -1725,6 +1727,7 @@ GF_EXPORT void gf_rtp_depacketizer_process(GF_RTPDepacketizer *rtp, GF_RTPHeader *hdr, char *payload, u32 size) { assert(rtp && rtp->depacketize); + rtp->sl_hdr.sender_ntp = hdr->recomputed_ntp_ts; rtp->depacketize(rtp, hdr, payload, size); } diff --git a/src/ietf/rtp_packetizer.c b/src/ietf/rtp_packetizer.c index bf57b3a..087bd9e 100644 --- a/src/ietf/rtp_packetizer.c +++ b/src/ietf/rtp_packetizer.c @@ -28,7 +28,7 @@ #ifndef GPAC_DISABLE_STREAMING #include <gpac/constants.h> -#include <gpac/math.h> +#include <gpac/maths.h> void InitSL_RTP(GF_SLConfig *slc); diff --git a/src/ietf/rtp_pck_mpeg4.c b/src/ietf/rtp_pck_mpeg4.c index 7a721be..e52dc2f 100644 --- a/src/ietf/rtp_pck_mpeg4.c +++ b/src/ietf/rtp_pck_mpeg4.c @@ -251,7 +251,7 @@ GF_Err gp_rtp_builder_do_mpeg4(GP_RTPPacketizer *builder, char *data, u32 data_s /*first SL in RTP*/ builder->first_sl_in_rtp = 1; - /*if this is the end of an AU we will set it to 0 as soon as an AU is splited*/ + /*if this is the end of an AU we will set it to 0 as soon as an AU is splitted*/ builder->rtp_header.Marker = 1; builder->rtp_header.PayloadType = builder->PayloadType; builder->rtp_header.SequenceNumber += 1; diff --git a/src/ietf/rtp_streamer.c b/src/ietf/rtp_streamer.c index a4531ee..fad3b3a 100644 --- a/src/ietf/rtp_streamer.c +++ b/src/ietf/rtp_streamer.c @@ -387,6 +387,12 @@ GF_RTPStreamer *gf_rtp_streamer_new_extended(u32 streamType, u32 oti, u32 timeSc oti = (oti==GF_ISOM_SUBTYPE_3GP_EVRC) ? GPAC_OTI_AUDIO_EVRC_VOICE : GPAC_OTI_AUDIO_SMV_VOICE; nb_ch = 1; break; + case GF_ISOM_SUBTYPE_MP3: + rtp_type = GF_RTP_PAYT_MPEG12_AUDIO; + /*use official RTP/AVP payload type*/ + OfficialPayloadType = 14; + required_rate = 90000; + break; } break; @@ -774,13 +780,13 @@ char *gf_rtp_streamer_format_sdp_header(char *app_name, char *ip_dest, char *ses if (iod64) fprintf(tmp, "a=mpeg4-iod:\"data:application/mpeg4-iod;base64,%s\"\n", iod64); - gf_f64_seek(tmp, 0, SEEK_END); - size = gf_f64_tell(tmp); - gf_f64_seek(tmp, 0, SEEK_SET); + gf_fseek(tmp, 0, SEEK_END); + size = gf_ftell(tmp); + gf_fseek(tmp, 0, SEEK_SET); sdp = gf_malloc(sizeof(char) * (size_t)(size+1)); size = fread(sdp, 1, (size_t)size, tmp); sdp[size] = 0; - fclose(tmp); + gf_fclose(tmp); return sdp; } diff --git a/src/ietf/rtsp_session.c b/src/ietf/rtsp_session.c index 29ef73a..6c7a384 100644 --- a/src/ietf/rtsp_session.c +++ b/src/ietf/rtsp_session.c @@ -417,7 +417,7 @@ GF_Err gf_rtsp_set_deinterleave(GF_RTSPSession *sess) } /*end of packet*/ else if (sess->payloadSize - sess->pck_start <= Size) { -// GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed begining of packet (%d bytes) in stream %d\n", Size, sess->InterID)); +// GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed beginning of packet (%d bytes) in stream %d\n", Size, sess->InterID)); res = sess->payloadSize - sess->pck_start; memcpy(sess->rtsp_pck_buf + sess->pck_start, buffer, res); @@ -435,7 +435,7 @@ GF_Err gf_rtsp_set_deinterleave(GF_RTSPSession *sess) } /*middle of packet*/ else { -// GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed begining of RTP packet in stream %d\n", sess->InterID)); +// GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed beginning of RTP packet in stream %d\n", sess->InterID)); memcpy(sess->rtsp_pck_buf + sess->pck_start, buffer, Size); sess->pck_start += Size; sess->CurrentPos += Size; diff --git a/src/ietf/sdp.c b/src/ietf/sdp.c index 3473409..25643c8 100644 --- a/src/ietf/sdp.c +++ b/src/ietf/sdp.c @@ -453,16 +453,19 @@ s32 SDP_MakeSeconds(char *buf) memset(num, 0, 30); test = strstr(buf, "d"); if (test) { + assert(strlen(buf)-strlen(test) < sizeof(num)); strncpy(num, buf, strlen(buf)-strlen(test)); return (atoi(num)*sign*86400); } test = strstr(buf, "h"); if (test) { + assert(strlen(buf)-strlen(test) < sizeof(num)); strncpy(num, buf, strlen(buf)-strlen(test)); return (atoi(num)*sign*3600); } test = strstr(buf, "m"); if (test) { + assert(strlen(buf)-strlen(test) < sizeof(num)); strncpy(num, buf, strlen(buf)-strlen(test)); return (atoi(num)*sign*60); } diff --git a/src/isomedia/avc_ext.c b/src/isomedia/avc_ext.c index cb21f70..b46d167 100644 --- a/src/isomedia/avc_ext.c +++ b/src/isomedia/avc_ext.c @@ -198,22 +198,41 @@ static GF_Err process_extractor(GF_ISOFile *file, GF_MediaBox *mdia, u32 sampleN return GF_OK; } -static u8 is_sample_idr(GF_ISOSample *sample, GF_MPEGVisualSampleEntryBox *entry) +#ifndef GPAC_DISABLE_HEVC +/* returns the SAP type as defined in the 14496-12 specification */ +static SAPType sap_type_from_nal_type(u8 nal_type) { + switch (nal_type) { + case GF_HEVC_NALU_SLICE_CRA: + return SAP_TYPE_3; + case GF_HEVC_NALU_SLICE_IDR_N_LP: + case GF_HEVC_NALU_SLICE_BLA_N_LP: + return SAP_TYPE_1; + case GF_HEVC_NALU_SLICE_IDR_W_DLP: + case GF_HEVC_NALU_SLICE_BLA_W_DLP: + case GF_HEVC_NALU_SLICE_BLA_W_LP: + return SAP_TYPE_2; + default: + return RAP_NO; + } +} +#endif + +static SAPType is_sample_idr(GF_ISOSample *sample, GF_MPEGVisualSampleEntryBox *entry) { - Bool is_hevc = 0; + Bool is_hevc = GF_FALSE; u32 nalu_size_field = 0; GF_BitStream *bs; if (entry->avc_config && entry->avc_config->config) nalu_size_field = entry->avc_config->config->nal_unit_size; else if (entry->svc_config && entry->svc_config->config) nalu_size_field = entry->svc_config->config->nal_unit_size; else if (entry->hevc_config && entry->hevc_config->config) { nalu_size_field = entry->hevc_config->config->nal_unit_size; - is_hevc = 1; + is_hevc = GF_TRUE; } else if (entry->shvc_config && entry->shvc_config->config) { nalu_size_field = entry->shvc_config->config->nal_unit_size; - is_hevc = 1; + is_hevc = GF_TRUE; } - if (!nalu_size_field) return 0; + if (!nalu_size_field) return RAP_NO; bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ); while (gf_bs_available(bs)) { @@ -226,26 +245,28 @@ static u8 is_sample_idr(GF_ISOSample *sample, GF_MPEGVisualSampleEntryBox *entry nal_type = (nal_hdr&0x7E00) >> 9; switch (nal_type) { - case GF_HEVC_NALU_VID_PARAM: - case GF_HEVC_NALU_SEQ_PARAM: - case GF_HEVC_NALU_PIC_PARAM: - case GF_HEVC_NALU_SLICE_BLA_W_LP: - case GF_HEVC_NALU_SLICE_BLA_W_DLP: - case GF_HEVC_NALU_SLICE_BLA_N_LP: case GF_HEVC_NALU_SLICE_CRA: gf_bs_del(bs); - return 3; - case GF_HEVC_NALU_SLICE_IDR_W_DLP: + return SAP_TYPE_3; case GF_HEVC_NALU_SLICE_IDR_N_LP: + case GF_HEVC_NALU_SLICE_BLA_N_LP: gf_bs_del(bs); - return 1; + return SAP_TYPE_1; + case GF_HEVC_NALU_SLICE_IDR_W_DLP: + case GF_HEVC_NALU_SLICE_BLA_W_DLP: + case GF_HEVC_NALU_SLICE_BLA_W_LP: + gf_bs_del(bs); + return SAP_TYPE_2; case GF_HEVC_NALU_ACCESS_UNIT: case GF_HEVC_NALU_FILLER_DATA: case GF_HEVC_NALU_SEI_PREFIX: + case GF_HEVC_NALU_VID_PARAM: + case GF_HEVC_NALU_SEQ_PARAM: + case GF_HEVC_NALU_PIC_PARAM: break; default: gf_bs_del(bs); - return 0; + return RAP_NO; } gf_bs_skip_bytes(bs, size - 2); #endif @@ -254,26 +275,26 @@ static u8 is_sample_idr(GF_ISOSample *sample, GF_MPEGVisualSampleEntryBox *entry nal_type = nal_hdr & 0x1F; switch (nal_type) { - case GF_AVC_NALU_SEQ_PARAM: - case GF_AVC_NALU_PIC_PARAM: - case GF_AVC_NALU_SEQ_PARAM_EXT: - case GF_AVC_NALU_SVC_SUBSEQ_PARAM: - case GF_AVC_NALU_IDR_SLICE: + /* case GF_AVC_NALU_SEQ_PARAM: + case GF_AVC_NALU_PIC_PARAM: + case GF_AVC_NALU_SEQ_PARAM_EXT: + case GF_AVC_NALU_SVC_SUBSEQ_PARAM: + */ case GF_AVC_NALU_IDR_SLICE: gf_bs_del(bs); - return 1; + return SAP_TYPE_1; case GF_AVC_NALU_ACCESS_UNIT: case GF_AVC_NALU_FILLER_DATA: case GF_AVC_NALU_SEI: break; default: gf_bs_del(bs); - return 0; + return RAP_NO; } - gf_bs_skip_bytes(bs, size - 2); + gf_bs_skip_bytes(bs, size - 1); } } gf_bs_del(bs); - return 0; + return RAP_NO; } static void nalu_merge_ps(GF_BitStream *ps_bs, Bool rewrite_start_codes, u32 nal_unit_size_field, GF_MPEGVisualSampleEntryBox *entry, Bool is_hevc) @@ -312,7 +333,7 @@ static void nalu_merge_ps(GF_BitStream *ps_bs, Bool rewrite_start_codes, u32 nal GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry) { - Bool is_hevc = 0; + Bool is_hevc = GF_FALSE; //if only one sync given in the sample sync table, insert sps/pps/vps before cra/bla in hevc // Bool check_cra_bla = (mdia->information->sampleTable->SyncSample && mdia->information->sampleTable->SyncSample->nb_entries>1) ? 0 : 1; Bool check_cra_bla = 1; @@ -335,8 +356,10 @@ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 buffer = NULL; rewrite_ps = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ? 1 : 0; - if (mdia->information->sampleTable->no_sync_found || (!sample->IsRAP && check_cra_bla) ) { - sample->IsRAP = is_sample_idr(sample, entry); + if (sample->IsRAP < SAP_TYPE_2) { + if (mdia->information->sampleTable->no_sync_found || (!sample->IsRAP && check_cra_bla) ) { + sample->IsRAP = is_sample_idr(sample, entry); + } } if (!sample->IsRAP) rewrite_ps = 0; @@ -366,7 +389,7 @@ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 /*if shvc rewrite*/ else if (entry->shvc_config && entry->shvc_config->config) { - is_hevc = 1; + is_hevc = GF_TRUE; nal_unit_size_field = entry->shvc_config->config->nal_unit_size; } @@ -379,7 +402,7 @@ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 if (entry->avc_config) nal_unit_size_field = entry->avc_config->config->nal_unit_size; else if (entry->hevc_config || entry->shvc_config ) { nal_unit_size_field = entry->shvc_config ? entry->shvc_config->config->nal_unit_size : entry->hevc_config->config->nal_unit_size; - is_hevc = 1; + is_hevc = GF_TRUE; } } @@ -448,7 +471,7 @@ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 if (!rewrite_start_codes && !entry->shvc_config && !scal) { if (ps_bs) { u8 nal_type = (sample->data[nal_unit_size_field] & 0x7E) >> 1; - //temp fix - if we detect xPS in the begining of the sample do NOT copy the ps bitstream + //temp fix - if we detect xPS in the beginning of the sample do NOT copy the ps bitstream //this is not correct since we are not sure whether they are the same xPS or not, but it crashes openHEVC ... switch (nal_type) { #ifndef GPAC_DISABLE_HEVC @@ -541,7 +564,7 @@ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 case GF_HEVC_NALU_SLICE_IDR_W_DLP: case GF_HEVC_NALU_SLICE_IDR_N_LP: case GF_HEVC_NALU_SLICE_CRA: - //insert xPS before CRA/BLS + //insert xPS before CRA/BLA if (check_cra_bla && !sample->IsRAP) { if (ref_samp) gf_isom_sample_del(&ref_samp); if (src_bs) gf_bs_del(src_bs); @@ -549,7 +572,7 @@ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 if (dst_bs) gf_bs_del(dst_bs); if (buffer) gf_free(buffer); - sample->IsRAP=3; + sample->IsRAP = sap_type_from_nal_type(nal_type); return gf_isom_nalu_sample_rewrite(mdia, sample, sampleNumber, entry); } default: @@ -798,6 +821,8 @@ void merge_all_config(GF_AVCConfig *avc_cfg, GF_HEVCConfig *hevc_cfg, GF_MediaBo void AVC_RewriteESDescriptorEx(GF_MPEGVisualSampleEntryBox *avc, GF_MediaBox *mdia) { GF_AVCConfig *avcc, *svcc; + GF_BitRateBox *btrt = gf_isom_sample_entry_get_bitrate((GF_SampleEntryBox *)avc, GF_FALSE); + if (avc->emul_esd) gf_odf_desc_del((GF_Descriptor *)avc->emul_esd); avc->emul_esd = gf_odf_desc_esd_new(2); avc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL; @@ -807,10 +832,11 @@ void AVC_RewriteESDescriptorEx(GF_MPEGVisualSampleEntryBox *avc, GF_MediaBox *md avc->emul_esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_SVC; else avc->emul_esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_AVC; - if (avc->bitrate) { - avc->emul_esd->decoderConfig->bufferSizeDB = avc->bitrate->bufferSizeDB; - avc->emul_esd->decoderConfig->avgBitrate = avc->bitrate->avgBitrate; - avc->emul_esd->decoderConfig->maxBitrate = avc->bitrate->maxBitrate; + + if (btrt) { + avc->emul_esd->decoderConfig->bufferSizeDB = btrt->bufferSizeDB; + avc->emul_esd->decoderConfig->avgBitrate = btrt->avgBitrate; + avc->emul_esd->decoderConfig->maxBitrate = btrt->maxBitrate; } if (avc->descr) { u32 i=0; @@ -852,6 +878,8 @@ void AVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *avc) void HEVC_RewriteESDescriptorEx(GF_MPEGVisualSampleEntryBox *hevc, GF_MediaBox *mdia) { + GF_BitRateBox *btrt = gf_isom_sample_entry_get_bitrate((GF_SampleEntryBox *)hevc, GF_FALSE); + if (hevc->emul_esd) gf_odf_desc_del((GF_Descriptor *)hevc->emul_esd); hevc->emul_esd = gf_odf_desc_esd_new(2); hevc->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL; @@ -859,10 +887,10 @@ void HEVC_RewriteESDescriptorEx(GF_MPEGVisualSampleEntryBox *hevc, GF_MediaBox * if (hevc->shvc_config && !hevc->hevc_config) hevc->emul_esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_SHVC; - if (hevc->bitrate) { - hevc->emul_esd->decoderConfig->bufferSizeDB = hevc->bitrate->bufferSizeDB; - hevc->emul_esd->decoderConfig->avgBitrate = hevc->bitrate->avgBitrate; - hevc->emul_esd->decoderConfig->maxBitrate = hevc->bitrate->maxBitrate; + if (btrt) { + hevc->emul_esd->decoderConfig->bufferSizeDB = btrt->bufferSizeDB; + hevc->emul_esd->decoderConfig->avgBitrate = btrt->avgBitrate; + hevc->emul_esd->decoderConfig->maxBitrate = btrt->maxBitrate; } if (hevc->descr) { u32 i=0; @@ -900,12 +928,13 @@ void HEVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *hevc) GF_Err AVC_HEVC_UpdateESD(GF_MPEGVisualSampleEntryBox *avc, GF_ESD *esd) { - if (!avc->bitrate) avc->bitrate = (GF_MPEG4BitRateBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT); + GF_BitRateBox *btrt = gf_isom_sample_entry_get_bitrate((GF_SampleEntryBox *)avc, GF_TRUE); + if (avc->descr) gf_isom_box_del((GF_Box *) avc->descr); avc->descr = NULL; - avc->bitrate->avgBitrate = esd->decoderConfig->avgBitrate; - avc->bitrate->maxBitrate = esd->decoderConfig->maxBitrate; - avc->bitrate->bufferSizeDB = esd->decoderConfig->bufferSizeDB; + btrt->avgBitrate = esd->decoderConfig->avgBitrate; + btrt->maxBitrate = esd->decoderConfig->maxBitrate; + btrt->bufferSizeDB = esd->decoderConfig->bufferSizeDB; if (gf_list_count(esd->IPIDataSet) || gf_list_count(esd->IPMPDescriptorPointers) @@ -1301,12 +1330,12 @@ GF_Err gf_isom_hevc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber, u32 } else if (operand_type != GF_ISOM_HVCC_SET_TILE) { operand_type=GF_ISOM_HVCC_SET_INBAND; } - array_incomplete = 0; + array_incomplete = (operand_type==GF_ISOM_HVCC_SET_INBAND) ? 1 : 0; for (i=0; i<gf_list_count(entry->hevc_config->config->param_array); i++) { GF_HEVCParamArray *ar = gf_list_get(entry->hevc_config->config->param_array, i); /*we want to force hev1*/ - if (operand_type==GF_ISOM_HVCC_SET_INBAND) + if (operand_type==GF_ISOM_HVCC_SET_INBAND) ar->array_completeness = 0; if (!ar->array_completeness) { @@ -1522,12 +1551,12 @@ GF_HEVCConfig *gf_isom_shvc_config_get(GF_ISOFile *the_file, u32 trackNumber, u3 void btrt_del(GF_Box *s) { - GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *)s; + GF_BitRateBox *ptr = (GF_BitRateBox *)s; if (ptr) gf_free(ptr); } GF_Err btrt_Read(GF_Box *s, GF_BitStream *bs) { - GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *)s; + GF_BitRateBox *ptr = (GF_BitRateBox *)s; ptr->bufferSizeDB = gf_bs_read_u32(bs); ptr->maxBitrate = gf_bs_read_u32(bs); ptr->avgBitrate = gf_bs_read_u32(bs); @@ -1535,9 +1564,9 @@ GF_Err btrt_Read(GF_Box *s, GF_BitStream *bs) } GF_Box *btrt_New() { - GF_MPEG4BitRateBox *tmp = (GF_MPEG4BitRateBox *) gf_malloc(sizeof(GF_MPEG4BitRateBox)); + GF_BitRateBox *tmp = (GF_BitRateBox *) gf_malloc(sizeof(GF_BitRateBox)); if (tmp == NULL) return NULL; - memset(tmp, 0, sizeof(GF_MPEG4BitRateBox)); + memset(tmp, 0, sizeof(GF_BitRateBox)); tmp->type = GF_ISOM_BOX_TYPE_BTRT; return (GF_Box *)tmp; } @@ -1546,7 +1575,7 @@ GF_Box *btrt_New() GF_Err btrt_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; - GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *) s; + GF_BitRateBox *ptr = (GF_BitRateBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; @@ -1558,7 +1587,7 @@ GF_Err btrt_Write(GF_Box *s, GF_BitStream *bs) GF_Err btrt_Size(GF_Box *s) { GF_Err e; - GF_MPEG4BitRateBox *ptr = (GF_MPEG4BitRateBox *)s; + GF_BitRateBox *ptr = (GF_BitRateBox *)s; e = gf_isom_box_get_size(s); ptr->size += 12; return e; diff --git a/src/isomedia/box_code_3gpp.c b/src/isomedia/box_code_3gpp.c index 0512039..7597162 100644 --- a/src/isomedia/box_code_3gpp.c +++ b/src/isomedia/box_code_3gpp.c @@ -1212,7 +1212,6 @@ void dims_del(GF_Box *s) gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); if (p->config) gf_isom_box_del((GF_Box *)p->config); - if (p->bitrate ) gf_isom_box_del((GF_Box *)p->bitrate); if (p->scripts) gf_isom_box_del((GF_Box *)p->scripts); gf_free(p); } @@ -1229,10 +1228,6 @@ static GF_Err dims_AddBox(GF_Box *s, GF_Box *a) if (ptr->scripts) ERROR_ON_DUPLICATED_BOX(a, ptr) ptr->scripts = (GF_DIMSScriptTypesBox*)a; break; - case GF_ISOM_BOX_TYPE_BTRT: - if (ptr->bitrate) ERROR_ON_DUPLICATED_BOX(a, ptr) - ptr->bitrate = (GF_MPEG4BitRateBox*)a; - break; case GF_ISOM_BOX_TYPE_SINF: gf_list_add(ptr->protections, a); break; @@ -1266,10 +1261,6 @@ GF_Err dims_Write(GF_Box *s, GF_BitStream *bs) e = gf_isom_box_write((GF_Box *)p->scripts, bs); if (e) return e; } - if (p->bitrate) { - e = gf_isom_box_write((GF_Box *)p->bitrate, bs); - if (e) return e; - } return gf_isom_box_array_write(s, p->protections, bs); } @@ -1285,11 +1276,6 @@ GF_Err dims_Size(GF_Box *s) if (e) return e; p->size += p->config->size; } - if (p->bitrate) { - e = gf_isom_box_size((GF_Box *) p->bitrate); - if (e) return e; - p->size += p->bitrate->size; - } if (p->scripts) { e = gf_isom_box_size((GF_Box *) p->scripts); if (e) return e; diff --git a/src/isomedia/box_code_adobe.c b/src/isomedia/box_code_adobe.c index 3b5db45..751a9d7 100644 --- a/src/isomedia/box_code_adobe.c +++ b/src/isomedia/box_code_adobe.c @@ -175,6 +175,7 @@ GF_Err abst_Read(GF_Box *s, GF_BitStream *bs) return GF_OK; } +GF_EXPORT GF_Box *abst_New() { ISOM_DECL_BOX_ALLOC(GF_AdobeBootstrapInfoBox, GF_ISOM_BOX_TYPE_ABST); @@ -187,6 +188,7 @@ GF_Box *abst_New() #ifndef GPAC_DISABLE_ISOM_WRITE +GF_EXPORT GF_Err abst_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; @@ -246,7 +248,7 @@ GF_Err abst_Write(GF_Box *s, GF_BitStream *bs) return GF_OK; } - +GF_EXPORT GF_Err abst_Size(GF_Box *s) { GF_Err e; @@ -367,6 +369,7 @@ GF_Err afra_Read(GF_Box *s, GF_BitStream *bs) return GF_OK; } +GF_EXPORT GF_Box *afra_New() { ISOM_DECL_BOX_ALLOC(GF_AdobeFragRandomAccessBox, GF_ISOM_BOX_TYPE_AFRA); @@ -499,6 +502,7 @@ GF_Err asrt_Read(GF_Box *s, GF_BitStream *bs) return GF_OK; } +GF_EXPORT GF_Box *asrt_New() { ISOM_DECL_BOX_ALLOC(GF_AdobeSegmentRunTableBox, GF_ISOM_BOX_TYPE_ASRT); @@ -615,6 +619,7 @@ GF_Err afrt_Read(GF_Box *s, GF_BitStream *bs) return GF_OK; } +GF_EXPORT GF_Box *afrt_New() { ISOM_DECL_BOX_ALLOC(GF_AdobeFragmentRunTableBox, GF_ISOM_BOX_TYPE_AFRT); diff --git a/src/isomedia/box_code_base.c b/src/isomedia/box_code_base.c index 4c3ddb0..64b73ee 100644 --- a/src/isomedia/box_code_base.c +++ b/src/isomedia/box_code_base.c @@ -280,7 +280,7 @@ GF_Err cprt_Write(GF_Box *s, GF_BitStream *bs) gf_bs_write_int(bs, 0, 15); } if (ptr->notice) { - gf_bs_write_data(bs, ptr->notice, (unsigned long)strlen(ptr->notice) + 1); + gf_bs_write_data(bs, ptr->notice, (u32) (strlen(ptr->notice) + 1) ); } return GF_OK; } @@ -299,6 +299,89 @@ GF_Err cprt_Size(GF_Box *s) #endif /*GPAC_DISABLE_ISOM_WRITE*/ +void kind_del(GF_Box *s) +{ + GF_KindBox *ptr = (GF_KindBox *) s; + if (ptr == NULL) return; + if (ptr->schemeURI) gf_free(ptr->schemeURI); + if (ptr->value) gf_free(ptr->value); + gf_free(ptr); +} + +GF_Err kind_Read(GF_Box *s,GF_BitStream *bs) +{ + GF_Err e; + GF_KindBox *ptr = (GF_KindBox *)s; + + e = gf_isom_full_box_read(s, bs); + if (e) return e; + + if (ptr->size) { + u32 bytesToRead = (u32) ptr->size; + char *data; + u32 schemeURIlen; + data = (char*)gf_malloc(bytesToRead * sizeof(char)); + if (data == NULL) return GF_OUT_OF_MEM; + gf_bs_read_data(bs, data, bytesToRead); + /*safety check in case the string is not null-terminated*/ + if (data[bytesToRead-1]) { + char *str = (char*)gf_malloc((u32) bytesToRead + 1); + memcpy(str, data, (u32) bytesToRead); + str[ptr->size] = 0; + gf_free(data); + data = str; + bytesToRead++; + } + ptr->schemeURI = gf_strdup(data); + schemeURIlen = (u32) strlen(data); + if (bytesToRead > schemeURIlen+1) { + /* read the value */ + char *data_value = data + schemeURIlen +1; + ptr->value = gf_strdup(data_value); + } + gf_free(data); + } + return GF_OK; +} + +GF_Box *kind_New() +{ + ISOM_DECL_BOX_ALLOC(GF_KindBox, GF_ISOM_BOX_TYPE_KIND); + gf_isom_full_box_init((GF_Box *)tmp); + return (GF_Box *)tmp; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err kind_Write(GF_Box *s, GF_BitStream *bs) +{ + GF_Err e; + GF_KindBox *ptr = (GF_KindBox *) s; + + e = gf_isom_full_box_write(s, bs); + if (e) return e; + gf_bs_write_data(bs, ptr->schemeURI, (u32) (strlen(ptr->schemeURI) + 1 )); + if (ptr->value) { + gf_bs_write_data(bs, ptr->value, (u32) (strlen(ptr->value) + 1) ); + } + return GF_OK; +} + +GF_Err kind_Size(GF_Box *s) +{ + GF_Err e; + GF_KindBox *ptr = (GF_KindBox *)s; + e = gf_isom_full_box_get_size(s); + if (e) return e; + ptr->size += strlen(ptr->schemeURI) + 1; + if (ptr->value) { + ptr->size += strlen(ptr->value) + 1; + } + return GF_OK; +} + +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + void ctts_del(GF_Box *s) { GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s; @@ -919,7 +1002,7 @@ GF_Err edts_Write(GF_Box *s, GF_BitStream *bs) GF_EditBox *ptr = (GF_EditBox *)s; //here we have a trick: if editList is empty, skip the box - if (gf_list_count(ptr->editList->entryList)) { + if (ptr->editList && gf_list_count(ptr->editList->entryList)) { e = gf_isom_box_write_header(s, bs); if (e) return e; e = gf_isom_box_write((GF_Box *) ptr->editList, bs); @@ -934,7 +1017,7 @@ GF_Err edts_Size(GF_Box *s) GF_EditBox *ptr = (GF_EditBox *)s; //here we have a trick: if editList is empty, skip the box - if (! gf_list_count(ptr->editList->entryList)) { + if (!ptr->editList || ! gf_list_count(ptr->editList->entryList)) { ptr->size = 0; } else { e = gf_isom_box_get_size(s); @@ -1245,6 +1328,10 @@ GF_Err ftyp_Read(GF_Box *s,GF_BitStream *bs) u32 i; GF_FileTypeBox *ptr = (GF_FileTypeBox *)s; + if (ptr->size < 8) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Found ftyp with size < 8, likely broken!\n")); + return GF_BAD_PARAM; + } ptr->majorBrand = gf_bs_read_u32(bs); ptr->minorVersion = gf_bs_read_u32(bs); ptr->size -= 8; @@ -1414,6 +1501,7 @@ GF_Box *gnra_New() #ifndef GPAC_DISABLE_ISOM_WRITE + GF_Err gnra_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; @@ -1426,7 +1514,9 @@ GF_Err gnra_Write(GF_Box *s, GF_BitStream *bs) ptr->type = GF_ISOM_BOX_TYPE_GNRA; gf_isom_audio_sample_entry_write((GF_AudioSampleEntryBox *)ptr, bs); - gf_bs_write_data(bs, ptr->data, ptr->data_size); + if (ptr->data) { + gf_bs_write_data(bs, ptr->data, ptr->data_size); + } return GF_OK; } @@ -2885,6 +2975,71 @@ GF_Err mdia_Size(GF_Box *s) #endif /*GPAC_DISABLE_ISOM_WRITE*/ +void elng_del(GF_Box *s) +{ + GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; + if (ptr == NULL) return; + if (ptr->extended_language) gf_free(ptr->extended_language); + gf_free(ptr); +} + +GF_Err elng_Read(GF_Box *s, GF_BitStream *bs) +{ + GF_Err e; + GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; + + e = gf_isom_full_box_read(s, bs); + if (e) return e; + if (ptr->size) { + ptr->extended_language = (char*)gf_malloc((u32) ptr->size); + if (ptr->extended_language == NULL) return GF_OUT_OF_MEM; + gf_bs_read_data(bs, ptr->extended_language, (u32) ptr->size); + /*safety check in case the string is not null-terminated*/ + if (ptr->extended_language[ptr->size-1]) { + char *str = (char*)gf_malloc((u32) ptr->size + 1); + memcpy(str, ptr->extended_language, (u32) ptr->size); + str[ptr->size] = 0; + gf_free(ptr->extended_language); + ptr->extended_language = str; + } + } + return GF_OK; +} + +GF_Box *elng_New() +{ + ISOM_DECL_BOX_ALLOC(GF_MediaBox, GF_ISOM_BOX_TYPE_ELNG); + return (GF_Box *)tmp; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err elng_Write(GF_Box *s, GF_BitStream *bs) +{ + GF_Err e; + GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; + e = gf_isom_full_box_write(s, bs); + if (e) return e; + if (ptr->extended_language) { + gf_bs_write_data(bs, ptr->extended_language, (u32)(strlen(ptr->extended_language)+1)); + } + return GF_OK; +} + +GF_Err elng_Size(GF_Box *s) +{ + GF_Err e; + GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; + e = gf_isom_box_get_size(s); + if (e) return e; + ptr->size += 4; + if (ptr->extended_language) { + ptr->size += strlen(ptr->extended_language)+1; + } + return GF_OK; +} + +#endif /*GPAC_DISABLE_ISOM_WRITE*/ #ifndef GPAC_DISABLE_ISOM_FRAGMENTS @@ -3534,7 +3689,6 @@ void mp4v_del(GF_Box *s) if (ptr->svc_config) gf_isom_box_del((GF_Box *) ptr->svc_config); if (ptr->hevc_config) gf_isom_box_del((GF_Box *) ptr->hevc_config); if (ptr->shvc_config) gf_isom_box_del((GF_Box *) ptr->shvc_config); - if (ptr->bitrate) gf_isom_box_del((GF_Box *) ptr->bitrate); if (ptr->descr) gf_isom_box_del((GF_Box *) ptr->descr); if (ptr->ipod_ext) gf_isom_box_del((GF_Box *)ptr->ipod_ext); /*for publishing*/ @@ -3573,10 +3727,6 @@ GF_Err mp4v_AddBox(GF_Box *s, GF_Box *a) if (ptr->shvc_config) ERROR_ON_DUPLICATED_BOX(a, ptr) ptr->shvc_config = (GF_HEVCConfigurationBox *)a; break; - case GF_ISOM_BOX_TYPE_BTRT: - if (ptr->bitrate) ERROR_ON_DUPLICATED_BOX(a, ptr) - ptr->bitrate = (GF_MPEG4BitRateBox *)a; - break; case GF_ISOM_BOX_TYPE_M4DS: if (ptr->descr) ERROR_ON_DUPLICATED_BOX(a, ptr) ptr->descr = (GF_MPEG4ExtensionDescriptorsBox *)a; @@ -3661,10 +3811,6 @@ GF_Err mp4v_Write(GF_Box *s, GF_BitStream *bs) e = gf_isom_box_write((GF_Box *) ptr->ipod_ext, bs); if (e) return e; } - if (ptr->bitrate) { - e = gf_isom_box_write((GF_Box *) ptr->bitrate, bs); - if (e) return e; - } if (ptr->descr) { e = gf_isom_box_write((GF_Box *) ptr->descr, bs); if (e) return e; @@ -3732,11 +3878,6 @@ GF_Err mp4v_Size(GF_Box *s) if (e) return e; ptr->size += ptr->ipod_ext->size; } - if (ptr->bitrate) { - e = gf_isom_box_size((GF_Box *) ptr->bitrate); - if (e) return e; - ptr->size += ptr->bitrate->size; - } if (ptr->descr) { e = gf_isom_box_size((GF_Box *) ptr->descr); if (e) return e; @@ -3768,6 +3909,7 @@ void mvex_del(GF_Box *s) if (ptr == NULL) return; if (ptr->mehd) gf_isom_box_del((GF_Box*)ptr->mehd); gf_isom_box_array_del(ptr->TrackExList); + gf_isom_box_array_del(ptr->TrackExPropList); gf_free(ptr); } @@ -3779,6 +3921,8 @@ GF_Err mvex_AddBox(GF_Box *s, GF_Box *a) switch (a->type) { case GF_ISOM_BOX_TYPE_TREX: return gf_list_add(ptr->TrackExList, a); + case GF_ISOM_BOX_TYPE_TREP: + return gf_list_add(ptr->TrackExPropList, a); case GF_ISOM_BOX_TYPE_MEHD: if (ptr->mehd) break; ptr->mehd = (GF_MovieExtendsHeaderBox*)a; @@ -3804,6 +3948,12 @@ GF_Box *mvex_New() gf_free(tmp); return NULL; } + tmp->TrackExPropList = gf_list_new(); + if (!tmp->TrackExPropList) { + gf_list_del(tmp->TrackExList); + gf_free(tmp); + return NULL; + } return (GF_Box *)tmp; } @@ -3823,7 +3973,9 @@ GF_Err mvex_Write(GF_Box *s, GF_BitStream *bs) e = gf_isom_box_write((GF_Box *)ptr->mehd, bs); if (e) return e; } - return gf_isom_box_array_write(s, ptr->TrackExList, bs); + e = gf_isom_box_array_write(s, ptr->TrackExList, bs); + if (e) return e; + return gf_isom_box_array_write(s, ptr->TrackExPropList, bs); } GF_Err mvex_Size(GF_Box *s) @@ -3837,7 +3989,9 @@ GF_Err mvex_Size(GF_Box *s) if (e) return e; ptr->size += ptr->mehd->size; } - return gf_isom_box_array_size(s, ptr->TrackExList); + e = gf_isom_box_array_size(s, ptr->TrackExList); + if (e) return e; + return gf_isom_box_array_size(s, ptr->TrackExPropList); } @@ -4250,7 +4404,8 @@ GF_Err smhd_Read(GF_Box *s, GF_BitStream *bs) GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s; e = gf_isom_full_box_read(s, bs); if (e) return e; - ptr->reserved = gf_bs_read_u32(bs); + ptr->balance = gf_bs_read_u16(bs); + ptr->reserved = gf_bs_read_u16(bs); return GF_OK; } @@ -4270,7 +4425,8 @@ GF_Err smhd_Write(GF_Box *s, GF_BitStream *bs) GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s; e = gf_isom_full_box_write(s, bs); if (e) return e; - gf_bs_write_u32(bs, ptr->reserved); + gf_bs_write_u16(bs, ptr->balance); + gf_bs_write_u16(bs, ptr->reserved); return GF_OK; } @@ -4983,13 +5139,15 @@ GF_Err stsd_AddBox(GF_SampleDescriptionBox *ptr, GF_Box *a) case GF_ISOM_BOX_TYPE_ENCT: case GF_ISOM_BOX_TYPE_METX: case GF_ISOM_BOX_TYPE_METT: - case GF_ISOM_BOX_TYPE_STSE: + case GF_ISOM_BOX_TYPE_STXT: case GF_ISOM_BOX_TYPE_DIMS: case GF_ISOM_BOX_TYPE_AC3: case GF_ISOM_BOX_TYPE_LSR1: case GF_ISOM_BOX_TYPE_WVTT: case GF_ISOM_BOX_TYPE_STPP: case GF_ISOM_BOX_TYPE_SBTT: + case GF_ISOM_BOX_TYPE_ELNG: + case GF_ISOM_BOX_TYPE_MP3: return gf_isom_box_add_default((GF_Box*)ptr, a); /*for 3GP config, we must set the type*/ case GF_ISOM_SUBTYPE_3GP_AMR: @@ -5601,6 +5759,9 @@ GF_Err stts_Read(GF_Box *s, GF_BitStream *bs) GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] more than one sample at the end of the track with sample_delta=0 - forbidden ! Fixing to 1\n" )); ptr->entries[i].sampleDelta = 1; } + } else if ((s32) ptr->entries[i].sampleDelta < 0) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] stts entry %d has negative duration %d - forbidden ! Fixing to 1, sync may get lost (consider reimport raw media)\n", i, (s32) ptr->entries[i].sampleDelta )); + ptr->entries[i].sampleDelta = 1; } } //remove the last sample delta. @@ -6027,10 +6188,11 @@ GF_Err traf_Read(GF_Box *s, GF_BitStream *bs) a->size = s; } if (ptr->size<a->size) { - gf_isom_box_del(a); - return GF_ISOM_INVALID_FILE; + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box \"%s\" is larger than container box\n", gf_4cc_to_str(a->type))); + ptr->size = 0; + } else { + ptr->size -= a->size; } - ptr->size -= a->size; e = traf_AddBox((GF_Box*)ptr, a); if (e) return e; } @@ -6186,12 +6348,15 @@ void trak_del(GF_Box *s) static void gf_isom_check_sample_desc(GF_TrackBox *trak) { GF_BitStream *bs; - GF_GenericVisualSampleEntryBox *genv; - GF_GenericAudioSampleEntryBox *gena; - GF_GenericSampleEntryBox *genm; GF_UnknownBox *a; u32 i; + if (!trak->Media->information->sampleTable->SampleDescription) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Track with no sample description box !\n" )); + trak->Media->information->sampleTable->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSD); + return; + } + i=0; while ((a = (GF_UnknownBox*)gf_list_enum(trak->Media->information->sampleTable->SampleDescription->other_boxes, &i))) { switch (a->type) { @@ -6211,7 +6376,7 @@ static void gf_isom_check_sample_desc(GF_TrackBox *trak) case GF_ISOM_BOX_TYPE_RTP_STSD: case GF_ISOM_BOX_TYPE_METX: case GF_ISOM_BOX_TYPE_METT: - case GF_ISOM_BOX_TYPE_STSE: + case GF_ISOM_BOX_TYPE_STXT: case GF_ISOM_BOX_TYPE_AVC1: case GF_ISOM_BOX_TYPE_AVC2: case GF_ISOM_BOX_TYPE_AVC3: @@ -6237,65 +6402,127 @@ static void gf_isom_check_sample_desc(GF_TrackBox *trak) default: break; } + if (!a->data || (a->dataSize<8) ) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Sample description %s does not have at least 8 bytes!\n", gf_4cc_to_str(a->type) )); + continue; + } + /*only process visual or audio*/ switch (trak->Media->handler->handlerType) { case GF_ISOM_MEDIA_VISUAL: + { + GF_GenericVisualSampleEntryBox *genv; /*remove entry*/ gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1); genv = (GF_GenericVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRV); bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); - genv->size = a->size; + genv->size = a->size-8; gf_isom_video_sample_entry_read((GF_VisualSampleEntryBox *) genv, bs); - genv->data_size = (u32) gf_bs_available(bs); - if (genv->data_size) { - genv->data = (char*)gf_malloc(sizeof(char) * genv->data_size); - gf_bs_read_data(bs, genv->data, genv->data_size); + + if (gf_bs_available(bs)) { + u64 pos = gf_bs_get_position(bs); + //try to parse as boxes + GF_Err e = gf_isom_read_box_list((GF_Box *) genv, bs, mp4v_AddBox); + if (e) { + gf_bs_seek(bs, pos); + genv->data_size = (u32) gf_bs_available(bs); + if (genv->data_size) { + genv->data = a->data; + a->data = NULL; + memmove(genv->data, genv->data + pos, genv->data_size); + } + } else { + genv->data_size = 0; + } } gf_bs_del(bs); - genv->size = a->size; + if (!genv->data_size && genv->data) { + gf_free(genv->data); + genv->data = NULL; + } + + genv->size = 0; genv->EntryType = a->type; gf_isom_box_del((GF_Box *)a); gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, genv, i-1); + } break; case GF_ISOM_MEDIA_AUDIO: + { + GF_GenericAudioSampleEntryBox *gena; /*remove entry*/ gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1); gena = (GF_GenericAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRA); - gena->size = a->size; + gena->size = a->size-8; bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); gf_isom_audio_sample_entry_read((GF_AudioSampleEntryBox *) gena, bs); - gena->data_size = (u32) gf_bs_available(bs); - if (gena->data_size) { - gena->data = (char*)gf_malloc(sizeof(char) * gena->data_size); - gf_bs_read_data(bs, gena->data, gena->data_size); + + if (gf_bs_available(bs)) { + u64 pos = gf_bs_get_position(bs); + //try to parse as boxes + GF_Err e = gf_isom_read_box_list((GF_Box *) gena, bs, mp4a_AddBox); + if (e) { + gf_bs_seek(bs, pos); + gena->data_size = (u32) gf_bs_available(bs); + if (gena->data_size) { + gena->data = a->data; + a->data = NULL; + memmove(gena->data, gena->data + pos, gena->data_size); + } + } else { + gena->data_size = 0; + } } gf_bs_del(bs); - gena->size = a->size; + if (!gena->data_size && gena->data) { + gf_free(gena->data); + gena->data = NULL; + } + gena->size = 0; gena->EntryType = a->type; gf_isom_box_del((GF_Box *)a); gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, gena, i-1); + } break; default: + { + GF_GenericSampleEntryBox *genm; /*remove entry*/ - if (a->data && a->size) { - gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1); - genm = (GF_GenericSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM); - genm->size = a->size; - bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); - gf_bs_read_data(bs, genm->reserved, 6); - genm->dataReferenceIndex = gf_bs_read_u16(bs); - genm->data_size = (u32) gf_bs_available(bs); - if (genm->data_size) { - genm->data = (char*)gf_malloc(sizeof(char) * genm->data_size); - gf_bs_read_data(bs, genm->data, genm->data_size); + gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, i-1); + genm = (GF_GenericSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM); + genm->size = a->size-8; + bs = gf_bs_new(a->data, a->dataSize, GF_BITSTREAM_READ); + gf_bs_read_data(bs, genm->reserved, 6); + genm->dataReferenceIndex = gf_bs_read_u16(bs); + + if (gf_bs_available(bs)) { + u64 pos = gf_bs_get_position(bs); + //try to parse as boxes + GF_Err e = gf_isom_read_box_list((GF_Box *) genm, bs, mp4s_AddBox); + if (e) { + gf_bs_seek(bs, pos); + genm->data_size = (u32) gf_bs_available(bs); + if (genm->data_size) { + genm->data = a->data; + a->data = NULL; + memmove(genm->data, genm->data + pos, genm->data_size); + } + } else { + genm->data_size = 0; } - gf_bs_del(bs); - genm->size = a->size; - genm->EntryType = a->type; - gf_isom_box_del((GF_Box *)a); - gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, genm, i-1); } + gf_bs_del(bs); + if (!genm->data_size && genm->data) { + gf_free(genm->data); + genm->data = NULL; + } + genm->size = 0; + + genm->EntryType = a->type; + gf_isom_box_del((GF_Box *)a); + gf_list_insert(trak->Media->information->sampleTable->SampleDescription->other_boxes, genm, i-1); + } break; } @@ -6650,6 +6877,68 @@ GF_Err trex_Size(GF_Box *s) +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + + + +void trep_del(GF_Box *s) +{ + GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s; + if (ptr == NULL) return; + gf_free(ptr); +} + + +GF_Err trep_Read(GF_Box *s, GF_BitStream *bs) +{ + GF_Err e; + GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s; + + e = gf_isom_full_box_read(s, bs); + if (e) return e; + + ptr->trackID = gf_bs_read_u32(bs); + ptr->size-=4; + + return gf_isom_read_box_list(s, bs, gf_isom_box_add_default); +} + +GF_Box *trep_New() +{ + ISOM_DECL_BOX_ALLOC(GF_TrackExtensionPropertiesBox, GF_ISOM_BOX_TYPE_TREP); + tmp->other_boxes = gf_list_new(); + return (GF_Box *)tmp; +} + + + +#ifndef GPAC_DISABLE_ISOM_WRITE + + +GF_Err trep_Write(GF_Box *s, GF_BitStream *bs) +{ + GF_Err e; + GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *) s; + if (!s) return GF_BAD_PARAM; + e = gf_isom_full_box_write(s, bs); + if (e) return e; + + gf_bs_write_u32(bs, ptr->trackID); + return GF_OK; +} + +GF_Err trep_Size(GF_Box *s) +{ + GF_Err e; + GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s; + e = gf_isom_full_box_get_size(s); + if (e) return e; + ptr->size += 4; + return GF_OK; +} + + + #endif /*GPAC_DISABLE_ISOM_WRITE*/ #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/ @@ -6721,7 +7010,11 @@ GF_Err trun_Read(GF_Box *s, GF_BitStream *bs) trun_size += 4; } if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) { - p->CTS_Offset = gf_bs_read_u32(bs); + if (ptr->version==0) { + p->CTS_Offset = (u32) gf_bs_read_u32(bs); + } else { + p->CTS_Offset = (s32) gf_bs_read_u32(bs); + } } gf_list_add(ptr->entries, p); if (ptr->size<trun_size) return GF_ISOM_INVALID_FILE; @@ -6780,7 +7073,11 @@ GF_Err trun_Write(GF_Box *s, GF_BitStream *bs) gf_bs_write_u32(bs, p->flags); } if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) { - gf_bs_write_u32(bs, p->CTS_Offset); + if (ptr->version==0) { + gf_bs_write_u32(bs, p->CTS_Offset); + } else { + gf_bs_write_u32(bs, (u32) p->CTS_Offset); + } } } return GF_OK; @@ -7286,9 +7583,10 @@ void metx_del(GF_Box *s) gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); if (ptr->content_encoding) gf_free(ptr->content_encoding); - if (ptr->mime_type_or_namespace) gf_free(ptr->mime_type_or_namespace); + if (ptr->xml_namespace) gf_free(ptr->xml_namespace); if (ptr->xml_schema_loc) gf_free(ptr->xml_schema_loc); - if (ptr->bitrate) gf_isom_box_del((GF_Box *) ptr->bitrate); + if (ptr->mime_type) gf_free(ptr->mime_type); + if (ptr->config) gf_isom_box_del((GF_Box *)ptr->config); gf_free(ptr); } @@ -7300,9 +7598,10 @@ GF_Err metx_AddBox(GF_Box *s, GF_Box *a) case GF_ISOM_BOX_TYPE_SINF: gf_list_add(ptr->protections, a); break; - case GF_ISOM_BOX_TYPE_BTRT: - if (ptr->bitrate) ERROR_ON_DUPLICATED_BOX(a, ptr) - ptr->bitrate = (GF_MPEG4BitRateBox *)a; + case GF_ISOM_BOX_TYPE_TXTC: + //we allow the config box on metx + if (ptr->config) ERROR_ON_DUPLICATED_BOX(a, ptr) + ptr->config = (GF_TextConfigBox *)a; break; default: return gf_isom_box_add_default(s, a); @@ -7331,7 +7630,13 @@ GF_Err metx_Read(GF_Box *s, GF_BitStream *bs) break; i++; } - if (i) ptr->content_encoding = gf_strdup(str); + if (i) { + if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { + ptr->xml_namespace = gf_strdup(str); + } else { + ptr->content_encoding = gf_strdup(str); + } + } i=0; while (size) { @@ -7341,9 +7646,15 @@ GF_Err metx_Read(GF_Box *s, GF_BitStream *bs) break; i++; } - if (i) ptr->mime_type_or_namespace = gf_strdup(str); + if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) { + if (i) { + if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { + ptr->xml_schema_loc = gf_strdup(str); + } else { + ptr->xml_namespace = gf_strdup(str); + } + } - if (ptr->type==GF_ISOM_BOX_TYPE_METX) { i=0; while (size) { str[i] = gf_bs_read_u8(bs); @@ -7352,7 +7663,17 @@ GF_Err metx_Read(GF_Box *s, GF_BitStream *bs) break; i++; } - if (i) ptr->xml_schema_loc = gf_strdup(str); + if (i) { + if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { + ptr->mime_type = gf_strdup(str); + } else { + ptr->xml_schema_loc = gf_strdup(str); + } + } + } + //mett, sbtt, stxt, stpp + else { + if (i) ptr->mime_type = gf_strdup(str); } ptr->size = size; gf_free(str); @@ -7371,24 +7692,41 @@ GF_Err metx_Write(GF_Box *s, GF_BitStream *bs) gf_bs_write_data(bs, ptr->reserved, 6); gf_bs_write_u16(bs, ptr->dataReferenceIndex); - if (ptr->content_encoding) - gf_bs_write_data(bs, ptr->content_encoding, (u32) strlen(ptr->content_encoding)); - gf_bs_write_u8(bs, 0); + if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) { + if (ptr->content_encoding) + gf_bs_write_data(bs, ptr->content_encoding, (u32) strlen(ptr->content_encoding)); + gf_bs_write_u8(bs, 0); + } - if (ptr->mime_type_or_namespace) - gf_bs_write_data(bs, ptr->mime_type_or_namespace, (u32) strlen(ptr->mime_type_or_namespace)); - gf_bs_write_u8(bs, 0); + if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) { + if (ptr->xml_namespace) + gf_bs_write_data(bs, ptr->xml_namespace, (u32) strlen(ptr->xml_namespace)); + + gf_bs_write_u8(bs, 0); - if (ptr->type == GF_ISOM_BOX_TYPE_METX) { if (ptr->xml_schema_loc) gf_bs_write_data(bs, ptr->xml_schema_loc, (u32) strlen(ptr->xml_schema_loc)); gf_bs_write_u8(bs, 0); + + if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { + if (ptr->mime_type) + gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type)); + + gf_bs_write_u8(bs, 0); + } } + //mett, sbtt, stxt + else { + if (ptr->mime_type) + gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type)); - if (ptr->bitrate) { - e = gf_isom_box_write((GF_Box *)ptr->bitrate, bs); - if (e) return e; + gf_bs_write_u8(bs, 0); + + if (ptr->config) { + gf_isom_box_write((GF_Box *)ptr->config, bs); + } } + return gf_isom_box_array_write(s, ptr->protections, bs); } @@ -7399,82 +7737,77 @@ GF_Err metx_Size(GF_Box *s) if (e) return e; ptr->size += 8; - if (ptr->content_encoding) - ptr->size += strlen(ptr->content_encoding); - ptr->size++; - if (ptr->mime_type_or_namespace) - ptr->size += strlen(ptr->mime_type_or_namespace); - ptr->size++; - if (ptr->type == GF_ISOM_BOX_TYPE_METX) { + if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) { + if (ptr->content_encoding) + ptr->size += strlen(ptr->content_encoding); + ptr->size++; + } + + if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) { + + if (ptr->xml_namespace) + ptr->size += strlen(ptr->xml_namespace); + ptr->size++; + if (ptr->xml_schema_loc) ptr->size += strlen(ptr->xml_schema_loc); ptr->size++; - } - if (ptr->bitrate) { - e = gf_isom_box_size((GF_Box *)ptr->bitrate); - if (e) return e; - ptr->size += ptr->bitrate->size; + if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { + if (ptr->mime_type) + ptr->size += strlen(ptr->mime_type); + ptr->size++; + } + + } + //mett, sbtt, stxt + else { + if (ptr->mime_type) + ptr->size += strlen(ptr->mime_type); + ptr->size++; + + if (ptr->config) { + e = gf_isom_box_size((GF_Box *)ptr->config); + if (e) return e; + ptr->size += ptr->config->size; + } } + return gf_isom_box_array_size(s, ptr->protections); } #endif /*GPAC_DISABLE_ISOM_WRITE*/ + /* SimpleTextSampleEntry */ -GF_Box *stse_New() +GF_Box *txtc_New() { - ISOM_DECL_BOX_ALLOC(GF_SimpleTextSampleEntryBox, GF_ISOM_BOX_TYPE_STSE); - gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); + ISOM_DECL_BOX_ALLOC(GF_TextConfigBox, GF_ISOM_BOX_TYPE_TXTC); + gf_isom_full_box_init((GF_Box *)tmp); return (GF_Box *)tmp; } -void stse_del(GF_Box *s) +void txtc_del(GF_Box *s) { - GF_SimpleTextSampleEntryBox *ptr = (GF_SimpleTextSampleEntryBox*)s; + GF_TextConfigBox *ptr = (GF_TextConfigBox*)s; if (ptr == NULL) return; - gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); - if (ptr->content_encoding) gf_free(ptr->content_encoding); - if (ptr->mime_type) gf_free(ptr->mime_type); - if (ptr->bitrate) gf_isom_box_del((GF_Box *)ptr->bitrate); - if (ptr->config) gf_isom_box_del((GF_Box *)ptr->config); + if (ptr->config) gf_free(ptr->config); gf_free(ptr); } - -GF_Err stse_AddBox(GF_Box *s, GF_Box *a) -{ - GF_SimpleTextSampleEntryBox *ptr = (GF_SimpleTextSampleEntryBox *)s; - switch (a->type) { - case GF_ISOM_BOX_TYPE_STTC: - if (ptr->config) ERROR_ON_DUPLICATED_BOX(a, ptr) - ptr->config = (GF_StringBox *)a; - break; - case GF_ISOM_BOX_TYPE_BTRT: - if (ptr->bitrate) ERROR_ON_DUPLICATED_BOX(a, ptr) - ptr->bitrate = (GF_MPEG4BitRateBox *)a; - break; - case GF_ISOM_BOX_TYPE_SINF: - gf_list_add(ptr->protections, a); - break; - default: - return gf_isom_box_add_default(s, a); - } - return GF_OK; -} - -GF_Err stse_Read(GF_Box *s, GF_BitStream *bs) +GF_Err txtc_Read(GF_Box *s, GF_BitStream *bs) { + GF_Err e; u32 size, i; char *str; - GF_SimpleTextSampleEntryBox *ptr = (GF_SimpleTextSampleEntryBox*)s; + GF_TextConfigBox *ptr = (GF_TextConfigBox*)s; - gf_bs_read_data(bs, ptr->reserved, 6); - ptr->dataReferenceIndex = gf_bs_read_u16(bs); + e = gf_isom_full_box_read(s, bs); + if (e) return e; - size = (u32) ptr->size - 8; + size = (u32) ptr->size; str = (char *)gf_malloc(sizeof(char)*size); i=0; @@ -7486,78 +7819,35 @@ GF_Err stse_Read(GF_Box *s, GF_BitStream *bs) break; i++; } - if (i) ptr->content_encoding = gf_strdup(str); - - i=0; - while (size) { - str[i] = gf_bs_read_u8(bs); - size--; - if (!str[i]) - break; - i++; - } - if (i) ptr->mime_type = gf_strdup(str); + if (i) ptr->config = gf_strdup(str); - ptr->size = size; - gf_free(str); - return gf_isom_read_box_list(s, bs, stse_AddBox); + return GF_OK; } #ifndef GPAC_DISABLE_ISOM_WRITE -GF_Err stse_Write(GF_Box *s, GF_BitStream *bs) +GF_Err txtc_Write(GF_Box *s, GF_BitStream *bs) { - GF_SimpleTextSampleEntryBox *ptr = (GF_SimpleTextSampleEntryBox *)s; - GF_Err e = gf_isom_box_write_header(s, bs); + GF_TextConfigBox *ptr = (GF_TextConfigBox *)s; + GF_Err e = gf_isom_full_box_write(s, bs); if (e) return e; - gf_bs_write_data(bs, ptr->reserved, 6); - gf_bs_write_u16(bs, ptr->dataReferenceIndex); - - if (ptr->content_encoding) - gf_bs_write_data(bs, ptr->content_encoding, (u32) strlen(ptr->content_encoding)); - gf_bs_write_u8(bs, 0); - - if (ptr->mime_type) - gf_bs_write_data(bs, ptr->mime_type, (u32) strlen(ptr->mime_type)); + if (ptr->config) + gf_bs_write_data(bs, ptr->config, (u32) strlen(ptr->config)); gf_bs_write_u8(bs, 0); - - if (ptr->bitrate) { - e = gf_isom_box_write((GF_Box *)ptr->bitrate, bs); - if (e) return e; - } - if (ptr->config) { - e = gf_isom_box_write((GF_Box *)ptr->config, bs); - if (e) return e; - } - return gf_isom_box_array_write(s, ptr->protections, bs); + return GF_OK; } -GF_Err stse_Size(GF_Box *s) +GF_Err txtc_Size(GF_Box *s) { - GF_SimpleTextSampleEntryBox *ptr = (GF_SimpleTextSampleEntryBox *)s; - GF_Err e = gf_isom_box_get_size(s); + GF_TextConfigBox *ptr = (GF_TextConfigBox *)s; + GF_Err e = gf_isom_full_box_get_size(s); if (e) return e; - ptr->size += 8; - - if (ptr->content_encoding) - ptr->size += strlen(ptr->content_encoding); - ptr->size++; - if (ptr->mime_type) - ptr->size += strlen(ptr->mime_type); + if (ptr->config) + ptr->size += strlen(ptr->config); ptr->size++; - if (ptr->bitrate) { - e = gf_isom_box_size((GF_Box *)ptr->bitrate); - if (e) return e; - ptr->size += ptr->bitrate->size; - } - if (ptr->config) { - e = gf_isom_box_size((GF_Box *)ptr->config); - if (e) return e; - ptr->size += ptr->config->size; - } - return gf_isom_box_array_size(s, ptr->protections); + return GF_OK; } #endif /*GPAC_DISABLE_ISOM_WRITE*/ @@ -7801,7 +8091,6 @@ void lsr1_del(GF_Box *s) if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc); if (ptr->lsr_config) gf_isom_box_del((GF_Box *) ptr->lsr_config); - if (ptr->bitrate) gf_isom_box_del((GF_Box *) ptr->bitrate); if (ptr->descr) gf_isom_box_del((GF_Box *) ptr->descr); gf_free(ptr); } @@ -7814,10 +8103,6 @@ GF_Err lsr1_AddBox(GF_Box *s, GF_Box *a) if (ptr->lsr_config) ERROR_ON_DUPLICATED_BOX(a, ptr) ptr->lsr_config = (GF_LASERConfigurationBox *)a; break; - case GF_ISOM_BOX_TYPE_BTRT: - if (ptr->bitrate) ERROR_ON_DUPLICATED_BOX(a, ptr) - ptr->bitrate = (GF_MPEG4BitRateBox *)a; - break; case GF_ISOM_BOX_TYPE_M4DS: if (ptr->descr) ERROR_ON_DUPLICATED_BOX(a, ptr) ptr->descr = (GF_MPEG4ExtensionDescriptorsBox *)a; @@ -7865,10 +8150,6 @@ GF_Err lsr1_Write(GF_Box *s, GF_BitStream *bs) e = gf_isom_box_write((GF_Box *)ptr->descr, bs); if (e) return e; } - if (ptr->bitrate) { - e = gf_isom_box_write((GF_Box *)ptr->bitrate, bs); - if (e) return e; - } return e; } @@ -7884,15 +8165,10 @@ GF_Err lsr1_Size(GF_Box *s) if (e) return e; ptr->size += ptr->lsr_config->size; } - if (ptr->bitrate) { - e = gf_isom_box_size((GF_Box *)ptr->bitrate); - if (e) return e; - ptr->size += ptr->bitrate->size; - } if (ptr->descr) { - e = gf_isom_box_size((GF_Box *)ptr->bitrate); + e = gf_isom_box_size((GF_Box *)ptr->descr); if (e) return e; - ptr->size += ptr->bitrate->size; + ptr->size += ptr->descr->size; } return GF_OK; } @@ -8028,9 +8304,9 @@ GF_Err pcrb_Read(GF_Box *s,GF_BitStream *bs) ptr->pcr_values = gf_malloc(sizeof(u64)*ptr->subsegment_count); for (i=0; i<ptr->subsegment_count; i++) { u64 data1 = gf_bs_read_u32(bs); - u64 data2 = gf_bs_read_u32(bs); - ptr->size -= 8; - ptr->pcr_values[i] = (data1 << 10) | (data2 >> 22); + u64 data2 = gf_bs_read_u16(bs); + ptr->size -= 6; + ptr->pcr_values[i] = (data1 << 10) | (data2 >> 6); } return GF_OK; @@ -8051,10 +8327,10 @@ GF_Err pcrb_Write(GF_Box *s, GF_BitStream *bs) for (i=0; i<ptr->subsegment_count; i++ ) { u32 data1 = (u32) (ptr->pcr_values[i] >> 10); - u32 data2 = (u32) ((ptr->pcr_values[i]& 0x3FF) << 22); + u16 data2 = (u16) (ptr->pcr_values[i] << 6); gf_bs_write_u32(bs, data1); - gf_bs_write_u32(bs, data2); + gf_bs_write_u16(bs, data2); } return GF_OK; } @@ -8067,7 +8343,7 @@ GF_Err pcrb_Size(GF_Box *s) if (e) return e; ptr->size += 4; - ptr->size += ptr->subsegment_count * 8; + ptr->size += ptr->subsegment_count * 6; return GF_OK; } diff --git a/src/isomedia/box_code_drm.c b/src/isomedia/box_code_drm.c index 1c3adae..2a6ac6d 100644 --- a/src/isomedia/box_code_drm.c +++ b/src/isomedia/box_code_drm.c @@ -1291,11 +1291,21 @@ void senc_del(GF_Box *s) gf_free(s); } +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *ptr) +#else +GF_Err senc_Parse(GF_BitStream *bs, GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *ptr) +#endif { GF_Err e; u32 i, j, count; u64 pos = gf_bs_get_position(bs); + +#ifdef GPAC_DISABLE_ISOM_FRAGMENTS + if (!traf) + return GF_BAD_PARAM; +#endif + gf_bs_seek(bs, ptr->bs_offset); count = gf_bs_read_u32(bs); diff --git a/src/isomedia/box_code_meta.c b/src/isomedia/box_code_meta.c index a58b677..e950091 100644 --- a/src/isomedia/box_code_meta.c +++ b/src/isomedia/box_code_meta.c @@ -296,7 +296,7 @@ GF_Box *iloc_New() return (GF_Box *)tmp; } -void iloc_entry_del(GF_ItemLocationEntry *location) +void iloc_entry_del(GF_ItemLocationEntry *location) { u32 j, extent_count; extent_count = gf_list_count(location->extent_entries); diff --git a/src/isomedia/box_dump.c b/src/isomedia/box_dump.c index b5f0c45..bf0e695 100644 --- a/src/isomedia/box_dump.c +++ b/src/isomedia/box_dump.c @@ -26,15 +26,20 @@ #include <gpac/internal/isomedia_dev.h> #include <gpac/utf.h> #include <gpac/network.h> +#include <gpac/color.h> #include <time.h> #ifndef GPAC_DISABLE_ISOM_DUMP static GF_Err apple_tag_dump(GF_Box *a, FILE * trace); -void NullBoxErr(FILE * trace) +void NullBoxErr(FILE * trace, u32 box_4cc) { - fprintf(trace, "<!--ERROR: NULL Box Found-->\n"); + if (box_4cc) { + fprintf(trace, "<!--ERROR: NULL Box Found, expecting %s -->\n", gf_4cc_to_str(box_4cc) ); + } else { + fprintf(trace, "<!--ERROR: NULL Box Found-->\n"); + } } void BadTopBoxErr(GF_Box *a, FILE * trace) @@ -81,12 +86,12 @@ GF_Err DumpBox(GF_Box *a, FILE * trace) return GF_OK; } -GF_Err gf_box_dump(void *ptr, FILE * trace) +GF_Err gf_box_dump_ex(void *ptr, FILE * trace, u32 box_4cc) { GF_Box *a = (GF_Box *) ptr; if (!a) { - NullBoxErr(trace); + NullBoxErr(trace, box_4cc); return GF_OK; } @@ -127,6 +132,8 @@ GF_Err gf_box_dump(void *ptr, FILE * trace) return urn_dump(a, trace); case GF_ISOM_BOX_TYPE_CPRT: return cprt_dump(a, trace); + case GF_ISOM_BOX_TYPE_KIND: + return kind_dump(a, trace); case GF_ISOM_BOX_TYPE_HDLR: return hdlr_dump(a, trace); case GF_ISOM_BOX_TYPE_IODS: @@ -188,6 +195,8 @@ GF_Err gf_box_dump(void *ptr, FILE * trace) return tref_dump(a, trace); case GF_ISOM_BOX_TYPE_MDIA: return mdia_dump(a, trace); + case GF_ISOM_BOX_TYPE_ELNG: + return elng_dump(a, trace); case GF_ISOM_BOX_TYPE_CHPL: return chpl_dump(a, trace); case GF_ISOM_BOX_TYPE_PDIN: @@ -265,6 +274,8 @@ GF_Err gf_box_dump(void *ptr, FILE * trace) return mehd_dump(a, trace); case GF_ISOM_BOX_TYPE_TREX: return trex_dump(a, trace); + case GF_ISOM_BOX_TYPE_TREP: + return trep_dump(a, trace); case GF_ISOM_BOX_TYPE_MOOF: return moof_dump(a, trace); case GF_ISOM_BOX_TYPE_MFHD: @@ -496,15 +507,18 @@ GF_Err gf_box_dump(void *ptr, FILE * trace) return defa_dump(a, trace); } #ifndef GPAC_DISABLE_TTXT - case GF_ISOM_BOX_TYPE_STSE: - return stse_dump(a, trace); + case GF_ISOM_BOX_TYPE_STXT: + return metx_dump(a, trace); + + case GF_ISOM_BOX_TYPE_TXTC: + return txtc_dump(a, trace); - case GF_ISOM_BOX_TYPE_STTC: case GF_ISOM_BOX_TYPE_VTTC: case GF_ISOM_BOX_TYPE_CTIM: case GF_ISOM_BOX_TYPE_IDEN: case GF_ISOM_BOX_TYPE_STTG: case GF_ISOM_BOX_TYPE_PAYL: + case GF_ISOM_BOX_TYPE_VTTA: return boxstring_dump(a, trace); case GF_ISOM_BOX_TYPE_VTCU: return vtcu_dump(a, trace); @@ -514,7 +528,7 @@ GF_Err gf_box_dump(void *ptr, FILE * trace) return wvtt_dump(a, trace); case GF_ISOM_BOX_TYPE_STPP: - return stpp_dump(a, trace); + return metx_dump(a, trace); case GF_ISOM_BOX_TYPE_SBTT: return metx_dump(a, trace); #endif @@ -540,6 +554,12 @@ GF_Err gf_box_dump(void *ptr, FILE * trace) } } + +GF_Err gf_box_dump(void *ptr, FILE * trace) +{ + return gf_box_dump_ex(ptr, trace, 0); +} + GF_Err gf_box_array_dump(GF_List *list, FILE * trace) { u32 i; @@ -691,7 +711,7 @@ GF_Err moov_dump(GF_Box *a, FILE * trace) if (p->iods) gf_box_dump(p->iods, trace); if (p->meta) gf_box_dump(p->meta, trace); - gf_box_dump(p->mvhd, trace); + gf_box_dump_ex(p->mvhd, trace,GF_ISOM_BOX_TYPE_MVHD); #ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (p->mvex) gf_box_dump(p->mvex, trace); @@ -795,15 +815,15 @@ GF_Err stbl_dump(GF_Box *a, FILE * trace) fprintf(trace, "<SampleTableBox>\n"); DumpBox(a, trace); - gf_box_dump(p->SampleDescription, trace); - gf_box_dump(p->TimeToSample, trace); + gf_box_dump_ex(p->SampleDescription, trace, GF_ISOM_BOX_TYPE_STSD); + gf_box_dump_ex(p->TimeToSample, trace, GF_ISOM_BOX_TYPE_STTS); if (p->CompositionOffset) gf_box_dump(p->CompositionOffset, trace); if (p->CompositionToDecode) gf_box_dump(p->CompositionToDecode, trace); if (p->SyncSample) gf_box_dump(p->SyncSample, trace); if (p->ShadowSync) gf_box_dump(p->ShadowSync, trace); - gf_box_dump(p->SampleToChunk, trace); - gf_box_dump(p->SampleSize, trace); - gf_box_dump(p->ChunkOffset, trace); + gf_box_dump_ex(p->SampleToChunk, trace, GF_ISOM_BOX_TYPE_STSC); + gf_box_dump_ex(p->SampleSize, trace, GF_ISOM_BOX_TYPE_STSZ); + gf_box_dump_ex(p->ChunkOffset, trace, GF_ISOM_BOX_TYPE_STCO); if (p->DegradationPriority) gf_box_dump(p->DegradationPriority, trace); if (p->SampleDep) gf_box_dump(p->SampleDep, trace); if (p->PaddingBits) gf_box_dump(p->PaddingBits, trace); @@ -837,7 +857,7 @@ GF_Err dinf_dump(GF_Box *a, FILE * trace) p = (GF_DataInformationBox *)a; fprintf(trace, "<DataInformationBox>"); DumpBox(a, trace); - gf_box_dump(p->dref, trace); + gf_box_dump_ex(p->dref, trace, GF_ISOM_BOX_TYPE_DREF); gf_box_dump_done("DataInformationBox", a, trace); return GF_OK; } @@ -892,6 +912,18 @@ GF_Err cprt_dump(GF_Box *a, FILE * trace) return GF_OK; } +GF_Err kind_dump(GF_Box *a, FILE * trace) +{ + GF_KindBox *p; + + p = (GF_KindBox *)a; + fprintf(trace, "<KindBox schemeURI=\"%s\" value=\"%s\">\n", p->schemeURI, (p->value ? p->value : "")); + DumpBox(a, trace); + gf_full_box_dump(a, trace); + gf_box_dump_done("KindBox", a, trace); + return GF_OK; +} + static char *format_duration(u64 dur, u32 timescale, char *szDur) { @@ -908,6 +940,15 @@ static char *format_duration(u64 dur, u32 timescale, char *szDur) return szDur; } +static void dump_escape_string(FILE * trace, char *name) +{ + u32 i, len = (u32) strlen(name); + for (i=0; i<len; i++) { + if (name[i]=='"') fprintf(trace, """); + else fputc(name[i], trace); + } +} + GF_Err chpl_dump(GF_Box *a, FILE * trace) { u32 i, count; @@ -920,7 +961,9 @@ GF_Err chpl_dump(GF_Box *a, FILE * trace) count = gf_list_count(p->list); for (i=0; i<count; i++) { GF_ChapterEntry *ce = (GF_ChapterEntry *)gf_list_get(p->list, i); - fprintf(trace, "<Chapter name=\"%s\" startTime=\"%s\" />\n", ce->name, format_duration(ce->start_time, 1000*10000, szDur)); + fprintf(trace, "<Chapter name=\""); + dump_escape_string(trace, ce->name); + fprintf(trace, "\" startTime=\"%s\" />\n", format_duration(ce->start_time, 1000*10000, szDur)); } gf_box_dump_done("ChapterListBox", a, trace); @@ -1052,7 +1095,6 @@ GF_Err mp4v_dump(GF_Box *a, FILE * trace) if (p->avc_config) gf_box_dump(p->avc_config, trace); if (p->ipod_ext) gf_box_dump(p->ipod_ext, trace); if (p->descr) gf_box_dump(p->descr, trace); - if (p->bitrate) gf_box_dump(p->bitrate, trace); if (p->svc_config) gf_box_dump(p->svc_config, trace); if (p->shvc_config) gf_box_dump(p->shvc_config, trace); } @@ -1138,7 +1180,7 @@ GF_Err edts_dump(GF_Box *a, FILE * trace) p = (GF_EditBox *)a; fprintf(trace, "<EditBox>\n"); DumpBox(a, trace); - gf_box_dump(p->editList, trace); + gf_box_dump_ex(p->editList, trace, GF_ISOM_BOX_TYPE_ELST); gf_box_dump_done("EditBox", a, trace); return GF_OK; } @@ -1155,9 +1197,7 @@ GF_Err udta_dump(GF_Box *a, FILE * trace) i=0; while ((map = (GF_UserDataMap *)gf_list_enum(p->recordList, &i))) { - fprintf(trace, "<UDTARecord Type=\"%s\">\n", gf_4cc_to_str(map->boxType)); gf_box_array_dump(map->other_boxes, trace); - fprintf(trace, "</UDTARecord>\n"); } gf_box_dump_done("UserDataBox", a, trace); return GF_OK; @@ -1506,9 +1546,9 @@ GF_Err minf_dump(GF_Box *a, FILE * trace) fprintf(trace, "<MediaInformationBox>\n"); DumpBox(a, trace); - gf_box_dump(p->InfoHeader, trace); - gf_box_dump(p->dataInformation, trace); - gf_box_dump(p->sampleTable, trace); + gf_box_dump_ex(p->InfoHeader, trace, GF_ISOM_BOX_TYPE_NMHD); + gf_box_dump_ex(p->dataInformation, trace, GF_ISOM_BOX_TYPE_DINF); + gf_box_dump_ex(p->sampleTable, trace, GF_ISOM_BOX_TYPE_STBL); gf_box_dump_done("MediaInformationBox", a, trace); return GF_OK; } @@ -1559,13 +1599,22 @@ GF_Err mdia_dump(GF_Box *a, FILE * trace) GF_MediaBox *p = (GF_MediaBox *)a; fprintf(trace, "<MediaBox>\n"); DumpBox(a, trace); - gf_box_dump(p->mediaHeader, trace); - gf_box_dump(p->handler, trace); - gf_box_dump(p->information, trace); + gf_box_dump_ex(p->mediaHeader, trace, GF_ISOM_BOX_TYPE_MDHD); + gf_box_dump_ex(p->handler, trace,GF_ISOM_BOX_TYPE_HDLR); + gf_box_dump_ex(p->information, trace, GF_ISOM_BOX_TYPE_MINF); gf_box_dump_done("MediaBox", a, trace); return GF_OK; } +GF_Err elng_dump(GF_Box *a, FILE * trace) +{ + GF_ExtendedLanguageBox *p = (GF_ExtendedLanguageBox *)a; + fprintf(trace, "<ExtendedLanguageBox LanguageCode=\"%s\">\n", p->extended_language); + DumpBox(a, trace); + gf_box_dump_done("ExtendedLanguageBox", a, trace); + return GF_OK; +} + GF_Err defa_dump(GF_Box *a, FILE * trace) { fprintf(trace, "<UnknownBox>\n"); @@ -1880,10 +1929,10 @@ GF_Err m4ds_dump(GF_Box *a, FILE * trace) GF_Err btrt_dump(GF_Box *a, FILE * trace) { - GF_MPEG4BitRateBox *p = (GF_MPEG4BitRateBox*)a; - fprintf(trace, "<MPEG4BitRateBox BufferSizeDB=\"%d\" avgBitRate=\"%d\" maxBitRate=\"%d\">\n", p->bufferSizeDB, p->avgBitrate, p->maxBitrate); + GF_BitRateBox *p = (GF_BitRateBox*)a; + fprintf(trace, "<BitRateBox BufferSizeDB=\"%d\" avgBitRate=\"%d\" maxBitRate=\"%d\">\n", p->bufferSizeDB, p->avgBitrate, p->maxBitrate); DumpBox(a, trace); - gf_box_dump_done("MPEG4BitRateBox", a, trace); + gf_box_dump_done("BitRateBox", a, trace); return GF_OK; } @@ -1923,7 +1972,7 @@ static void gpp_dump_style(FILE * trace, GF_StyleRecord *rec) if (rec->style_flags & 4) fprintf(trace, "Underlined "); } fprintf(trace, "\" fontSize=\"%d\" ", rec->font_size); - gpp_dump_rgba8(trace, "text-color", rec->text_color); + gpp_dump_rgba8(trace, "textColor", rec->text_color); fprintf(trace, "/>\n"); } @@ -1933,7 +1982,7 @@ GF_Err tx3g_dump(GF_Box *a, FILE * trace) fprintf(trace, "<Tx3gSampleEntryBox dataReferenceIndex=\"%d\" displayFlags=\"%x\" horizontal-justification=\"%d\" vertical-justification=\"%d\" ", p->dataReferenceIndex, p->displayFlags, p->horizontal_justification, p->vertical_justification); - gpp_dump_rgba8(trace, "background-color", p->back_color); + gpp_dump_rgba8(trace, "backgroundColor", p->back_color); fprintf(trace, ">\n"); DumpBox(a, trace); @@ -1943,7 +1992,7 @@ GF_Err tx3g_dump(GF_Box *a, FILE * trace) fprintf(trace, "<DefaultStyle>\n"); gpp_dump_style(trace, &p->default_style); fprintf(trace, "</DefaultStyle>\n"); - gf_box_dump(p->font_table, trace); + gf_box_dump_ex(p->font_table, trace, GF_ISOM_BOX_TYPE_FTAB); gf_box_dump_done("Tx3gSampleEntryBox", a, trace); return GF_OK; } @@ -1954,9 +2003,9 @@ GF_Err text_dump(GF_Box *a, FILE * trace) fprintf(trace, "<TextSampleEntryBox dataReferenceIndex=\"%d\" displayFlags=\"%x\" textJustification=\"%d\" ", p->dataReferenceIndex, p->displayFlags, p->textJustification); if (p->textName) - fprintf(trace, "textName=%s ", p->textName); + fprintf(trace, "textName=\"%s\" ", p->textName); gpp_dump_rgb16(trace, "background-color", p->background_color); - gpp_dump_rgb16(trace, "foreground-color", p->foreground_color); + gpp_dump_rgb16(trace, " foreground-color", p->foreground_color); fprintf(trace, ">\n"); DumpBox(a, trace); @@ -2463,6 +2512,7 @@ GF_Err mvex_dump(GF_Box *a, FILE * trace) DumpBox(a, trace); if (p->mehd) gf_box_dump(p->mehd, trace); gf_box_array_dump(p->TrackExList, trace); + gf_box_array_dump(p->TrackExPropList, trace); gf_box_dump_done("MovieExtendsBox", a, trace); return GF_OK; } @@ -2506,6 +2556,16 @@ GF_Err trex_dump(GF_Box *a, FILE * trace) return GF_OK; } +GF_Err trep_dump(GF_Box *a, FILE * trace) +{ + GF_TrackExtensionPropertiesBox *p = (GF_TrackExtensionPropertiesBox*)a; + fprintf(trace, "<TrackExtensionPropertiesBox TrackID=\"%d\">\n", p->trackID); + DumpBox(a, trace); + gf_full_box_dump(a, trace); + gf_box_dump_done("TrackExtensionPropertiesBox", a, trace); + return GF_OK; +} + GF_Err moof_dump(GF_Box *a, FILE * trace) { GF_MovieFragmentBox *p; @@ -2842,8 +2902,8 @@ static GF_Err gf_isom_dump_ttxt_track(GF_ISOFile *the_file, u32 track, FILE *dum txt = (GF_Tx3gSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, 0); switch (txt->type) { case GF_ISOM_BOX_TYPE_TX3G: - break; case GF_ISOM_BOX_TYPE_TEXT: + break; case GF_ISOM_BOX_TYPE_STPP: case GF_ISOM_BOX_TYPE_SBTT: default: @@ -2864,83 +2924,121 @@ static GF_Err gf_isom_dump_ttxt_track(GF_ISOFile *the_file, u32 track, FILE *dum for (i=0; i<nb_descs; i++) { GF_Tx3gSampleEntryBox *txt = (GF_Tx3gSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, i); - fprintf(dump, "<TextSampleDescription horizontalJustification=\""); - switch (txt->horizontal_justification) { - case 1: - fprintf(dump, "center"); - break; - case -1: - fprintf(dump, "right"); - break; - default: - fprintf(dump, "left"); - break; - } - fprintf(dump, "\" verticalJustification=\""); - switch (txt->vertical_justification) { - case 1: - fprintf(dump, "center"); - break; - case -1: - fprintf(dump, "bottom"); - break; - default: - fprintf(dump, "top"); - break; - } - fprintf(dump, "\" "); - gpp_dump_rgba8(dump, "backColor", txt->back_color); - fprintf(dump, " verticalText=\"%s\"", (txt->displayFlags & GF_TXT_VERTICAL) ? "yes" : "no"); - fprintf(dump, " fillTextRegion=\"%s\"", (txt->displayFlags & GF_TXT_FILL_REGION) ? "yes" : "no"); - fprintf(dump, " continuousKaraoke=\"%s\"", (txt->displayFlags & GF_TXT_KARAOKE) ? "yes" : "no"); - has_scroll = 0; - if (txt->displayFlags & GF_TXT_SCROLL_IN) { - has_scroll = 1; - if (txt->displayFlags & GF_TXT_SCROLL_OUT) fprintf(dump, " scroll=\"InOut\""); - else fprintf(dump, " scroll=\"In\""); - } else if (txt->displayFlags & GF_TXT_SCROLL_OUT) { - has_scroll = 1; - fprintf(dump, " scroll=\"Out\""); - } else { - fprintf(dump, " scroll=\"None\""); - } - if (has_scroll) { - u32 mode = (txt->displayFlags & GF_TXT_SCROLL_DIRECTION)>>7; - switch (mode) { - case GF_TXT_SCROLL_CREDITS: - fprintf(dump, " scrollMode=\"Credits\""); + if (txt->type==GF_ISOM_BOX_TYPE_TX3G) { + fprintf(dump, "<TextSampleDescription horizontalJustification=\""); + switch (txt->horizontal_justification) { + case 1: + fprintf(dump, "center"); + break; + case -1: + fprintf(dump, "right"); + break; + default: + fprintf(dump, "left"); break; - case GF_TXT_SCROLL_MARQUEE: - fprintf(dump, " scrollMode=\"Marquee\""); + } + fprintf(dump, "\" verticalJustification=\""); + switch (txt->vertical_justification) { + case 1: + fprintf(dump, "center"); break; - case GF_TXT_SCROLL_DOWN: - fprintf(dump, " scrollMode=\"Down\""); + case -1: + fprintf(dump, "bottom"); break; - case GF_TXT_SCROLL_RIGHT: - fprintf(dump, " scrollMode=\"Right\""); + default: + fprintf(dump, "top"); + break; + } + fprintf(dump, "\" "); + gpp_dump_rgba8(dump, "backColor", txt->back_color); + fprintf(dump, " verticalText=\"%s\"", (txt->displayFlags & GF_TXT_VERTICAL) ? "yes" : "no"); + fprintf(dump, " fillTextRegion=\"%s\"", (txt->displayFlags & GF_TXT_FILL_REGION) ? "yes" : "no"); + fprintf(dump, " continuousKaraoke=\"%s\"", (txt->displayFlags & GF_TXT_KARAOKE) ? "yes" : "no"); + has_scroll = 0; + if (txt->displayFlags & GF_TXT_SCROLL_IN) { + has_scroll = 1; + if (txt->displayFlags & GF_TXT_SCROLL_OUT) fprintf(dump, " scroll=\"InOut\""); + else fprintf(dump, " scroll=\"In\""); + } else if (txt->displayFlags & GF_TXT_SCROLL_OUT) { + has_scroll = 1; + fprintf(dump, " scroll=\"Out\""); + } else { + fprintf(dump, " scroll=\"None\""); + } + if (has_scroll) { + u32 mode = (txt->displayFlags & GF_TXT_SCROLL_DIRECTION)>>7; + switch (mode) { + case GF_TXT_SCROLL_CREDITS: + fprintf(dump, " scrollMode=\"Credits\""); + break; + case GF_TXT_SCROLL_MARQUEE: + fprintf(dump, " scrollMode=\"Marquee\""); + break; + case GF_TXT_SCROLL_DOWN: + fprintf(dump, " scrollMode=\"Down\""); + break; + case GF_TXT_SCROLL_RIGHT: + fprintf(dump, " scrollMode=\"Right\""); + break; + default: + fprintf(dump, " scrollMode=\"Unknown\""); + break; + } + } + fprintf(dump, ">\n"); + fprintf(dump, "<FontTable>\n"); + if (txt->font_table) { + for (j=0; j<txt->font_table->entry_count; j++) { + fprintf(dump, "<FontTableEntry fontName=\"%s\" fontID=\"%d\"/>\n", txt->font_table->fonts[j].fontName, txt->font_table->fonts[j].fontID); + + } + } + fprintf(dump, "</FontTable>\n"); + if ((txt->default_box.bottom == txt->default_box.top) || (txt->default_box.right == txt->default_box.left)) { + txt->default_box.top = txt->default_box.left = 0; + txt->default_box.right = trak->Header->width / 65536; + txt->default_box.bottom = trak->Header->height / 65536; + } + gpp_dump_box_nobox(dump, &txt->default_box); + gpp_dump_style_nobox(dump, &txt->default_style, NULL, 0); + fprintf(dump, "</TextSampleDescription>\n"); + } else { + GF_TextSampleEntryBox *text = (GF_TextSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, i); + fprintf(dump, "<TextSampleDescription horizontalJustification=\""); + switch (text->textJustification) { + case 1: + fprintf(dump, "center"); + break; + case -1: + fprintf(dump, "right"); break; default: - fprintf(dump, " scrollMode=\"Unknown\""); + fprintf(dump, "left"); break; } - } - fprintf(dump, ">\n"); - fprintf(dump, "<FontTable>\n"); - if (txt->font_table) { - for (j=0; j<txt->font_table->entry_count; j++) { - fprintf(dump, "<FontTableEntry fontName=\"%s\" fontID=\"%d\"/>\n", txt->font_table->fonts[j].fontName, txt->font_table->fonts[j].fontID); + fprintf(dump, "\""); + gpp_dump_rgb16(dump, " backColor", text->background_color); + + if ((text->default_box.bottom == text->default_box.top) || (text->default_box.right == text->default_box.left)) { + text->default_box.top = text->default_box.left = 0; + text->default_box.right = trak->Header->width / 65536; + text->default_box.bottom = trak->Header->height / 65536; } + + if (text->displayFlags & GF_TXT_SCROLL_IN) { + if (text->displayFlags & GF_TXT_SCROLL_OUT) fprintf(dump, " scroll=\"InOut\""); + else fprintf(dump, " scroll=\"In\""); + } else if (text->displayFlags & GF_TXT_SCROLL_OUT) { + fprintf(dump, " scroll=\"Out\""); + } else { + fprintf(dump, " scroll=\"None\""); + } + fprintf(dump, ">\n"); + + gpp_dump_box_nobox(dump, &text->default_box); + fprintf(dump, "</TextSampleDescription>\n"); } - fprintf(dump, "</FontTable>\n"); - if ((txt->default_box.bottom == txt->default_box.top) || (txt->default_box.right == txt->default_box.left)) { - txt->default_box.top = txt->default_box.left = 0; - txt->default_box.right = trak->Header->width / 65536; - txt->default_box.bottom = trak->Header->height / 65536; - } - gpp_dump_box_nobox(dump, &txt->default_box); - gpp_dump_style_nobox(dump, &txt->default_style, NULL, 0); - fprintf(dump, "</TextSampleDescription>\n"); } fprintf(dump, "</TextStreamHeader>\n"); @@ -3173,7 +3271,7 @@ static GF_Err gf_isom_dump_srt_track(GF_ISOFile *the_file, u32 track, FILE *dump if (!txt->len) { fprintf(dump, "\n"); } else { - u32 styles, char_num, new_styles; + u32 styles, char_num, new_styles, color, new_color; u16 utf16Line[10000]; /*UTF16*/ @@ -3191,17 +3289,21 @@ static GF_Err gf_isom_dump_srt_track(GF_ISOFile *the_file, u32 track, FILE *dump char_num = 0; styles = 0; new_styles = txtd->default_style.style_flags; + color = new_color = txtd->default_style.text_color; + for (j=0; j<len; j++) { Bool is_new_line; if (txt->styles) { new_styles = txtd->default_style.style_flags; + new_color = txtd->default_style.text_color; for (k=0; k<txt->styles->entry_count; k++) { if (txt->styles->styles[k].startCharOffset>char_num) continue; if (txt->styles->styles[k].endCharOffset<char_num+1) continue; if (txt->styles->styles[k].style_flags & (GF_TXT_STYLE_ITALIC | GF_TXT_STYLE_BOLD | GF_TXT_STYLE_UNDERLINED)) { new_styles = txt->styles->styles[k].style_flags; + new_color = txt->styles->styles[k].text_color; break; } } @@ -3211,12 +3313,20 @@ static GF_Err gf_isom_dump_srt_track(GF_ISOFile *the_file, u32 track, FILE *dump if ((new_styles & GF_TXT_STYLE_ITALIC) && !(styles & GF_TXT_STYLE_ITALIC)) fprintf(dump, "<i>"); if ((new_styles & GF_TXT_STYLE_UNDERLINED) && !(styles & GF_TXT_STYLE_UNDERLINED)) fprintf(dump, "<u>"); - if ((styles & GF_TXT_STYLE_BOLD) && !(new_styles & GF_TXT_STYLE_BOLD)) fprintf(dump, "</b>"); - if ((styles & GF_TXT_STYLE_ITALIC) && !(new_styles & GF_TXT_STYLE_ITALIC)) fprintf(dump, "</i>"); if ((styles & GF_TXT_STYLE_UNDERLINED) && !(new_styles & GF_TXT_STYLE_UNDERLINED)) fprintf(dump, "</u>"); + if ((styles & GF_TXT_STYLE_ITALIC) && !(new_styles & GF_TXT_STYLE_ITALIC)) fprintf(dump, "</i>"); + if ((styles & GF_TXT_STYLE_BOLD) && !(new_styles & GF_TXT_STYLE_BOLD)) fprintf(dump, "</b>"); styles = new_styles; } + if (new_color != color) { + if (new_color ==txtd->default_style.text_color) { + fprintf(dump, "</font>"); + } else { + fprintf(dump, "<font color=\"%s\">", gf_color_get_name(new_color) ); + } + color = new_color; + } /*not sure if styles must be reseted at line breaks in srt...*/ is_new_line = 0; @@ -3242,16 +3352,17 @@ static GF_Err gf_isom_dump_srt_track(GF_ISOFile *the_file, u32 track, FILE *dump } new_styles = 0; if (new_styles != styles) { - if ((new_styles & GF_TXT_STYLE_BOLD) && !(styles & GF_TXT_STYLE_BOLD)) fprintf(dump, "<b>"); - if ((new_styles & GF_TXT_STYLE_ITALIC) && !(styles & GF_TXT_STYLE_ITALIC)) fprintf(dump, "<i>"); - if ((new_styles & GF_TXT_STYLE_UNDERLINED) && !(styles & GF_TXT_STYLE_UNDERLINED)) fprintf(dump, "<u>"); - - if ((styles & GF_TXT_STYLE_BOLD) && !(new_styles & GF_TXT_STYLE_BOLD)) fprintf(dump, "</b>"); - if ((styles & GF_TXT_STYLE_ITALIC) && !(new_styles & GF_TXT_STYLE_ITALIC)) fprintf(dump, "</i>"); - if ((styles & GF_TXT_STYLE_UNDERLINED) && !(new_styles & GF_TXT_STYLE_UNDERLINED)) fprintf(dump, "</u>"); + if (styles & GF_TXT_STYLE_UNDERLINED) fprintf(dump, "</u>"); + if (styles & GF_TXT_STYLE_ITALIC) fprintf(dump, "</i>"); + if (styles & GF_TXT_STYLE_BOLD) fprintf(dump, "</b>"); - styles = new_styles; + styles = 0; } + + if (color != txtd->default_style.text_color) { + fprintf(dump, "</font>"); + color = txtd->default_style.text_color; + } fprintf(dump, "\n"); } gf_isom_sample_del(&s); @@ -3283,7 +3394,7 @@ static GF_Err gf_isom_dump_svg_track(GF_ISOFile *the_file, u32 track, FILE *dump strcpy(nhmlFileName, the_file->fileName); strcat(nhmlFileName, ".nhml"); - nhmlFile = gf_f64_open(nhmlFileName, "wt"); + nhmlFile = gf_fopen(nhmlFileName, "wt"); fprintf(nhmlFile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); fprintf(nhmlFile, "<NHNTStream streamType=\"3\" objectTypeIndication=\"10\" timeScale=\"%d\" baseMediaFile=\"file.svg\" inRootOD=\"yes\">\n", trak->Media->mediaHeader->timeScale); fprintf(nhmlFile, "<NHNTSample isRAP=\"yes\" DTS=\"0\" xmlFrom=\"doc.start\" xmlTo=\"text_1.start\"/>\n"); @@ -3342,20 +3453,21 @@ static GF_Err gf_isom_dump_svg_track(GF_ISOFile *the_file, u32 track, FILE *dump fprintf(dump, "</svg>\n"); fprintf(nhmlFile, "</NHNTStream>\n"); - fclose(nhmlFile); + gf_fclose(nhmlFile); if (count) gf_set_progress("SRT Extract", i, count); return GF_OK; } GF_EXPORT -GF_Err gf_isom_text_dump(GF_ISOFile *the_file, u32 track, FILE *dump, u32 dump_type) +GF_Err gf_isom_text_dump(GF_ISOFile *the_file, u32 track, FILE *dump, GF_TextDumpType dump_type) { switch (dump_type) { - case 2: + case GF_TEXTDUMPTYPE_SVG: return gf_isom_dump_svg_track(the_file, track, dump); - case 1: + case GF_TEXTDUMPTYPE_SRT: return gf_isom_dump_srt_track(the_file, track, dump); + case GF_TEXTDUMPTYPE_TTXT: default: return gf_isom_dump_ttxt_track(the_file, track, dump); } @@ -3370,9 +3482,9 @@ GF_Err sinf_dump(GF_Box *a, FILE * trace) fprintf(trace, "<ProtectionInfoBox>\n"); DumpBox(a, trace); - gf_box_dump(p->original_format, trace); - gf_box_dump(p->scheme_type, trace); - gf_box_dump(p->info, trace); + gf_box_dump_ex(p->original_format, trace, GF_ISOM_BOX_TYPE_FRMA); + gf_box_dump_ex(p->scheme_type, trace, GF_ISOM_BOX_TYPE_SCHM); + gf_box_dump_ex(p->info, trace, GF_ISOM_BOX_TYPE_SCHI); gf_box_dump_done("ProtectionInfoBox", a, trace); return GF_OK; } @@ -3898,20 +4010,51 @@ GF_Err tsel_dump(GF_Box *a, FILE * trace) GF_Err metx_dump(GF_Box *a, FILE * trace) { GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox*)a; - const char *name = (ptr->type==GF_ISOM_BOX_TYPE_METX) ? "XMLMetaDataSampleEntryBox" : "TextMetaDataSampleEntryBox"; + const char *name; + switch (ptr->type) { + case GF_ISOM_BOX_TYPE_METX: + name = "XMLMetaDataSampleEntryBox"; + break; + case GF_ISOM_BOX_TYPE_METT: + name = "TextMetaDataSampleEntryBox"; + break; + case GF_ISOM_BOX_TYPE_SBTT: + name = "SubtitleSampleEntryBox"; + break; + case GF_ISOM_BOX_TYPE_STXT: + name = "SimpleTextSampleEntryBox"; + break; + case GF_ISOM_BOX_TYPE_STPP: + name = "XMLSubtitleSampleEntryBox"; + break; + default: + name = "UnknownTextSampleEntryBox"; + break; + } fprintf(trace, "<%s ", name); + if (ptr->type==GF_ISOM_BOX_TYPE_METX) { - fprintf(trace, "namespace=\"%s\" ", ptr->mime_type_or_namespace); + fprintf(trace, "namespace=\"%s\" ", ptr->xml_namespace); if (ptr->xml_schema_loc) fprintf(trace, "schema_location=\"%s\" ", ptr->xml_schema_loc); - } else { - fprintf(trace, "mime_type=\"%s\" ", ptr->mime_type_or_namespace); + if (ptr->content_encoding) fprintf(trace, "content_encoding=\"%s\" ", ptr->content_encoding); + + } else if (ptr->type==GF_ISOM_BOX_TYPE_STPP) { + fprintf(trace, "namespace=\"%s\" ", ptr->xml_namespace); + if (ptr->xml_schema_loc) fprintf(trace, "schema_location=\"%s\" ", ptr->xml_schema_loc); + if (ptr->mime_type) fprintf(trace, "auxiliary_mime_types=\"%s\" ", ptr->mime_type); + } + //mett, sbtt, stxt + else { + fprintf(trace, "mime_type=\"%s\" ", ptr->mime_type); + if (ptr->content_encoding) fprintf(trace, "content_encoding=\"%s\" ", ptr->content_encoding); } - if (ptr->content_encoding) fprintf(trace, "content_encoding=\"%s\" ", ptr->content_encoding); fprintf(trace, ">\n"); DumpBox(a, trace); - if (ptr->bitrate) gf_box_dump(ptr->bitrate, trace); + if ((ptr->type!=GF_ISOM_BOX_TYPE_METX) && (ptr->type!=GF_ISOM_BOX_TYPE_STPP) ) { + if (ptr->config) gf_box_dump(ptr->config, trace); + } gf_box_array_dump(ptr->protections, trace); gf_box_dump_done(NULL, a, trace); @@ -3919,19 +4062,15 @@ GF_Err metx_dump(GF_Box *a, FILE * trace) return GF_OK; } -GF_Err stse_dump(GF_Box *a, FILE * trace) +GF_Err txtc_dump(GF_Box *a, FILE * trace) { - GF_SimpleTextSampleEntryBox *ptr = (GF_SimpleTextSampleEntryBox*)a; - const char *name = "SimpleTextSampleEntryBox"; + GF_TextConfigBox *ptr = (GF_TextConfigBox*)a; + const char *name = "TextConfigBox"; - fprintf(trace, "<%s ", name); - fprintf(trace, "mime_type=\"%s\" ", ptr->mime_type); - if (ptr->content_encoding) fprintf(trace, "content_encoding=\"%s\" ", ptr->content_encoding); - fprintf(trace, ">\n"); + fprintf(trace, "<%s>", name); DumpBox(a, trace); - if (ptr->bitrate) gf_box_dump(ptr->bitrate, trace); - if (ptr->config) gf_box_dump(ptr->config, trace); + if (ptr->config) fprintf(trace, "%s", ptr->config); gf_box_dump_done(NULL, a, trace); fprintf(trace, "</%s>\n", name); @@ -3946,7 +4085,6 @@ GF_Err dims_dump(GF_Box *a, FILE * trace) DumpBox(a, trace); if (p->config) gf_box_dump(p->config, trace); if (p->scripts) gf_box_dump(p->scripts, trace); - if (p->bitrate) gf_box_dump(p->bitrate, trace); gf_box_array_dump(p->protections, trace); gf_box_dump_done("DIMSSampleEntryBox", a, trace); return GF_OK; @@ -4012,7 +4150,7 @@ GF_Err ac3_dump(GF_Box *a, FILE * trace) DumpBox(a, trace); if (p->is_ec3) a->type = GF_ISOM_BOX_TYPE_AC3; - gf_box_dump(p->info, trace); + gf_box_dump_ex(p->info, trace, p->is_ec3 ? GF_ISOM_BOX_TYPE_DEC3 : GF_ISOM_BOX_TYPE_DAC3); gf_box_dump_done(p->is_ec3 ? "EC3SampleEntryBox" : "AC3SampleEntryBox", a, trace); return GF_OK; } @@ -4035,7 +4173,6 @@ GF_Err lsr1_dump(GF_Box *a, FILE * trace) fprintf(trace, "<LASeRSampleEntryBox DataReferenceIndex=\"%d\">\n", p->dataReferenceIndex); DumpBox(a, trace); if (p->lsr_config) gf_box_dump(p->lsr_config, trace); - if (p->bitrate) gf_box_dump(p->bitrate, trace); if (p->descr) gf_box_dump(p->descr, trace); gf_box_dump_done("LASeRSampleEntryBox", a, trace); return GF_OK; @@ -4181,7 +4318,7 @@ GF_Err sgpd_dump(GF_Box *a, FILE * trace) u32 x,y,w,h, id, independent; Bool full_frame; - gf_isom_parse_trif_info( ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data, ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length, &id, &independent, &full_frame, &x, &y, &w, &h); + gf_isom_parse_trif_info( (const char *) ((GF_DefaultSampleGroupDescriptionEntry*)entry)->data, ((GF_DefaultSampleGroupDescriptionEntry*)entry)->length, &id, &independent, &full_frame, &x, &y, &w, &h); fprintf(trace, "<TileRegionGroupEntry ID=\"%d\" independent=\"%d\"", id, independent); if (!full_frame) fprintf(trace, " x=\"%d\" y=\"%d\"", x, y); @@ -4407,11 +4544,14 @@ GF_Err senc_dump(GF_Box *a, FILE * trace) GF_Err prft_dump(GF_Box *a, FILE * trace) { + Double fracs; GF_ProducerReferenceTimeBox *ptr = (GF_ProducerReferenceTimeBox *) a; - time_t secs = (ptr->ntp >> 32) - GF_NTP_SEC_1900_TO_1970; struct tm t = *gmtime(&secs); - fprintf(trace, "<ProducerReferenceTimeBox referenceTrackID=\"%d\" timestamp=\""LLU"\" NTP_frac=\"%d\" UTCClock=\"%d-%02d-%02dT%02d:%02d:%02dZ\">\n", ptr->refTrackID, ptr->timestamp, (u32) (ptr->ntp&0xFFFFFFFFULL), 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, (u32) t.tm_sec); + fracs = (Double) (ptr->ntp & 0xFFFFFFFFULL); + fracs /= 0xFFFFFFFF; + fracs *= 1000; + fprintf(trace, "<ProducerReferenceTimeBox referenceTrackID=\"%d\" timestamp=\""LLU"\" NTP=\""LLU"\" UTC=\"%d-%02d-%02dT%02d:%02d:%02d.%03dZ\">\n", ptr->refTrackID, ptr->timestamp, ptr->ntp, 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, (u32) t.tm_sec, (u32) fracs); DumpBox(a, trace); gf_full_box_dump((GF_Box *)a, trace); gf_box_dump_done("ProducerReferenceTimeBox", a, trace); diff --git a/src/isomedia/box_funcs.c b/src/isomedia/box_funcs.c index 87389e4..fec4efb 100644 --- a/src/isomedia/box_funcs.c +++ b/src/isomedia/box_funcs.c @@ -245,11 +245,11 @@ GF_Err gf_isom_read_box_list_ex(GF_Box *parent, GF_BitStream *bs, GF_Err (*add_b return e; } if (parent->size < a->size) { - if (a) gf_isom_box_del(a); - return GF_OK; - //return GF_ISOM_INVALID_FILE; + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Box \"%s\" is larger than container box\n", gf_4cc_to_str(a->type))); + parent->size = 0; + } else { + parent->size -= a->size; } - parent->size -= a->size; e = add_box(parent, a); if (e) { gf_isom_box_del(a); @@ -432,6 +432,8 @@ GF_Box *gf_isom_box_new(u32 boxType) return urn_New(); case GF_ISOM_BOX_TYPE_CPRT: return cprt_New(); + case GF_ISOM_BOX_TYPE_KIND: + return kind_New(); case GF_ISOM_BOX_TYPE_CHPL: return chpl_New(); case GF_ISOM_BOX_TYPE_HDLR: @@ -495,6 +497,8 @@ GF_Box *gf_isom_box_new(u32 boxType) return tref_New(); case GF_ISOM_BOX_TYPE_MDIA: return mdia_New(); + case GF_ISOM_BOX_TYPE_ELNG: + return elng_New(); case GF_ISOM_BOX_TYPE_FTYP: case GF_ISOM_BOX_TYPE_STYP: @@ -584,6 +588,8 @@ GF_Box *gf_isom_box_new(u32 boxType) return mehd_New(); case GF_ISOM_BOX_TYPE_TREX: return trex_New(); + case GF_ISOM_BOX_TYPE_TREP: + return trep_New(); case GF_ISOM_BOX_TYPE_MOOF: return moof_New(); case GF_ISOM_BOX_TYPE_MFHD: @@ -826,10 +832,10 @@ GF_Box *gf_isom_box_new(u32 boxType) return prft_New(); #ifndef GPAC_DISABLE_TTXT - case GF_ISOM_BOX_TYPE_STSE: - return stse_New(); - case GF_ISOM_BOX_TYPE_STTC: - return boxstring_New(GF_ISOM_BOX_TYPE_STTC); + case GF_ISOM_BOX_TYPE_STXT: + return metx_New(GF_ISOM_BOX_TYPE_STXT); + case GF_ISOM_BOX_TYPE_TXTC: + return txtc_New(); case GF_ISOM_BOX_TYPE_VTCU: return vtcu_New(); @@ -843,13 +849,15 @@ GF_Box *gf_isom_box_new(u32 boxType) return boxstring_New(GF_ISOM_BOX_TYPE_IDEN); case GF_ISOM_BOX_TYPE_STTG: return boxstring_New(GF_ISOM_BOX_TYPE_STTG); + case GF_ISOM_BOX_TYPE_VTTA: + return boxstring_New(GF_ISOM_BOX_TYPE_VTTA); case GF_ISOM_BOX_TYPE_PAYL: return boxstring_New(GF_ISOM_BOX_TYPE_PAYL); case GF_ISOM_BOX_TYPE_WVTT: return wvtt_New(); case GF_ISOM_BOX_TYPE_STPP: - return stpp_New(); + return metx_New(GF_ISOM_BOX_TYPE_STPP); case GF_ISOM_BOX_TYPE_SBTT: return metx_New(GF_ISOM_BOX_TYPE_SBTT); #endif //GPAC_DISABLE_TTXT @@ -947,6 +955,9 @@ void gf_isom_box_del(GF_Box *a) case GF_ISOM_BOX_TYPE_CPRT: cprt_del(a); return; + case GF_ISOM_BOX_TYPE_KIND: + kind_del(a); + return; case GF_ISOM_BOX_TYPE_HDLR: hdlr_del(a); return; @@ -1039,6 +1050,9 @@ void gf_isom_box_del(GF_Box *a) case GF_ISOM_BOX_TYPE_MDIA: mdia_del(a); return; + case GF_ISOM_BOX_TYPE_ELNG: + elng_del(a); + return; case GF_ISOM_BOX_TYPE_FTYP: case GF_ISOM_BOX_TYPE_STYP: ftyp_del(a); @@ -1163,6 +1177,9 @@ void gf_isom_box_del(GF_Box *a) case GF_ISOM_BOX_TYPE_TREX: trex_del(a); return; + case GF_ISOM_BOX_TYPE_TREP: + trep_del(a); + return; case GF_ISOM_BOX_TYPE_MOOF: moof_del(a); return; @@ -1472,11 +1489,11 @@ void gf_isom_box_del(GF_Box *a) return; #ifndef GPAC_DISABLE_TTXT - case GF_ISOM_BOX_TYPE_STSE: - stse_del(a); + case GF_ISOM_BOX_TYPE_STXT: + metx_del(a); return; - case GF_ISOM_BOX_TYPE_STTC: - boxstring_del(a); + case GF_ISOM_BOX_TYPE_TXTC: + txtc_del(a); return; case GF_ISOM_BOX_TYPE_VTCU: @@ -1486,17 +1503,10 @@ void gf_isom_box_del(GF_Box *a) vtte_del(a); return; case GF_ISOM_BOX_TYPE_VTTC: - boxstring_del(a); - return; case GF_ISOM_BOX_TYPE_CTIM: - boxstring_del(a); - return; case GF_ISOM_BOX_TYPE_IDEN: - boxstring_del(a); - return; case GF_ISOM_BOX_TYPE_STTG: - boxstring_del(a); - return; + case GF_ISOM_BOX_TYPE_VTTA: case GF_ISOM_BOX_TYPE_PAYL: boxstring_del(a); return; @@ -1505,7 +1515,7 @@ void gf_isom_box_del(GF_Box *a) return; case GF_ISOM_BOX_TYPE_STPP: - stpp_del(a); + metx_del(a); return; case GF_ISOM_BOX_TYPE_SBTT: metx_del(a); @@ -1580,6 +1590,8 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) return urn_Read(a, bs); case GF_ISOM_BOX_TYPE_CPRT: return cprt_Read(a, bs); + case GF_ISOM_BOX_TYPE_KIND: + return kind_Read(a, bs); case GF_ISOM_BOX_TYPE_HDLR: return hdlr_Read(a, bs); case GF_ISOM_BOX_TYPE_IODS: @@ -1635,6 +1647,8 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) return tref_Read(a, bs); case GF_ISOM_BOX_TYPE_MDIA: return mdia_Read(a, bs); + case GF_ISOM_BOX_TYPE_ELNG: + return elng_Read(a, bs); case GF_ISOM_BOX_TYPE_CHPL: return chpl_Read(a, bs); case GF_ISOM_BOX_TYPE_FTYP: @@ -1721,6 +1735,8 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) return mehd_Read(a, bs); case GF_ISOM_BOX_TYPE_TREX: return trex_Read(a, bs); + case GF_ISOM_BOX_TYPE_TREP: + return trep_Read(a, bs); case GF_ISOM_BOX_TYPE_MOOF: return moof_Read(a, bs); case GF_ISOM_BOX_TYPE_MFHD: @@ -1951,30 +1967,27 @@ GF_Err gf_isom_box_read(GF_Box *a, GF_BitStream *bs) return prft_Read(a, bs); #ifndef GPAC_DISABLE_TTXT - case GF_ISOM_BOX_TYPE_STSE: - return stse_Read(a, bs); - case GF_ISOM_BOX_TYPE_STTC: - return boxstring_Read(a, bs); + case GF_ISOM_BOX_TYPE_STXT: + return metx_Read(a, bs); + case GF_ISOM_BOX_TYPE_TXTC: + return txtc_Read(a, bs); case GF_ISOM_BOX_TYPE_VTCU: return vtcu_Read(a, bs); case GF_ISOM_BOX_TYPE_VTTE: return vtte_Read(a, bs); case GF_ISOM_BOX_TYPE_VTTC: - return boxstring_Read(a, bs); case GF_ISOM_BOX_TYPE_CTIM: - return boxstring_Read(a, bs); case GF_ISOM_BOX_TYPE_IDEN: - return boxstring_Read(a, bs); case GF_ISOM_BOX_TYPE_STTG: - return boxstring_Read(a, bs); + case GF_ISOM_BOX_TYPE_VTTA: case GF_ISOM_BOX_TYPE_PAYL: return boxstring_Read(a, bs); case GF_ISOM_BOX_TYPE_WVTT: return wvtt_Read(a, bs); case GF_ISOM_BOX_TYPE_STPP: - return stpp_Read(a, bs); + return metx_Read(a, bs); case GF_ISOM_BOX_TYPE_SBTT: return metx_Read(a, bs); @@ -2042,6 +2055,8 @@ GF_Err gf_isom_box_write_listing(GF_Box *a, GF_BitStream *bs) return chpl_Write(a, bs); case GF_ISOM_BOX_TYPE_CPRT: return cprt_Write(a, bs); + case GF_ISOM_BOX_TYPE_KIND: + return kind_Write(a, bs); case GF_ISOM_BOX_TYPE_HDLR: return hdlr_Write(a, bs); case GF_ISOM_BOX_TYPE_IODS: @@ -2103,6 +2118,8 @@ GF_Err gf_isom_box_write_listing(GF_Box *a, GF_BitStream *bs) return tref_Write(a, bs); case GF_ISOM_BOX_TYPE_MDIA: return mdia_Write(a, bs); + case GF_ISOM_BOX_TYPE_ELNG: + return elng_Write(a, bs); case GF_ISOM_BOX_TYPE_FTYP: case GF_ISOM_BOX_TYPE_STYP: return ftyp_Write(a, bs); @@ -2187,6 +2204,8 @@ GF_Err gf_isom_box_write_listing(GF_Box *a, GF_BitStream *bs) return mehd_Write(a, bs); case GF_ISOM_BOX_TYPE_TREX: return trex_Write(a, bs); + case GF_ISOM_BOX_TYPE_TREP: + return trep_Write(a, bs); case GF_ISOM_BOX_TYPE_MOOF: return moof_Write(a, bs); case GF_ISOM_BOX_TYPE_MFHD: @@ -2416,30 +2435,27 @@ GF_Err gf_isom_box_write_listing(GF_Box *a, GF_BitStream *bs) return rvcc_Write(a, bs); #ifndef GPAC_DISABLE_TTXT - case GF_ISOM_BOX_TYPE_STSE: - return stse_Write(a, bs); - case GF_ISOM_BOX_TYPE_STTC: - return boxstring_Write(a, bs); + case GF_ISOM_BOX_TYPE_STXT: + return metx_Write(a, bs); + case GF_ISOM_BOX_TYPE_TXTC: + return txtc_Write(a, bs); case GF_ISOM_BOX_TYPE_VTCU: return vtcu_Write(a, bs); case GF_ISOM_BOX_TYPE_VTTE: return vtte_Write(a, bs); case GF_ISOM_BOX_TYPE_VTTC: - return boxstring_Write(a, bs); case GF_ISOM_BOX_TYPE_CTIM: - return boxstring_Write(a, bs); case GF_ISOM_BOX_TYPE_IDEN: - return boxstring_Write(a, bs); case GF_ISOM_BOX_TYPE_STTG: - return boxstring_Write(a, bs); case GF_ISOM_BOX_TYPE_PAYL: + case GF_ISOM_BOX_TYPE_VTTA: return boxstring_Write(a, bs); case GF_ISOM_BOX_TYPE_WVTT: return wvtt_Write(a, bs); case GF_ISOM_BOX_TYPE_STPP: - return stpp_Write(a, bs); + return metx_Write(a, bs); case GF_ISOM_BOX_TYPE_SBTT: return metx_Write(a, bs); #endif//GPAC_DISABLE_TTXT @@ -2515,6 +2531,8 @@ static GF_Err gf_isom_box_size_listing(GF_Box *a) return chpl_Size(a); case GF_ISOM_BOX_TYPE_CPRT: return cprt_Size(a); + case GF_ISOM_BOX_TYPE_KIND: + return kind_Size(a); case GF_ISOM_BOX_TYPE_HDLR: return hdlr_Size(a); case GF_ISOM_BOX_TYPE_IODS: @@ -2574,6 +2592,8 @@ static GF_Err gf_isom_box_size_listing(GF_Box *a) return tref_Size(a); case GF_ISOM_BOX_TYPE_MDIA: return mdia_Size(a); + case GF_ISOM_BOX_TYPE_ELNG: + return elng_Size(a); case GF_ISOM_BOX_TYPE_FTYP: case GF_ISOM_BOX_TYPE_STYP: return ftyp_Size(a); @@ -2659,6 +2679,8 @@ static GF_Err gf_isom_box_size_listing(GF_Box *a) return mehd_Size(a); case GF_ISOM_BOX_TYPE_TREX: return trex_Size(a); + case GF_ISOM_BOX_TYPE_TREP: + return trep_Size(a); case GF_ISOM_BOX_TYPE_MOOF: return moof_Size(a); case GF_ISOM_BOX_TYPE_MFHD: @@ -2886,30 +2908,27 @@ static GF_Err gf_isom_box_size_listing(GF_Box *a) return rvcc_Size(a); #ifndef GPAC_DISABLE_TTXT - case GF_ISOM_BOX_TYPE_STSE: - return stse_Size(a); - case GF_ISOM_BOX_TYPE_STTC: - return boxstring_Size(a); + case GF_ISOM_BOX_TYPE_STXT: + return metx_Size(a); + case GF_ISOM_BOX_TYPE_TXTC: + return txtc_Size(a); case GF_ISOM_BOX_TYPE_VTCU: return vtcu_Size(a); case GF_ISOM_BOX_TYPE_VTTE: return vtte_Size(a); case GF_ISOM_BOX_TYPE_VTTC: - return boxstring_Size(a); case GF_ISOM_BOX_TYPE_CTIM: - return boxstring_Size(a); case GF_ISOM_BOX_TYPE_IDEN: - return boxstring_Size(a); case GF_ISOM_BOX_TYPE_STTG: - return boxstring_Size(a); case GF_ISOM_BOX_TYPE_PAYL: + case GF_ISOM_BOX_TYPE_VTTA: return boxstring_Size(a); case GF_ISOM_BOX_TYPE_WVTT: return wvtt_Size(a); case GF_ISOM_BOX_TYPE_STPP: - return stpp_Size(a); + return metx_Size(a); case GF_ISOM_BOX_TYPE_SBTT: return metx_Size(a); #endif // GPAC_DISABLE_TTXT diff --git a/src/isomedia/data_map.c b/src/isomedia/data_map.c index 0969885..e747f26 100644 --- a/src/isomedia/data_map.c +++ b/src/isomedia/data_map.c @@ -106,11 +106,11 @@ static Bool IsLargeFile(char *path) #ifndef _WIN32_WCE FILE *stream; s64 size; - stream = gf_f64_open(path, "rb"); + stream = gf_fopen(path, "rb"); if (!stream) return 0; - gf_f64_seek(stream, 0, SEEK_END); - size = gf_f64_tell(stream); - fclose(stream); + gf_fseek(stream, 0, SEEK_END); + size = gf_ftell(stream); + gf_fclose(stream); if (size == -1L) return 0; if (size > 0xFFFFFFFF) return 1; #endif @@ -297,8 +297,8 @@ void gf_isom_datamap_flush(GF_DataMap *map) gf_bs_flush(fdm->bs); #ifdef NODEJS_FS_WATCH_PATCH if (fdm->stream && fdm->szName) { - fclose(fdm->stream); - fdm->stream = gf_f64_open(fdm->szName, "a+b"); + gf_fclose(fdm->stream); + fdm->stream = gf_fopen(fdm->szName, "a+b"); gf_bs_reassign(fdm->bs, fdm->stream); } #endif @@ -338,9 +338,10 @@ GF_Err gf_isom_datamap_add_data(GF_DataMap *ptr, char *data, u32 dataSize) GF_DataMap *gf_isom_fdm_new_temp(const char *sPath) { - GF_FileDataMap *tmp = (GF_FileDataMap *) gf_malloc(sizeof(GF_FileDataMap)); + GF_FileDataMap *tmp; + GF_SAFEALLOC(tmp, GF_FileDataMap); if (!tmp) return NULL; - memset(tmp, 0, sizeof(GF_FileDataMap)); + tmp->type = GF_ISOM_DATA_FILE; tmp->mode = GF_ISOM_DATA_MAP_WRITE; @@ -353,7 +354,7 @@ GF_DataMap *gf_isom_fdm_new_temp(const char *sPath) } else { sprintf(szPath, "%s%p_isotmp", sPath, (void*) tmp); } - tmp->stream = gf_f64_open(szPath, "w+b"); + tmp->stream = gf_fopen(szPath, "w+b"); tmp->temp_file = gf_strdup(szPath); } if (!tmp->stream) { @@ -363,7 +364,7 @@ GF_DataMap *gf_isom_fdm_new_temp(const char *sPath) } tmp->bs = gf_bs_from_file(tmp->stream, GF_BITSTREAM_WRITE); if (!tmp->bs) { - fclose(tmp->stream); + gf_fclose(tmp->stream); gf_free(tmp); return NULL; } @@ -382,10 +383,10 @@ GF_DataMap *gf_isom_fdm_new_temp(const char *sPath) GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode) { u8 bs_mode; - - GF_FileDataMap *tmp = (GF_FileDataMap *) gf_malloc(sizeof(GF_FileDataMap)); + GF_FileDataMap *tmp; + GF_SAFEALLOC(tmp, GF_FileDataMap); if (!tmp) return NULL; - memset(tmp, 0, sizeof(GF_FileDataMap)); + tmp->type = GF_ISOM_DATA_FILE; tmp->mode = mode; @@ -412,7 +413,7 @@ GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode) switch (mode) { case GF_ISOM_DATA_MAP_READ: - if (!tmp->stream) tmp->stream = gf_f64_open(sPath, "rb"); + if (!tmp->stream) tmp->stream = gf_fopen(sPath, "rb"); bs_mode = GF_BITSTREAM_READ; break; ///we open the file in READ/WRITE mode, in case @@ -422,8 +423,8 @@ GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode) tmp->is_stdout = 1; } - if (!tmp->stream) tmp->stream = gf_f64_open(sPath, "w+b"); - if (!tmp->stream) tmp->stream = gf_f64_open(sPath, "wb"); + if (!tmp->stream) tmp->stream = gf_fopen(sPath, "w+b"); + if (!tmp->stream) tmp->stream = gf_fopen(sPath, "wb"); bs_mode = GF_BITSTREAM_WRITE; break; ///we open the file in CAT mode, in case @@ -433,8 +434,8 @@ GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode) tmp->is_stdout = 1; } - if (!tmp->stream) tmp->stream = gf_f64_open(sPath, "a+b"); - if (tmp->stream) gf_f64_seek(tmp->stream, 0, SEEK_END); + if (!tmp->stream) tmp->stream = gf_fopen(sPath, "a+b"); + if (tmp->stream) gf_fseek(tmp->stream, 0, SEEK_END); bs_mode = GF_BITSTREAM_WRITE; break; default: @@ -447,7 +448,7 @@ GF_DataMap *gf_isom_fdm_new(const char *sPath, u8 mode) } tmp->bs = gf_bs_from_file(tmp->stream, bs_mode); if (!tmp->bs) { - fclose(tmp->stream); + gf_fclose(tmp->stream); gf_free(tmp); return NULL; } @@ -462,7 +463,7 @@ void gf_isom_fdm_del(GF_FileDataMap *ptr) if (!ptr || (ptr->type != GF_ISOM_DATA_FILE)) return; if (ptr->bs) gf_bs_del(ptr->bs); if (ptr->stream && !ptr->is_stdout) - fclose(ptr->stream); + gf_fclose(ptr->stream); #ifndef GPAC_DISABLE_ISOM_WRITE if (ptr->temp_file) { @@ -564,7 +565,6 @@ GF_DataMap *gf_isom_fmo_new(const char *sPath, u8 mode) { GF_FileMappingDataMap *tmp; HANDLE fileH, fileMapH; - DWORD err; #ifdef _WIN32_WCE unsigned short sWPath[MAX_PATH]; #endif @@ -572,9 +572,9 @@ GF_DataMap *gf_isom_fmo_new(const char *sPath, u8 mode) //only in read only if (mode != GF_ISOM_DATA_MAP_READ) return NULL; - tmp = (GF_FileMappingDataMap *) gf_malloc(sizeof(GF_FileMappingDataMap)); + GF_SAFEALLOC(tmp, GF_FileMappingDataMap); if (!tmp) return NULL; - memset(tmp, 0, sizeof(GF_FileMappingDataMap)); + tmp->type = GF_ISOM_DATA_FILE_MAPPING; tmp->mode = mode; tmp->name = gf_strdup(sPath); @@ -616,7 +616,6 @@ GF_DataMap *gf_isom_fmo_new(const char *sPath, u8 mode) CloseHandle(fileH); gf_free(tmp->name); gf_free(tmp); - err = GetLastError(); return NULL; } @@ -650,11 +649,8 @@ void gf_isom_fmo_del(GF_FileMappingDataMap *ptr) u32 gf_isom_fmo_get_data(GF_FileMappingDataMap *ptr, char *buffer, u32 bufferLength, u64 fileOffset) { - u32 size; - //can we seek till that point ??? if (fileOffset > ptr->file_size) return 0; - size = (u32) fileOffset; //we do only read operations, so trivial memcpy(buffer, ptr->byte_map + fileOffset, bufferLength); diff --git a/src/isomedia/drm_sample.c b/src/isomedia/drm_sample.c index 90e81eb..f5c440b 100644 --- a/src/isomedia/drm_sample.c +++ b/src/isomedia/drm_sample.c @@ -429,7 +429,7 @@ static GF_Err gf_isom_set_protected_entry(GF_ISOFile *the_file, u32 trackNumber, case GF_ISOM_BOX_TYPE_LSR1: sea->type = GF_ISOM_BOX_TYPE_ENCS; break; - case GF_ISOM_BOX_TYPE_STSE: + case GF_ISOM_BOX_TYPE_STXT: case GF_ISOM_BOX_TYPE_WVTT: case GF_ISOM_BOX_TYPE_STPP: sea->type = GF_ISOM_BOX_TYPE_ENCT; diff --git a/src/isomedia/isom_intern.c b/src/isomedia/isom_intern.c index 4403795..46fd021 100644 --- a/src/isomedia/isom_intern.c +++ b/src/isomedia/isom_intern.c @@ -396,6 +396,13 @@ GF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u64 *bytesMissing, Bool progre #endif } + + //create a default mdat if none was found + if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_CAT_FRAGMENTS)) { + mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT); + e = gf_list_add(mov->TopBoxes, mov->mdat); + if (e) return e; + } #endif /*GPAC_DISABLE_ISOM_WRITE*/ return GF_OK; diff --git a/src/isomedia/isom_read.c b/src/isomedia/isom_read.c index 0ee42be..c046000 100644 --- a/src/isomedia/isom_read.c +++ b/src/isomedia/isom_read.c @@ -105,7 +105,7 @@ u32 gf_isom_probe_file(const char *fileName) type = GF_4CC(mem_address[4], mem_address[5], mem_address[6], mem_address[7]); } else { unsigned char data[4]; - FILE *f = gf_f64_open(fileName, "rb"); + FILE *f = gf_fopen(fileName, "rb"); if (!f) return 0; type = 0; if (fread(data, 1, 4, f) == 4) { @@ -113,7 +113,7 @@ u32 gf_isom_probe_file(const char *fileName) type = GF_4CC(data[0], data[1], data[2], data[3]); } } - fclose(f); + gf_fclose(f); } switch (type) { case GF_ISOM_BOX_TYPE_FTYP: @@ -546,30 +546,13 @@ u32 gf_isom_get_timescale(GF_ISOFile *movie) GF_EXPORT u64 gf_isom_get_duration(GF_ISOFile *movie) { -#ifndef GPAC_DISABLE_ISOM_WRITE - u32 i; - u64 maxDur; - GF_TrackBox *trak; -#endif - if (!movie || !movie->moov) return 0; //if file was open in Write or Edit mode, recompute the duration //the duration of a movie is the MaxDuration of all the tracks... #ifndef GPAC_DISABLE_ISOM_WRITE - - if (movie->openMode != GF_ISOM_OPEN_READ) { - maxDur = 0; - i=0; - while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) { - if( (movie->LastError = SetTrackDuration(trak)) ) return 0; - if (trak->Header->duration > maxDur) - maxDur = trak->Header->duration; - } - movie->moov->mvhd->duration = maxDur; - } - + gf_isom_update_duration(movie); #endif /*GPAC_DISABLE_ISOM_WRITE*/ return movie->moov->mvhd->duration; @@ -654,12 +637,90 @@ u64 gf_isom_get_track_duration(GF_ISOFile *movie, u32 trackNumber) } GF_EXPORT -GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char *three_char_code) +GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char **lang) { + u32 count; + Bool elng_found = GF_FALSE; GF_TrackBox *trak; + if (!lang) { + return GF_BAD_PARAM; + } + *lang = NULL; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return GF_BAD_PARAM; - memcpy(three_char_code, trak->Media->mediaHeader->packedLanguage, sizeof(char)*4); + count = gf_list_count(trak->Media->other_boxes); + if (count>0) { + u32 i; + for (i = 0; i < count; i++) { + GF_Box *box = (GF_Box *)gf_list_get(trak->Media->other_boxes, i); + if (box->type == GF_ISOM_BOX_TYPE_ELNG) { + elng_found = GF_TRUE; + *lang = gf_strdup(((GF_ExtendedLanguageBox *)box)->extended_language); + return GF_OK; + } + } + } + if (!elng_found) { + *lang = gf_strdup(trak->Media->mediaHeader->packedLanguage); + } + return GF_OK; +} + +GF_EXPORT +u32 gf_isom_get_track_kind_count(GF_ISOFile *the_file, u32 trackNumber) +{ + GF_UserDataBox *udta; + GF_UserDataMap *map; + if (trackNumber) { + GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber); + if (!trak) return 0; + if (!trak->udta) { + return 0; + } + udta = trak->udta; + } else { + return 0; + } + map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL); + if (!map) return 0; + + return gf_list_count(map->other_boxes); +} + +GF_EXPORT +GF_Err gf_isom_get_track_kind(GF_ISOFile *the_file, u32 trackNumber, u32 index, char **scheme, char **value) +{ + GF_Err e; + GF_UserDataBox *udta; + GF_UserDataMap *map; + GF_KindBox *kindBox; + if (!scheme || !value) { + return GF_BAD_PARAM; + } + *scheme = NULL; + *value = NULL; + + if (trackNumber) { + GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber); + if (!trak) return GF_BAD_PARAM; + if (!trak->udta) { + e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA)); + if (e) return e; + } + udta = trak->udta; + } else { + return GF_BAD_PARAM; + } + map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL); + if (!map) return GF_BAD_PARAM; + + kindBox = (GF_KindBox *)gf_list_get(map->other_boxes, index); + if (!kindBox) return GF_BAD_PARAM; + + *scheme = gf_strdup(kindBox->schemeURI); + if (kindBox->value) { + *value = gf_strdup(kindBox->value); + } return GF_OK; } @@ -1154,7 +1215,7 @@ u32 gf_isom_get_sample_count(GF_ISOFile *the_file, u32 trackNumber) { GF_TrackBox *trak; trak = gf_isom_get_track_from_file(the_file, trackNumber); - if (!trak) return 0; + if (!trak || !trak->Media->information->sampleTable->SampleSize) return 0; return trak->Media->information->sampleTable->SampleSize->sampleCount #ifndef GPAC_DISABLE_ISOM_FRAGMENTS + trak->sample_count_at_seg_start @@ -1206,6 +1267,20 @@ Bool gf_isom_has_sample_dependency(GF_ISOFile *the_file, u32 trackNumber) return 1; } +GF_EXPORT +GF_Err gf_isom_get_sample_flags(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant) +{ + GF_TrackBox *trak = NULL; + *isLeading = 0; + *dependsOn = 0; + *dependedOn = 0; + *redundant = 0; + trak = gf_isom_get_track_from_file(the_file, trackNumber); + if (!trak) return GF_BAD_PARAM; + if (!trak->Media->information->sampleTable->SampleDep) return GF_BAD_PARAM; + return stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, isLeading, dependsOn, dependedOn, redundant); +} + //return a sample give its number, and set the SampleDescIndex of this sample //this index allows to retrieve the stream description if needed (2 media in 1 track) //return NULL if error @@ -1276,7 +1351,7 @@ u32 gf_isom_get_sample_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNum GF_EXPORT u8 gf_isom_get_sample_sync(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber) { - u8 is_rap; + SAPType is_rap; GF_Err e; GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !sampleNumber) return 0; @@ -1513,7 +1588,7 @@ GF_Err gf_isom_get_sample_for_media_time(GF_ISOFile *the_file, u32 trackNumber, shadow = gf_isom_get_sample(the_file, trackNumber, shadowSync, StreamDescriptionIndex); //if no sample, the shadowSync is broken, return the sample if (!shadow) return GF_OK; - (*sample)->IsRAP = 1; + (*sample)->IsRAP = RAP; gf_free((*sample)->data); (*sample)->dataLength = shadow->dataLength; (*sample)->data = shadow->data; @@ -1603,8 +1678,13 @@ GF_Err gf_isom_get_sample_for_movie_time(GF_ISOFile *the_file, u32 trackNumber, //OK, we have a sample so fetch it e = gf_isom_get_sample_for_media_time(the_file, trackNumber, mediaTime, StreamDescriptionIndex, SearchMode, sample, &sampNum); if (e) { - if ((e==GF_EOS) && nextMediaTime) { - return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime-1, StreamDescriptionIndex, SearchMode, sample, sampleNumber); + if (e==GF_EOS) { + //movie is fragmented and samples not yet received, return EOS + if (the_file->moov->mvex && !trak->Media->information->sampleTable->SampleSize->sampleCount) + return e; + + if (nextMediaTime) + return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime-1, StreamDescriptionIndex, SearchMode, sample, sampleNumber); } return e; } @@ -1826,6 +1906,46 @@ Bool gf_isom_has_padding_bits(GF_ISOFile *the_file, u32 trackNumber) return 0; } +GF_EXPORT +u32 gf_isom_get_udta_count(GF_ISOFile *movie, u32 trackNumber) +{ + GF_TrackBox *trak; + GF_UserDataBox *udta; + if (!movie || !movie->moov) return 0; + + if (trackNumber) { + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak) return 0; + udta = trak->udta; + } else { + udta = movie->moov->udta; + } + if (udta) return gf_list_count(udta->recordList); + return 0; +} + +GF_EXPORT +GF_Err gf_isom_get_udta_type(GF_ISOFile *movie, u32 trackNumber, u32 udta_idx, u32 *UserDataType, bin128 *UUID) +{ + GF_TrackBox *trak; + GF_UserDataBox *udta; + GF_UserDataMap *map; + if (!movie || !movie->moov || !udta_idx) return GF_BAD_PARAM; + + if (trackNumber) { + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak) return 0; + udta = trak->udta; + } else { + udta = movie->moov->udta; + } + if (!udta) return GF_BAD_PARAM; + if (udta_idx>gf_list_count(udta->recordList)) return GF_BAD_PARAM; + map = gf_list_get(udta->recordList, udta_idx - 1); + if (UserDataType) *UserDataType = map->boxType; + if (UUID) memcpy(*UUID, map->uuid, 16); + return GF_OK; +} GF_EXPORT u32 gf_isom_get_user_data_count(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID) @@ -1865,6 +1985,7 @@ GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataTyp { GF_UserDataMap *map; GF_UnknownBox *ptr; + GF_BitStream *bs; u32 i; bin128 t; GF_TrackBox *trak; @@ -1884,7 +2005,6 @@ GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataTyp if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0; memset(t, 1, 16); - if (!UserDataIndex) return GF_BAD_PARAM; if (!userData || !userDataSize || *userData) return GF_BAD_PARAM; i=0; @@ -1896,15 +2016,32 @@ GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataTyp return GF_BAD_PARAM; found: + if (UserDataIndex) { + if (UserDataIndex > gf_list_count(map->other_boxes) ) return GF_BAD_PARAM; + ptr = (GF_UnknownBox*)gf_list_get(map->other_boxes, UserDataIndex-1); + + //ok alloc the data + *userData = (char *)gf_malloc(sizeof(char)*ptr->dataSize); + if (!*userData) return GF_OUT_OF_MEM; + memcpy(*userData, ptr->data, sizeof(char)*ptr->dataSize); + *userDataSize = ptr->dataSize; + return GF_OK; + } - if (UserDataIndex > gf_list_count(map->other_boxes) ) return GF_BAD_PARAM; - ptr = (GF_UnknownBox*)gf_list_get(map->other_boxes, UserDataIndex-1); + //serialize all boxes + bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); + i=0; + while ( (ptr = gf_list_enum(map->other_boxes, &i))) { + u32 s = ptr->dataSize+8; + if (ptr->type==GF_ISOM_BOX_TYPE_UUID) s += 16; - //ok alloc the data - *userData = (char *)gf_malloc(sizeof(char)*ptr->dataSize); - if (!*userData) return GF_OUT_OF_MEM; - memcpy(*userData, ptr->data, sizeof(char)*ptr->dataSize); - *userDataSize = ptr->dataSize; + gf_bs_write_u32(bs, s); + gf_bs_write_u32(bs, ptr->type); + if (ptr->type==GF_ISOM_BOX_TYPE_UUID) gf_bs_write_data(bs, (char *) map->uuid, 16); + gf_bs_write_data(bs, ptr->data, ptr->dataSize); + } + gf_bs_get_content(bs, userData, userDataSize); + gf_bs_del(bs); return GF_OK; } @@ -2180,6 +2317,13 @@ GF_Err gf_isom_reset_data_offset(GF_ISOFile *movie, u64 *top_box_start) return GF_OK; } +#define RECREATE_BOX(_a, __cast) \ + if (_a) { \ + type = _a->type;\ + gf_isom_box_del((GF_Box *)_a);\ + _a = __cast gf_isom_box_new(type);\ + }\ + GF_EXPORT GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count) @@ -2202,13 +2346,7 @@ GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count) trak->dts_at_seg_start += dts + dur; } } -#define RECREATE_BOX(_a, __cast) \ - if (_a) { \ - type = _a->type;\ - gf_isom_box_del((GF_Box *)_a);\ - _a = __cast gf_isom_box_new(type);\ - }\ - + RECREATE_BOX(stbl->ChunkOffset, (GF_Box *)); RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *)); RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *)); @@ -2226,6 +2364,7 @@ GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count) trak->sample_count_at_seg_start = 0; #endif } + } #endif @@ -2271,13 +2410,17 @@ GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables) gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, 1, &on_track); base = gf_isom_get_track_from_file(movie, on_track); - if (!base) scalable = GF_FALSE; + if (!base) { + scalable = GF_FALSE; + base_track_sample_count=0; + } else { + base_track_sample_count = base->Media->information->sampleTable->SampleSize->sampleCount; + } } } - if (scalable && !gf_isom_get_reference_count(movie, i+1, GF_ISOM_REF_SCAL)) - base_track_sample_count = stbl->SampleSize->sampleCount; - trak->sample_count_at_seg_start += scalable ? base_track_sample_count : stbl->SampleSize->sampleCount; + trak->sample_count_at_seg_start += base_track_sample_count ? base_track_sample_count : stbl->SampleSize->sampleCount; + if (trak->sample_count_at_seg_start) { GF_Err e; e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur); @@ -2285,13 +2428,7 @@ GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables) trak->dts_at_seg_start += dts + dur; } } -#define RECREATE_BOX(_a, __cast) \ - if (_a) { \ - type = _a->type;\ - gf_isom_box_del((GF_Box *)_a);\ - _a = __cast gf_isom_box_new(type);\ - }\ - + RECREATE_BOX(stbl->ChunkOffset, (GF_Box *)); RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *)); RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *)); @@ -2302,6 +2439,7 @@ GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables) RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *)); RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *)); RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *)); + } @@ -2322,7 +2460,7 @@ GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables) } GF_EXPORT -GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, Bool is_scalable_segment) +GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, u32 flags) { #ifdef GPAC_DISABLE_ISOM_FRAGMENTS return GF_NOT_SUPPORTED; @@ -2331,6 +2469,8 @@ GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_r GF_Err e; u32 i; Bool segment_map_assigned = 0; + Bool is_scalable_segment = (flags & GF_ISOM_SEGMENT_SCALABLE_FLAG) ? 1 : 0; + Bool no_order_check = (flags & GF_ISOM_SEGMENT_NO_ORDER_FLAG) ? 1: 0; GF_DataMap *tmp = NULL; GF_DataMap *orig_file_map = NULL; if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM; @@ -2372,6 +2512,7 @@ GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_r trak->present_in_scalable_segment = 0; } } + if (no_order_check) movie->NextMoofNumber = 0; //ok parse root boxes @@ -2604,6 +2745,7 @@ GF_Err gf_isom_get_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDesc case GF_ISOM_SUBTYPE_3GP_QCELP: case GF_ISOM_SUBTYPE_3GP_SMV: case GF_ISOM_BOX_TYPE_AC3: + case GF_ISOM_BOX_TYPE_GNRA: if (SampleRate) (*SampleRate) = ((GF_AudioSampleEntryBox*)entry)->samplerate_hi; if (Channels) (*Channels) = ((GF_AudioSampleEntryBox*)entry)->channel_count; if (bitsPerSample) (*bitsPerSample) = (u8) ((GF_AudioSampleEntryBox*)entry)->bitspersample; @@ -3040,28 +3182,6 @@ const u32 *gf_isom_get_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber return (const u32 *) tsel->attributeList; } - -GF_EXPORT -GF_Err gf_isom_get_timed_meta_data_info(GF_ISOFile *file, u32 track, u32 sampleDescription, Bool *is_xml, const char **mime_or_namespace, const char **content_encoding, const char **schema_loc) -{ - GF_TrackBox *trak; - GF_MetaDataSampleEntryBox *ptr; - trak = gf_isom_get_track_from_file(file, track); - if (!trak || !sampleDescription) return GF_BAD_PARAM; - ptr = (GF_MetaDataSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, sampleDescription-1); - if (!ptr) return GF_BAD_PARAM; - - if (ptr->type==GF_ISOM_BOX_TYPE_METX) { - if (is_xml) *is_xml = 1; - if (schema_loc) *schema_loc = ptr->xml_schema_loc; - } else { - if (schema_loc) *schema_loc = NULL; - } - if (mime_or_namespace) *mime_or_namespace = ptr->mime_type_or_namespace; - if (content_encoding) *content_encoding = ptr->content_encoding; - return GF_OK; -} - GF_EXPORT u32 gf_isom_get_next_alternate_group_id(GF_ISOFile *movie) { @@ -3247,7 +3367,7 @@ GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u switch (sgdesc->grouping_type) { case GF_4CC('r','a','p',' '): - if (is_rap) *is_rap = 1; + if (is_rap) *is_rap = (group_desc_index-1) ? 1 : 0; break; case GF_4CC('r','o','l','l'): if (has_roll) *has_roll = 1; @@ -3295,7 +3415,7 @@ Bool gf_isom_get_sample_group_info(GF_ISOFile *the_file, u32 trackNumber, u32 sa return 1; default: entry = gf_list_get(sgdesc->group_descriptions, sample_description_index-1); - if (entry && data) *data = entry->data; + if (entry && data) *data = (char *) entry->data; if (entry && size) *size = entry->length; return 1; } @@ -3465,7 +3585,11 @@ GF_Err gf_isom_get_pssh_info(GF_ISOFile *file, u32 pssh_index, bin128 SystemID, } GF_EXPORT +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID) +#else +GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, void *traf, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID) +#endif { GF_SampleGroupBox *sample_group; u32 j, group_desc_index; @@ -3481,6 +3605,11 @@ GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, GF_TrackFragmentBox *t if (IV_size) *IV_size = 0; if (KID) memset(*KID, 0, 16); +#ifdef GPAC_DISABLE_ISOM_FRAGMENTS + if (!traf) + return GF_BAD_PARAM; +#endif + if (trak->Media->information->sampleTable->SampleSize && trak->Media->information->sampleTable->SampleSize->sampleCount>=sample_number) { stbl_GetSampleInfos(trak->Media->information->sampleTable, sample_number, &offset, &chunkNum, &descIndex, &edit); } else { diff --git a/src/isomedia/isom_store.c b/src/isomedia/isom_store.c index f108778..5543c14 100644 --- a/src/isomedia/isom_store.c +++ b/src/isomedia/isom_store.c @@ -221,12 +221,13 @@ static GF_Err ShiftOffset(GF_ISOFile *file, GF_List *writers, u64 offset) last = ent->nextChunk ? ent->nextChunk : stco->nb_entries + 1; for (k = ent->firstChunk; k < last; k++) { - if (stco->offsets[k-1] + offset > 0xFFFFFFFF) { + if (file->force_co64 || (stco->offsets[k-1] + offset > 0xFFFFFFFF)) { //too bad, rewrite the table.... co64 = (GF_ChunkLargeOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CO64); if (!co64) return GF_OUT_OF_MEM; co64->nb_entries = stco->nb_entries; co64->offsets = (u64*)gf_malloc(co64->nb_entries * sizeof(u64)); + memset(co64->offsets, 0, co64->nb_entries * sizeof(u64)); if (!co64) { gf_isom_box_del((GF_Box *)co64); return GF_OUT_OF_MEM; @@ -418,11 +419,11 @@ GF_Err DoWriteMeta(GF_ISOFile *file, GF_MetaBox *meta, GF_BitStream *bs, Bool Em FILE *src=NULL; if (!iinf->data_len) { - src = gf_f64_open(iinf->full_path, "rb"); + src = gf_fopen(iinf->full_path, "rb"); if (!src) continue; - gf_f64_seek(src, 0, SEEK_END); - it_size = gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_END); + it_size = gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); } else { it_size = iinf->data_len; } @@ -452,7 +453,7 @@ GF_Err DoWriteMeta(GF_ISOFile *file, GF_MetaBox *meta, GF_BitStream *bs, Bool Em gf_bs_write_data(bs, iinf->full_path, iinf->data_len); } } - if (src) fclose(src); + if (src) gf_fclose(src); } else if (gf_list_count(iloc->extent_entries)) { u32 j; @@ -774,7 +775,7 @@ GF_Err WriteFlat(MovieWriter *mw, u8 moovFirst, GF_BitStream *bs) e = gf_isom_box_write((GF_Box *)movie->pdin, bs); if (e) goto exit; } - //What we will do is first emulate the write from the begining... + //What we will do is first emulate the write from the beginning... //note: this will set the size of the mdat e = DoWrite(mw, writers, bs, 1, gf_bs_get_position(bs)); if (e) goto exit; @@ -787,9 +788,6 @@ GF_Err WriteFlat(MovieWriter *mw, u8 moovFirst, GF_BitStream *bs) //get the size and see if it has changed (eg, we moved to 64 bit offsets) finalSize = GetMoovAndMetaSize(movie, writers); if (firstSize != finalSize) { - //we need to remove our offsets - ResetWriters(writers); - //finalOffset = (finalSize > 0xFFFFFFFF ? finalSize + 8 : finalSize) + 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0); finalOffset = finalSize + 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0); //OK, now we're sure about the final size. //we don't need to re-emulate, as the only thing that changed is the offset @@ -1209,8 +1207,6 @@ static GF_Err WriteInterleaved(MovieWriter *mw, GF_BitStream *bs, Bool drift_int //get the size and see if it has changed (eg, we moved to 64 bit offsets) finalSize = GetMoovAndMetaSize(movie, writers); if (firstSize != finalSize) { - //we need to remove our offsets - ResetWriters(writers); finalOffset = finalSize; if (movie->mdat->dataSize) finalOffset += 8 + (movie->mdat->dataSize > 0xFFFFFFFF ? 8 : 0); //OK, now we're sure about the final size -> shift the offsets @@ -1290,13 +1286,13 @@ GF_Err WriteToFile(GF_ISOFile *movie) is_stdout = 1; //OK, we need a new bitstream - stream = is_stdout ? stdout : gf_f64_open(movie->finalName, "w+b"); + stream = is_stdout ? stdout : gf_fopen(movie->finalName, "w+b"); if (!stream) return GF_IO_ERR; bs = gf_bs_from_file(stream, GF_BITSTREAM_WRITE); if (!bs) { if (!is_stdout) - fclose(stream); + gf_fclose(stream); return GF_OUT_OF_MEM; } @@ -1322,7 +1318,7 @@ GF_Err WriteToFile(GF_ISOFile *movie) gf_bs_del(bs); if (!is_stdout) - fclose(stream); + gf_fclose(stream); } if (mw.buffer) gf_free(mw.buffer); if (mw.nb_done<mw.total_samples) { diff --git a/src/isomedia/isom_write.c b/src/isomedia/isom_write.c index 5f20f22..4d37791 100644 --- a/src/isomedia/isom_write.c +++ b/src/isomedia/isom_write.c @@ -236,7 +236,7 @@ GF_Err gf_isom_set_track_enabled(GF_ISOFile *movie, u32 trackNumber, u8 enableTr } GF_EXPORT -GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *three_char_code) +GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *code) { GF_Err e; GF_TrackBox *trak; @@ -244,7 +244,32 @@ GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *thre if (!trak) return GF_BAD_PARAM; e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); if (e) return e; - memcpy(trak->Media->mediaHeader->packedLanguage, three_char_code, sizeof(char)*3); + if (strlen(code) == 3) { + memcpy(trak->Media->mediaHeader->packedLanguage, code, sizeof(char)*3); + } else { + u32 i, count; + GF_ExtendedLanguageBox *elng; + elng = NULL; + count = gf_list_count(trak->Media->other_boxes); + for (i = 0; i < count; i++) { + GF_Box *box = (GF_Box *)gf_list_get(trak->Media->other_boxes, i); + if (box->type == GF_ISOM_BOX_TYPE_ELNG) { + elng = (GF_ExtendedLanguageBox *)box; + break; + } + } + if (!elng) { + elng = (GF_ExtendedLanguageBox *)elng_New(); + if (!count) { + trak->Media->other_boxes = gf_list_new(); + } + gf_list_add(trak->Media->other_boxes, elng); + } + if (elng->extended_language) { + gf_free(elng->extended_language); + } + elng->extended_language = gf_strdup(code); + } if (!movie->keep_utc) trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); return GF_OK; @@ -321,13 +346,36 @@ GF_Err gf_isom_add_desc_to_root_od(GF_ISOFile *movie, GF_Descriptor *theDesc) GF_EXPORT GF_Err gf_isom_set_timescale(GF_ISOFile *movie, u32 timeScale) { + Double ts_scale; + GF_TrackBox *trak; + u32 i; GF_Err e; e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); if (e) return e; gf_isom_insert_moov(movie); + if (movie->moov->mvhd->timeScale == timeScale) return GF_OK; + + /*rewrite all durations and edit lists*/ + ts_scale = timeScale; + ts_scale /= movie->moov->mvhd->timeScale; + movie->moov->mvhd->timeScale = timeScale; movie->interleavingTime = timeScale; + + movie->moov->mvhd->duration = (u64) (s64) ((s64) movie->moov->mvhd->duration * ts_scale); + + i=0; + while ((trak = gf_list_enum(movie->moov->trackList, &i))) { + trak->Header->duration = (u64) (s64) ((s64) trak->Header->duration * ts_scale); + if (trak->editBox && trak->editBox->editList) { + u32 j, count = gf_list_count(trak->editBox->editList->entryList); + for (j=0; j<count; j++) { + GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, j); + ent->segmentDuration = (u64) (s64) ((s64) ent->segmentDuration * ts_scale); + } + } + } return GF_OK; } @@ -591,7 +639,7 @@ GF_Err gf_isom_new_mpeg4_description(GF_ISOFile *movie, //Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several) GF_EXPORT -GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample) +GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ISOSample *sample) { GF_Err e; GF_TrackBox *trak; @@ -789,7 +837,7 @@ GF_Err gf_isom_append_sample_data(GF_ISOFile *movie, u32 trackNumber, char *data //Add sample reference to a track. The SampleOffset is the offset of the data in the referenced file //you must have created a StreamDescription with URL or URN specifying your referenced file -//the data offset specifies the begining of the chunk +//the data offset specifies the beginning of the chunk //Use streamDescriptionIndex to specify the desired stream (if several) GF_EXPORT GF_Err gf_isom_add_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample, u64 dataOffset) @@ -1204,6 +1252,13 @@ GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDes trak->Header->width = Width<<16; trak->Header->height = Height<<16; return GF_OK; + case GF_ISOM_BOX_TYPE_GNRV: + ((GF_GenericVisualSampleEntryBox*)entry)->Width = Width; + ((GF_GenericVisualSampleEntryBox*)entry)->Height = Height; + trak->Header->width = Width<<16; + trak->Header->height = Height<<16; + return GF_OK; + /*check BIFS*/ default: if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) { @@ -1298,6 +1353,8 @@ GF_Err gf_isom_set_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDesc switch (entry->type) { case GF_ISOM_BOX_TYPE_MP4A: + case GF_ISOM_BOX_TYPE_AC3: + case GF_ISOM_BOX_TYPE_EC3: case GF_ISOM_SUBTYPE_3GP_AMR: case GF_ISOM_SUBTYPE_3GP_AMR_WB: case GF_ISOM_SUBTYPE_3GP_EVRC: @@ -1335,6 +1392,12 @@ GF_Err gf_isom_set_storage_mode(GF_ISOFile *movie, u8 storageMode) } } +GF_EXPORT +void gf_isom_force_64bit_chunk_offset(GF_ISOFile *file, Bool set_on) +{ + file->force_co64 = set_on; +} + //update or insert a new edit segment in the track time line. Edits are used to modify //the media normal timing. EditTime and EditDuration are expressed in Movie TimeScale @@ -1724,6 +1787,98 @@ GF_Err gf_isom_set_copyright(GF_ISOFile *movie, const char *threeCharCode, char return udta_AddBox(movie->moov->udta, (GF_Box *) ptr); } +GF_EXPORT +GF_Err gf_isom_add_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value) +{ + GF_Err e; + GF_KindBox *ptr; + GF_UserDataBox *udta; + GF_UserDataMap *map; + u32 i, count; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + gf_isom_insert_moov(movie); + + if (trackNumber) { + GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak) return GF_BAD_PARAM; + if (!trak->udta) { + e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA)); + if (e) return e; + } + udta = trak->udta; + } else { + return GF_BAD_PARAM; + } + + map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL); + if (map) { + count = gf_list_count(map->other_boxes); + for (i=0; i<count; i++) { + GF_Box *b = (GF_Box *)gf_list_get(map->other_boxes, i); + if (b->type == GF_ISOM_BOX_TYPE_KIND) { + GF_KindBox *kb = (GF_KindBox *)b; + if (!strcmp(kb->schemeURI, schemeURI) && + ((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value))) { + // Already there + return GF_OK; + } + } + } + } + + ptr = (GF_KindBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_KIND); + if (e) return e; + + ptr->schemeURI = gf_strdup(schemeURI); + if (value) ptr->value = gf_strdup(value); + return udta_AddBox(udta, (GF_Box *) ptr); +} + +GF_EXPORT +GF_Err gf_isom_remove_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value) +{ + GF_Err e; + GF_UserDataBox *udta; + GF_UserDataMap *map; + u32 i; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + gf_isom_insert_moov(movie); + + if (trackNumber) { + GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak) return GF_BAD_PARAM; + if (!trak->udta) { + e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA)); + if (e) return e; + } + udta = trak->udta; + } else { + return GF_OK; + } + map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL); + if (map) { + for (i=0; i<gf_list_count(map->other_boxes); i++) { + GF_Box *b = (GF_Box *)gf_list_get(map->other_boxes, i); + if (b->type == GF_ISOM_BOX_TYPE_KIND) { + GF_KindBox *kb = (GF_KindBox *)b; + if (!schemeURI || + (!strcmp(kb->schemeURI, schemeURI) && + ((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value)))) { + gf_isom_box_del(b); + gf_list_rem(map->other_boxes, i); + i--; + } + } + } + } + return GF_OK; +} + GF_EXPORT GF_Err gf_isom_add_chapter(GF_ISOFile *movie, u32 trackNumber, u64 timestamp, char *name) { @@ -2127,6 +2282,7 @@ found: } +GF_EXPORT GF_Err gf_isom_reset_alt_brands(GF_ISOFile *movie) { u32 *p; @@ -2154,6 +2310,7 @@ GF_Err gf_isom_reset_alt_brands(GF_ISOFile *movie) return GF_OK; } +GF_EXPORT GF_Err gf_isom_set_sample_padding_bits(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u8 NbBits) { GF_TrackBox *trak; @@ -2170,6 +2327,7 @@ GF_Err gf_isom_set_sample_padding_bits(GF_ISOFile *movie, u32 trackNumber, u32 s } +GF_EXPORT GF_Err gf_isom_remove_user_data_item(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex) { GF_UserDataMap *map; @@ -2223,6 +2381,7 @@ found: return GF_OK; } +GF_EXPORT GF_Err gf_isom_remove_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID) { GF_UserDataMap *map; @@ -2265,6 +2424,7 @@ found: return GF_OK; } +GF_EXPORT GF_Err gf_isom_add_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, char *data, u32 DataLength) { GF_UnknownBox *a; @@ -2304,6 +2464,40 @@ GF_Err gf_isom_add_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataTyp return udta_AddBox(udta, (GF_Box *) a); } +GF_EXPORT +GF_Err gf_isom_add_user_data_boxes(GF_ISOFile *movie, u32 trackNumber, char *data, u32 DataLength) +{ + GF_Err e; + GF_TrackBox *trak; + GF_UserDataBox *udta; + GF_BitStream *bs; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + if (trackNumber) { + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak) return GF_BAD_PARAM; + if (!trak->udta) trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA)); + udta = trak->udta; + } else { + if (!movie->moov->udta) moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA)); + udta = movie->moov->udta; + } + if (!udta) return GF_OUT_OF_MEM; + + bs = gf_bs_new(data, DataLength, GF_BITSTREAM_READ); + while (gf_bs_available(bs)) { + GF_Box *a; + e = gf_isom_parse_box(&a, bs); + if (e) break; + e = udta_AddBox(udta, a); + if (e) break; + } + gf_bs_del(bs); + return e; +} + GF_Err gf_isom_add_sample_fragment(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u16 FragmentSize) { @@ -2540,6 +2734,8 @@ GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *de /*also clone sampleGroups description tables if any*/ stbl_temp->sampleGroupsDescription = stbl->sampleGroupsDescription; trak->Media->information->sampleTable = stbl_temp; + /*clone CompositionToDecode table, we may remove it later*/ + stbl_temp->CompositionToDecode = stbl->CompositionToDecode; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); @@ -2555,6 +2751,7 @@ GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *de stbl_temp->SampleDescription = NULL; stbl_temp->sampleGroupsDescription = NULL; + stbl_temp->CompositionToDecode = NULL; gf_isom_box_del((GF_Box *)stbl_temp); if (e) return e; @@ -2783,8 +2980,8 @@ GF_Err gf_isom_new_generic_sample_description(GF_ISOFile *movie, u32 trackNumber gena->revision = udesc->revision; gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16; gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2; - gena->samplerate_hi = udesc->samplerate>>16; - gena->samplerate_lo = udesc->samplerate & 0xFF; + gena->samplerate_hi = udesc->samplerate; + gena->samplerate_lo = 0; if (udesc->extension_buf && udesc->extension_buf_size) { gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size); @@ -2875,8 +3072,8 @@ GF_Err gf_isom_change_generic_sample_description(GF_ISOFile *movie, u32 trackNum gena->revision = udesc->revision; gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16; gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2; - gena->samplerate_hi = udesc->samplerate>>16; - gena->samplerate_lo = udesc->samplerate & 0xFF; + gena->samplerate_hi = udesc->samplerate; + gena->samplerate_lo = 0; if (gena->data) gf_free(gena->data); gena->data = NULL; gena->data_size = 0; @@ -3008,6 +3205,7 @@ GF_Err gf_isom_remove_track_reference(GF_ISOFile *the_file, u32 trackNumber, u32 //changes track ID +GF_EXPORT GF_Err gf_isom_set_track_id(GF_ISOFile *movie, u32 trackNumber, u32 trackID) { GF_TrackReferenceTypeBox *ref; @@ -3445,9 +3643,9 @@ Bool gf_isom_is_same_sample_description(GF_ISOFile *f1, u32 tk1, u32 sdesc_index break; case GF_ISOM_BOX_TYPE_STPP: { - GF_XMLSubtitleSampleEntryBox *stpp1 = (GF_XMLSubtitleSampleEntryBox *)ent1; - GF_XMLSubtitleSampleEntryBox *stpp2 = (GF_XMLSubtitleSampleEntryBox *)ent2; - if (stpp1->xmlnamespace && stpp2->xmlnamespace && !strcmp(stpp1->xmlnamespace, stpp2->xmlnamespace)) { + GF_MetaDataSampleEntryBox *stpp1 = (GF_MetaDataSampleEntryBox *)ent1; + GF_MetaDataSampleEntryBox *stpp2 = (GF_MetaDataSampleEntryBox *)ent2; + if (stpp1->xml_namespace && stpp2->xml_namespace && !strcmp(stpp1->xml_namespace, stpp2->xml_namespace)) { return 1; } return 0; @@ -3458,14 +3656,14 @@ Bool gf_isom_is_same_sample_description(GF_ISOFile *f1, u32 tk1, u32 sdesc_index return 0; } break; - case GF_ISOM_BOX_TYPE_STSE: + case GF_ISOM_BOX_TYPE_STXT: { - GF_SimpleTextSampleEntryBox *stse1 = (GF_SimpleTextSampleEntryBox *)ent1; - GF_SimpleTextSampleEntryBox *stse2 = (GF_SimpleTextSampleEntryBox *)ent2; - if (stse1->mime_type && stse2->mime_type && - ( (!stse1->config && !stse2->config) || - (stse1->config && stse2->config && stse1->config->string && stse2->config->string && - !strcmp(stse1->config->string, stse2->config->string)))) { + GF_MetaDataSampleEntryBox *stxt1 = (GF_MetaDataSampleEntryBox *)ent1; + GF_MetaDataSampleEntryBox *stxt2 = (GF_MetaDataSampleEntryBox *)ent2; + if (stxt1->mime_type && stxt2->mime_type && + ( (!stxt1->config && !stxt2->config) || + (stxt1->config && stxt2->config && stxt1->config->config && stxt2->config->config && + !strcmp(stxt1->config->config, stxt2->config->config)))) { return 1; } return 0; @@ -3554,7 +3752,7 @@ GF_Err gf_isom_set_sync_shadow(GF_ISOFile *movie, u32 trackNumber, u32 sampleNum { GF_TrackBox *trak; GF_SampleTableBox *stbl; - u8 isRAP; + SAPType isRAP; GF_Err e; if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE; @@ -3725,7 +3923,7 @@ GF_Err gf_isom_make_interleave(GF_ISOFile *file, Double TimeInSec) { GF_Err e; if (gf_isom_get_mode(file) < GF_ISOM_OPEN_EDIT) return GF_BAD_PARAM; - e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_INTERLEAVED); + e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_DRIFT_INTERLEAVED); if (e) return e; return gf_isom_set_interleave_time(file, (u32) (TimeInSec * gf_isom_get_timescale(file))); } @@ -3744,27 +3942,27 @@ GF_Err gf_isom_set_handler_name(GF_ISOFile *the_file, u32 trackNumber, const cha if (!strnicmp(nameUTF8, "file://", 7)) { u8 BOM[4]; - FILE *f = gf_f64_open(nameUTF8+7, "rb"); + FILE *f = gf_fopen(nameUTF8+7, "rb"); u64 size; if (!f) return GF_URL_ERROR; - gf_f64_seek(f, 0, SEEK_END); - size = gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + size = gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); if (3!=fread(BOM, sizeof(char), 3, f)) { - fclose(f); + gf_fclose(f); return GF_CORRUPTED_DATA; } /*skip BOM if any*/ if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) size -= 3; else if ((BOM[0]==0xEF) || (BOM[0]==0xFF)) { - fclose(f); + gf_fclose(f); return GF_BAD_PARAM; } - else gf_f64_seek(f, 0, SEEK_SET); + else gf_fseek(f, 0, SEEK_SET); trak->Media->handler->nameUTF8 = (char*)gf_malloc(sizeof(char)*(size_t)(size+1)); size = fread(trak->Media->handler->nameUTF8, sizeof(char), (size_t)size, f); trak->Media->handler->nameUTF8[size] = 0; - fclose(f); + gf_fclose(f); } else { u32 i, j, len; char szOrig[1024], szLine[1024]; @@ -3966,7 +4164,11 @@ GF_Err gf_isom_apple_set_tag(GF_ISOFile *mov, u32 tag, const char *data, u32 dat if (!meta) return GF_BAD_PARAM; ilst = gf_ismo_locate_box(meta->other_boxes, GF_ISOM_BOX_TYPE_ILST, NULL); - if (!ilst) return GF_NOT_SUPPORTED; + if (!ilst) { + ilst = (GF_ItemListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ILST); + if (!meta->other_boxes) meta->other_boxes = gf_list_new(); + gf_list_add(meta->other_boxes, ilst); + } if (tag==GF_ISOM_ITUNE_GENRE) { btype = data ? GF_ISOM_BOX_TYPE_0xA9GEN : GF_ISOM_BOX_TYPE_GNRE; @@ -3979,6 +4181,7 @@ GF_Err gf_isom_apple_set_tag(GF_ISOFile *mov, u32 tag, const char *data, u32 dat if (info->type==btype) { gf_list_rem(ilst->other_boxes, i-1); gf_isom_box_del((GF_Box *) info); + info = NULL; break; } } @@ -4036,6 +4239,15 @@ GF_Err gf_isom_apple_set_tag(GF_ISOFile *mov, u32 tag, const char *data, u32 dat info->data->flags = 0x15; gf_bs_del(bs); } + + if (!info || (tag==GF_ISOM_ITUNE_ALL) ) { + if (!gf_list_count(ilst->other_boxes) || (tag==GF_ISOM_ITUNE_ALL) ) { + gf_list_del_item(meta->other_boxes, ilst); + gf_isom_box_del((GF_Box *) ilst); + } + return GF_OK; + } + return gf_list_add(ilst->other_boxes, info); } @@ -4197,46 +4409,6 @@ GF_Err gf_isom_reset_switch_parameters(GF_ISOFile *movie) return GF_OK; } -GF_Err gf_isom_timed_meta_data_config_new(GF_ISOFile *movie, u32 trackNumber, Bool is_xml, char *mime_or_namespace, char *content_encoding, char *schema_loc, char *URLname, char *URNname, u32 *outDescriptionIndex) -{ - GF_TrackBox *trak; - GF_Err e; - u32 dataRefIndex; - GF_MetaDataSampleEntryBox *metad; - - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return e; - - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media || !mime_or_namespace) - return GF_BAD_PARAM; - - if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_META) - return GF_BAD_PARAM; - - //get or create the data ref - e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - if (!dataRefIndex) { - e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - } - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - - metad = (GF_MetaDataSampleEntryBox*) gf_isom_box_new(is_xml ? GF_ISOM_BOX_TYPE_METX : GF_ISOM_BOX_TYPE_METT); - if (!metad) return GF_OUT_OF_MEM; - - metad->dataReferenceIndex = dataRefIndex; - metad->mime_type_or_namespace = gf_strdup(mime_or_namespace); - if (content_encoding) metad->content_encoding = gf_strdup(content_encoding); - if (schema_loc) metad->xml_schema_loc = gf_strdup(schema_loc); - - e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, metad); - if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); - return e; -} - GF_Err gf_isom_add_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 subSampleSize, u8 priority, u32 reserved, Bool discardable) { @@ -4815,6 +4987,192 @@ GF_Err gf_isom_set_sync_table(GF_ISOFile *file, u32 track) return GF_OK; } + +GF_Err gf_isom_copy_sample_info(GF_ISOFile *dst, u32 dst_track, GF_ISOFile *src, u32 src_track, u32 sampleNumber) +{ + u32 i, count; + GF_SubSampleInfoEntry *sub_sample; + GF_Err e; + GF_TrackBox *src_trak, *dst_trak; + + src_trak = gf_isom_get_track_from_file(src, src_track); + if (!src_trak) return GF_BAD_PARAM; + + dst_trak = gf_isom_get_track_from_file(dst, dst_track); + if (!dst_trak) return GF_BAD_PARAM; + + /*modify depends flags*/ + if (src_trak->Media->information->sampleTable->SampleDep) { + u32 isLeading, dependsOn, dependedOn, redundant; + + isLeading = dependsOn = dependedOn = redundant = 0; + + e = stbl_GetSampleDepType(src_trak->Media->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant); + if (e) return e; + + e = stbl_AppendDependencyType(dst_trak->Media->information->sampleTable, isLeading, dependsOn, dependedOn, redundant); + if (e) return e; + } + + /*copy subsample info if any*/ + if ( gf_isom_sample_get_subsample_entry(src, src_track, sampleNumber, &sub_sample)) { + + /*create subsample if needed*/ + if (!dst_trak->Media->information->sampleTable->SubSamples) { + dst_trak->Media->information->sampleTable->SubSamples = (GF_SubSampleInformationBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SUBS); + dst_trak->Media->information->sampleTable->SubSamples->version = 0; + } + + count = gf_list_count(sub_sample->SubSamples); + for (i=0; i<count; i++) { + GF_SubSampleEntry *entry = gf_list_get(sub_sample->SubSamples, i); + e = gf_isom_add_subsample_info(dst_trak->Media->information->sampleTable->SubSamples, sampleNumber, entry->subsample_size, entry->subsample_priority, entry->reserved, entry->discardable); + if (e) return e; + } + } + + /*copy sampleToGroup info if any*/ + if (src_trak->Media->information->sampleTable->sampleGroups) { + count = gf_list_count(src_trak->Media->information->sampleTable->sampleGroups); + for (i=0; i<count; i++) { + GF_SampleGroupBox *sg; + u32 j; + u32 first_sample_in_entry, last_sample_in_entry; + first_sample_in_entry = 1; + + sg = gf_list_get(src_trak->Media->information->sampleTable->sampleGroups, i); + for (j=0; j<sg->entry_count; j++) { + last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1; + if ((sampleNumber<first_sample_in_entry) || (sampleNumber>last_sample_in_entry)) { + first_sample_in_entry = last_sample_in_entry+1; + continue; + } + + if (!dst_trak->Media->information->sampleTable->sampleGroups) + dst_trak->Media->information->sampleTable->sampleGroups = gf_list_new(); + + /*found our sample, add it to trak->sampleGroups*/ + e = gf_isom_add_sample_group_entry(dst_trak->Media->information->sampleTable->sampleGroups, sampleNumber, sg->grouping_type, sg->sample_entries[j].group_description_index); + if (e) return e; + + break; + } + } + } + return GF_OK; +} + +GF_EXPORT +GF_Err gf_isom_text_set_display_flags(GF_ISOFile *file, u32 track, u32 desc_index, u32 flags, GF_TextFlagsMode op_type) +{ + u32 i; + GF_Err e; + GF_TrackBox *trak; + + e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(file, track); + if (!trak) return GF_BAD_PARAM; + + for (i=0; i < gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); i++) { + GF_Tx3gSampleEntryBox *txt; + if (desc_index && (i+1 != desc_index)) continue; + + txt = gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, i); + if (txt->type != GF_ISOM_BOX_TYPE_TX3G) continue; + + switch (op_type) { + case GF_ISOM_TEXT_FLAGS_TOGGLE: + txt->displayFlags |= flags; + break; + case GF_ISOM_TEXT_FLAGS_UNTOGGLE: + txt->displayFlags &= ~flags; + break; + default: + txt->displayFlags = flags; + break; + } + } + return GF_OK; + +} + + +GF_EXPORT +GF_Err gf_isom_update_duration(GF_ISOFile *movie) +{ + u32 i; + u64 maxDur; + GF_TrackBox *trak; + + if (!movie || !movie->moov) return GF_BAD_PARAM; + + //if file was open in Write or Edit mode, recompute the duration + //the duration of a movie is the MaxDuration of all the tracks... + + maxDur = 0; + i=0; + while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) { + if( (movie->LastError = SetTrackDuration(trak)) ) return movie->LastError; + if (trak->Header->duration > maxDur) + maxDur = trak->Header->duration; + } + movie->moov->mvhd->duration = maxDur; + + return GF_OK; +} + +GF_EXPORT +GF_Err gf_isom_update_edit_list_duration(GF_ISOFile *file, u32 track) +{ + u32 i; + u64 trackDuration; + GF_EdtsEntry *ent; + GF_EditListBox *elst; + GF_Err e; + GF_TrackBox *trak; + + e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(file, track); + if (!trak) return GF_BAD_PARAM; + + + //the total duration is the media duration: adjust it in case... + e = Media_SetDuration(trak); + if (e) return e; + + //assert the timeScales are non-NULL + if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale) return GF_ISOM_INVALID_FILE; + trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale; + + //if we have an edit list, the duration is the sum of all the editList + //entries' duration (always expressed in MovieTimeScale) + if (trak->editBox && trak->editBox->editList) { + u64 editListDuration = 0; + elst = trak->editBox->editList; + i=0; + while ((ent = (GF_EdtsEntry*)gf_list_enum(elst->entryList, &i))) { + if (ent->segmentDuration > trackDuration) + ent->segmentDuration = trackDuration; + if ((ent->mediaTime>=0) && ((u64) ent->mediaTime>=trak->Media->mediaHeader->duration)) { + ent->mediaTime = trak->Media->mediaHeader->duration; + } + editListDuration += ent->segmentDuration; + } + trackDuration = editListDuration; + } + if (!trackDuration) { + trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale; + } + trak->Header->duration = trackDuration; + + return GF_OK; + +} + #endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)*/ diff --git a/src/isomedia/media.c b/src/isomedia/media.c index 91e8361..3bfa6a0 100644 --- a/src/isomedia/media.c +++ b/src/isomedia/media.c @@ -240,7 +240,7 @@ GF_Err Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bo /* TODO */ } break; - case GF_ISOM_BOX_TYPE_STSE: + case GF_ISOM_BOX_TYPE_STXT: { GF_BitStream *bs; esd = gf_odf_desc_esd_new(2); @@ -249,7 +249,7 @@ GF_Err Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bo esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_SIMPLE_TEXT_MP4; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, entry->type); - boxstring_Write((GF_Box *)((GF_SimpleTextSampleEntryBox*)entry)->config, bs); + boxstring_Write((GF_Box *)((GF_MetaDataSampleEntryBox*)entry)->config, bs); gf_bs_get_content(bs, & esd->decoderConfig->decoderSpecificInfo->data, & esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); } @@ -285,6 +285,17 @@ GF_Err Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bo break; } + case GF_ISOM_SUBTYPE_MP3: + if (true_desc_only) { + return GF_ISOM_INVALID_MEDIA; + } else { + esd = gf_odf_desc_esd_new(2); + *out_esd = esd; + esd->decoderConfig->streamType = GF_STREAM_AUDIO; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1; + break; + } + case GF_ISOM_SUBTYPE_LSR1: if (true_desc_only) { return GF_ISOM_INVALID_MEDIA; @@ -337,8 +348,9 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, u8 isEdited; GF_SampleEntryBox *entry; - if (!mdia || !mdia->information->sampleTable) return GF_BAD_PARAM; + if (!mdia->information->sampleTable->SampleSize) + return GF_ISOM_INVALID_FILE; //OK, here we go.... if (sampleNumber > mdia->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM; @@ -362,22 +374,22 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, if (e) return e; } else { //if no SyncSample, all samples are sync (cf spec) - (*samp)->IsRAP = 1; + (*samp)->IsRAP = RAP; } /*overwrite sync sample with sample dep if any*/ if (mdia->information->sampleTable->SampleDep) { - u32 dependsOn, dependedOn, redundant; - e = stbl_GetSampleDepType(mdia->information->sampleTable->SampleDep, sampleNumber, &dependsOn, &dependedOn, &redundant); + u32 isLeading, dependsOn, dependedOn, redundant; + e = stbl_GetSampleDepType(mdia->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant); if (!e) { - if (dependsOn==1) (*samp)->IsRAP = 0; - else if (dependsOn==2) (*samp)->IsRAP = 1; + if (dependsOn==1) (*samp)->IsRAP = RAP_NO; + else if (dependsOn==2) (*samp)->IsRAP = RAP; /*if not depended upon and redundant, mark as carousel sample*/ - if ((dependedOn==2) && (redundant==1)) (*samp)->IsRAP = 2; + if ((dependedOn==2) && (redundant==1)) (*samp)->IsRAP = RAP_REDUNDANT; /*TODO FIXME - we must enhance the IsRAP semantics to carry disposable info ... */ } } /*get sync shadow*/ - if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = 2; + if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = RAP_REDUNDANT; //the data info if (!sIDX && !no_data) return GF_BAD_PARAM; @@ -437,7 +449,7 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, e = Media_RewriteODFrame(mdia, *samp); if (e) return e; } - /*FIXME: we don NOT rewrite sample if we have a encrypted track*/ + /*FIXME: we do NOT rewrite sample if we have a encrypted track*/ else if (gf_isom_is_nalu_based_entry(mdia, entry) && !gf_isom_is_track_encrypted(mdia->mediaTrack->moov->mov, gf_isom_get_tracknum_from_id(mdia->mediaTrack->moov, mdia->mediaTrack->Header->trackID)) ) { @@ -513,7 +525,7 @@ Bool Media_IsSelfContained(GF_MediaBox *mdia, u32 StreamDescIndex) //look for a sync sample from a given point in media time GF_Err Media_FindSyncSample(GF_SampleTableBox *stbl, u32 searchFromSample, u32 *sampleNumber, u8 mode) { - u8 isRAP; + SAPType isRAP; u32 next, prev; if (!stbl || !stbl->SyncSample) return GF_BAD_PARAM; @@ -594,7 +606,12 @@ GF_Err Media_SetDuration(GF_TrackBox *trak) GF_ESD *esd; u64 DTS; GF_SttsEntry *ent; - u32 nbSamp = trak->Media->information->sampleTable->SampleSize->sampleCount; + u32 nbSamp; + + if (!trak->Media->information->sampleTable->SampleSize) + return GF_BAD_PARAM; + else + nbSamp = trak->Media->information->sampleTable->SampleSize->sampleCount; //we need to check how many samples we have. // == 1 -> last sample duration == default duration @@ -618,6 +635,7 @@ GF_Err Media_SetDuration(GF_TrackBox *trak) stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp, &DTS); ent = &trak->Media->information->sampleTable->TimeToSample->entries[trak->Media->information->sampleTable->TimeToSample->nb_entries-1]; trak->Media->mediaHeader->duration = DTS; + trak->Media->mediaHeader->duration += trak->dts_at_seg_start; #if 1 trak->Media->mediaHeader->duration += ent->sampleDelta; @@ -731,7 +749,7 @@ GF_Err Media_CreateDataRef(GF_DataReferenceBox *dref, char *URLname, char *URNna } -GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, GF_ISOSample *sample, u32 StreamDescIndex, u32 syncShadowNumber) +GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, const GF_ISOSample *sample, u32 StreamDescIndex, u32 syncShadowNumber) { GF_Err e; GF_SampleTableBox *stbl; @@ -763,7 +781,7 @@ GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, GF_ISOSample *sample, //The first non sync sample we see must create a syncTable if (sample->IsRAP) { //insert it only if we have a sync table and if we have an IDR slice - if (stbl->SyncSample && (sample->IsRAP == 1)) { + if (stbl->SyncSample && (sample->IsRAP == RAP)) { e = stbl_AddRAP(stbl->SyncSample, sampleNumber); if (e) return e; } @@ -780,7 +798,7 @@ GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, GF_ISOSample *sample, } } } - if (sample->IsRAP==2) { + if (sample->IsRAP==RAP_REDUNDANT) { e = stbl_AddRedundant(stbl, sampleNumber); if (e) return e; } diff --git a/src/isomedia/media_odf.c b/src/isomedia/media_odf.c index ab18c88..f97c905 100644 --- a/src/isomedia/media_odf.c +++ b/src/isomedia/media_odf.c @@ -227,7 +227,7 @@ err_exit: // Update the dependancies when an OD AU is inserted in the file -GF_Err Media_ParseODFrame(GF_MediaBox *mdia, GF_ISOSample *sample, GF_ISOSample **od_samp) +GF_Err Media_ParseODFrame(GF_MediaBox *mdia, const GF_ISOSample *sample, GF_ISOSample **od_samp) { GF_TrackReferenceBox *tref; GF_TrackReferenceTypeBox *mpod; diff --git a/src/isomedia/meta.c b/src/isomedia/meta.c index a84f963..23e88b2 100644 --- a/src/isomedia/meta.c +++ b/src/isomedia/meta.c @@ -84,10 +84,10 @@ GF_Err gf_isom_extract_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, } if (!xml || !xml->xml || !xml->xml_length) return GF_BAD_PARAM; - didfile = gf_f64_open(outName, "wb"); + didfile = gf_fopen(outName, "wb"); if (!didfile) return GF_IO_ERR; gf_fwrite(xml->xml, xml->xml_length, 1, didfile); - fclose(didfile); + gf_fclose(didfile); if (is_binary) *is_binary = (xml->type==GF_ISOM_BOX_TYPE_BXML) ? 1 : 0; return GF_OK; @@ -254,12 +254,12 @@ GF_Err gf_isom_extract_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 item_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); } else if (dump_file_name) { strcpy(szPath, dump_file_name); - resource = gf_f64_open(szPath, "wb"); + resource = gf_fopen(szPath, "wb"); item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE); } else { if (item_name) strcpy(szPath, item_name); else sprintf(szPath, "item_id%02d", item_id); - resource = gf_f64_open(szPath, "wb"); + resource = gf_fopen(szPath, "wb"); item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE); } @@ -281,7 +281,7 @@ GF_Err gf_isom_extract_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 gf_bs_get_content(item_bs, out_data, out_size); } if (resource) { - fclose(resource); + gf_fclose(resource); } gf_bs_del(item_bs); return GF_OK; @@ -412,12 +412,12 @@ GF_Err gf_isom_set_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, cha /*assume 32bit max size = 4Go should be sufficient for a DID!!*/ - xmlfile = gf_f64_open(XMLFileName, "rb"); + xmlfile = gf_fopen(XMLFileName, "rb"); if (!xmlfile) return GF_URL_ERROR; - gf_f64_seek(xmlfile, 0, SEEK_END); - assert(gf_f64_tell(xmlfile) < 1<<31); - xml->xml_length = (u32) gf_f64_tell(xmlfile); - gf_f64_seek(xmlfile, 0, SEEK_SET); + gf_fseek(xmlfile, 0, SEEK_END); + assert(gf_ftell(xmlfile) < 1<<31); + xml->xml_length = (u32) gf_ftell(xmlfile); + gf_fseek(xmlfile, 0, SEEK_SET); xml->xml = (char*)gf_malloc(sizeof(unsigned char)*xml->xml_length); xml->xml_length = (u32) fread(xml->xml, 1, sizeof(unsigned char)*xml->xml_length, xmlfile); if (ferror(xmlfile)) { @@ -425,7 +425,7 @@ GF_Err gf_isom_set_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, cha xml->xml = NULL; return GF_BAD_PARAM; } - fclose(xmlfile); + gf_fclose(xmlfile); return GF_OK; } @@ -479,9 +479,9 @@ GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 trac /*check file exists */ if (!URN && !URL && !self_reference && !data) { - FILE *src = gf_f64_open(resource_path, "rb"); + FILE *src = gf_fopen(resource_path, "rb"); if (!src) return GF_URL_ERROR; - fclose(src); + gf_fclose(src); } if (meta->item_infos) { @@ -596,13 +596,13 @@ GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 trac if (entry->extent_length>0xFFFFFFFF) meta->item_locations->length_size = 8; else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4; } else if (resource_path) { - src = gf_f64_open(resource_path, "rb"); + src = gf_fopen(resource_path, "rb"); if (src) { char cache_data[4096]; u64 remain; - gf_f64_seek(src, 0, SEEK_END); - entry->extent_length = gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_END); + entry->extent_length = gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); remain = entry->extent_length; while (remain) { @@ -612,7 +612,7 @@ GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 trac gf_bs_write_data(file->editFileMap->bs, cache_data, (u32) read); remain -= (u32) read; } - fclose(src); + gf_fclose(src); /*update length size*/ if (entry->extent_length>0xFFFFFFFF) meta->item_locations->length_size = 8; diff --git a/src/isomedia/movie_fragments.c b/src/isomedia/movie_fragments.c index b7a7091..a101abd 100644 --- a/src/isomedia/movie_fragments.c +++ b/src/isomedia/movie_fragments.c @@ -40,6 +40,17 @@ GF_TrackExtendsBox *GetTrex(GF_MovieBox *moov, u32 TrackID) return NULL; } +GF_TrackExtensionPropertiesBox *GetTrep(GF_MovieBox *moov, u32 TrackID) +{ + u32 i; + GF_TrackExtensionPropertiesBox *trep; + i=0; + while ((trep = (GF_TrackExtensionPropertiesBox*) gf_list_enum(moov->mvex->TrackExPropList, &i))) { + if (trep->trackID == TrackID) return trep; + } + return NULL; +} + GF_TrackFragmentBox *GetTraf(GF_ISOFile *mov, u32 TrackID) { u32 i; @@ -67,6 +78,7 @@ GF_Err gf_isom_set_movie_duration(GF_ISOFile *movie, u64 duration) return GF_OK; } + GF_EXPORT GF_Err gf_isom_finalize_for_fragment(GF_ISOFile *movie, u32 media_segment_type) { @@ -102,6 +114,32 @@ GF_Err gf_isom_finalize_for_fragment(GF_ISOFile *movie, u32 media_segment_type) i=0; while ((trex = (GF_TrackExtendsBox *)gf_list_enum(movie->moov->mvex->TrackExList, &i))) { + GF_TrackExtensionPropertiesBox *trep; + if (trex->type != GF_ISOM_BOX_TYPE_TREX) continue; + trep = GetTrep(movie->moov, trex->trackID); + + if (!trep) { + trep = (GF_TrackExtensionPropertiesBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREP); + trep->trackID = trex->trackID; + gf_list_add(movie->moov->mvex->TrackExPropList, trep); + } + + if (trex->track->Media->information->sampleTable->CompositionToDecode) { + + if (!trex->track->Media->information->sampleTable->SampleSize || ! trex->track->Media->information->sampleTable->SampleSize->sampleCount) { + gf_list_add(trep->other_boxes, trex->track->Media->information->sampleTable->CompositionToDecode); + trex->track->Media->information->sampleTable->CompositionToDecode = NULL; + } else { + GF_CompositionToDecodeBox *cslg; + + //clone it! + GF_SAFEALLOC(cslg, GF_CompositionToDecodeBox); + memcpy(cslg, trex->track->Media->information->sampleTable->CompositionToDecode, sizeof(GF_CompositionToDecodeBox) ); + cslg->other_boxes = gf_list_new(); + gf_list_add(trep->other_boxes, trex->track->Media->information->sampleTable->CompositionToDecode); + } + } + if (movie->moov->mvex->mehd && movie->moov->mvex->mehd->fragment_duration) { trex->track->Header->duration = 0; Media_SetDuration(trex->track); @@ -128,7 +166,7 @@ GF_Err gf_isom_finalize_for_fragment(GF_ISOFile *movie, u32 media_segment_type) //dependancies } - //ok we are fine - note the data map is created at the begining + //ok we are fine - note the data map is created at the beginning if (i) movie->FragmentsFlags |= GF_ISOM_FRAG_WRITE_READY; if (media_segment_type) { @@ -181,6 +219,10 @@ GF_Err gf_isom_change_track_fragment_defaults(GF_ISOFile *movie, u32 TrackID, trex->def_sample_duration = DefaultSampleDuration; trex->def_sample_size = DefaultSampleSize; trex->def_sample_flags = GF_ISOM_FORMAT_FRAG_FLAGS(DefaultSamplePadding, DefaultSampleIsSync, DefaultDegradationPriority); + //if sample is sync by default, set sample_depends_on flags to 2 (does not depend on other samples) + if (DefaultSampleIsSync) { + trex->def_sample_flags |= (2<<24); + } return GF_OK; } @@ -382,7 +424,12 @@ void update_trun_offsets(GF_ISOFile *movie, s32 offset) u32 UpdateRuns(GF_ISOFile *movie, GF_TrackFragmentBox *traf) { - u32 sampleCount, i, j, RunSize, UseDefaultSize, RunDur, UseDefaultDur, RunFlags, NeedFlags, UseDefaultFlag, UseCTS, count; + u32 sampleCount, i, j, RunSize, RunDur, RunFlags, NeedFlags, UseCTS, count; + /* enum: + 0 - use values per sample in the trun box + 1 - use default values from track fragment header + 2 - use default values from track extends header */ + u32 UseDefaultSize, UseDefaultDur, UseDefaultFlag; GF_TrackFragmentRunBox *trun; GF_TrunEntry *ent, *first_ent; @@ -484,34 +531,44 @@ u32 UpdateRuns(GF_ISOFile *movie, GF_TrackFragmentBox *traf) //flag checking if (!NeedFlags) { + // all samples flags are the same after the 2nd entry if (RunFlags == traf->trex->def_sample_flags) { - if (!UseDefaultFlag) UseDefaultFlag = 2; - else if (UseDefaultFlag==1) NeedFlags = 1; + /* this run can use trex flags */ + if (!UseDefaultFlag) { + /* if all previous runs used explicit flags per sample, we can still use trex flags for this run */ + UseDefaultFlag = 2; + } else if (UseDefaultFlag==1) { + /* otherwise if one of the previous runs did use tfhd flags, + we have no choice but to explicitly use flags per sample for this run */ + NeedFlags = GF_TRUE; + } } else if (RunFlags == traf->tfhd->def_sample_flags) { - if (!UseDefaultFlag) UseDefaultFlag = 1; - else if(UseDefaultFlag==2) NeedFlags = 1; + /* this run can use tfhd flags */ + if (!UseDefaultFlag) { + /* if all previous runs used explicit flags per sample, we can still use tfhd flags for this run */ + UseDefaultFlag = 1; + } else if(UseDefaultFlag==2) { + /* otherwise if one of the previous runs did use trex flags, + we have no choice but to explicitly use flags per sample for this run */ + NeedFlags = GF_TRUE; + } + } else { + /* the flags for the 2nd and following entries are different from trex and tfhd default values + (possible case: 2 samples in trun, and first sample was used to set default flags) */ + NeedFlags = GF_TRUE; } } if (NeedFlags) { //one flags entry per sample only trun->flags |= GF_ISOM_TRUN_FLAGS; } else { - //indicated in global setup - if (first_ent->flags == traf->trex->def_sample_flags) { - if (!UseDefaultFlag) UseDefaultFlag = 2; - else if (UseDefaultFlag==1) trun->flags |= GF_ISOM_TRUN_FIRST_FLAG; - } - //indicated in local setup - else if (first_ent->flags == traf->tfhd->def_sample_flags) { - if (!UseDefaultFlag) UseDefaultFlag = 1; - else if (UseDefaultFlag==2) trun->flags |= GF_ISOM_TRUN_FIRST_FLAG; - } - //explicit store - else { + /* this run can use default flags for the 2nd and following entries, + we just need to check if the first entry flags need to be singled out*/ + if (first_ent->flags != RunFlags) { trun->flags |= GF_ISOM_TRUN_FIRST_FLAG; } } - + //CTS flag if (UseCTS) trun->flags |= GF_ISOM_TRUN_CTS_OFFSET; @@ -522,7 +579,7 @@ u32 UpdateRuns(GF_ISOFile *movie, GF_TrackFragmentBox *traf) sampleCount += trun->sample_count; } - //last update TRAF flags + //after all runs in the traf are processed, update TRAF flags if (UseDefaultSize==1) traf->tfhd->flags |= GF_ISOM_TRAF_SAMPLE_SIZE; if (UseDefaultDur==1) traf->tfhd->flags |= GF_ISOM_TRAF_SAMPLE_DUR; if (UseDefaultFlag==1) traf->tfhd->flags |= GF_ISOM_TRAF_SAMPLE_FLAGS; @@ -539,17 +596,17 @@ static u32 moof_get_sap_info(GF_MovieFragmentBox *moof, u32 refTrackID, u32 *sap GF_TrunEntry *ent; GF_TrackFragmentBox *traf=NULL; GF_TrackFragmentRunBox *trun; + sap_type = 0; *sap_delta = 0; - *starts_with_sap = 0; + *starts_with_sap = GF_FALSE; for (i=0; i<gf_list_count(moof->TrackList); i++) { traf = gf_list_get(moof->TrackList, i); if (traf->tfhd->trackID==refTrackID) break; traf=NULL; } - if (!traf) return 0; + if (!traf) return sap_type; earliest_cts = 0; - /*first check if we have a roll/rap sample in this traf, and mark its sample count*/ sap_type = 0; sap_sample_num = 0; @@ -558,13 +615,12 @@ static u32 moof_get_sap_info(GF_MovieFragmentBox *moof, u32 refTrackID, u32 *sap for (i=0; i<count; i++) { GF_SampleGroupBox *sg; u32 j, first_sample; - Bool rap_type = 0; + Bool rap_type = GF_FALSE; sg = gf_list_get(traf->sampleGroups, i); - switch (sg->grouping_type) { case GF_4CC('r','a','p',' '): - rap_type = 1; + rap_type = GF_TRUE; break; case GF_4CC('r','o','l','l'): break; @@ -579,7 +635,7 @@ static u32 moof_get_sap_info(GF_MovieFragmentBox *moof, u32 refTrackID, u32 *sap continue; } if (!j) { - *starts_with_sap = 1; + *starts_with_sap = GF_TRUE; sap_sample_num = 0; } if (!sap_sample_num || (sap_sample_num>first_sample)) { @@ -601,7 +657,8 @@ static u32 moof_get_sap_info(GF_MovieFragmentBox *moof, u32 refTrackID, u32 *sap if (!delta) earliest_cts = ent->CTS_Offset; *sap_delta = delta + ent->CTS_Offset - ent->CTS_Offset; *starts_with_sap = first; - return 1; + sap_type = ent->SAP_type; + return sap_type; } } j=0; @@ -611,7 +668,8 @@ static u32 moof_get_sap_info(GF_MovieFragmentBox *moof, u32 refTrackID, u32 *sap if (GF_ISOM_GET_FRAG_SYNC(ent->flags)) { *sap_delta = delta + ent->CTS_Offset - earliest_cts; *starts_with_sap = first; - return 1; + sap_type = ent->SAP_type; + return sap_type; } /*we found our roll or rap sample*/ if (cur_sample==sap_sample_num) { @@ -654,9 +712,10 @@ u32 moof_get_duration(GF_MovieFragmentBox *moof, u32 refTrackID) return duration; } -u32 moof_get_earliest_cts(GF_MovieFragmentBox *moof, u32 refTrackID) +static u64 moof_get_earliest_cts(GF_MovieFragmentBox *moof, u32 refTrackID) { - u32 i, j, cts, duration; + u32 i, j; + u64 cts, duration; GF_TrunEntry *ent; GF_TrackFragmentBox *traf=NULL; GF_TrackFragmentRunBox *trun; @@ -668,7 +727,7 @@ u32 moof_get_earliest_cts(GF_MovieFragmentBox *moof, u32 refTrackID) if (!traf) return 0; duration = 0; - cts = 0xFFFFFFFF; + cts = LLU_CAST (-1); i=0; while ((trun = gf_list_enum(traf->TrackRuns, &i))) { j=0; @@ -1464,7 +1523,7 @@ GF_Err gf_isom_close_segment(GF_ISOFile *movie, s32 subsegments_per_sidx, u32 re if ((root_sidx || sidx) && !daisy_chain_sidx) { if (index_start_range) *index_start_range = sidx_start; - if (index_end_range) *index_end_range = sidx_end; + if (index_end_range) *index_end_range = sidx_end - 1; } if (movie->append_segment) { @@ -1494,7 +1553,7 @@ GF_Err gf_isom_close_fragments(GF_ISOFile *movie) } GF_EXPORT -GF_Err gf_isom_start_segment(GF_ISOFile *movie, char *SegName, Bool memory_mode) +GF_Err gf_isom_start_segment(GF_ISOFile *movie, const char *SegName, Bool memory_mode) { GF_Err e; //and only at setup @@ -1631,7 +1690,7 @@ u32 GetRunSize(GF_TrackFragmentRunBox *trun) } GF_EXPORT -GF_Err gf_isom_fragment_add_sample(GF_ISOFile *movie, u32 TrackID, GF_ISOSample *sample, u32 DescIndex, +GF_Err gf_isom_fragment_add_sample(GF_ISOFile *movie, u32 TrackID, const GF_ISOSample *sample, u32 DescIndex, u32 Duration, u8 PaddingBits, u16 DegradationPriority, Bool redundant_coding) { u32 count, buffer_size; @@ -1731,9 +1790,13 @@ GF_Err gf_isom_fragment_add_sample(GF_ISOFile *movie, u32 TrackID, GF_ISOSample ent->flags = GF_ISOM_FORMAT_FRAG_FLAGS(PaddingBits, sample->IsRAP, DegradationPriority); if (sample->IsRAP) { ent->flags |= GF_ISOM_GET_FRAG_DEPEND_FLAGS(0, 2, 0, (redundant_coding ? 1 : 0) ); + ent->SAP_type = sample->IsRAP; } gf_list_add(trun->entries, ent); + if (sample->CTS_Offset<0) { + trun->version = 1; + } trun->sample_count += 1; //rewrite OD frames @@ -1746,12 +1809,12 @@ GF_Err gf_isom_fragment_add_sample(GF_ISOFile *movie, u32 TrackID, GF_ISOSample //finally write the data if (!traf->DataCache) { if (!gf_bs_write_data(movie->editFileMap->bs, sample->data, sample->dataLength)) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso fragment] Could not add a sample with a size if %u bytes (no DataCache)\n", sample->dataLength)); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso fragment] Could not add a sample with a size of %u bytes (no DataCache)\n", sample->dataLength)); return GF_OUT_OF_MEM; } } else if (trun->cache) { if (!gf_bs_write_data(trun->cache, sample->data, sample->dataLength)) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso fragment] Could not add a sample with a size if %u bytes (with cache)\n", sample->dataLength)); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso fragment] Could not add a sample with a size of %u bytes (with cache)\n", sample->dataLength)); return GF_OUT_OF_MEM; } } else { @@ -1906,9 +1969,9 @@ GF_Err gf_isom_fragment_copy_subsample(GF_ISOFile *dest, u32 TrackID, GF_ISOFile /*modify depends flags*/ if (trak->Media->information->sampleTable->SampleDep) { - u32 dependsOn, dependedOn, redundant; + u32 isLeading, dependsOn, dependedOn, redundant; - dependsOn = dependedOn = redundant = 0; + isLeading = dependsOn = dependedOn = redundant = 0; count = gf_list_count(traf->TrackRuns); if (!count) return GF_BAD_PARAM; trun = (GF_TrackFragmentRunBox *)gf_list_get(traf->TrackRuns, count-1); @@ -1916,7 +1979,7 @@ GF_Err gf_isom_fragment_copy_subsample(GF_ISOFile *dest, u32 TrackID, GF_ISOFile if (!count) return GF_BAD_PARAM; ent = (GF_TrunEntry *)gf_list_get(trun->entries, count-1); - e = stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, &dependsOn, &dependedOn, &redundant); + e = stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant); if (e) return e; GF_ISOM_RESET_FRAG_DEPEND_FLAGS(ent->flags); @@ -2045,7 +2108,7 @@ GF_Err gf_isom_start_fragment(GF_ISOFile *the_file, u32 free_data_insert_size) return GF_NOT_SUPPORTED; } -GF_Err gf_isom_fragment_add_sample(GF_ISOFile *the_file, u32 TrackID, GF_ISOSample *sample, u32 DescIndex, +GF_Err gf_isom_fragment_add_sample(GF_ISOFile *the_file, u32 TrackID, const GF_ISOSample *sample, u32 DescIndex, u32 Duration, u8 PaddingBits, u16 DegradationPriority, Bool redCoded) { return GF_NOT_SUPPORTED; diff --git a/src/isomedia/sample_descs.c b/src/isomedia/sample_descs.c index c164d70..4f2254c 100644 --- a/src/isomedia/sample_descs.c +++ b/src/isomedia/sample_descs.c @@ -381,9 +381,15 @@ GF_Err gf_isom_ac3_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AC3Confi if (!the_file->keep_utc) trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - entry = (GF_AC3SampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AC3); - if (!entry) return GF_OUT_OF_MEM; - entry->info = (GF_AC3ConfigBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_DAC3); + if (cfg->is_ec3) { + entry = (GF_AC3SampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EC3); + if (!entry) return GF_OUT_OF_MEM; + entry->info = (GF_AC3ConfigBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_DEC3); + } else { + entry = (GF_AC3SampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AC3); + if (!entry) return GF_OUT_OF_MEM; + entry->info = (GF_AC3ConfigBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_DAC3); + } if (!entry->info) { gf_isom_box_del((GF_Box *) entry); return GF_OUT_OF_MEM; @@ -525,16 +531,15 @@ GF_Err gf_isom_update_dims_description(GF_ISOFile *movie, u32 trackNumber, GF_DI } #endif /*GPAC_DISABLE_ISOM_WRITE*/ - - GF_Err LSR_UpdateESD(GF_LASeRSampleEntryBox *lsr, GF_ESD *esd) { - if (!lsr->bitrate) lsr->bitrate = (GF_MPEG4BitRateBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT); + GF_BitRateBox *btrt = gf_isom_sample_entry_get_bitrate((GF_SampleEntryBox *)lsr, GF_TRUE); + if (lsr->descr) gf_isom_box_del((GF_Box *) lsr->descr); lsr->descr = NULL; - lsr->bitrate->avgBitrate = esd->decoderConfig->avgBitrate; - lsr->bitrate->maxBitrate = esd->decoderConfig->maxBitrate; - lsr->bitrate->bufferSizeDB = esd->decoderConfig->bufferSizeDB; + btrt->avgBitrate = esd->decoderConfig->avgBitrate; + btrt->maxBitrate = esd->decoderConfig->maxBitrate; + btrt->bufferSizeDB = esd->decoderConfig->bufferSizeDB; if (gf_list_count(esd->IPIDataSet) || gf_list_count(esd->IPMPDescriptorPointers) @@ -588,5 +593,506 @@ GF_Err LSR_UpdateESD(GF_LASeRSampleEntryBox *lsr, GF_ESD *esd) return GF_OK; } +/* MetadataSampleEntry */ +GF_EXPORT +GF_Err gf_isom_get_xml_metadata_description(GF_ISOFile *file, u32 track, u32 sampleDescription, + const char **_namespace, const char **schema_loc, const char **content_encoding) +{ + GF_TrackBox *trak; + GF_MetaDataSampleEntryBox *ptr; + *_namespace = NULL; + *content_encoding = NULL; + *schema_loc = NULL; + trak = gf_isom_get_track_from_file(file, track); + if (!trak || !sampleDescription) return GF_BAD_PARAM; + ptr = (GF_MetaDataSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, sampleDescription-1); + if (!ptr) return GF_BAD_PARAM; + + if (schema_loc) *schema_loc = ptr->xml_schema_loc; + if (_namespace) *_namespace = ptr->xml_namespace; + if (content_encoding) *content_encoding = ptr->content_encoding; + return GF_OK; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err gf_isom_new_xml_metadata_description(GF_ISOFile *movie, u32 trackNumber, + const char *_namespace, const char *schema_loc, const char *content_encoding, + u32 *outDescriptionIndex) +{ + GF_TrackBox *trak; + GF_Err e; + u32 dataRefIndex; + GF_MetaDataSampleEntryBox *metad; + char *URLname = NULL; + char *URNname = NULL; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media || !_namespace) + return GF_BAD_PARAM; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_MPEG_SUBT: + case GF_ISOM_MEDIA_META: + case GF_ISOM_MEDIA_TEXT: + break; + default: + return GF_BAD_PARAM; + } + + //get or create the data ref + e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + if (!dataRefIndex) { + e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + } + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + metad = (GF_MetaDataSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_METX); + if (!metad) return GF_OUT_OF_MEM; + + metad->dataReferenceIndex = dataRefIndex; + metad->xml_namespace = gf_strdup(_namespace); + if (content_encoding) metad->content_encoding = gf_strdup(content_encoding); + if (schema_loc) metad->xml_schema_loc = gf_strdup(schema_loc); + + e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, metad); + if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); + return e; +} + +GF_Err gf_isom_update_xml_metadata_description(GF_ISOFile *movie, u32 trackNumber, + const char *schema_loc, const char *encoding, + u32 DescriptionIndex) +{ + /* TODO */ + return GF_NOT_SUPPORTED; +} + +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + +/* XMLSubtitleSampleEntry */ +GF_EXPORT +GF_Err gf_isom_xml_subtitle_get_description(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, + const char **xmlnamespace, const char **xml_schema_loc, const char **mimes) +{ + GF_TrackBox *trak; + GF_MetaDataSampleEntryBox *entry; + *xmlnamespace = NULL; + *xml_schema_loc = NULL; + *mimes = NULL; + trak = gf_isom_get_track_from_file(the_file, trackNumber); + if (!trak || !StreamDescriptionIndex) return GF_BAD_PARAM; + + entry = (GF_MetaDataSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, StreamDescriptionIndex-1); + if (!entry || + (entry->type!=GF_ISOM_BOX_TYPE_STPP)) { + return GF_BAD_PARAM; + } + + if (entry->mime_type) { + *mimes = entry->mime_type; + } + if (entry->xml_schema_loc) { + *xml_schema_loc = entry->xml_schema_loc; + } + *xmlnamespace = entry->xml_namespace; + return GF_OK; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err gf_isom_new_xml_subtitle_description(GF_ISOFile *movie, u32 trackNumber, + const char *xmlnamespace, const char *xml_schema_loc, const char *mimes, + u32 *outDescriptionIndex) +{ + GF_TrackBox *trak; + GF_Err e; + u32 dataRefIndex; + GF_MetaDataSampleEntryBox *stpp; + char *URLname = NULL; + char *URNname = NULL; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media) return GF_BAD_PARAM; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_MPEG_SUBT: + case GF_ISOM_MEDIA_META: + case GF_ISOM_MEDIA_TEXT: + break; + default: + return GF_BAD_PARAM; + } + + if (!xmlnamespace) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("XML (Subtitle, Metadata or Text) SampleEntry: namespace is mandatory. Abort.\n")); + return GF_BAD_PARAM; + } + + //get or create the data ref + e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + if (!dataRefIndex) { + e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + } + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + stpp = (GF_MetaDataSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STPP); + stpp->dataReferenceIndex = dataRefIndex; + gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, stpp); + if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); + + stpp->xml_namespace = gf_strdup(xmlnamespace); + if (xml_schema_loc) stpp->xml_schema_loc = gf_strdup(xml_schema_loc); //optional + if (mimes) stpp->mime_type = gf_strdup(mimes); //optional + return e; +} + +GF_Err gf_isom_update_xml_subtitle_description(GF_ISOFile *movie, u32 trackNumber, + u32 descriptionIndex, GF_GenericSubtitleSampleDescriptor *desc) +{ + GF_TrackBox *trak; + GF_Err e; + + if (!descriptionIndex || !desc) return GF_BAD_PARAM; + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media) return GF_BAD_PARAM; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_MPEG_SUBT: + break; + default: + return GF_BAD_PARAM; + } + + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + return e; +} + +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + + +/* SimpleTextSampleEntry: also used for MetadataTextSampleEntry and SubtitleTextSampleEntry */ +GF_EXPORT +GF_Err gf_isom_stxt_get_description(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, + const char **mime, const char **encoding, const char **config) +{ + GF_TrackBox *trak; + GF_MetaDataSampleEntryBox *entry; + *mime = NULL; + *config = NULL; + *encoding = NULL; + trak = gf_isom_get_track_from_file(the_file, trackNumber); + if (!trak || !StreamDescriptionIndex) return GF_BAD_PARAM; + + entry = (GF_MetaDataSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, StreamDescriptionIndex-1); + if (!entry || + ((entry->type!=GF_ISOM_BOX_TYPE_STXT) && + (entry->type!=GF_ISOM_BOX_TYPE_METT) && + (entry->type!=GF_ISOM_BOX_TYPE_SBTT))) { + return GF_BAD_PARAM; + } + + if (entry->config) { + *config = entry->config->config; + } + if (entry->mime_type) { + *mime = entry->mime_type; + } + if (entry->content_encoding) { + *encoding = entry->content_encoding; + } + return GF_OK; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE +GF_Err gf_isom_new_stxt_description(GF_ISOFile *movie, u32 trackNumber, u32 type, + const char *mime, const char *encoding, const char * config, + u32 *outDescriptionIndex) +{ + GF_TrackBox *trak; + GF_Err e; + u32 dataRefIndex; + GF_MetaDataSampleEntryBox *sample_entry; + char *URLname = NULL; + char *URNname = NULL; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media) return GF_BAD_PARAM; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_MPEG_SUBT: + case GF_ISOM_MEDIA_META: + case GF_ISOM_MEDIA_SCENE: + case GF_ISOM_MEDIA_TEXT: + case GF_ISOM_MEDIA_SUBT: + break; + default: + return GF_BAD_PARAM; + } + switch (type) { + case GF_ISOM_SUBTYPE_SBTT: + case GF_ISOM_SUBTYPE_STXT: + case GF_ISOM_SUBTYPE_METT: + break; + default: + GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("SampleEntry shall be either Metadata, Subtitle or SimpleText. Abort.\n")); + return GF_BAD_PARAM; + } + + if (!mime) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Text (Metadata, Subtitle or SimpleText) SampleEntry: mime is mandatory. Using text/plain.\n")); + mime = "text/plain"; + } + + //get or create the data ref + e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + if (!dataRefIndex) { + e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + } + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + sample_entry = (GF_MetaDataSampleEntryBox *) gf_isom_box_new(type); + sample_entry->dataReferenceIndex = dataRefIndex; + gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, sample_entry); + if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); + + sample_entry->mime_type = gf_strdup(mime); + if (encoding) sample_entry->content_encoding = gf_strdup(encoding); + if (config) { + sample_entry->config = (GF_TextConfigBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TXTC); + sample_entry->config->config = gf_strdup(config); + } + return e; +} + + +GF_Err gf_isom_update_stxt_description(GF_ISOFile *movie, u32 trackNumber, + const char *encoding, const char *config, + u32 DescriptionIndex) +{ + GF_TrackBox *trak; + GF_Err e; + GF_MetaDataSampleEntryBox *sample_entry; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media || !DescriptionIndex) return GF_BAD_PARAM; + + sample_entry = (GF_MetaDataSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex-1); + if (!sample_entry) return GF_BAD_PARAM; + if (sample_entry->type != GF_ISOM_BOX_TYPE_METT && + sample_entry->type != GF_ISOM_BOX_TYPE_SBTT && + sample_entry->type != GF_ISOM_BOX_TYPE_STXT) { + return GF_BAD_PARAM; + } + + if (!sample_entry->config) + sample_entry->config = (GF_TextConfigBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TXTC); + + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + if (sample_entry->config->config) { + gf_free(sample_entry->config->config); + } + sample_entry->config->config = gf_strdup(config); + + if (sample_entry->content_encoding) { + gf_free(sample_entry->content_encoding); + } + if (encoding) { + sample_entry->content_encoding = gf_strdup(encoding); + } + return e; +} +#endif /*GPAC_DISABLE_ISOM_WRITE*/ + +GF_WebVTTSampleEntryBox *gf_webvtt_isom_get_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex) +{ + GF_WebVTTSampleEntryBox *wvtt; + GF_TrackBox *trak; + + if (!descriptionIndex) return NULL; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media) return NULL; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_TEXT: + break; + default: + return NULL; + } + + wvtt = (GF_WebVTTSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, descriptionIndex - 1); + if (!wvtt) return NULL; + switch (wvtt->type) { + case GF_ISOM_BOX_TYPE_WVTT: + break; + default: + return NULL; + } + return wvtt; +} + +#ifndef GPAC_DISABLE_ISOM_WRITE + +GF_Err gf_isom_update_webvtt_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, const char *config) +{ + GF_Err e; + GF_WebVTTSampleEntryBox *wvtt; + GF_TrackBox *trak; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return GF_BAD_PARAM; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media) return GF_BAD_PARAM; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_TEXT: + case GF_ISOM_MEDIA_SUBT: + case GF_ISOM_MEDIA_MPEG_SUBT: + break; + default: + return GF_BAD_PARAM; + } + + wvtt = (GF_WebVTTSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, descriptionIndex - 1); + if (!wvtt) return GF_BAD_PARAM; + switch (wvtt->type) { + case GF_ISOM_BOX_TYPE_WVTT: + break; + default: + return GF_BAD_PARAM; + } + if (wvtt) { + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + wvtt->config = (GF_StringBox *)boxstring_new_with_data(GF_ISOM_BOX_TYPE_VTTC, config); + } else { + e = GF_BAD_PARAM; + } + return e; +} + +GF_Err gf_isom_new_webvtt_description(GF_ISOFile *movie, u32 trackNumber, GF_TextSampleDescriptor *desc, char *URLname, char *URNname, u32 *outDescriptionIndex) +{ + GF_TrackBox *trak; + GF_Err e; + u32 dataRefIndex; + GF_WebVTTSampleEntryBox *wvtt; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return e; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !trak->Media) return GF_BAD_PARAM; + + switch (trak->Media->handler->handlerType) { + case GF_ISOM_MEDIA_TEXT: + case GF_ISOM_MEDIA_SUBT: + case GF_ISOM_MEDIA_MPEG_SUBT: + break; + default: + return GF_BAD_PARAM; + } + + //get or create the data ref + e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + if (!dataRefIndex) { + e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); + if (e) return e; + } + if (!movie->keep_utc) + trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + + wvtt = (GF_WebVTTSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_WVTT); + wvtt->dataReferenceIndex = dataRefIndex; + gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, wvtt); + if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); + return e; +} + +GF_BitRateBox *gf_isom_sample_entry_get_bitrate(GF_SampleEntryBox *ent, Bool create) +{ + u32 i=0; + GF_BitRateBox *a; + while ((a = (GF_BitRateBox *)gf_list_enum(ent->other_boxes, &i))) { + if (a->type==GF_ISOM_BOX_TYPE_BTRT) return a; + } + if (!create) return NULL; + a = (GF_BitRateBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_BTRT); + if (!ent->other_boxes) ent->other_boxes = gf_list_new(); + gf_list_add(ent->other_boxes, a); + return a; +} + +GF_EXPORT +GF_Err gf_isom_update_bitrate(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, u32 average_bitrate, u32 max_bitrate, u32 decode_buffer_size) +{ + GF_BitRateBox *a; + GF_Err e; + GF_SampleEntryBox *ent; + GF_TrackBox *trak; + + e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); + if (e) return GF_BAD_PARAM; + + trak = gf_isom_get_track_from_file(movie, trackNumber); + if (!trak || !sampleDescriptionIndex || !trak->Media) return GF_BAD_PARAM; + + ent = (GF_SampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, sampleDescriptionIndex - 1); + if (!ent) return GF_BAD_PARAM; + + a = gf_isom_sample_entry_get_bitrate(ent, max_bitrate ? GF_TRUE : GF_FALSE); + if (!max_bitrate) { + if (a) { + gf_list_del_item(ent->other_boxes, a); + gf_isom_box_del((GF_Box *) a); + + if (!gf_list_count(ent->other_boxes)) { + gf_list_del(ent->other_boxes); + ent->other_boxes = NULL; + } + } + return GF_OK; + } + + a->avgBitrate = average_bitrate; + a->maxBitrate = max_bitrate; + a->bufferSizeDB = decode_buffer_size; + return GF_OK; +} + + +#endif /*GPAC_DISABLE_ISOM_WRITE*/ #endif /*GPAC_DISABLE_ISOM*/ diff --git a/src/isomedia/stbl_read.c b/src/isomedia/stbl_read.c index 7ec4aa0..e060a3d 100644 --- a/src/isomedia/stbl_read.c +++ b/src/isomedia/stbl_read.c @@ -68,7 +68,7 @@ GF_Err findEntryForTime(GF_SampleTableBox *stbl, u64 DTS, u8 useCTS, u32 *sample curDTS -= ent->sampleDelta * ent->sampleCount; i --; } else if (!i) { - //begining of the table, no choice + //beginning of the table, no choice curDTS = stbl->TimeToSample->r_CurrentDTS = 0; curSampNum = stbl->TimeToSample->r_FirstSampleInEntry = 1; stbl->TimeToSample->r_currentEntryIndex = 0; @@ -218,9 +218,6 @@ GF_Err stbl_GetSampleDTS_and_Duration(GF_TimeToSampleBox *stts, u32 SampleNumber found: (*DTS) = stts->r_CurrentDTS + j * (u64) ent->sampleDelta; if (duration) *duration = ent->sampleDelta; - if (stts->r_FirstSampleInEntry == 1) - stts->r_FirstSampleInEntry = 1; - return GF_OK; } @@ -229,13 +226,13 @@ GF_Err stbl_GetSampleDTS(GF_TimeToSampleBox *stts, u32 SampleNumber, u64 *DTS) return stbl_GetSampleDTS_and_Duration(stts, SampleNumber, DTS, NULL); } //Retrieve closes RAP for a given sample - if sample is RAP, sets the RAP flag -GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, u8 *IsRAP, u32 *prevRAP, u32 *nextRAP) +GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP) { u32 i; if (prevRAP) *prevRAP = 0; if (nextRAP) *nextRAP = 0; - (*IsRAP) = 0; + (*IsRAP) = RAP_NO; if (!stss || !SampleNumber) return GF_BAD_PARAM; if (stss->r_LastSyncSample && (stss->r_LastSyncSample < SampleNumber) ) { @@ -249,7 +246,7 @@ GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, u8 *IsRAP, u3 //update the cache stss->r_LastSyncSample = SampleNumber; stss->r_LastSampleIndex = i; - (*IsRAP) = 1; + (*IsRAP) = RAP; } else if (stss->sampleNumbers[i] > SampleNumber) { if (nextRAP) *nextRAP = stss->sampleNumbers[i]; @@ -260,12 +257,12 @@ GF_Err stbl_GetSampleRAP(GF_SyncSampleBox *stss, u32 SampleNumber, u8 *IsRAP, u3 return GF_OK; } -GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, u8 *IsRAP, u32 *prevRAP, u32 *nextRAP) +GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, SAPType *IsRAP, u32 *prevRAP, u32 *nextRAP) { u32 i, j, count, count2; assert(prevRAP); assert(nextRAP); - (*IsRAP) = 0; + (*IsRAP) = RAP_NO; if (!stbl->sampleGroups || !stbl->sampleGroupsDescription) return GF_OK; @@ -333,13 +330,13 @@ GF_Err stbl_SearchSAPs(GF_SampleTableBox *stbl, u32 SampleNumber, u8 *IsRAP, u32 /*sample lies in this (rap) group, it is rap*/ if (is_rap_group) { if ((first_rap_in_entry <= SampleNumber) && (SampleNumber <= last_rap_in_entry)) { - (*IsRAP) = 1; + (*IsRAP) = RAP; return GF_OK; } } else { /*prevRAP or nextRAP matches SampleNumber, sample is RAP*/ if ((*prevRAP == SampleNumber) || (*nextRAP == SampleNumber)) { - (*IsRAP) = 1; + (*IsRAP) = RAP; return GF_OK; } } @@ -546,7 +543,7 @@ GF_Err stbl_GetPaddingBits(GF_PaddingBitsBox *padb, u32 SampleNumber, u8 *PadBit } //Set the RAP flag of a sample -GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *sdep, u32 SampleNumber, u32 *dependsOn, u32 *dependedOn, u32 *redundant) +GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *sdep, u32 SampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant) { u8 flag; @@ -555,6 +552,7 @@ GF_Err stbl_GetSampleDepType(GF_SampleDependencyTypeBox *sdep, u32 SampleNumber, if (SampleNumber > sdep->sampleCount) return GF_BAD_PARAM; flag = sdep->sample_info[SampleNumber-1]; + *isLeading = (flag >> 6) & 3; *dependsOn = (flag >> 4) & 3; *dependedOn = (flag >> 2) & 3; *redundant = (flag) & 3; diff --git a/src/isomedia/stbl_write.c b/src/isomedia/stbl_write.c index b4f86f8..e472bae 100644 --- a/src/isomedia/stbl_write.c +++ b/src/isomedia/stbl_write.c @@ -243,7 +243,7 @@ GF_Err stbl_AddCTS(GF_SampleTableBox *stbl, u32 sampleNumber, u32 CTSoffset) } } - /*we will at most add 2 new entries (spliting of an existing one)*/ + /*we will at most add 2 new entries (splitting of an existing one)*/ if (ctts->nb_entries+2>=ctts->alloc_size) { ctts->alloc_size += 2; ctts->entries = gf_realloc(ctts->entries, sizeof(GF_DttsEntry)*ctts->alloc_size); @@ -474,7 +474,7 @@ GF_Err stbl_AddRedundant(GF_SampleTableBox *stbl, u32 sampleNumber) sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * (sdtp->sampleCount+missed) ); memset(&sdtp->sample_info[sdtp->sampleCount], 0, sizeof(u8) * missed ); while (missed) { - u8 isRAP; + SAPType isRAP; if (stbl->SyncSample) stbl_GetSampleRAP(stbl->SyncSample, sdtp->sampleCount+1, &isRAP, NULL, NULL); else isRAP = 1; sdtp->sample_info[sdtp->sampleCount] = isRAP ? 0x20 : 0; @@ -497,6 +497,30 @@ GF_Err stbl_AddRedundant(GF_SampleTableBox *stbl, u32 sampleNumber) return GF_OK; } +GF_Err stbl_AppendDependencyType(GF_SampleTableBox *stbl, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant) +{ + GF_SampleDependencyTypeBox *sdtp; + u32 flags; + if (stbl->SampleDep == NULL) { + stbl->SampleDep = (GF_SampleDependencyTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SDTP); + if (!stbl->SampleDep) return GF_OUT_OF_MEM; + } + sdtp = stbl->SampleDep; + + flags = 0; + flags |= isLeading << 6; + flags |= dependsOn << 4; + flags |= dependedOn << 2; + flags |= redundant; + + + sdtp->sample_info = (u8*) gf_realloc(sdtp->sample_info, sizeof(u8) * (sdtp->sampleCount + 1)); + if (!sdtp->sample_info) return GF_OUT_OF_MEM; + sdtp->sample_info[sdtp->sampleCount] = flags; + sdtp->sampleCount ++; + return GF_OK; +} + //this function is always called in INCREASING order of shadow sample numbers GF_Err stbl_AddShadow(GF_ShadowSyncBox *stsh, u32 sampleNumber, u32 shadowNumber) { @@ -877,12 +901,12 @@ GF_Err stbl_RemoveDTS(GF_SampleTableBox *stbl, u32 sampleNumber, u32 LastAUDefDu } else if (DTSs[i+1] - DTSs[i] == stts->entries[j].sampleDelta) { stts->entries[j].sampleCount += 1; } else { - j++; stts->nb_entries++; if (j+1==stts->alloc_size) { stts->alloc_size++; stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry) * stts->alloc_size); } + j++; stts->entries[j].sampleCount = 1; stts->entries[j].sampleDelta = (u32) (DTSs[i+1] - DTSs[i]); } @@ -893,7 +917,7 @@ GF_Err stbl_RemoveDTS(GF_SampleTableBox *stbl, u32 sampleNumber, u32 LastAUDefDu } //reset write the cache to the end stts->w_currentSampleNum = stbl->SampleSize->sampleCount - 1; - //reset read the cache to the begining + //reset read the cache to the beginning stts->r_FirstSampleInEntry = stts->r_currentEntryIndex = 0; stts->r_CurrentDTS = 0; return GF_OK; @@ -1355,7 +1379,7 @@ void stbl_AppendChunk(GF_SampleTableBox *stbl, u64 offset) //large offsets else { co64 = (GF_ChunkLargeOffsetBox *)stbl->ChunkOffset; - off_64 = (u64*)gf_malloc(sizeof(u32)*(co64->nb_entries+1)); + off_64 = (u64*)gf_malloc(sizeof(u64)*(co64->nb_entries+1)); if (!off_64) return; for (i=0; i<co64->nb_entries; i++) off_64[i] = co64->offsets[i]; off_64[i] = offset; diff --git a/src/isomedia/track.c b/src/isomedia/track.c index 07dc14e..0f49ec7 100644 --- a/src/isomedia/track.c +++ b/src/isomedia/track.c @@ -401,7 +401,7 @@ GF_Err SetTrackDuration(GF_TrackBox *trak) Bool gf_isom_is_identical_sgpd(void *ptr1, void *ptr2, u32 grouping_type) { Bool res = GF_FALSE; -#ifndef GPAC_DISABLE_ISOM_WRITE +#ifndef GPAC_DISABLE_ISOM_WRITE GF_BitStream *bs1, *bs2; char *buf1, *buf2; u32 len1, len2; @@ -474,7 +474,7 @@ GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u64 moof_offset, /*in playback mode*/ if (traf->tfdt && is_first_merge) { #ifndef GPAC_DISABLE_LOG - if (trak->present_in_scalable_segment && trak->sample_count_at_seg_start && (trak->dts_at_seg_start != traf->tfdt->baseMediaDecodeTime)) { + if (trak->moov->mov->NextMoofNumber && trak->present_in_scalable_segment && trak->sample_count_at_seg_start && (trak->dts_at_seg_start != traf->tfdt->baseMediaDecodeTime)) { s32 drift = (s32) ((s64) traf->tfdt->baseMediaDecodeTime - (s64)trak->dts_at_seg_start); if (drift<0) { GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: TFDT timing "LLD" less than cumulated timing "LLD" - using tfdt\n", traf->tfdt->baseMediaDecodeTime, trak->dts_at_seg_start )); @@ -547,6 +547,8 @@ GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u64 moof_offset, if (pad) stbl_AppendPadding(trak->Media->information->sampleTable, pad); degr = GF_ISOM_GET_FRAG_DEG(flags); if (degr) stbl_AppendDegradation(trak->Media->information->sampleTable, degr); + + stbl_AppendDependencyType(trak->Media->information->sampleTable, GF_ISOM_GET_FRAG_LEAD(flags), GF_ISOM_GET_FRAG_DEPENDS(flags), GF_ISOM_GET_FRAG_DEPENDED(flags), GF_ISOM_GET_FRAG_REDUNDANT(flags)); } } /*merge sample groups*/ @@ -1110,7 +1112,7 @@ GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex, e = LSR_UpdateESD((GF_LASeRSampleEntryBox*)entry, esd); if (e) return e; break; - case GF_ISOM_BOX_TYPE_STSE: + case GF_ISOM_BOX_TYPE_STXT: case GF_ISOM_BOX_TYPE_WVTT: case GF_ISOM_BOX_TYPE_STPP: /* TODO */ @@ -1153,13 +1155,20 @@ GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex, entry = (GF_MPEGSampleEntryBox*) entry_v; break; case GF_ISOM_MEDIA_AUDIO: - entry_a = (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MP4A); - entry_a->samplerate_hi = trak->Media->mediaHeader->timeScale; - if (!entry_a) return GF_OUT_OF_MEM; - entry_a->esd = (GF_ESDBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ESDS); - entry_a->esd->desc = esd; - //type cast possible now - entry = (GF_MPEGSampleEntryBox*) entry_a; + if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_AUDIO_AC3) { + GF_AC3SampleEntryBox *ac3 = (GF_AC3SampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AC3); + if (!ac3) return GF_OUT_OF_MEM; + ac3->info = (GF_AC3ConfigBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_DAC3); + entry = (GF_MPEGSampleEntryBox*) ac3; + } else { + entry_a = (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MP4A); + entry_a->samplerate_hi = trak->Media->mediaHeader->timeScale; + if (!entry_a) return GF_OUT_OF_MEM; + entry_a->esd = (GF_ESDBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ESDS); + entry_a->esd->desc = esd; + //type cast possible now + entry = (GF_MPEGSampleEntryBox*) entry_a; + } break; default: if ((esd->decoderConfig->streamType==0x03) && (esd->decoderConfig->objectTypeIndication==0x09)) { diff --git a/src/isomedia/ttml.c b/src/isomedia/ttml.c index 70219b8..6f211ad 100644 --- a/src/isomedia/ttml.c +++ b/src/isomedia/ttml.c @@ -31,247 +31,6 @@ #ifndef GPAC_DISABLE_TTML -GF_Box *stpp_New() -{ - ISOM_DECL_BOX_ALLOC(GF_XMLSubtitleSampleEntryBox, GF_ISOM_BOX_TYPE_STPP); - gf_isom_sample_entry_init((GF_SampleEntryBox*)tmp); - return (GF_Box *)tmp; -} - -void stpp_del(GF_Box *s) -{ - GF_XMLSubtitleSampleEntryBox *stpp= (GF_XMLSubtitleSampleEntryBox *)s; - if (stpp == NULL) return; - gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s); - if (stpp->xmlnamespace) gf_free(stpp->xmlnamespace); - if (stpp->schema_location) gf_free(stpp->schema_location); - if (stpp->auxiliary_mime_types) gf_free(stpp->auxiliary_mime_types); - gf_free(s); -} - -static GF_Err stpp_Add(GF_Box *s, GF_Box *a) -{ - GF_XMLSubtitleSampleEntryBox *stpp = (GF_XMLSubtitleSampleEntryBox *)s; - switch(a->type) { - case GF_ISOM_BOX_TYPE_BTRT: - if (stpp->bitrate) ERROR_ON_DUPLICATED_BOX(a, s) - stpp->bitrate = (GF_MPEG4BitRateBox *)a; - break; - case GF_ISOM_BOX_TYPE_SINF: - gf_list_add(stpp->protections, a); - break; - default: - return gf_isom_box_add_default(s, a); - } - return GF_OK; -} - -GF_Err stpp_Read(GF_Box *s, GF_BitStream *bs) -{ - u32 size, i; - char *str; - GF_XMLSubtitleSampleEntryBox *stpp = (GF_XMLSubtitleSampleEntryBox *)s; - gf_bs_read_data(bs, stpp->reserved, 6); - stpp->dataReferenceIndex = gf_bs_read_u16(bs); - - size = (u32) stpp->size - 8; - str = (char *)gf_malloc(sizeof(char)*size); - - i=0; - while (size) { - str[i] = gf_bs_read_u8(bs); - size--; - if (!str[i]) - break; - i++; - } - if (i) stpp->xmlnamespace = gf_strdup(str); - - i=0; - while (size) { - str[i] = gf_bs_read_u8(bs); - size--; - if (!str[i]) - break; - i++; - } - if (i) stpp->schema_location = gf_strdup(str); - - i=0; - while (size) { - str[i] = gf_bs_read_u8(bs); - size--; - if (!str[i]) - break; - i++; - } - if (i) stpp->auxiliary_mime_types = gf_strdup(str); - - stpp->size = size; - gf_free(str); - return gf_isom_read_box_list(s, bs, stpp_Add); -} - -#ifndef GPAC_DISABLE_ISOM_WRITE -GF_Err stpp_Write(GF_Box *s, GF_BitStream *bs) -{ - GF_Err e; - GF_XMLSubtitleSampleEntryBox *stpp = (GF_XMLSubtitleSampleEntryBox *)s; - e = gf_isom_box_write_header(s, bs); - gf_bs_write_data(bs, stpp->reserved, 6); - gf_bs_write_u16(bs, stpp->dataReferenceIndex); - - gf_bs_write_data(bs, stpp->xmlnamespace, (u32) strlen(stpp->xmlnamespace)); - gf_bs_write_u8(bs, 0); - - if (stpp->schema_location) - gf_bs_write_data(bs, stpp->schema_location, (u32) strlen(stpp->schema_location)); - gf_bs_write_u8(bs, 0); - - if (stpp->auxiliary_mime_types) - gf_bs_write_data(bs, stpp->auxiliary_mime_types, (u32) strlen(stpp->auxiliary_mime_types)); - gf_bs_write_u8(bs, 0); - - e = gf_isom_box_write((GF_Box *)stpp->bitrate, bs); - if (e) return e; - - return gf_isom_box_array_write(s, stpp->protections, bs); -} - -GF_Err stpp_Size(GF_Box *s) -{ - GF_Err e; - GF_XMLSubtitleSampleEntryBox *stpp = (GF_XMLSubtitleSampleEntryBox *)s; - e = gf_isom_box_get_size(s); - if (e) return e; - s->size += 8; // reserved and dataReferenceIndex - - stpp->size += strlen(stpp->xmlnamespace); - stpp->size++; - - if (stpp->schema_location) - stpp->size += strlen(stpp->schema_location); - stpp->size++; - - if (stpp->auxiliary_mime_types) - stpp->size += strlen(stpp->auxiliary_mime_types); - stpp->size++; - - e = gf_isom_box_size((GF_Box *)stpp->bitrate); - if (e) return e; - stpp->size += stpp->bitrate->size; - - return gf_isom_box_array_size(s, stpp->protections); -} - -#endif /*GPAC_DISABLE_ISOM_WRITE*/ - -#ifndef GPAC_DISABLE_ISOM_DUMP -GF_Err DumpBox(GF_Box *a, FILE * trace); -void gf_box_dump_done(char *name, GF_Box *ptr, FILE *trace); - -GF_Err stpp_dump(GF_Box *a, FILE * trace) -{ - GF_XMLSubtitleSampleEntryBox *stpp = (GF_XMLSubtitleSampleEntryBox *)a; - const char *name = "XMLSubtitleSampleEntryBox"; - - fprintf(trace, "<%s ", name); - fprintf(trace, "namespace=\"%s\" ", stpp->xmlnamespace); - if (stpp->schema_location) fprintf(trace, "schema_location=\"%s\" ", stpp->schema_location); - if (stpp->auxiliary_mime_types) fprintf(trace, "auxiliary_mime_types=\"%s\" ", stpp->auxiliary_mime_types); - fprintf(trace, ">\n"); - DumpBox(a, trace); - - gf_box_dump(stpp->bitrate, trace); - - gf_box_dump_done(NULL, a, trace); - fprintf(trace, "</%s>\n", name); - return GF_OK; -} - -#endif /* GPAC_DISABLE_ISOM_DUMP */ - -#ifndef GPAC_DISABLE_ISOM_WRITE - -GF_Err gf_isom_update_xml_subtitle_description( GF_ISOFile *movie, - u32 trackNumber, - u32 descriptionIndex, - GF_GenericSubtitleSampleDescriptor *desc) -{ - GF_TrackBox *trak; - GF_Err e; - - if (!descriptionIndex || !desc) return GF_BAD_PARAM; - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return e; - - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return GF_BAD_PARAM; - - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_MPEG_SUBT: - break; - default: - return GF_BAD_PARAM; - } - - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - - return e; -} - -GF_Err gf_isom_new_xml_subtitle_description(GF_ISOFile *movie, - u32 trackNumber, - char *xmlnamespace, - char *xml_schema_loc, - char *mimes, - u32 *outDescriptionIndex) -{ - GF_TrackBox *trak; - GF_Err e; - u32 dataRefIndex; - GF_XMLSubtitleSampleEntryBox *stpp; - char *URLname = NULL; - char *URNname = NULL; - - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return e; - - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return GF_BAD_PARAM; - - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_MPEG_SUBT: - break; - default: - return GF_BAD_PARAM; - } - - //get or create the data ref - e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - if (!dataRefIndex) { - e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - } - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - - stpp = (GF_XMLSubtitleSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STPP); - stpp->dataReferenceIndex = dataRefIndex; - gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, stpp); - if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); - - stpp->bitrate = (GF_MPEG4BitRateBox *)btrt_New(); - stpp->xmlnamespace = gf_strdup(xmlnamespace); - stpp->schema_location = gf_strdup(xml_schema_loc); - stpp->auxiliary_mime_types = gf_strdup(mimes); - return e; -} - -#endif - /* blindly adds text to a sample following 3GPP Timed Text style */ GF_Err gf_isom_xml_subtitle_sample_add_text(GF_GenericSubtitleSample *samp, char *text_data, u32 text_len) { @@ -306,7 +65,7 @@ GF_ISOSample *gf_isom_xml_subtitle_to_sample(GF_GenericSubtitleSample *samp) } gf_bs_get_content(bs, &res->data, &res->dataLength); gf_bs_del(bs); - res->IsRAP = 1; + res->IsRAP = RAP; return res; } diff --git a/src/isomedia/tx3g.c b/src/isomedia/tx3g.c index 045143e..c3ca4f6 100644 --- a/src/isomedia/tx3g.c +++ b/src/isomedia/tx3g.c @@ -94,7 +94,7 @@ GF_Err gf_isom_new_text_description(GF_ISOFile *movie, u32 trackNumber, GF_TextS if (e) return e; trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media || !desc->font_count) return GF_BAD_PARAM; + if (!trak || !trak->Media || !desc || !desc->font_count) return GF_BAD_PARAM; switch (trak->Media->handler->handlerType) { case GF_ISOM_MEDIA_TEXT: @@ -347,7 +347,7 @@ GF_ISOSample *gf_isom_text_to_sample(GF_TextSample *samp) } gf_bs_get_content(bs, &res->data, &res->dataLength); gf_bs_del(bs); - res->IsRAP = 1; + res->IsRAP = RAP; return res; } @@ -610,7 +610,7 @@ GF_Err gf_isom_get_ttxt_esd(GF_MediaBox *mdia, GF_ESD **out_esd) esd = gf_odf_desc_esd_new(2); esd->decoderConfig->streamType = GF_STREAM_TEXT; - esd->decoderConfig->objectTypeIndication = 0x08; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_TEXT_MPEG4; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); diff --git a/src/laser/lsr_dec.c b/src/laser/lsr_dec.c index 09a80f1..fe4daef 100644 --- a/src/laser/lsr_dec.c +++ b/src/laser/lsr_dec.c @@ -26,7 +26,6 @@ #include <gpac/internal/laser_dev.h> #include <gpac/internal/scenegraph_dev.h> #include <gpac/bitstream.h> -#include <gpac/math.h> #include <gpac/events.h> #ifndef GPAC_DISABLE_LASER diff --git a/src/laser/lsr_enc.c b/src/laser/lsr_enc.c index ebc5803..d0536de 100644 --- a/src/laser/lsr_enc.c +++ b/src/laser/lsr_enc.c @@ -26,7 +26,6 @@ #include <gpac/internal/laser_dev.h> #include <gpac/internal/scenegraph_dev.h> #include <gpac/bitstream.h> -#include <gpac/math.h> #ifndef GPAC_DISABLE_LASER @@ -187,7 +186,7 @@ GF_Err gf_laser_encoder_get_rap(GF_LASeRCodec *codec, char **out_data, u32 *out_ codec->res_factor = INT2FIX(1 << (-codec->info->cfg.resolution)); codec->bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); - e = lsr_write_laser_unit(codec, NULL, 0); + e = lsr_write_laser_unit(codec, NULL, GF_FALSE); if (e == GF_OK) gf_bs_get_content(codec->bs, out_data, out_data_length); gf_bs_del(codec->bs); codec->bs = NULL; @@ -400,14 +399,14 @@ static void lsr_write_byte_align_string_list(GF_LASeRCodec *lsr, GF_List *l, con static void lsr_write_any_uri(GF_LASeRCodec *lsr, XMLRI *iri, const char *name) { - Bool is_iri = 0; + Bool is_iri = GF_FALSE; if (iri->type==XMLRI_STRING) { - is_iri = 1; + is_iri = GF_TRUE; if (iri->string[0]=='#') { iri->target = (SVG_Element*)gf_sg_find_node_by_name(lsr->sg, iri->string+1); if (iri->target) { - is_iri = 0; + is_iri = GF_FALSE; iri->type = XMLRI_ELEMENTID; } } @@ -925,7 +924,7 @@ static void lsr_write_smil_times(GF_LASeRCodec *lsr, GF_List **l, const char *na { SMIL_Time *v; u32 r_count, i, count; - Bool indef = 0; + Bool indef = GF_FALSE; count = l ? gf_list_count(*l) : 0; @@ -933,7 +932,7 @@ static void lsr_write_smil_times(GF_LASeRCodec *lsr, GF_List **l, const char *na for (i=0; i<count; i++) { v = (SMIL_Time*)gf_list_get(*l, i); if (v->type==GF_SMIL_TIME_INDEFINITE) { - indef = 1; + indef = GF_TRUE; break; } else if (v->type!=GF_SMIL_TIME_EVENT_RESOLVED) r_count++; @@ -991,29 +990,29 @@ static Bool lsr_elt_has_same_base(GF_LASeRCodec *lsr, SVGAllAttributes *atts, SV SVGAllAttributes base_atts; GF_FieldInfo info, base_info; - if (same_stroke) *same_stroke = 0; - if (same_fill) *same_fill = 0; + if (same_stroke) *same_stroke = GF_FALSE; + if (same_fill) *same_fill = GF_FALSE; - if (!base) return 0; + if (!base) return GF_FALSE; gf_svg_flatten_attributes(base, &base_atts); - if (atts->externalResourcesRequired != base_atts.externalResourcesRequired) return 0; + if (atts->externalResourcesRequired != base_atts.externalResourcesRequired) return GF_FALSE; info.fieldType = base_info.fieldType = SVG_Paint_datatype; info.far_ptr = atts->stroke; base_info.far_ptr = base_atts.stroke; /*check stroke color*/ if (!gf_svg_attributes_equal(&info, &base_info)) { - if (!no_stroke_check) return 0; + if (!no_stroke_check) return GF_FALSE; } else { - if (same_stroke) *same_stroke = 1; + if (same_stroke) *same_stroke = GF_TRUE; } if (same_fill) { info.fieldType = base_info.fieldType = SVG_Paint_datatype; info.far_ptr = atts->fill; base_info.far_ptr = base_atts.fill; /*check stroke color*/ - *same_fill = gf_svg_attributes_equal(&info, &base_info) ? 1 : 0; + *same_fill = gf_svg_attributes_equal(&info, &base_info) ? GF_TRUE : GF_FALSE; } switch (gf_node_get_tag((GF_Node*) base)) { @@ -1022,43 +1021,43 @@ static Bool lsr_elt_has_same_base(GF_LASeRCodec *lsr, SVGAllAttributes *atts, SV info.fieldType = base_info.fieldType = SVG_Number_datatype; info.far_ptr = atts->pathLength; base_info.far_ptr = base_atts.pathLength; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; break; /*check rx and ry for rect*/ case TAG_SVG_rect: info.fieldType = base_info.fieldType = SVG_Length_datatype; info.far_ptr = atts->rx; base_info.far_ptr = base_atts.rx; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; info.fieldType = base_info.fieldType = SVG_Length_datatype; info.far_ptr = atts->ry; base_info.far_ptr = base_atts.ry; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; break; /*check x and y for use*/ case TAG_SVG_use: info.fieldType = base_info.fieldType = SVG_Coordinate_datatype; info.far_ptr = atts->x; base_info.far_ptr = base_atts.x; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; info.fieldType = base_info.fieldType = SVG_Coordinate_datatype; info.far_ptr = atts->y; base_info.far_ptr = base_atts.y; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; break; /*check editable and rotate for text*/ case TAG_SVG_text: info.fieldType = base_info.fieldType = SVG_Boolean_datatype; info.far_ptr = atts->editable; base_info.far_ptr = base_atts.editable; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; info.fieldType = base_info.fieldType = SVG_Numbers_datatype; info.far_ptr = atts->text_rotate; base_info.far_ptr = base_atts.text_rotate; - if (!gf_svg_attributes_equal(&info, &base_info)) return 0; + if (!gf_svg_attributes_equal(&info, &base_info)) return GF_FALSE; break; } @@ -1093,7 +1092,7 @@ static void lsr_write_rare(GF_LASeRCodec *lsr, GF_Node *n) } /*RARE extension*/ if (field_rare==49) { - Bool is_string = 0; + Bool is_string = GF_FALSE; u32 size, cur_bits; u32 len = 2+3; switch (att->tag) { @@ -1110,7 +1109,7 @@ static void lsr_write_rare(GF_LASeRCodec *lsr, GF_Node *n) len++; cur_bits++; } - is_string = 1; + is_string = GF_TRUE; break; default: len +=2; @@ -1256,10 +1255,10 @@ static void lsr_write_rare(GF_LASeRCodec *lsr, GF_Node *n) GF_LSR_WRITE_INT(lsr, *(SVG_PointerEvents*)att->data, 2, "visibility"); break; case TAG_SVG_ATT_requiredExtensions: - lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "requiredExtensions", 1); + lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "requiredExtensions", GF_TRUE); break; case TAG_SVG_ATT_requiredFormats: - lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "requiredFormats", 0); + lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "requiredFormats", GF_FALSE); break; case TAG_SVG_ATT_requiredFeatures: { @@ -1419,7 +1418,7 @@ static void lsr_write_rare(GF_LASeRCodec *lsr, GF_Node *n) break; case TAG_SVG_ATT_systemLanguage: - lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "systemLanguage", 0); + lsr_write_byte_align_string_list(lsr, *(GF_List **)att->data, "systemLanguage", GF_FALSE); break; case TAG_XML_ATT_base: lsr_write_byte_align_string(lsr, ((XMLRI*)att->data)->string, "xml:base"); @@ -1506,13 +1505,13 @@ static void lsr_write_rare(GF_LASeRCodec *lsr, GF_Node *n) GF_LSR_WRITE_INT(lsr, 0, 3, "xlink:show"); break; case TAG_SVG_ATT_end: - lsr_write_smil_times(lsr, (GF_List **)att->data, "end", 0); + lsr_write_smil_times(lsr, (GF_List **)att->data, "end", GF_FALSE); break; case TAG_SVG_ATT_min: - lsr_write_duration_ex(lsr, (SMIL_Duration*)att->data, "min", 0); + lsr_write_duration_ex(lsr, (SMIL_Duration*)att->data, "min", GF_FALSE); break; case TAG_SVG_ATT_max: - lsr_write_duration_ex(lsr, (SMIL_Duration*)att->data, "max", 0); + lsr_write_duration_ex(lsr, (SMIL_Duration*)att->data, "max", GF_FALSE); break; case TAG_SVG_ATT_transform: lsr_write_matrix(lsr, (SVG_Transform*)att->data); @@ -1544,16 +1543,16 @@ static void lsr_write_stroke(GF_LASeRCodec *lsr, SVG_Element *n, SVGAllAttribute } static void lsr_write_href(GF_LASeRCodec *lsr, XMLRI *iri) { - Bool has_href = iri ? 1 : 0; + Bool has_href = iri ? GF_TRUE : GF_FALSE; if (iri) { if (iri->type==XMLRI_ELEMENTID) { if (!iri->target && iri->string) iri->target = (SVG_Element *)gf_sg_find_node_by_name(lsr->sg, iri->string+1); - if (!iri->target || !gf_node_get_id((GF_Node *)iri->target)) has_href = 0; + if (!iri->target || !gf_node_get_id((GF_Node *)iri->target)) has_href = GF_FALSE; } else if (iri->type==XMLRI_STREAMID) { - if (!iri->lsr_stream_id) has_href = 0; + if (!iri->lsr_stream_id) has_href = GF_FALSE; } - else if (!iri->string) has_href = 0; + else if (!iri->string) has_href = GF_FALSE; } GF_LSR_WRITE_INT(lsr, has_href, 1, "has_href"); @@ -1894,11 +1893,11 @@ static void lsr_write_an_anim_value(GF_LASeRCodec *lsr, void *val, u32 lsr_type, break; case 9: // point if (svg_type==SVG_Motion_datatype) { - lsr_write_coordinate(lsr, ((GF_Matrix2D*)val)->m[2], 0, "valX"); - lsr_write_coordinate(lsr, ((GF_Matrix2D*)val)->m[5], 0, "valY"); + lsr_write_coordinate(lsr, ((GF_Matrix2D*)val)->m[2], GF_FALSE, "valX"); + lsr_write_coordinate(lsr, ((GF_Matrix2D*)val)->m[5], GF_FALSE, "valY"); } else { - lsr_write_coordinate(lsr, ((SVG_Point *)val)->x, 0, "valX"); - lsr_write_coordinate(lsr, ((SVG_Point *)val)->y, 0, "valY"); + lsr_write_coordinate(lsr, ((SVG_Point *)val)->x, GF_FALSE, "valX"); + lsr_write_coordinate(lsr, ((SVG_Point *)val)->y, GF_FALSE, "valY"); } break; default: @@ -2353,8 +2352,8 @@ static void lsr_write_a(GF_LASeRCodec *lsr, SVG_Element *elt) GF_LSR_WRITE_INT(lsr, (atts.target!=NULL) ? 1 : 0, 1, "hasTarget"); if (atts.target) lsr_write_byte_align_string(lsr, *(SVG_String*)atts.target, "target"); lsr_write_href(lsr, atts.xlink_href); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_animate(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *parent) @@ -2375,7 +2374,7 @@ static void lsr_write_animate(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element lsr_write_fraction_12(lsr, atts.keyTimes, "keyTimes"); lsr_write_anim_values(lsr, atts.values, "values"); lsr_write_attribute_type(lsr, &atts); - lsr_write_smil_times(lsr, atts.begin, "begin", 1); + lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE); lsr_write_duration(lsr, atts.dur, "dur"); lsr_write_anim_fill(lsr, atts.smil_fill); lsr_write_anim_repeat(lsr, atts.repeatCount); @@ -2385,8 +2384,8 @@ static void lsr_write_animate(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element lsr_write_href_anim(lsr, atts.xlink_href, parent); GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } @@ -2406,7 +2405,7 @@ static void lsr_write_animateMotion(GF_LASeRCodec *lsr, SVG_Element*elt, SVG_Ele lsr_write_fraction_12(lsr, atts.keyTimes, "keyTimes"); lsr_write_anim_values(lsr, atts.values, "values"); lsr_write_attribute_type(lsr, &atts); - lsr_write_smil_times(lsr, atts.begin, "begin", 1); + lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE); lsr_write_duration(lsr, atts.dur, "dur"); lsr_write_anim_fill(lsr, atts.smil_fill); lsr_write_anim_repeat(lsr, atts.repeatCount); @@ -2425,8 +2424,8 @@ static void lsr_write_animateMotion(GF_LASeRCodec *lsr, SVG_Element*elt, SVG_Ele lsr_write_href_anim(lsr, atts.xlink_href, parent); GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_animateTransform(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *parent) @@ -2469,7 +2468,7 @@ static void lsr_write_animateTransform(GF_LASeRCodec *lsr, SVG_Element *elt, SVG lsr_write_fraction_12(lsr, atts.keyTimes, "keyTimes"); lsr_write_anim_values(lsr, atts.values, "values"); lsr_write_attribute_type(lsr, &atts); - lsr_write_smil_times(lsr, atts.begin, "begin", 1); + lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE); lsr_write_duration(lsr, atts.dur, "dur"); lsr_write_anim_fill(lsr, atts.smil_fill); lsr_write_anim_repeat(lsr, atts.repeatCount); @@ -2479,8 +2478,8 @@ static void lsr_write_animateTransform(GF_LASeRCodec *lsr, SVG_Element *elt, SVG lsr_write_href_anim(lsr, atts.xlink_href, parent); GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_audio(GF_LASeRCodec *lsr, SVG_Element *elt) @@ -2490,7 +2489,7 @@ static void lsr_write_audio(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_id(lsr, (GF_Node *) elt); lsr_write_rare(lsr, (GF_Node *) elt); - lsr_write_smil_times(lsr, atts.begin, "begin", 1); + lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE); lsr_write_duration(lsr, atts.dur, "dur"); GF_LSR_WRITE_INT(lsr, atts.externalResourcesRequired ? *atts.externalResourcesRequired : 0, 1, "externalResourcesRequired"); lsr_write_anim_repeat(lsr, atts.repeatCount); @@ -2506,8 +2505,8 @@ static void lsr_write_audio(GF_LASeRCodec *lsr, SVG_Element *elt) GF_LSR_WRITE_INT(lsr, atts.syncReference ? 1 : 0, 1, "hasSyncReference"); if (atts.syncReference) lsr_write_any_uri(lsr, atts.syncReference, "syncReference"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_circle(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2518,11 +2517,11 @@ static void lsr_write_circle(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); - lsr_write_coordinate_ptr(lsr, atts.cx, 1, "cx"); - lsr_write_coordinate_ptr(lsr, atts.cy, 1, "cy"); - lsr_write_coordinate_ptr(lsr, atts.r, 0, "r"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_coordinate_ptr(lsr, atts.cx, GF_TRUE, "cx"); + lsr_write_coordinate_ptr(lsr, atts.cy, GF_TRUE, "cy"); + lsr_write_coordinate_ptr(lsr, atts.r, GF_FALSE, "r"); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_conditional(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2535,9 +2534,9 @@ static void lsr_write_conditional(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_smil_times(lsr, atts.begin, "begin", 1); GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); up = elt->children ? (GF_DOMUpdates*)elt->children->node : NULL; - lsr_write_command_list(lsr, up ? up->updates : NULL, elt, 0); + lsr_write_command_list(lsr, up ? up->updates : NULL, elt, GF_FALSE); lsr_write_private_attributes(lsr, elt); } @@ -2548,19 +2547,19 @@ static void lsr_write_cursorManager(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_id(lsr, (GF_Node *) elt); lsr_write_rare(lsr, (GF_Node *) elt); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "y"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "y"); lsr_write_href(lsr, atts.xlink_href); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_data(GF_LASeRCodec *lsr, SVG_Element *elt) { lsr_write_id(lsr, (GF_Node *) elt); lsr_write_rare(lsr, (GF_Node *) elt); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_defs(GF_LASeRCodec *lsr, SVG_Element *elt) @@ -2572,8 +2571,8 @@ static void lsr_write_defs(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_ellipse(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2584,12 +2583,12 @@ static void lsr_write_ellipse(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); - lsr_write_coordinate_ptr(lsr, atts.cx, 1, "cx"); - lsr_write_coordinate_ptr(lsr, atts.cy, 1, "cy"); - lsr_write_coordinate_ptr(lsr, atts.rx, 0, "rx"); - lsr_write_coordinate_ptr(lsr, atts.ry, 0, "ry"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_coordinate_ptr(lsr, atts.cx, GF_TRUE, "cx"); + lsr_write_coordinate_ptr(lsr, atts.cy, GF_TRUE, "cy"); + lsr_write_coordinate_ptr(lsr, atts.rx, GF_FALSE, "rx"); + lsr_write_coordinate_ptr(lsr, atts.ry, GF_FALSE, "ry"); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_foreignObject(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2601,12 +2600,12 @@ static void lsr_write_foreignObject(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired&&*atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); - lsr_write_coordinate_ptr(lsr, atts.height, 0, "height"); - lsr_write_coordinate_ptr(lsr, atts.width, 0, "width"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.y, 1, "y"); + lsr_write_coordinate_ptr(lsr, atts.height, GF_FALSE, "height"); + lsr_write_coordinate_ptr(lsr, atts.width, GF_FALSE, "width"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); /* TODO bit(1) opt_group; if(opt_group) { @@ -2622,20 +2621,20 @@ static void lsr_write_foreignObject(GF_LASeRCodec *lsr, SVG_Element *elt) static void lsr_write_g(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) { - Bool is_same = 0; + Bool is_same = GF_FALSE; Bool same_fill; SVGAllAttributes atts; gf_svg_flatten_attributes(elt, &atts); if (!ommit_tag - && lsr_elt_has_same_base(lsr, &atts, lsr->prev_g, &same_fill, NULL, 0) + && lsr_elt_has_same_base(lsr, &atts, lsr->prev_g, &same_fill, NULL, GF_FALSE) && same_fill ) { /*samegType*/ GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sameg, 6, "ch4"); lsr_write_id(lsr, (GF_Node *) elt); - is_same = 1; + is_same = GF_TRUE; } else { /*gType*/ if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_g, 6, "ch4"); @@ -2645,7 +2644,7 @@ static void lsr_write_g(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_g = elt; } lsr_write_group_content(lsr, elt, is_same); @@ -2658,7 +2657,7 @@ static void lsr_write_image(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_id(lsr, (GF_Node *) elt); lsr_write_rare(lsr, (GF_Node *) elt); GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); - lsr_write_coordinate_ptr(lsr, atts.height, 1, "height"); + lsr_write_coordinate_ptr(lsr, atts.height, GF_TRUE, "height"); if (atts.opacity && (atts.opacity->type == SVG_NUMBER_VALUE)) { GF_LSR_WRITE_INT(lsr, 1, 1, "opacity"); @@ -2669,28 +2668,28 @@ static void lsr_write_image(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_preserve_aspect_ratio(lsr, atts.preserveAspectRatio); lsr_write_content_type(lsr, atts.xlink_type, "type"); - lsr_write_coordinate_ptr(lsr, atts.width, 1, "width"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.y, 1, "y"); + lsr_write_coordinate_ptr(lsr, atts.width, GF_TRUE, "width"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y"); lsr_write_href(lsr, atts.xlink_href); lsr_write_transform_behavior(lsr, atts.transformBehavior); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_line(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) { Bool same_fill; - Bool is_same = 0; + Bool is_same = GF_FALSE; SVGAllAttributes atts; gf_svg_flatten_attributes(elt, &atts); - if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_line, &same_fill, NULL, 0) + if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_line, &same_fill, NULL, GF_FALSE) && same_fill ) { /*samelineType*/ GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sameline, 6, "ch4"); lsr_write_id(lsr, (GF_Node *) elt); - is_same = 1; + is_same = GF_TRUE; } else { /*lineType*/ if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_line, 6, "ch4"); @@ -2701,12 +2700,12 @@ static void lsr_write_line(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) lsr_write_stroke(lsr, elt, &atts); } - lsr_write_coordinate_ptr(lsr, atts.x1, 1, "x1"); - lsr_write_coordinate_ptr(lsr, atts.x2, 0, "x2"); - lsr_write_coordinate_ptr(lsr, atts.y1, 1, "y1"); - lsr_write_coordinate_ptr(lsr, atts.y2, 0, "y2"); + lsr_write_coordinate_ptr(lsr, atts.x1, GF_TRUE, "x1"); + lsr_write_coordinate_ptr(lsr, atts.x2, GF_FALSE, "x2"); + lsr_write_coordinate_ptr(lsr, atts.y1, GF_TRUE, "y1"); + lsr_write_coordinate_ptr(lsr, atts.y2, GF_FALSE, "y2"); if (!is_same) { - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_line = elt; } lsr_write_group_content(lsr, elt, is_same); @@ -2721,12 +2720,12 @@ static void lsr_write_linearGradient(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_fill(lsr, elt, &atts); lsr_write_stroke(lsr, elt, &atts); lsr_write_gradient_units(lsr, atts.gradientUnits); - lsr_write_coordinate_ptr(lsr, atts.x1, 1, "x1"); - lsr_write_coordinate_ptr(lsr, atts.x2, 1, "x2"); - lsr_write_coordinate_ptr(lsr, atts.y1, 1, "y1"); - lsr_write_coordinate_ptr(lsr, atts.y2, 1, "y2"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_coordinate_ptr(lsr, atts.x1, GF_TRUE, "x1"); + lsr_write_coordinate_ptr(lsr, atts.x2, GF_TRUE, "x2"); + lsr_write_coordinate_ptr(lsr, atts.y1, GF_TRUE, "y1"); + lsr_write_coordinate_ptr(lsr, atts.y2, GF_TRUE, "y2"); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_mpath(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2736,18 +2735,18 @@ static void lsr_write_mpath(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_id(lsr, (GF_Node *) elt); lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_href(lsr, atts.xlink_href); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_path(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) { Bool same_fill; - Bool is_same = 0; + Bool is_same = GF_FALSE; SVGAllAttributes atts; gf_svg_flatten_attributes(elt, &atts); - if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_path, &same_fill, NULL, 0) ) { - is_same = 1; + if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_path, &same_fill, NULL, GF_FALSE) ) { + is_same = GF_TRUE; if (!same_fill) { /*samepathfillType*/ GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_samepathfill, 6, "ch4"); @@ -2774,7 +2773,7 @@ static void lsr_write_path(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) } else { GF_LSR_WRITE_INT(lsr, 0, 1, "hasPathLength"); } - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_path = elt; } lsr_write_group_content(lsr, elt, is_same); @@ -2787,7 +2786,7 @@ static void lsr_write_polygon(GF_LASeRCodec *lsr, SVG_Element *elt, Bool is_poly SVGAllAttributes atts; gf_svg_flatten_attributes(elt, &atts); - if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_polygon, &same_fill, &same_stroke, 1) + if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_polygon, &same_fill, &same_stroke, GF_TRUE) ) { if (same_fill && same_stroke) same_type = 1; else if (same_fill) same_type = 3; @@ -2816,7 +2815,7 @@ static void lsr_write_polygon(GF_LASeRCodec *lsr, SVG_Element *elt, Bool is_poly lsr_write_fill(lsr, elt, &atts); lsr_write_stroke(lsr, elt, &atts); lsr_write_point_sequence(lsr, atts.points, "points"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_polygon = elt; } lsr_write_group_content(lsr, elt, same_type); @@ -2830,12 +2829,12 @@ static void lsr_write_radialGradient(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_fill(lsr, elt, &atts); lsr_write_stroke(lsr, elt, &atts); - lsr_write_coordinate_ptr(lsr, atts.cx, 1, "cx"); - lsr_write_coordinate_ptr(lsr, atts.cy, 1, "cy"); + lsr_write_coordinate_ptr(lsr, atts.cx, GF_TRUE, "cx"); + lsr_write_coordinate_ptr(lsr, atts.cy, GF_TRUE, "cy"); lsr_write_gradient_units(lsr, atts.gradientUnits); - lsr_write_coordinate_ptr(lsr, atts.r, 1, "r"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_coordinate_ptr(lsr, atts.r, GF_TRUE, "r"); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_rect(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) { @@ -2844,7 +2843,7 @@ static void lsr_write_rect(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) SVGAllAttributes atts; gf_svg_flatten_attributes(elt, &atts); - if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_rect, &same_fill, NULL, 0) + if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_rect, &same_fill, NULL, GF_FALSE) ) { if (!same_fill) { same_type = 2; @@ -2857,10 +2856,10 @@ static void lsr_write_rect(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) } lsr_write_id(lsr, (GF_Node *) elt); if (same_type==2) lsr_write_fill(lsr, elt, &atts); - lsr_write_coordinate_ptr(lsr, atts.height, 0, "height"); - lsr_write_coordinate_ptr(lsr, atts.width, 0, "width"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.y, 1, "y"); + lsr_write_coordinate_ptr(lsr, atts.height, GF_FALSE, "height"); + lsr_write_coordinate_ptr(lsr, atts.width, GF_FALSE, "width"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y"); } else { /*rectType*/ if (!ommit_tag) GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_rect, 6, "ch4"); @@ -2868,13 +2867,13 @@ static void lsr_write_rect(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_fill(lsr, elt, &atts); lsr_write_stroke(lsr, elt, &atts); - lsr_write_coordinate_ptr(lsr, atts.height, 0, "height"); - lsr_write_coordinate_ptr(lsr, atts.rx, 1, "rx"); - lsr_write_coordinate_ptr(lsr, atts.ry, 1, "ry"); - lsr_write_coordinate_ptr(lsr, atts.width, 0, "width"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.y, 1, "y"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_coordinate_ptr(lsr, atts.height, GF_FALSE, "height"); + lsr_write_coordinate_ptr(lsr, atts.rx, GF_TRUE, "rx"); + lsr_write_coordinate_ptr(lsr, atts.ry, GF_TRUE, "ry"); + lsr_write_coordinate_ptr(lsr, atts.width, GF_FALSE, "width"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y"); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_rect = elt; } lsr_write_group_content(lsr, elt, same_type); @@ -2892,13 +2891,13 @@ static void lsr_write_rectClip(GF_LASeRCodec *lsr, SVG_Element *elt) GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); if (atts.size) { GF_LSR_WRITE_INT(lsr, 1, 1, "size"); - lsr_write_coordinate(lsr, atts.size->width, 0, "width"); - lsr_write_coordinate(lsr, atts.size->height, 0, "height"); + lsr_write_coordinate(lsr, atts.size->width, GF_FALSE, "width"); + lsr_write_coordinate(lsr, atts.size->height, GF_FALSE, "height"); } else { GF_LSR_WRITE_INT(lsr, 0, 1, "size"); } - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_script(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2910,8 +2909,8 @@ static void lsr_write_script(GF_LASeRCodec *lsr, SVG_Element *elt) GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); lsr_write_script_type(lsr, atts.xlink_type); lsr_write_href(lsr, atts.xlink_href); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_selector(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -2934,8 +2933,8 @@ static void lsr_write_selector(GF_LASeRCodec *lsr, SVG_Element *elt) GF_LSR_WRITE_INT(lsr, atts.choice->type, 1, "type"); } } - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_set(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *parent) @@ -2947,7 +2946,7 @@ static void lsr_write_set(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *par lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_animatable(lsr, atts.attributeName, atts.xlink_href, "attributeName"); lsr_write_attribute_type(lsr, &atts); - lsr_write_smil_times(lsr, atts.begin, "begin", 1); + lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE); lsr_write_duration(lsr, atts.dur, "dur"); lsr_write_anim_fill(lsr, atts.smil_fill); lsr_write_anim_repeat(lsr, atts.repeatCount); @@ -2956,8 +2955,8 @@ static void lsr_write_set(GF_LASeRCodec *lsr, SVG_Element *elt, SVG_Element *par lsr_write_anim_value(lsr, atts.to, "to"); lsr_write_href_anim(lsr, atts.xlink_href, parent); GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_simpleLayout(GF_LASeRCodec *lsr, SVG_Element *elt) @@ -2971,15 +2970,15 @@ static void lsr_write_simpleLayout(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); if (atts.delta) { GF_LSR_WRITE_INT(lsr, 1, 1, "delta"); - lsr_write_coordinate(lsr, atts.delta->width, 0, "width"); - lsr_write_coordinate(lsr, atts.delta->height, 0, "height"); + lsr_write_coordinate(lsr, atts.delta->width, GF_FALSE, "width"); + lsr_write_coordinate(lsr, atts.delta->height, GF_FALSE, "height"); } else { GF_LSR_WRITE_INT(lsr, 0, 1, "delta"); } GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_stop(GF_LASeRCodec *lsr, SVG_Element *elt) @@ -2992,8 +2991,8 @@ static void lsr_write_stop(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_fill(lsr, elt, &atts); lsr_write_stroke(lsr, elt, &atts); lsr_write_fixed_16_8(lsr, atts.offset ? atts.offset->value : 0, "offset"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_svg(GF_LASeRCodec *lsr, SVG_Element *elt) { @@ -3062,8 +3061,8 @@ static void lsr_write_svg(GF_LASeRCodec *lsr, SVG_Element *elt) if (atts.zoomAndPan) { GF_LSR_WRITE_INT(lsr, (*atts.zoomAndPan==SVG_ZOOMANDPAN_MAGNIFY) ? 1 : 0, 1, "zoomAndPan"); } - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_switch(GF_LASeRCodec *lsr, SVG_Element *elt) @@ -3076,7 +3075,7 @@ static void lsr_write_switch(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr_write_group_content(lsr, elt, 0); } @@ -3113,7 +3112,7 @@ static void lsr_write_text(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) lsr_write_float_list(lsr, atts.text_rotate, "rotate"); lsr_write_coord_list(lsr, atts.text_x, "x"); lsr_write_coord_list(lsr, atts.text_y, "y"); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_text = elt; } lsr_write_group_content(lsr, elt, same_type); @@ -3128,20 +3127,20 @@ static void lsr_write_tspan(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_rare(lsr, (GF_Node *) elt); lsr_write_fill(lsr, (SVG_Element*)elt, &atts); lsr_write_stroke(lsr, (SVG_Element*)elt, &atts); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_use(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) { SVGAllAttributes atts; - Bool is_same = 0; + Bool is_same = GF_FALSE; gf_svg_flatten_attributes(elt, &atts); - if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_use, NULL, NULL, 0) + if (!ommit_tag && lsr_elt_has_same_base(lsr, &atts, lsr->prev_use, NULL, NULL, GF_FALSE) /*TODO check overflow*/ ) { - is_same = 1; + is_same = GF_TRUE; /*sameuseType*/ GF_LSR_WRITE_INT(lsr, LSR_SCENE_CONTENT_MODEL_sameuse, 6, "ch4"); lsr_write_id(lsr, (GF_Node *) elt); @@ -3159,10 +3158,10 @@ static void lsr_write_use(GF_LASeRCodec *lsr, SVG_Element *elt, Bool ommit_tag) /*one value only??*/ if (atts.overflow) GF_LSR_WRITE_INT(lsr, 0, 2, "overflow"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.y, 1, "y"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y"); lsr_write_href(lsr, atts.xlink_href); - lsr_write_any_attribute(lsr, elt, 1); + lsr_write_any_attribute(lsr, elt, GF_TRUE); lsr->prev_use = elt; } lsr_write_group_content(lsr, elt, is_same); @@ -3182,10 +3181,10 @@ static void lsr_write_video(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_id(lsr, (GF_Node *) elt); lsr_write_rare(lsr, (GF_Node *) elt); - lsr_write_smil_times(lsr, atts.begin, "begin", 1); + lsr_write_smil_times(lsr, atts.begin, "begin", GF_TRUE); lsr_write_duration(lsr, atts.dur, "dur"); GF_LSR_WRITE_INT(lsr, (atts.externalResourcesRequired && *atts.externalResourcesRequired) ? 1 : 0, 1, "externalResourcesRequired"); - lsr_write_coordinate_ptr(lsr, atts.height, 1, "height"); + lsr_write_coordinate_ptr(lsr, atts.height, GF_TRUE, "height"); GF_LSR_WRITE_INT(lsr, atts.overlay ? 1 : 0, 1, "hasOverlay"); if (atts.overlay) { @@ -3201,9 +3200,9 @@ static void lsr_write_video(GF_LASeRCodec *lsr, SVG_Element *elt) lsr_write_sync_tolerance(lsr, atts.syncTolerance, "syncBehavior"); lsr_write_transform_behavior(lsr, atts.transformBehavior); lsr_write_content_type(lsr, atts.xlink_type, "type"); - lsr_write_coordinate_ptr(lsr, atts.width, 1, "width"); - lsr_write_coordinate_ptr(lsr, atts.x, 1, "x"); - lsr_write_coordinate_ptr(lsr, atts.y, 1, "y"); + lsr_write_coordinate_ptr(lsr, atts.width, GF_TRUE, "width"); + lsr_write_coordinate_ptr(lsr, atts.x, GF_TRUE, "x"); + lsr_write_coordinate_ptr(lsr, atts.y, GF_TRUE, "y"); lsr_write_href(lsr, atts.xlink_href); lsr_write_clip_time(lsr, atts.clipBegin, "clipBegin"); @@ -3215,8 +3214,8 @@ static void lsr_write_video(GF_LASeRCodec *lsr, SVG_Element *elt) GF_LSR_WRITE_INT(lsr, atts.syncReference ? 1 : 0, 1, "hasSyncReference"); if (atts.syncReference) lsr_write_any_uri(lsr, atts.syncReference, "syncReference"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_listener(GF_LASeRCodec *lsr, SVG_Element *elt) @@ -3265,8 +3264,8 @@ static void lsr_write_listener(GF_LASeRCodec *lsr, SVG_Element *elt) } GF_LSR_WRITE_INT(lsr, (atts.lsr_enabled && *atts.lsr_enabled) ? 1 : 0, 1, "enabled"); - lsr_write_any_attribute(lsr, elt, 1); - lsr_write_group_content(lsr, elt, 0); + lsr_write_any_attribute(lsr, elt, GF_TRUE); + lsr_write_group_content(lsr, elt, GF_FALSE); } static void lsr_write_scene_content_model(GF_LASeRCodec *lsr, SVG_Element *parent, void *node) @@ -3647,32 +3646,32 @@ static void lsr_write_update_value(GF_LASeRCodec *lsr, SVG_Element *elt, u32 fie switch (fieldType) { case SVG_Points_datatype:/*points*/ { - GF_Point2D *pt = gf_list_get(*(GF_List **)val, 0); - lsr_write_coordinate(lsr, pt->x, 0, "x"); - lsr_write_coordinate(lsr, pt->y, 0, "y"); + GF_Point2D *pt = (GF_Point2D*)gf_list_get(*(GF_List **)val, 0); + lsr_write_coordinate(lsr, pt->x, GF_FALSE, "x"); + lsr_write_coordinate(lsr, pt->y, GF_FALSE, "y"); } break; case SMIL_Times_datatype:/*smil_times*/ { - SMIL_Time *st = gf_list_get(*(GF_List **)val, 0); + SMIL_Time *st = (SMIL_Time*)gf_list_get(*(GF_List **)val, 0); lsr_write_smil_time(lsr, st); } break; case SMIL_KeyPoints_datatype:/*0to1*/ { - Fixed *f = gf_list_get(*(GF_List **)val, 0); + Fixed *f = (Fixed*)gf_list_get(*(GF_List **)val, 0); lsr_write_fixed_clamp(lsr, *f, "v"); } break; case SMIL_KeySplines_datatype:/*float*/ { - Fixed *f = gf_list_get(*(GF_List **)val, 0); + Fixed *f = (Fixed*)gf_list_get(*(GF_List **)val, 0); lsr_write_fixed_16_8(lsr, *f, "v"); } break; case SMIL_KeyTimes_datatype:/*keyTime*/ { - Fixed *v = gf_list_get(*(GF_List **)val, 0); + Fixed *v = (Fixed*)gf_list_get(*(GF_List **)val, 0); Fixed f = *v; if ((f==0) || (f==FIX_ONE)) { GF_LSR_WRITE_INT(lsr, 1, 1, "hasShort"); @@ -3709,8 +3708,8 @@ static void lsr_write_update_value(GF_LASeRCodec *lsr, SVG_Element *elt, u32 fie break; case LASeR_Size_datatype: case SVG_Transform_Translate_datatype: - lsr_write_coordinate(lsr, ((SVG_Point *)val)->x, 0, "translation_x"); - lsr_write_coordinate(lsr, ((SVG_Point *)val)->y, 0, "translation_y"); + lsr_write_coordinate(lsr, ((SVG_Point *)val)->x, GF_FALSE, "translation_x"); + lsr_write_coordinate(lsr, ((SVG_Point *)val)->y, GF_FALSE, "translation_y"); break; case SVG_Transform_Rotate_datatype: GF_LSR_WRITE_INT(lsr, 0, 1, "isDefaultValue"); @@ -3743,7 +3742,7 @@ static void lsr_write_update_value(GF_LASeRCodec *lsr, SVG_Element *elt, u32 fie if (elt->sgprivate->tag==TAG_SVG_svg) { lsr_write_value_with_units(lsr, n, "val"); } else { - lsr_write_coordinate(lsr, n->value, 0, "val"); + lsr_write_coordinate(lsr, n->value, GF_FALSE, "val"); } break; default: @@ -3773,7 +3772,7 @@ static void lsr_write_update_value(GF_LASeRCodec *lsr, SVG_Element *elt, u32 fie break; case SVG_Coordinate_datatype: n = (SVG_Number*)val; - lsr_write_coordinate(lsr, n->value, 0, "val"); + lsr_write_coordinate(lsr, n->value, GF_FALSE, "val"); break; case SVG_Coordinates_datatype: GF_LSR_WRITE_INT(lsr, 0, 1, "isInherit"); @@ -3811,8 +3810,8 @@ static void lsr_write_update_value(GF_LASeRCodec *lsr, SVG_Element *elt, u32 fie lsr_write_byte_align_string(lsr, val ? *(DOM_String *)val : (char *)"", "val"); break; case SVG_Motion_datatype: - lsr_write_coordinate(lsr, ((GF_Matrix2D *)val)->m[2], 0, "pointValueX"); - lsr_write_coordinate(lsr, ((GF_Matrix2D *)val)->m[5], 0, "pointValueY"); + lsr_write_coordinate(lsr, ((GF_Matrix2D *)val)->m[2], GF_FALSE, "pointValueX"); + lsr_write_coordinate(lsr, ((GF_Matrix2D *)val)->m[5], GF_FALSE, "pointValueY"); break; case SVG_Points_datatype: lsr_write_point_sequence(lsr, (GF_List **)val, "val"); @@ -3882,7 +3881,7 @@ static GF_Err lsr_write_add_replace_insert(GF_LASeRCodec *lsr, GF_Command *com) { GF_CommandField *field; u8 type = 0; - Bool is_text_node = 0; + Bool is_text_node = GF_FALSE; u32 field_type, tr_type = 0; if (com->tag==GF_SG_LSR_REPLACE) type = LSR_UPDATE_REPLACE; else if (com->tag==GF_SG_LSR_ADD) type = LSR_UPDATE_ADD; @@ -3909,7 +3908,7 @@ static GF_Err lsr_write_add_replace_insert(GF_LASeRCodec *lsr, GF_Command *com) GF_LSR_WRITE_INT(lsr, 1, 1, "has_attributeName"); GF_LSR_WRITE_INT(lsr, 0, 1, "choice"); GF_LSR_WRITE_INT(lsr, LSR_UPDATE_TYPE_TEXT_CONTENT, 8, "attributeName"); - is_text_node = 1; + is_text_node = GF_TRUE; } else { GF_LSR_WRITE_INT(lsr, 0, 1, "has_attributeName"); } @@ -3938,15 +3937,15 @@ static GF_Err lsr_write_add_replace_insert(GF_LASeRCodec *lsr, GF_Command *com) lsr_write_codec_IDREF_Node(lsr, com->node, "ref"); if (field && !field->new_node && !field->node_list && !com->fromNodeID) { GF_LSR_WRITE_INT(lsr, 1, 1, "has_value"); - lsr_write_update_value(lsr, (SVG_Element *)com->node, field_type, field->fieldIndex, tr_type, field->field_ptr, (field->pos>=0) ? 1 : 0); + lsr_write_update_value(lsr, (SVG_Element *)com->node, field_type, field->fieldIndex, tr_type, field->field_ptr, (field->pos>=0) ? GF_TRUE : GF_FALSE); } else if (is_text_node) { GF_DOMText *t = (GF_DOMText *)field->new_node; GF_LSR_WRITE_INT(lsr, 1, 1, "has_value"); - lsr_write_update_value(lsr, (SVG_Element *)com->node, DOM_String_datatype, field->fieldIndex, 0, &t->textContent, (field->pos>=0) ? 1 : 0); + lsr_write_update_value(lsr, (SVG_Element *)com->node, DOM_String_datatype, field->fieldIndex, 0, &t->textContent, (field->pos>=0) ? GF_TRUE : GF_FALSE); } else { GF_LSR_WRITE_INT(lsr, 0, 1, "has_value"); } - lsr_write_any_attribute(lsr, NULL, 1); + lsr_write_any_attribute(lsr, NULL, GF_TRUE); /*if not add*/ if (type!=LSR_UPDATE_ADD) { if (field && field->node_list && !com->fromNodeID) { diff --git a/src/mcrypt/g_crypt.c b/src/mcrypt/g_crypt.c index e9b4734..4ae7c06 100644 --- a/src/mcrypt/g_crypt.c +++ b/src/mcrypt/g_crypt.c @@ -261,16 +261,12 @@ GF_Err gf_crypt_init(GF_Crypt *td, void *key, u32 lenofkey, const void *IV) if (ok == 0) { /* not supported key size */ key_size = gf_crypt_get_key_size(td); - if (sizes != NULL) { - for (i = 0; i < num_of_sizes; i++) { - if (lenofkey <= sizes[i]) { - key_size = sizes[i]; - break; - } - } - } else { /* well every key size is supported! */ - key_size = lenofkey; - } + for (i = 0; i < num_of_sizes; i++) { + if (lenofkey <= sizes[i]) { + key_size = sizes[i]; + break; + } + } } else { key_size = lenofkey; } diff --git a/src/media_tools/av_parsers.c b/src/media_tools/av_parsers.c index 0bd2534..d8a2535 100644 --- a/src/media_tools/av_parsers.c +++ b/src/media_tools/av_parsers.c @@ -29,14 +29,14 @@ #ifndef GPAC_DISABLE_OGG #include <gpac/internal/ogg.h> -#include <gpac/math.h> +#include <gpac/maths.h> #endif static const struct { u32 w, h; } std_par[ ] = { - { 4, 3}, {3, 2}, {16, 9}, {5, 3}, {5, 4}, {8, 5}, + { 4, 3}, {3, 2}, {16, 9}, {5, 3}, {5, 4}, {8, 5}, {2, 1}, {0, 0}, }; @@ -88,8 +88,6 @@ const char *gf_m4v_get_profile_name(u8 video_pl) return "Simple Scalable Profile @ Level 1"; case 0x12: return "Simple Scalable Profile @ Level 2"; - case 0x15: - return "AVC/H264 Profile"; case 0x21: return "Core Profile @ Level 1"; case 0x22: @@ -116,6 +114,8 @@ const char *gf_m4v_get_profile_name(u8 video_pl) return "Basic Animated Texture Profile @ Level 1"; case 0x72: return "Basic Animated Texture Profile @ Level 2"; + case 0x7F: + return "AVC/H264 Profile"; case 0x81: return "Hybrid Profile @ Level 1"; case 0x82: @@ -1108,16 +1108,21 @@ GF_Err gf_m4a_parse_config(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg, Bool size_k } else { cfg->base_sr = GF_M4ASampleRates[cfg->base_sr_index]; } - cfg->nb_chan = gf_bs_read_int(bs, 4); - /*this is 7+1 channels*/ - if (cfg->nb_chan==7) cfg->nb_chan=8; + { + u32 nb_chan = gf_bs_read_int(bs, 4); + if (nb_chan == 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[M4A config] invalid value 0, setting default 2 instead.\n")); + nb_chan = 2; + } + cfg->nb_chan = GF_M4ANumChannels[nb_chan-1]; + } if (cfg->base_object_type==5 || cfg->base_object_type==29) { if (cfg->base_object_type==29) { cfg->has_ps = 1; cfg->nb_chan = 1; } - cfg->has_sbr = 1; + cfg->has_sbr = GF_TRUE; cfg->sbr_sr_index = gf_bs_read_int(bs, 4); if (cfg->sbr_sr_index == 0x0F) { cfg->sbr_sr = gf_bs_read_int(bs, 24); @@ -1248,6 +1253,16 @@ u32 gf_latm_get_value(GF_BitStream *bs) return value; } +GF_EXPORT +u32 gf_m4a_get_channel_cfg(u32 nb_chan) +{ + u32 i, count = sizeof(GF_M4ANumChannels)/sizeof(u32); + for (i=0; i<count; i++) { + if (GF_M4ANumChannels[i] == nb_chan) return i+1; + } + return 0; +} + GF_EXPORT GF_Err gf_m4a_write_config_bs(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg) { @@ -1280,7 +1295,7 @@ GF_Err gf_m4a_write_config_bs(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg) if (cfg->nb_chan == 8) { gf_bs_write_int(bs, 7, 4); } else { - gf_bs_write_int(bs, cfg->nb_chan, 4); + gf_bs_write_int(bs, gf_m4a_get_channel_cfg( cfg->nb_chan) , 4); } if (cfg->base_object_type==5 || cfg->base_object_type==29) { @@ -1753,8 +1768,8 @@ u32 gf_media_nalu_is_start_code(GF_BitStream *bs) /*read that amount of data at each IO access rather than fetching byte by byte...*/ #define AVC_CACHE_SIZE 4096 -GF_EXPORT -u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs) + +static u32 gf_media_nalu_locate_start_code_bs(GF_BitStream *bs, Bool locate_trailing) { u32 v, bpos; char avc_cache[AVC_CACHE_SIZE]; @@ -1779,6 +1794,10 @@ u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs) } v = ( (v<<8) & 0xFFFFFF00) | ((u32) avc_cache[bpos]); bpos++; + if (locate_trailing) { + if ( (v & 0x00FFFFFF) == 0x00000000) end = cache_start+bpos-3; + } + if (v == 0x00000001) end = cache_start+bpos-4; else if ( (v & 0x00FFFFFF) == 0x00000001) end = cache_start+bpos-3; } @@ -1788,7 +1807,19 @@ u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs) } GF_EXPORT -u32 gf_media_nalu_next_start_code(u8 *data, u32 data_len, u32 *sc_size) +u32 gf_media_nalu_next_start_code_bs(GF_BitStream *bs) +{ + return gf_media_nalu_locate_start_code_bs(bs, 0); +} + +GF_EXPORT +u32 gf_media_nalu_payload_end_bs(GF_BitStream *bs) +{ + return gf_media_nalu_locate_start_code_bs(bs, 1); +} + +GF_EXPORT +u32 gf_media_nalu_next_start_code(const u8 *data, u32 data_len, u32 *sc_size) { u32 v, bpos; u32 end; @@ -1897,6 +1928,8 @@ static u32 avc_emulation_bytes_add_count(char *buffer, u32 nal_size) /*emulation code found*/ num_zero = 0; emulation_bytes_count++; + if (!buffer[i]) + num_zero = 1; } else { if (!buffer[i]) num_zero++; @@ -3139,9 +3172,9 @@ Bool gf_media_hevc_slice_is_intra(HEVCState *hevc) case GF_HEVC_NALU_SLICE_IDR_W_DLP: case GF_HEVC_NALU_SLICE_IDR_N_LP: case GF_HEVC_NALU_SLICE_CRA: - return 1; + return GF_TRUE; default: - return 0; + return GF_FALSE; } } @@ -3150,14 +3183,14 @@ Bool gf_media_hevc_slice_is_IDR(HEVCState *hevc) if (hevc->sei.recovery_point.valid) { hevc->sei.recovery_point.valid = 0; - return 1; + return GF_TRUE; } switch (hevc->s_info.nal_unit_type) { case GF_HEVC_NALU_SLICE_IDR_W_DLP: case GF_HEVC_NALU_SLICE_IDR_N_LP: - return 1; + return GF_TRUE; default: - return 0; + return GF_FALSE; } } @@ -3242,28 +3275,29 @@ s32 hevc_parse_slice_segment(GF_BitStream *bs, HEVCState *hevc, HEVCSliceInfo *s HEVC_PPS *pps; HEVC_SPS *sps; s32 pps_id; - Bool RapPicFlag = 0; - Bool IDRPicFlag = 0; + Bool RapPicFlag = GF_FALSE; + Bool IDRPicFlag = GF_FALSE; si->first_slice_segment_in_pic_flag = gf_bs_read_int(bs, 1); switch (si->nal_unit_type) { case GF_HEVC_NALU_SLICE_IDR_W_DLP: case GF_HEVC_NALU_SLICE_IDR_N_LP: - IDRPicFlag = 1; - RapPicFlag = 1; + IDRPicFlag = GF_TRUE; + RapPicFlag = GF_TRUE; break; case GF_HEVC_NALU_SLICE_BLA_W_LP: case GF_HEVC_NALU_SLICE_BLA_W_DLP: case GF_HEVC_NALU_SLICE_BLA_N_LP: case GF_HEVC_NALU_SLICE_CRA: - RapPicFlag = 1; + RapPicFlag = GF_TRUE; break; } if (RapPicFlag) { /*Bool no_output_of_prior_pics_flag = */gf_bs_read_int(bs, 1); } + pps_id = bs_get_ue(bs); if (pps_id>=64) return -1; @@ -3275,7 +3309,7 @@ s32 hevc_parse_slice_segment(GF_BitStream *bs, HEVCState *hevc, HEVCSliceInfo *s if (!si->first_slice_segment_in_pic_flag && pps->dependent_slice_segments_enabled_flag) { si->dependent_slice_segment_flag = gf_bs_read_int(bs, 1); } else { - si->dependent_slice_segment_flag = 0; + si->dependent_slice_segment_flag = GF_FALSE; } if (!si->first_slice_segment_in_pic_flag) { @@ -3665,8 +3699,9 @@ static void hevc_parse_vps_extension(HEVC_VPS *vps, GF_BitStream *bs) vps->profile_level_tier_idx[0] = 0; for (i=1; i<NumOutputLayerSets; i++) { u32 nb_bits; + //don't warn untiol we fix the entire syntax to last version of the spec if( i > vps->num_layer_sets - 1) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[HEVC] VPS Extensions: not supported number of layers\n")); +// GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[HEVC] VPS Extensions: not supported number of layers\n")); } nb_bits = 1; while ((u32) (1 << nb_bits) < num_profile_tier_level) { @@ -3886,7 +3921,7 @@ static s32 gf_media_hevc_read_sps_ex(char *data, u32 size, HEVCState *hevc, u32 } else { SubWidthC = SubHeightC = 1; } - + sps->cw_left = bs_get_ue(bs); sps->cw_right = bs_get_ue(bs); sps->cw_top = bs_get_ue(bs); @@ -4433,11 +4468,12 @@ static Bool AC3_FindSyncCodeBS(GF_BitStream *bs) u8 b2 = gf_bs_read_u8(bs); if ((b1 == 0x0b) && (b2==0x77)) { gf_bs_seek(bs, pos-1); - return 1; + return GF_TRUE; } pos++; + b1 = b2; } - return 0; + return GF_FALSE; } static const u32 ac3_sizecod_to_bitrate[] = { @@ -4480,77 +4516,39 @@ u32 gf_ac3_get_bitrate(u32 brcode) Bool gf_ac3_parser(u8 *buf, u32 buflen, u32 *pos, GF_AC3Header *hdr, Bool full_parse) { - u32 fscod, frmsizecod, bsid, ac3_mod, freq, framesize; - if (buflen < 6) return 0; - (*pos) = AC3_FindSyncCode(buf, buflen); - if (*pos >= buflen) return 0; - - buf += (*pos); - fscod = (buf[4] >> 6) & 0x3; - frmsizecod = (buf[4] & 0x3f); - bsid = (buf[5] >> 3) & 0x1f; - ac3_mod = (buf[6] >> 5) & 0x7; - if (bsid >= 12) return 0; + GF_BitStream *bs; + Bool ret; - if (full_parse && hdr) memset(hdr, 0, sizeof(GF_AC3Header)); + if (buflen < 6) return GF_FALSE; + (*pos) = AC3_FindSyncCode(buf, buflen); + if (*pos >= buflen) return GF_FALSE; - if (hdr) { - hdr->bitrate = ac3_sizecod_to_bitrate[frmsizecod / 2]; - if (bsid > 8) hdr->bitrate = hdr->bitrate >> (bsid - 8); - } - switch (fscod) { - case 0: - freq = 48000; - framesize = ac3_sizecod0_to_framesize[frmsizecod / 2] * 2; - break; - case 1: - freq = 44100; - framesize = (ac3_sizecod1_to_framesize[frmsizecod / 2] + (frmsizecod & 0x1)) * 2; - break; - case 2: - freq = 32000; - framesize = ac3_sizecod2_to_framesize[frmsizecod / 2] * 2; - break; - default: - return 0; - } - if (hdr) { - u16 maskbit, b67; - hdr->sample_rate = freq; - hdr->framesize = framesize; + bs = gf_bs_new((const char*)(buf+*pos), buflen, GF_BITSTREAM_READ); + ret = gf_ac3_parser_bs(bs, hdr, full_parse); + gf_bs_del(bs); - hdr->channels = ac3_mod_to_chans[ac3_mod]; - maskbit = 0x100; - if ((ac3_mod & 0x1) && (ac3_mod != 1)) maskbit >>= 2; - if (ac3_mod & 0x4) maskbit >>= 2; - if (ac3_mod == 0x2) maskbit += 2; - b67 = (buf[6] << 8) | buf[7]; - if ((b67 & maskbit) != 0) hdr->channels += 1; - } - return 1; + return ret; } - GF_EXPORT Bool gf_ac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse) { - u32 fscod, frmsizecod, bsid, ac3_mod, freq, framesize, bsmod; + u32 fscod, frmsizecod, bsid, ac3_mod, freq, framesize, bsmod, syncword; u64 pos; - if (!hdr || (gf_bs_available(bs) < 6)) return 0; - if (!AC3_FindSyncCodeBS(bs)) return 0; + if (!hdr || (gf_bs_available(bs) < 6)) return GF_FALSE; + if (!AC3_FindSyncCodeBS(bs)) return GF_FALSE; pos = gf_bs_get_position(bs); - gf_bs_read_u32(bs); + + syncword = gf_bs_read_u16(bs); + assert (syncword == 0x0B77); + gf_bs_read_u16(bs); //crc1 fscod = gf_bs_read_int(bs, 2); frmsizecod = gf_bs_read_int(bs, 6); bsid = gf_bs_read_int(bs, 5); bsmod = gf_bs_read_int(bs, 3); ac3_mod = gf_bs_read_int(bs, 3); - if (bsid >= 12) return 0; - - //memset(hdr, 0, sizeof(GF_AC3Header)); - hdr->bitrate = ac3_sizecod_to_bitrate[frmsizecod / 2]; if (bsid > 8) hdr->bitrate = hdr->bitrate >> (bsid - 8); @@ -4568,7 +4566,7 @@ Bool gf_ac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse) framesize = ac3_sizecod2_to_framesize[frmsizecod / 2] * 2; break; default: - return 0; + return GF_FALSE; } hdr->sample_rate = freq; hdr->framesize = framesize; @@ -4592,9 +4590,116 @@ Bool gf_ac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse) hdr->lfon = 1; } + gf_bs_seek(bs, pos); + + return GF_TRUE; +} + +GF_EXPORT +Bool gf_eac3_parser_bs(GF_BitStream *bs, GF_AC3Header *hdr, Bool full_parse) +{ + u32 fscod, bsid, ac3_mod, freq, framesize, syncword, substreamid, lfon, channels, numblkscod; + u64 pos; + +restart: + if (!hdr || (gf_bs_available(bs) < 6)) + return GF_FALSE; + if (!AC3_FindSyncCodeBS(bs)) + return GF_FALSE; + + pos = gf_bs_get_position(bs); + framesize = 0; + numblkscod = 0; + +block: + syncword = gf_bs_read_u16(bs); + assert(syncword == 0x0B77); + gf_bs_read_int(bs, 2); //strmtyp + substreamid = gf_bs_read_int(bs, 3); + framesize += gf_bs_read_int(bs, 11); + fscod = gf_bs_read_int(bs, 2); + if (fscod == 0x3) { + fscod = gf_bs_read_int(bs, 2); + numblkscod += 6; + } else { + numblkscod += gf_bs_read_int(bs, 2); + } + assert(numblkscod <= 9); + + if ((hdr->substreams >> substreamid) & 0x1) { + if (!substreamid) { + hdr->framesize = framesize; + + if (numblkscod < 6) { //we need 6 blocks to make a sample + gf_bs_seek(bs, pos+2*framesize); + if ((gf_bs_available(bs) < 6) || !AC3_FindSyncCodeBS(bs)) + return GF_FALSE; + goto block; + } + + gf_bs_seek(bs, pos); + return GF_TRUE; + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_CODING, ("[E-AC3] Detected sample in substream id=%u. Skipping.\n", substreamid)); + gf_bs_seek(bs, pos+framesize); + goto restart; + } + } + hdr->substreams |= (1 << substreamid); + + switch (fscod) { + case 0: + freq = 48000; + break; + case 1: + freq = 44100; + break; + case 2: + freq = 32000; + break; + default: + return GF_FALSE; + } + + ac3_mod = gf_bs_read_int(bs, 3); + lfon = gf_bs_read_int(bs, 1); + bsid = gf_bs_read_int(bs, 5); + if (!substreamid && (bsid!=16/*E-AC3*/)) + return GF_FALSE; + + channels = ac3_mod_to_chans[ac3_mod]; + if (lfon) + channels += 1; + + if (substreamid) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[E-AC3] Detected additional %u channels in substream id=%u - may not be handled correctly. Skipping.\n", channels, substreamid)); + gf_bs_seek(bs, pos+framesize); + goto restart; + } else { + hdr->bitrate = 0; + hdr->sample_rate = freq; + hdr->framesize = framesize; + hdr->lfon = lfon; + hdr->channels = channels; + if (full_parse) { + hdr->bsid = bsid; + hdr->bsmod = 0; + hdr->acmod = ac3_mod; + hdr->fscod = fscod; + hdr->brcode = 0; + } + } + + if (numblkscod < 6) { //we need 6 blocks to make a sample + gf_bs_seek(bs, pos+2*framesize); + if ((gf_bs_available(bs) < 6) || !AC3_FindSyncCodeBS(bs)) + return GF_FALSE; + goto block; + } gf_bs_seek(bs, pos); - return 1; + + return GF_TRUE; } #endif /*GPAC_DISABLE_AV_PARSERS*/ diff --git a/src/media_tools/avilib.c b/src/media_tools/avilib.c index 94cfce3..63abf4b 100644 --- a/src/media_tools/avilib.c +++ b/src/media_tools/avilib.c @@ -197,7 +197,7 @@ static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, u3 avi_write(AVI->fdes,(char *)data,length) != length || avi_write(AVI->fdes,&p,length&1) != (length&1)) // if len is uneven, write a pad byte { - gf_f64_seek(AVI->fdes,AVI->pos,SEEK_SET); + gf_fseek(AVI->fdes,AVI->pos,SEEK_SET); AVI_errno = AVI_ERR_WRITE; return -1; } @@ -628,7 +628,7 @@ avi_t* AVI_open_output_file(char * filename) } memset((void *)AVI,0,sizeof(avi_t)); - AVI->fdes = gf_f64_open(filename, "w+b"); + AVI->fdes = gf_fopen(filename, "w+b"); if (!AVI->fdes ) { AVI_errno = AVI_ERR_OPEN; @@ -643,7 +643,7 @@ avi_t* AVI_open_output_file(char * filename) i = avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES); if (i != HEADERBYTES) { - fclose(AVI->fdes); + gf_fclose(AVI->fdes); AVI_errno = AVI_ERR_WRITE; gf_free(AVI); return 0; @@ -681,6 +681,7 @@ void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compress avi_update_header(AVI); } +GF_EXPORT void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate) { /* may only be called if file is open for writing */ @@ -970,9 +971,9 @@ int avi_update_header(avi_t *AVI) /* Output the header, truncate the file to the number of bytes actually written, report an error if someting goes wrong */ - if ( (gf_f64_seek(AVI->fdes, 0, SEEK_SET) ==(u64)-1) || + if ( (gf_fseek(AVI->fdes, 0, SEEK_SET) ==(u64)-1) || avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES || - (gf_f64_seek(AVI->fdes,AVI->pos,SEEK_SET)==(u64)-1) + (gf_fseek(AVI->fdes,AVI->pos,SEEK_SET)==(u64)-1) ) { AVI_errno = AVI_ERR_CLOSE; return -1; @@ -1500,7 +1501,7 @@ static int avi_close_output_file(avi_t *AVI) /* Output the header, truncate the file to the number of bytes actually written, report an error if someting goes wrong */ - if ( (gf_f64_seek(AVI->fdes,0,SEEK_SET)==(u64)-1) || + if ( (gf_fseek(AVI->fdes,0,SEEK_SET)==(u64)-1) || avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES // || ftruncate(AVI->fdes,AVI->pos)<0 ) @@ -1518,13 +1519,13 @@ static int avi_close_output_file(avi_t *AVI) for (k=1; k<AVI->video_superindex->nEntriesInUse; k++) { // the len of the RIFF Chunk - gf_f64_seek(AVI->fdes, AVI->video_superindex->stdindex[k]->qwBaseOffset+4, SEEK_SET); + gf_fseek(AVI->fdes, AVI->video_superindex->stdindex[k]->qwBaseOffset+4, SEEK_SET); len = (u32) (AVI->video_superindex->stdindex[k+1]->qwBaseOffset - AVI->video_superindex->stdindex[k]->qwBaseOffset - 8); long2str((unsigned char *)f, len); avi_write(AVI->fdes, f, 4); // len of the LIST/movi chunk - gf_f64_seek(AVI->fdes, 8, SEEK_CUR); + gf_fseek(AVI->fdes, 8, SEEK_CUR); len -= 12; long2str((unsigned char *)f, len); avi_write(AVI->fdes, f, 4); @@ -1627,6 +1628,7 @@ int AVI_dup_frame(avi_t *AVI) return 0; } +GF_EXPORT int AVI_write_audio(avi_t *AVI, char *data, long bytes) { if(AVI->mode==AVI_MODE_READ) { @@ -1667,11 +1669,11 @@ int AVI_append_audio(avi_t *AVI, char *data, long bytes) AVI->track[AVI->aptr].audio_bytes += bytes; //update chunk header - gf_f64_seek(AVI->fdes, pos+4, SEEK_SET); + gf_fseek(AVI->fdes, pos+4, SEEK_SET); long2str(c, length+bytes); avi_write(AVI->fdes, (char *)c, 4); - gf_f64_seek(AVI->fdes, pos+8+length, SEEK_SET); + gf_fseek(AVI->fdes, pos+8+length, SEEK_SET); i=PAD_EVEN(length + bytes); @@ -1745,7 +1747,7 @@ int AVI_close(avi_t *AVI) /* Even if there happened an error, we first clean up */ - fclose(AVI->fdes); + gf_fclose(AVI->fdes); if(AVI->idx) gf_free(AVI->idx); if(AVI->video_index) gf_free(AVI->video_index); if(AVI->video_superindex) { @@ -1765,8 +1767,18 @@ int AVI_close(avi_t *AVI) { if(AVI->track[j].audio_index) gf_free(AVI->track[j].audio_index); if(AVI->track[j].audio_superindex) { - if(AVI->track[j].audio_superindex->aIndex) gf_free(AVI->track[j].audio_superindex->aIndex); - gf_free(AVI->track[j].audio_superindex); + avisuperindex_chunk *asi = AVI->track[j].audio_superindex; + if (asi->aIndex) gf_free(asi->aIndex); + + if (asi->stdindex) { + for (j=0; j < NR_IXNN_CHUNKS; j++) { + if (asi->stdindex[j]->aIndex) + gf_free(asi->stdindex[j]->aIndex); + gf_free(asi->stdindex[j]); + } + gf_free(asi->stdindex); + } + gf_free(asi); } } @@ -1809,7 +1821,7 @@ avi_t *AVI_open_input_file(char *filename, int getIndex) /* Open the file */ - AVI->fdes = gf_f64_open(filename,"rb"); + AVI->fdes = gf_fopen(filename,"rb"); if(!AVI->fdes ) { AVI_errno = AVI_ERR_OPEN; @@ -1898,7 +1910,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) while(1) { if( avi_read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */ - newpos = gf_f64_tell(AVI->fdes); + newpos = gf_ftell(AVI->fdes); if(oldpos==newpos) { /* This is a broken AVI stream... */ return -1; @@ -1920,16 +1932,16 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) // offset of header - header_offset = gf_f64_tell(AVI->fdes); + header_offset = gf_ftell(AVI->fdes); if( avi_read(AVI->fdes,(char *)hdrl_data, (u32) n) != n ) ERR_EXIT(AVI_ERR_READ) } else if(strnicmp(data,"movi",4) == 0) { - AVI->movi_start = gf_f64_tell(AVI->fdes); - if (gf_f64_seek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break; + AVI->movi_start = gf_ftell(AVI->fdes); + if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break; } - else if (gf_f64_seek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break; + else if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break; } else if(strnicmp(data,"idx1",4) == 0) { @@ -1946,7 +1958,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) } } else - gf_f64_seek(AVI->fdes,n,SEEK_CUR); + gf_fseek(AVI->fdes,n,SEEK_CUR); } if(!hdrl_data ) ERR_EXIT(AVI_ERR_NO_HDRL) @@ -2085,14 +2097,14 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) gf_realloc(wfe, sizeof(alWAVEFORMATEX) + str2ushort((unsigned char *)&wfe->cb_size)); if (nwfe != 0) { - s64 lpos = gf_f64_tell(AVI->fdes); - gf_f64_seek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX), + s64 lpos = gf_ftell(AVI->fdes); + gf_fseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX), SEEK_SET); wfe = (alWAVEFORMATEX *)nwfe; nwfe = &nwfe[sizeof(alWAVEFORMATEX)]; avi_read(AVI->fdes, nwfe, str2ushort((unsigned char *)&wfe->cb_size)); - gf_f64_seek(AVI->fdes, lpos, SEEK_SET); + gf_fseek(AVI->fdes, lpos, SEEK_SET); } } AVI->wave_format_ex[AVI->aptr] = wfe; @@ -2285,7 +2297,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) } } - gf_f64_seek(AVI->fdes,AVI->movi_start,SEEK_SET); + gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET); if(!getIndex) return(0); @@ -2308,7 +2320,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) pos = str2ulong(AVI->idx[i]+ 8); len = str2ulong(AVI->idx[i]+12); - gf_f64_seek(AVI->fdes,pos,SEEK_SET); + gf_fseek(AVI->fdes,pos,SEEK_SET); if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ) if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len ) { @@ -2316,7 +2328,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) } else { - gf_f64_seek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET); + gf_fseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET); if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ) if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len ) { @@ -2331,7 +2343,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) { /* we must search through the file to get the index */ - gf_f64_seek(AVI->fdes, AVI->movi_start, SEEK_SET); + gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET); AVI->n_idx = 0; @@ -2344,7 +2356,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) if(strnicmp(data,"LIST",4)==0) { - gf_f64_seek(AVI->fdes,4,SEEK_CUR); + gf_fseek(AVI->fdes,4,SEEK_CUR); continue; } @@ -2355,11 +2367,11 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) || ( (data[2]=='w' || data[2]=='W') && (data[3]=='b' || data[3]=='B') ) ) { - u64 __pos = gf_f64_tell(AVI->fdes) - 8; + u64 __pos = gf_ftell(AVI->fdes) - 8; avi_add_index_entry(AVI,(unsigned char *)data,0,__pos,n); } - gf_f64_seek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); + gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); } idx_type = 1; } @@ -2394,7 +2406,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) // read from file chunk_start = en = (char*) gf_malloc ((u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len) ); - if (gf_f64_seek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) { + if (gf_fseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) { gf_free(chunk_start); continue; } @@ -2472,7 +2484,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) // read from file chunk_start = en = (char*)gf_malloc ((u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len)); - if (gf_f64_seek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) { + if (gf_fseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) { gf_free(chunk_start); continue; } @@ -2531,7 +2543,7 @@ int avi_parse_input_file(avi_t *AVI, int getIndex) multiple_riff: - gf_f64_seek(AVI->fdes, AVI->movi_start, SEEK_SET); + gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET); AVI->n_idx = 0; @@ -2592,7 +2604,7 @@ multiple_riff: (data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) { AVI->video_index[nvi].key = 0x0; - AVI->video_index[nvi].pos = gf_f64_tell(AVI->fdes); + AVI->video_index[nvi].pos = gf_ftell(AVI->fdes); AVI->video_index[nvi].len = (u32) n; /* @@ -2600,7 +2612,7 @@ multiple_riff: nvi, AVI->video_index[nvi].pos, AVI->video_index[nvi].len, (long)AVI->video_index[nvi].key)); */ nvi++; - gf_f64_seek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); + gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); } //AUDIO @@ -2610,16 +2622,16 @@ multiple_riff: (data[3]=='b' || data[3]=='B') ) { - AVI->track[j].audio_index[nai[j]].pos = gf_f64_tell(AVI->fdes); + AVI->track[j].audio_index[nai[j]].pos = gf_ftell(AVI->fdes); AVI->track[j].audio_index[nai[j]].len = (u32) n; AVI->track[j].audio_index[nai[j]].tot = tot[j]; tot[j] += AVI->track[j].audio_index[nai[j]].len; nai[j]++; - gf_f64_seek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); + gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); } else { - gf_f64_seek(AVI->fdes,-4,SEEK_CUR); + gf_fseek(AVI->fdes,-4,SEEK_CUR); } } @@ -2711,7 +2723,7 @@ multiple_riff: /* Reposition the file */ - gf_f64_seek(AVI->fdes,AVI->movi_start,SEEK_SET); + gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET); AVI->video_pos = 0; return(0); @@ -2832,7 +2844,7 @@ int AVI_seek_start(avi_t *AVI) return -1; } - gf_f64_seek(AVI->fdes,AVI->movi_start,SEEK_SET); + gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET); AVI->video_pos = 0; return 0; } @@ -2888,7 +2900,7 @@ long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe) return n; } - gf_f64_seek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET); + gf_fseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET); if (avi_read(AVI->fdes,vidbuf,n) != (u32) n) { @@ -3011,7 +3023,7 @@ long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes, int *continuous) else todo = left; pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb; - gf_f64_seek(AVI->fdes, pos, SEEK_SET); + gf_fseek(AVI->fdes, pos, SEEK_SET); if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != todo) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] XXX pos = %"LLD", ret = %"LLD", todo = %ld\n", pos, ret, todo)); @@ -3060,7 +3072,7 @@ int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf, if(strnicmp(data,"LIST",4) == 0) { - gf_f64_seek(AVI->fdes,4,SEEK_CUR); + gf_fseek(AVI->fdes,4,SEEK_CUR); continue; } @@ -3072,7 +3084,7 @@ int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf, AVI->video_pos++; if(n>max_vidbuf) { - gf_f64_seek(AVI->fdes,n,SEEK_CUR); + gf_fseek(AVI->fdes,n,SEEK_CUR); return -1; } if(avi_read(AVI->fdes,vidbuf, (u32) n) != n ) return 0; @@ -3083,14 +3095,14 @@ int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf, *len = (u32) n; if(n>max_audbuf) { - gf_f64_seek(AVI->fdes,n,SEEK_CUR); + gf_fseek(AVI->fdes,n,SEEK_CUR); return -2; } if(avi_read(AVI->fdes,audbuf, (u32) n) != n ) return 0; return 2; break; } - else if(gf_f64_seek(AVI->fdes,n,SEEK_CUR) == (u64) -1) return 0; + else if(gf_fseek(AVI->fdes,n,SEEK_CUR) == (u64) -1) return 0; } } diff --git a/src/media_tools/dash_client.c b/src/media_tools/dash_client.c index d1a0478..6da3741 100644 --- a/src/media_tools/dash_client.c +++ b/src/media_tools/dash_client.c @@ -1,27 +1,27 @@ -/* -* GPAC - Multimedia Framework C SDK -* -* Authors: Jean Le Feuvre, Cyril Concolato -* Copyright (c) Telecom ParisTech 2010- -* All rights reserved -* -* This file is part of GPAC / Adaptive HTTP Streaming -* -* 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. -* -*/ +/** + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre, Cyril Concolato + * Copyright (c) Telecom ParisTech 2010- + * All rights reserved + * + * This file is part of GPAC / Adaptive HTTP Streaming + * + * 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 <gpac/thread.h> #include <gpac/network.h> @@ -30,6 +30,7 @@ #include <gpac/internal/m3u8.h> #include <gpac/internal/isomedia_dev.h> #include <string.h> +#include <sys/stat.h> #ifdef _WIN32_WCE #include <winbase.h> @@ -39,6 +40,9 @@ #ifndef GPAC_DISABLE_DASH_CLIENT +/*ISO 639 languages*/ +#include <gpac/iso639.h> + /*set to 1 if you want MPD to use SegmentTemplate if possible instead of SegmentList*/ #define M3U8_TO_MPD_USE_TEMPLATE 0 @@ -73,6 +77,9 @@ struct __dash_client Bool keep_files, disable_switching, allow_local_mpd_update, enable_buffering, estimate_utc_drift; Bool is_m3u8; + //set when MPD downloading fails. Will resetup DASH live once MPD is sync again + Bool in_error; + u64 mpd_fetch_time; GF_DASHInitialSelectionMode first_select_mode; @@ -83,7 +90,7 @@ struct __dash_client /* number of time the MPD has been reloaded and last update time*/ u32 reload_count, last_update_time; /*signature of last MPD*/ - u8 lastMPDSignature[20]; + u8 lastMPDSignature[GF_SHA1_DIGEST_SIZE]; /*mime type of media segments (m3u8)*/ char *mimeTypeForM3U8Segments; @@ -91,6 +98,8 @@ struct __dash_client u32 active_period_index; u32 request_period_switch; + Bool next_period_checked; + u64 start_time_in_active_period; Bool ignore_mpd_duration; @@ -114,9 +123,11 @@ struct __dash_client s32 utc_drift_estimate; s32 utc_shift; - /* TODO - handle playback status for SPEED/SEEK through SIDX */ - Double playback_start_range; - Double start_range_in_segment_at_next_period; + + Double start_range_period; + + Double speed; + u32 probe_times_before_switch; Bool force_mpd_update; @@ -124,10 +135,13 @@ struct __dash_client u32 min_timeout_between_404, segment_lost_after_ms; + //in ms + u32 time_in_tsb, prev_time_in_tsb; + u32 tsb_exceeded; s32 debug_group_index; }; -static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group); +static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group, Double seek_to, Bool is_dynamic); typedef struct @@ -139,6 +153,8 @@ typedef struct u32 representation_index; Bool loop_detected; u32 duration; + char *key_url; + bin128 key_IV; } segment_cache_entry; typedef enum @@ -204,10 +220,11 @@ struct __dash_group segment_cache_entry *cached; GF_DASHFileIOSession segment_download; - - const char *segment_local_url; + //0: not set, 1: abort because group has been stopped - 2: abort because bandwidth was too low + u32 download_abort_type; /*usually 0-0 (no range) but can be non-zero when playing local MPD/DASH sessions*/ - u64 local_url_start_range, local_url_end_range; + u64 bs_switching_init_segment_url_start_range, bs_switching_init_segment_url_end_range; + char *bs_switching_init_segment_url; u32 nb_segments_done; u32 last_segment_time; @@ -221,7 +238,7 @@ struct __dash_group u32 force_representation_idx_plus_one; Bool force_segment_switch; - Bool is_downloading, download_aborted; + Bool is_downloading; Bool loop_detected; u32 time_at_first_failure; @@ -244,8 +261,14 @@ struct __dash_group u32 current_timescale; void *udta; + + Bool has_pending_enhancement; }; +void drm_decrypt(unsigned char * data, unsigned long dataSize, const char * decryptMethod, const char * keyfileURL, const unsigned char * keyIV); + + + static const char *gf_dash_get_mime_type(GF_MPD_SubRepresentation *subrep, GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set) { if (subrep && subrep->mime_type) return subrep->mime_type; @@ -264,7 +287,7 @@ static void gf_dash_buffer_off(GF_DASH_Group *group) group->dash->dash_io->on_dash_event(group->dash->dash_io, GF_DASH_EVENT_BUFFER_DONE, -1, GF_OK); GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Session buffering done\n")); } - group->buffering = 0; + group->buffering = GF_FALSE; } } @@ -277,7 +300,7 @@ static void gf_dash_buffer_on(GF_DASH_Group *group) GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Starting session buffering\n")); } group->dash->nb_buffering++; - group->buffering = 1; + group->buffering = GF_TRUE; } } @@ -317,7 +340,7 @@ static u32 gf_dash_group_count_rep_needed(GF_DASH_Group *group) } GF_EXPORT -void gf_dash_get_buffer_info_buffering(GF_DashClient *dash, u32 *total_buffer, u32 *media_buffered) +void gf_dash_get_buffer_info(GF_DashClient *dash, u32 *total_buffer, u32 *media_buffered) { u32 nb_buffering = 0; if (dash->nb_buffering) { @@ -361,15 +384,15 @@ Bool gf_dash_check_mpd_root_type(const char *local_url) if (local_url) { char *rtype = gf_xml_get_root_type(local_url, NULL); if (rtype) { - Bool handled = 0; + Bool handled = GF_FALSE; if (!strcmp(rtype, "MPD")) { - handled = 1; + handled = GF_TRUE; } gf_free(rtype); return handled; } } - return 0; + return GF_FALSE; } @@ -395,14 +418,17 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 /*if no AST, do not use NTP sync */ if (! group->dash->mpd->availabilityStartTime) { - group->broken_timing = 1; + group->broken_timing = GF_TRUE; return; } - //temp hack - mpd->media_presentation_duration = 0; + if (!fetch_time) { + //when we initialize the timeline without an explicit fetch time, use our local clock - this allows for better precision + //when trying to locate the live edge + fetch_time = gf_net_get_utc(); + } + - if (!fetch_time) fetch_time = group->dash->mpd_fetch_time; if (group->dash->estimate_utc_drift && !group->dash->utc_drift_estimate && group->dash->mpd_dnload && group->dash->dash_io->get_header_value) { const char *val = group->dash->dash_io->get_header_value(group->dash->dash_io, group->dash->mpd_dnload, "Server-UTC"); if (val) { @@ -422,8 +448,11 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 } } + availabilityStartTime = 0; + if ((s64) mpd->availabilityStartTime + group->dash->utc_shift > (s64) - group->dash->utc_drift_estimate) { + availabilityStartTime = mpd->availabilityStartTime + group->dash->utc_shift + group->dash->utc_drift_estimate; + } - availabilityStartTime = mpd->availabilityStartTime + group->dash->utc_shift + group->dash->utc_drift_estimate; #ifdef FORCE_DESYNC availabilityStartTime -= FORCE_DESYNC; @@ -435,7 +464,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 if (current_time < availabilityStartTime) { //if more than 1 sec consider we have a pb if (availabilityStartTime - current_time >= 1000) { - Bool broken_timing = 1; + Bool broken_timing = GF_TRUE; #ifndef _WIN32_WCE time_t gtime1, gtime2; struct tm *t1, *t2; @@ -446,7 +475,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 if (t1 == t2) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Slight drift in UTC clock at time %d-%02d-%02dT%02d:%02d:%02dZ: diff AST - now %d ms\n", 1900+t1->tm_year, t1->tm_mon+1, t1->tm_mday, t1->tm_hour, t1->tm_min, t1->tm_sec, (s32) (availabilityStartTime - current_time) )); current_time = 0; - broken_timing = 0; + broken_timing = GF_FALSE; } else if (t1 && t2) { t1->tm_year = t2->tm_year; @@ -465,7 +494,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 availabilityStartTime = current_time; } else { current_time = 0; - group->broken_timing = 1; + group->broken_timing = GF_TRUE; return; } } @@ -505,13 +534,18 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 if (current_time < shift) current_time = 0; else current_time -= shift; - } else if (group->dash->user_buffer_ms) { + } + //commented for now, this increase the delay to the live ... +#if 0 + else if (group->dash->user_buffer_ms) { shift = MIN(group->dash->user_buffer_ms, mpd->time_shift_buffer_depth); if (current_time < shift) current_time = 0; else current_time -= shift; } +#endif } + group->dash->time_in_tsb = group->dash->prev_time_in_tsb = 0; timeline = NULL; timescale=1; @@ -593,7 +627,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 group->nb_segments_in_rep = count; group->start_playback_range = (segtime)*1.0/timescale; group->ast_at_init = availabilityStartTime - (u32) (ast_offset*1000); - group->broken_timing = 1; + group->broken_timing = GF_TRUE; return; } } @@ -601,7 +635,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 repeat = 1+ent->repeat_count; while (repeat) { if ((current_time_rescale >= segtime) && (current_time_rescale < segtime + ent->duration)) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Found segment %d for current time "LLU" is in SegmentTimeline ["LLU"-"LLU"] (timecale %d - current index %d)\n", seg_idx, current_time_rescale, start_segtime, segtime + ent->duration, timescale, group->download_segment_index)); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Found segment %d for current time "LLU" is in SegmentTimeline ["LLU"-"LLU"] (timecale %d - current index %d - startNumber %d)\n", seg_idx, current_time_rescale, start_segtime, segtime + ent->duration, timescale, group->download_segment_index, start_number)); group->download_segment_index = seg_idx; group->nb_segments_in_rep = seg_idx + count - i; @@ -619,11 +653,19 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 seg_idx++; } } - //NOT FOUND !! - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] current time "LLU" is NOT in SegmentTimeline ["LLU"-"LLU"] - cannot estimate current startNumber, default to 0 ...\n", current_time_rescale, start_segtime, segtime)); - group->download_segment_index = 0; - group->nb_segments_in_rep = 10; - group->broken_timing = 1; + + if (current_time_rescale >= segtime) { + group->download_segment_index = seg_idx; + group->nb_segments_in_rep = 10; + group->start_playback_range = (current_time)/1000.0; + group->ast_at_init = availabilityStartTime - (u32) (ast_offset*1000); + } else { + //NOT FOUND !! + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] current time "LLU" is NOT in SegmentTimeline ["LLU"-"LLU"] - cannot estimate current startNumber, default to 0 ...\n", current_time_rescale, start_segtime, segtime)); + group->download_segment_index = 0; + group->nb_segments_in_rep = 10; + group->broken_timing = GF_TRUE; + } return; } @@ -634,10 +676,30 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 nb_seg /= group->segment_duration; shift = (u32) nb_seg; - //when is the next segment available ? if less than 1/3 of a second till now start with next one - if (1000 * ( (1+shift /*next segment*/+ 1/*+seg duration for availability time*/) * group->segment_duration - ast_offset /*get exact AST time*/) - current_time < 330) { - group->start_playback_range = 0; - shift++; + //not time shifting, we are at the live edge, we must stick to start of segment otherwise we won't have enough data to play until next segment is ready + + if (!group->dash->initial_time_shift_value) { + Double ms_in_seg; + group->start_playback_range = shift * group->segment_duration; + + ms_in_seg = (Double) current_time/1000.0; + ms_in_seg -= group->start_playback_range; + + //if low latency, try to adjust + if (ast_offset) { + Double ast_diff; + if (ast_offset>group->segment_duration) ast_offset = group->segment_duration; + ast_diff = group->segment_duration - ast_offset; + + //we assume that in low latency mode, chunks are made available every (group->segment_duration - ast_offset) + //we need to seek such that the remaining time R satisfies now + R = NextSegAST + //hence S(n) + ms_in_seg + R = S(n+1) + Aoffset + //which gives us R = S(n+1) + Aoffset - S(n) - ms_in_seg = D + Aoffset - ms_in_seg + //seek = D - R = D - (D + Aoffset - ms_in_seg) = ms_in_seg - Ao + if (ms_in_seg > ast_diff) { + group->start_playback_range += ms_in_seg - ast_diff; + } + } } else { group->start_playback_range = (Double) current_time / 1000.0; } @@ -648,7 +710,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 group->ast_at_init = availabilityStartTime - (u32) (ast_offset*1000); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] At current time "LLD" ms: Initializing Timeline: startNumber=%d segmentNumber=%d segmentDuration=%g sec offset in segment %g sec\n", current_time, start_number, shift, group->segment_duration, group->start_playback_range ? group->start_playback_range - shift*group->segment_duration : 0)); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] At current time "LLD" ms: Initializing Timeline: startNumber=%d segmentNumber=%d segmentDuration=%f - %.03f seconds in segment\n", current_time, start_number, shift, group->segment_duration, group->start_playback_range ? group->start_playback_range - shift*group->segment_duration : 0)); } else { group->download_segment_index += start_number; if (group->download_segment_index > group->start_number_at_last_ast) { @@ -670,7 +732,7 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 if (group->nb_segments_in_rep && (group->download_segment_index + nb_segs_in_update > group->nb_segments_in_rep)) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Not enough segments (%d needed vs %d indicated) to reach period endTime indicated in MPD - ignoring MPD duration\n", nb_segs_in_update, group->nb_segments_in_rep - group->download_segment_index )); group->nb_segments_in_rep = shift + nb_segs_in_update; - group->dash->ignore_mpd_duration = 1; + group->dash->ignore_mpd_duration = GF_TRUE; } group->prev_segment_ok = GF_TRUE; } else { @@ -687,15 +749,15 @@ static void gf_dash_group_timeline_setup(GF_MPD *mpd, GF_DASH_Group *group, u64 * \param mime the mime-type to check * \return true if mime-type if MPD-OK */ -static Bool gf_dash_is_dash_mime(const char * mime) { +static Bool gf_dash_is_dash_mime(const char *mime) { u32 i; if (!mime) - return 0; + return GF_FALSE; for (i = 0 ; GF_DASH_MPD_MIME_TYPES[i] ; i++) { if ( !stricmp(mime, GF_DASH_MPD_MIME_TYPES[i])) - return 1; + return GF_TRUE; } - return 0; + return GF_FALSE; } /*! @@ -707,22 +769,22 @@ static Bool gf_dash_is_dash_mime(const char * mime) { static Bool gf_dash_is_m3u8_mime(const char *url, const char * mime) { u32 i; if (!url || !mime) - return 0; + return GF_FALSE; if (strstr(url, ".mpd") || strstr(url, ".MPD")) - return 0; + return GF_FALSE; for (i = 0 ; GF_DASH_M3U8_MIME_TYPES[i] ; i++) { if ( !stricmp(mime, GF_DASH_M3U8_MIME_TYPES[i])) - return 1; + return GF_TRUE; } - return 0; + return GF_FALSE; } GF_EXPORT GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 idx) { - Bool default_switch_mode = 0; + Bool default_switch_mode = GF_FALSE; u32 download_rate, set_idx, time_since_start, done, tot_size, time_until_end; GF_DASH_Group *group = gf_list_get(dash->groups, idx); if (!group) return GF_BAD_PARAM; @@ -779,11 +841,11 @@ GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 idx) GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Downloading from set #%d at rate %d kbps but media bitrate is %d kbps - %d/%d in cache - killing connection and switching\n", set_idx, download_rate/1024, group->active_bitrate/1024, group->nb_cached_segments, group->max_cached_segments )); + group->download_abort_type = 2; group->dash->dash_io->abort(group->dash->dash_io, group->segment_download); - group->download_aborted = GF_TRUE; //in live we just abort current download and go to next. In onDemand, we may want to rebuffer - default_switch_mode = (group->dash->mpd->type==GF_MPD_TYPE_DYNAMIC) ? 0 : 1; + default_switch_mode = (group->dash->mpd->type==GF_MPD_TYPE_DYNAMIC) ? GF_FALSE : GF_TRUE; //if we have time to download from another rep ? if (group->current_downloaded_segment_duration <= time_since_start) { @@ -805,7 +867,7 @@ GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 idx) //don't force bandwidth switch, we won't have time to redownload the segment. group->force_switch_bandwidth = default_switch_mode; } else { - group->force_switch_bandwidth = 1; + group->force_switch_bandwidth = GF_TRUE; GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Attempting to re-download at target rate %d\n", target_rate)); } //cap max bitrate for next rate adaptation pass @@ -821,12 +883,13 @@ GF_Err gf_dash_group_check_bandwidth(GF_DashClient *dash, u32 idx) * Parameters are identical to the ones of gf_service_download_new. * \see gf_service_download_new() */ -GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *sess, const char *url, u64 start_range, u64 end_range, u32 persistent_mode, GF_DASH_Group *group) +GF_Err gf_dash_download_resource(GF_DashClient *dash, GF_DASHFileIOSession *sess, const char *url, u64 start_range, u64 end_range, u32 persistent_mode, GF_DASH_Group *group) { s32 group_idx = -1; - Bool had_sess = 0; - Bool retry = 1; + Bool had_sess = GF_FALSE; + Bool retry = GF_TRUE; GF_Err e; + GF_DASHFileIO *dash_io = dash->dash_io; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Downloading %s starting at UTC "LLU" ms\n", url, gf_net_get_utc() )); @@ -841,7 +904,7 @@ GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *s return GF_OUT_OF_MEM; } } else { - had_sess = 1; + had_sess = GF_TRUE; if (persistent_mode!=2) { e = dash_io->setup_from_url(dash_io, *sess, url, group_idx); if (e) { @@ -851,23 +914,23 @@ GF_Err gf_dash_download_resource(GF_DASHFileIO *dash_io, GF_DASHFileIOSession *s } } if (group) { - group->is_downloading = 1; + group->is_downloading = GF_TRUE; group->download_start_time = gf_sys_clock(); } retry: if (end_range) { - e = dash_io->set_range(dash_io, *sess, start_range, end_range, (persistent_mode==2) ? 0 : 1); + e = dash_io->set_range(dash_io, *sess, start_range, end_range, (persistent_mode==2) ? GF_FALSE : GF_TRUE); if (e) { if (had_sess) { dash_io->del(dash_io, *sess); *sess = NULL; - return gf_dash_download_resource(dash_io, sess, url, start_range, end_range, persistent_mode ? 1 : 0, group); + return gf_dash_download_resource(dash, sess, url, start_range, end_range, persistent_mode ? 1 : 0, group); } GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot setup byte-range download for %s: %s\n", url, gf_error_to_string(e) )); if (group) - group->is_downloading = 0; + group->is_downloading = GF_FALSE; return e; } } @@ -879,7 +942,7 @@ retry: if (e>=GF_OK) { /*check mime type of the adaptation set if not provided*/ if (group) { - const char *mime = dash_io->get_mime(dash_io, *sess); + const char *mime = *sess ? dash_io->get_mime(dash_io, *sess) : NULL; if (mime && !group->service_mime) { group->service_mime = gf_strdup(mime); } @@ -903,38 +966,44 @@ retry: if (group) { if (dash_io->get_cache_name(dash_io, group->segment_download) == NULL) { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Segment %s cannot be cached on disk, will use direct streaming\n", url)); - group->segment_must_be_streamed = 1; + group->segment_must_be_streamed = GF_TRUE; if (group->segment_download) dash_io->abort(dash_io, group->segment_download); - group->is_downloading = 1; + group->is_downloading = GF_TRUE; return GF_OK; } - group->segment_must_be_streamed = 0; + group->segment_must_be_streamed = GF_FALSE; } /*we can download the file*/ e = dash_io->run(dash_io, *sess); } + if (group && group->download_abort_type) { + group->is_downloading = GF_FALSE; + return GF_IP_CONNECTION_CLOSED; + } switch (e) { case GF_IP_CONNECTION_FAILURE: case GF_IP_NETWORK_FAILURE: - { - dash_io->del(dash_io, *sess); - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] failed to download, retrying once with %s...\n", url)); - *sess = dash_io->create(dash_io, 0, url, group_idx); - if (! (*sess)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot retry to download %s... OUT of memory ?\n", url)); - if (group) - group->is_downloading = 0; - return GF_OUT_OF_MEM; - } + if (!dash->in_error || group) { + dash_io->del(dash_io, *sess); + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] failed to download, retrying once with %s...\n", url)); + *sess = dash_io->create(dash_io, 0, url, group_idx); + if (! (*sess)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot retry to download %s... OUT of memory ?\n", url)); + if (group) + group->is_downloading = GF_FALSE; + return GF_OUT_OF_MEM; + } - if (retry) { - retry = 0; - goto retry; + if (retry) { + retry = GF_FALSE; + goto retry; + } + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] two consecutive failures, aborting the download %s.\n", url)); + } else if (dash->in_error) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Downlod still in error for %s.\n", url)); } - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] two consecutive failures, aborting the download %s.\n", url)); break; - } case GF_OK: GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Download %s complete at UTC "LLU" ms\n", url, gf_net_get_utc() )); break; @@ -943,7 +1012,7 @@ retry: break; } if (group) - group->is_downloading = 0; + group->is_downloading = GF_FALSE; return e; } @@ -970,22 +1039,23 @@ static void gf_dash_get_timeline_duration(GF_MPD *mpd, GF_MPD_Period *period, GF *nb_segments += 1 + ent->repeat_count; if (ent->start_time) { start_time = ent->start_time; - dur = (1 + ent->repeat_count) * ent->duration; + dur = (1 + ent->repeat_count); } else { - dur += (1 + ent->repeat_count) * ent->duration; + dur += (1 + ent->repeat_count); } + dur *= ent->duration; } else { u32 nb_seg = 0; if (i+1<count) { GF_MPD_SegmentTimelineEntry *ent2 = gf_list_get(timeline->entries, i+1); if (ent2->start_time>0) { nb_seg = (u32) ( (ent2->start_time - start_time - dur) / ent->duration); - dur += nb_seg * ent->duration; + dur += ((u64)nb_seg) * ent->duration; } - } + } if (!nb_seg) { nb_seg = (u32) ( (period_duration - start_time) / ent->duration ); - dur += nb_seg * ent->duration; + dur += ((u64)nb_seg) * ent->duration; } *nb_segments += nb_seg; } @@ -996,7 +1066,7 @@ static void gf_dash_get_timeline_duration(GF_MPD *mpd, GF_MPD_Period *period, GF static void gf_dash_get_segment_duration(GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set, GF_MPD_Period *period, GF_MPD *mpd, u32 *nb_segments, Double *max_seg_duration) { Double mediaDuration; - Bool single_segment = 0; + Bool single_segment = GF_FALSE; u32 timescale; u64 duration; GF_MPD_SegmentTimeline *timeline = NULL; @@ -1023,7 +1093,7 @@ static void gf_dash_get_segment_duration(GF_MPD_Representation *rep, GF_MPD_Adap if (rep->segment_list->segment_URLs) segments = rep->segment_list->segment_URLs; if (rep->segment_list->segment_timeline) timeline = rep->segment_list->segment_timeline; } - if (! timescale) timescale=1; + if (!timescale) timescale=1; if (timeline) { gf_dash_get_timeline_duration(mpd, period, timeline, timescale, nb_segments, max_seg_duration); @@ -1047,21 +1117,21 @@ static void gf_dash_get_segment_duration(GF_MPD_Representation *rep, GF_MPD_Adap return; } - single_segment = 1; + single_segment = GF_TRUE; if (period->segment_template) { - single_segment = 0; + single_segment = GF_FALSE; if (period->segment_template->duration) duration = period->segment_template->duration; if (period->segment_template->timescale) timescale = period->segment_template->timescale; if (period->segment_template->segment_timeline) timeline = period->segment_template->segment_timeline; } if (set->segment_template) { - single_segment = 0; + single_segment = GF_FALSE; if (set->segment_template->duration) duration = set->segment_template->duration; if (set->segment_template->timescale) timescale = set->segment_template->timescale; if (set->segment_template->segment_timeline) timeline = set->segment_template->segment_timeline; } if (rep->segment_template) { - single_segment = 0; + single_segment = GF_FALSE; if (rep->segment_template->duration) duration = rep->segment_template->duration; if (rep->segment_template->timescale) timescale = rep->segment_template->timescale; if (rep->segment_template->segment_timeline) timeline = rep->segment_template->segment_timeline; @@ -1129,6 +1199,7 @@ static u64 gf_dash_segment_timeline_start(GF_MPD_SegmentTimeline *timeline, u32 return start_time; } + static u64 gf_dash_get_segment_start_time_with_timescale(GF_DASH_Group *group, u64 *segment_duration, u32 *scale) { GF_MPD_Representation *rep; @@ -1138,6 +1209,7 @@ static u64 gf_dash_get_segment_start_time_with_timescale(GF_DASH_Group *group, u u32 timescale; s32 segment_index; u64 duration; + GF_List *seglist = NULL; GF_MPD_SegmentTimeline *timeline = NULL; timescale = 0; duration = 0; @@ -1157,23 +1229,35 @@ static u64 gf_dash_get_segment_start_time_with_timescale(GF_DASH_Group *group, u if (period->segment_list->duration) duration = period->segment_list->duration; if (period->segment_list->timescale) timescale = period->segment_list->timescale; if (period->segment_list->segment_timeline) timeline = period->segment_list->segment_timeline; + if (gf_list_count(period->segment_list->segment_URLs)) seglist = period->segment_list->segment_URLs; } if (set->segment_list) { if (set->segment_list->duration) duration = set->segment_list->duration; if (set->segment_list->timescale) timescale = set->segment_list->timescale; if (set->segment_list->segment_timeline) timeline = set->segment_list->segment_timeline; + if (gf_list_count(set->segment_list->segment_URLs)) seglist = set->segment_list->segment_URLs; } if (rep->segment_list) { if (rep->segment_list->duration) duration = rep->segment_list->duration; if (rep->segment_list->timescale) timescale = rep->segment_list->timescale; - if (rep->segment_list->segment_timeline) timeline = rep->segment_list->segment_timeline; + if (gf_list_count(rep->segment_list->segment_URLs)) seglist = rep->segment_list->segment_URLs; } if (! timescale) timescale=1; if (timeline) { start_time = gf_dash_segment_timeline_start(timeline, segment_index, &duration); - } else { + } else if (duration) { start_time = segment_index * duration; + } else if (seglist && (segment_index>=0) ) { + u32 i; + start_time = 0; + for (i=0; i <= (u32) segment_index; i++) { + GF_MPD_SegmentURL *url = gf_list_get(seglist, i); + if (!url) break; + duration = url->duration; + if (i < (u32) segment_index) + start_time += url->duration; + } } if (segment_duration) *segment_duration = duration; if (scale) *scale = timescale; @@ -1325,22 +1409,21 @@ static u32 gf_dash_get_index_in_timeline(GF_MPD_SegmentTimeline *timeline, u64 s } //end of list in regular case: segment was the last one of the previous list and no changes happend if (start_timescale==timescale) { - if (start_time == start ) return count; + if (start_time == start ) return idx; } else { - if (start_time*start_timescale == start * timescale) return count; + if (start_time*start_timescale == start * timescale) return idx; } GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error: could not find previous segment start in current timeline ! seeking to end of timeline\n")); - return count; + return idx; } static GF_Err gf_dash_merge_segment_timeline(GF_DASH_Group *group, GF_DashClient *dash, GF_MPD_SegmentList *old_list, GF_MPD_SegmentTemplate *old_template, GF_MPD_SegmentList *new_list, GF_MPD_SegmentTemplate *new_template, Double min_start_time) { GF_MPD_SegmentTimeline *old_timeline, *new_timeline; - u32 i, idx, prev_count, timescale; - u64 start_time; - GF_MPD_SegmentTimelineEntry *first_new_entry; + u32 i, idx, timescale, nb_new_segs; + GF_MPD_SegmentTimelineEntry *ent; old_timeline = new_timeline = NULL; if (old_list && old_list->segment_timeline) { @@ -1362,9 +1445,6 @@ static GF_Err gf_dash_merge_segment_timeline(GF_DASH_Group *group, GF_DashClient } if (!old_timeline && !new_timeline) return GF_OK; - prev_count = gf_list_count(old_timeline->entries); - - if (group) { group->current_start_time = gf_dash_get_segment_start_time_with_timescale(group, NULL, &group->current_timescale); } else { @@ -1374,57 +1454,38 @@ static GF_Err gf_dash_merge_segment_timeline(GF_DASH_Group *group, GF_DashClient } } - - first_new_entry = gf_list_get(new_timeline->entries, 0); - idx = 0; - start_time=0; - while (1) { - GF_MPD_SegmentTimelineEntry *ent = gf_list_get(old_timeline->entries, 0); - if (!ent) break; - if (ent->start_time) - start_time = ent->start_time; - /*if starttime is equal or greater than first entry in new timeline, we're done*/ - if (start_time >= first_new_entry->start_time) - break; - - /*if entry overlaps first entry in new timeline, remove segments*/ - while (start_time + ent->duration * (1 + ent->repeat_count) > first_new_entry->start_time) { - ent->repeat_count--; - } - /*we will insert the first entry in the new timeline, make sure we have a start*/ - if (!idx && !ent->start_time) - ent->start_time = start_time; - - start_time += ent->duration * (1 + ent->repeat_count); - - gf_list_insert(new_timeline->entries, ent, idx); - idx ++; - gf_list_rem(old_timeline->entries, 0); + nb_new_segs = 0; + idx=0; + while ((ent = gf_list_enum(new_timeline->entries, &idx))) { + nb_new_segs += 1 + ent->repeat_count; } if (group) { - group->nb_segments_in_rep = gf_list_count(new_timeline->entries); - group->download_segment_index = gf_dash_get_index_in_timeline(new_timeline, group->current_start_time, group->current_timescale, timescale); + u32 prev_idx = group->download_segment_index; + group->nb_segments_in_rep = nb_new_segs; + group->download_segment_index = gf_dash_get_index_in_timeline(new_timeline, group->current_start_time, group->current_timescale, timescale ? timescale : group->current_timescale); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Updated SegmentTimeline: New segment number %d - old %d - start time "LLD"\n", group->download_segment_index , prev_idx, group->current_start_time)); } else { u32 i; for (i=0; i<gf_list_count(dash->groups); i++) { GF_DASH_Group *a_group = gf_list_get(dash->groups, i); - a_group->nb_segments_in_rep = gf_list_count(new_timeline->entries); - a_group->download_segment_index = gf_dash_get_index_in_timeline(new_timeline, a_group->current_start_time, a_group->current_timescale, timescale); + u32 prev_idx = a_group->download_segment_index; + a_group->nb_segments_in_rep = nb_new_segs; + a_group->download_segment_index = gf_dash_get_index_in_timeline(new_timeline, a_group->current_start_time, a_group->current_timescale, timescale ? timescale : a_group->current_timescale); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Updated SegmentTimeline: New segment number %d - old %d - start time "LLD"\n", a_group->download_segment_index , prev_idx, a_group->current_start_time)); } } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Updated SegmentTimeline: %d entries (%d previously)\n", gf_list_count(new_timeline->entries), prev_count)); -#if 0 - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Dumping new merged timeline: \n")); - start_time=0; - for (idx=0; idx<gf_list_count(new_timeline->entries); idx++) { - GF_MPD_SegmentTimelineEntry *ent = gf_list_get(new_timeline->entries, idx); - if (!idx) start_time = ent->start_time; - assert(!ent->start_time || (ent->start_time >=start_time)); - start_time += ent->duration*(1+ent->repeat_count); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("\tt="LLU" d=%d r=%d\n", ent->start_time, ent->duration, ent->repeat_count)); +#ifndef GPAC_DISABLE_LOG + if (gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_DEBUG) ) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] New SegmentTimeline: \n")); + for (idx=0; idx<gf_list_count(new_timeline->entries); idx++) { + GF_MPD_SegmentTimelineEntry *ent = gf_list_get(new_timeline->entries, idx); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("\tt="LLU" d=%d r=%d\n", ent->start_time, ent->duration, ent->repeat_count)); + } } #endif @@ -1494,25 +1555,26 @@ static u32 gf_dash_purge_segment_timeline(GF_DASH_Group *group, Double min_start static GF_Err gf_dash_update_manifest(GF_DashClient *dash) { GF_Err e; + Bool force_timeline_setup; u32 group_idx, rep_idx, i, j; u64 fetch_time=0; GF_DOMParser *mpd_parser; - u8 signature[sizeof(dash->lastMPDSignature)]; + u8 signature[GF_SHA1_DIGEST_SIZE]; GF_MPD_Period *period, *new_period; const char *local_url; char mime[128]; char * purl; Double timeline_start_time; GF_MPD *new_mpd; - Bool fetch_only = 0; + Bool fetch_only = GF_FALSE; if (!dash->mpd_dnload) { local_url = purl = NULL; if (!gf_list_count(dash->mpd->locations)) { - FILE *t = fopen(dash->base_url, "rt"); + FILE *t = gf_fopen(dash->base_url, "rt"); if (t) { local_url = dash->base_url; - fclose(t); + gf_fclose(t); } if (!local_url) { /*we will no longer attempt to update the MPD ...*/ @@ -1533,11 +1595,10 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) } } else { local_url = dash->dash_io->get_cache_name(dash->dash_io, dash->mpd_dnload); - if (!local_url) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot update playlist: wrong cache file %s\n", local_url)); - return GF_IO_ERR; + if (local_url) { + gf_delete_file(local_url); } - gf_delete_file(local_url); + //use the redirected url purl = gf_strdup( dash->dash_io->get_url(dash->dash_io, dash->mpd_dnload) ); } @@ -1555,10 +1616,15 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) if (purl) { const char *mime_type; /*use non-persistent connection for MPD*/ - e = gf_dash_download_resource(dash->dash_io, &(dash->mpd_dnload), purl, 0, 0, 0, NULL); + e = gf_dash_download_resource(dash, &(dash->mpd_dnload), purl, 0, 0, 0, NULL); if (e!=GF_OK) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot update playlist: download problem %s for MPD file\n", gf_error_to_string(e))); + if (!dash->in_error) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot update playlist: download problem %s for MPD file\n", gf_error_to_string(e))); + dash->in_error = GF_TRUE; + } gf_free(purl); + //try to refetch MPD every second + dash->last_update_time+=1000; return e; } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Playlist %s updated with success\n", purl)); @@ -1578,7 +1644,18 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) } gf_free(purl); + + purl = (char *) dash->dash_io->get_url(dash->dash_io, dash->mpd_dnload) ; + + /*if relocated, reassign MPD base URL*/ + if (strcmp(purl, dash->base_url)) { + gf_free(dash->base_url); + dash->base_url = gf_strdup(purl); + } + purl = NULL; + + } fetch_time = dash_get_fetch_time(dash); @@ -1592,7 +1669,7 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) return GF_IO_ERR; } - if (! memcmp( signature, dash->lastMPDSignature, sizeof(dash->lastMPDSignature))) { + if (!dash->in_error && ! memcmp( signature, dash->lastMPDSignature, GF_SHA1_DIGEST_SIZE)) { dash->reload_count++; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] MPD file did not change for %d consecutive reloads\n", dash->reload_count)); @@ -1604,11 +1681,15 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) } else { dash->last_update_time = gf_sys_clock(); } + + dash->mpd_fetch_time = fetch_time; return GF_OK; } + force_timeline_setup = dash->in_error; + dash->in_error = GF_FALSE; dash->reload_count = 0; - memccpy(dash->lastMPDSignature, signature, sizeof(char), sizeof(dash->lastMPDSignature)); + memcpy(dash->lastMPDSignature, signature, GF_SHA1_DIGEST_SIZE); /* It means we have to reparse the file ... */ /* parse the MPD */ @@ -1710,22 +1791,32 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) } else if (rep->segment_template || group->adaptation_set->segment_template || period->segment_template) { - u32 start; if (!new_rep->segment_template && !new_set->segment_template && !new_period->segment_template) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot update playlist: representation does not use segment template as previous version\n")); gf_mpd_del(new_mpd); return GF_NON_COMPLIANT_BITSTREAM; } - start = 0; - /*override new startNum with old one - otherwise we would need to get rid of the entries before the start number in the MPD ...*/ - if (period->segment_template && (period->segment_template->start_number != (u32) -1) ) start = period->segment_template->start_number; - if (set->segment_template && (set->segment_template->start_number != (u32) -1) ) start = set->segment_template->start_number; - if (rep->segment_template && (rep->segment_template->start_number != (u32) -1) ) start = rep->segment_template->start_number; + //if no segment timeline, adjust current idx of the group if start number changes (not needed if SegmentTimeline, otherwise, we will look for the index with the same starttime in the timeline) + if ((period->segment_template && period->segment_template->segment_timeline) + || (set->segment_template && set->segment_template->segment_timeline) + || (rep->segment_template && rep->segment_template->segment_timeline) + ) { + } else { + s32 sn_diff = 0; + + if (period->segment_template && (period->segment_template->start_number != (u32) -1) ) sn_diff = period->segment_template->start_number; + else if (set->segment_template && (set->segment_template->start_number != (u32) -1) ) sn_diff = set->segment_template->start_number; + else if (rep->segment_template && (rep->segment_template->start_number != (u32) -1) ) sn_diff = rep->segment_template->start_number; - if (new_period->segment_template && (new_period->segment_template->start_number != (u32) -1) ) new_period->segment_template->start_number = start; - if (new_set->segment_template && (new_set->segment_template->start_number != (u32) -1) ) new_set->segment_template->start_number = start; - if (new_rep->segment_template && (new_rep->segment_template->start_number != (u32) -1) ) new_rep->segment_template->start_number = start; + if (new_period->segment_template && (new_period->segment_template->start_number != (u32) -1) ) sn_diff -= (s32) new_period->segment_template->start_number; + else if (new_set->segment_template && (new_set->segment_template->start_number != (u32) -1) ) sn_diff -= (s32) new_set->segment_template->start_number; + else if (new_rep->segment_template && (new_rep->segment_template->start_number != (u32) -1) ) sn_diff -= (s32) new_rep->segment_template->start_number; + if (sn_diff != 0) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] startNumber change for SegmentTemplate without SegmentTimeline - adjusting current segment index by %d\n", sn_diff)); + group->download_segment_index += sn_diff; + } + } /*OK, this rep is fine*/ } else { @@ -1750,7 +1841,7 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) for (i=0; i<gf_list_count(new_segments); i++) { GF_MPD_SegmentURL *new_seg = gf_list_get(new_segments, i); - Bool found = 0; + Bool found = GF_FALSE; for (j=0; j<gf_list_count(segments); j++) { GF_MPD_SegmentURL *seg = gf_list_get(segments, j); if (seg->media && new_seg->media && !strcmp(seg->media, new_seg->media)) { @@ -1826,10 +1917,15 @@ static GF_Err gf_dash_update_manifest(GF_DashClient *dash) } } - if (new_mpd->availabilityStartTime != dash->mpd->availabilityStartTime) { + if (force_timeline_setup) { + group->timeline_setup = 0; + group->start_number_at_last_ast = 0; + gf_dash_group_timeline_setup(new_mpd, group, fetch_time); + } + else if (new_mpd->availabilityStartTime != dash->mpd->availabilityStartTime) { s64 diff = new_mpd->availabilityStartTime; diff -= dash->mpd->availabilityStartTime; - if (diff < 0) diff = diff; + if (diff < 0) diff = -diff; if (diff>3000) gf_dash_group_timeline_setup(new_mpd, group, fetch_time); } @@ -1953,6 +2049,8 @@ static void gf_dash_set_group_representation(GF_DASH_Group *group, GF_MPD_Repres if (timeshift == -1) timeshift = (s32) group->dash->mpd->time_shift_buffer_depth; group->time_shift_buffer_depth = (u32) timeshift; + + group->dash->dash_io->on_dash_event(group->dash->dash_io, GF_DASH_EVENT_QUALITY_SWITCH, gf_list_find(group->dash->groups, group), GF_OK); } static void gf_dash_switch_group_representation(GF_DashClient *mpd, GF_DASH_Group *group) @@ -1960,7 +2058,7 @@ static void gf_dash_switch_group_representation(GF_DashClient *mpd, GF_DASH_Grou u32 i, bandwidth, min_bandwidth; GF_MPD_Representation *rep_sel = NULL; GF_MPD_Representation *min_rep_sel = NULL; - Bool min_bandwidth_selected = 0; + Bool min_bandwidth_selected = GF_FALSE; bandwidth = 0; min_bandwidth = (u32) -1; @@ -2011,399 +2109,141 @@ static void gf_dash_switch_group_representation(GF_DashClient *mpd, GF_DASH_Grou } - -typedef enum -{ - GF_DASH_RESOLVE_URL_MEDIA, - GF_DASH_RESOLVE_URL_INIT, - GF_DASH_RESOLVE_URL_INDEX, - //same as GF_DASH_RESOLVE_URL_MEDIA but does not replace $Time$ and $Number$ - GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE, -} GF_DASHURLResolveType; - - - -static GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Group *group, const char *mpd_url, GF_DASHURLResolveType resolve_type, u32 item_index, char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url) +static GF_Err gf_dash_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_DASH_Group *group, const char *mpd_url, GF_MPD_URLResolveType resolve_type, u32 item_index, char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url, char **out_key_url, bin128 *out_key_iv) { - GF_MPD_BaseURL *url_child; - GF_MPD_SegmentTimeline *timeline = NULL; - u32 start_number = 1; + GF_Err e; GF_MPD_AdaptationSet *set = group->adaptation_set; GF_MPD_Period *period = group->period; u32 timescale; - char *url; - char *url_to_solve, *solved_template, *first_sep, *media_url; - char *init_template, *index_template; - - *out_range_start = *out_range_end = 0; - *out_url = NULL; if (!group->timeline_setup) { gf_dash_group_timeline_setup(mpd, group, 0); group->timeline_setup = 1; + item_index = group->download_segment_index; } - /*resolve base URLs from document base (download location) to representation (media)*/ - url = gf_strdup(mpd_url); + gf_dash_resolve_duration(rep, set, period, segment_duration, ×cale, NULL, NULL); + *segment_duration = (resolve_type==GF_MPD_RESOLVE_URL_MEDIA) ? (u32) ((Double) ((*segment_duration) * 1000.0) / timescale) : 0; - url_child = gf_list_get(mpd->base_URLs, 0); - if (url_child) { - char *t_url = gf_url_concatenate(url, url_child->URL); - gf_free(url); - url = t_url; + e = gf_mpd_resolve_url(mpd, rep, set, period, mpd_url, resolve_type, item_index, group->nb_segments_purged, out_url, out_range_start, out_range_end, segment_duration, is_in_base_url, out_key_url, out_key_iv); + if (e == GF_NON_COMPLIANT_BITSTREAM) { + group->selection = GF_DASH_GROUP_NOT_SELECTABLE; } + return e; +} - url_child = gf_list_get(period->base_URLs, 0); - if (url_child) { - char *t_url = gf_url_concatenate(url, url_child->URL); - gf_free(url); - url = t_url; - } +static void dash_do_rate_adaptation(GF_DashClient *dash, GF_DASH_Group *group, GF_MPD_Representation *rep) +{ + Double bitrate, time, speed; + u32 k, dl_rate; + Bool go_up = GF_FALSE; + u32 nb_inter_rep = 0; + GF_MPD_Representation *new_rep; + u32 total_size, bytes_per_sec; - url_child = gf_list_get(set->base_URLs, 0); - if (url_child) { - char *t_url = gf_url_concatenate(url, url_child->URL); - gf_free(url); - url = t_url; - } + if (dash->auto_switch_count) return; + if (group->dash->disable_switching) return; - url_child = gf_list_get(rep->base_URLs, 0); - if (url_child) { - char *t_url = gf_url_concatenate(url, url_child->URL); - gf_free(url); - url = t_url; - } + total_size = dash->dash_io->get_total_size(dash->dash_io, group->segment_download); + bytes_per_sec = dash->dash_io->get_bytes_per_sec(dash->dash_io, group->segment_download); + group->last_segment_time = gf_sys_clock(); - gf_dash_resolve_duration(rep, set, period, segment_duration, ×cale, NULL, NULL); - *segment_duration = (resolve_type==GF_DASH_RESOLVE_URL_MEDIA) ? (u32) ((Double) ((*segment_duration) * 1000.0) / timescale) : 0; - - /*single URL*/ -// if (rep->segment_base || set->segment_base || period->segment_base) { - if (!rep->segment_list && !set->segment_list && !period->segment_list && !rep->segment_template && !set->segment_template && !period->segment_template) { - GF_MPD_URL *res_url; - GF_MPD_SegmentBase *base_seg = NULL; - if (item_index > 0) - return GF_EOS; - switch (resolve_type) { - case GF_DASH_RESOLVE_URL_MEDIA: - case GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE: - if (!url) return GF_NON_COMPLIANT_BITSTREAM; - *out_url = url; - return GF_OK; - case GF_DASH_RESOLVE_URL_INIT: - case GF_DASH_RESOLVE_URL_INDEX: - res_url = NULL; - base_seg = rep->segment_base; - if (!base_seg) base_seg = set->segment_base; - if (!base_seg) base_seg = period->segment_base; - - if (base_seg) { - if (resolve_type == GF_DASH_RESOLVE_URL_INDEX) { - res_url = base_seg->representation_index; - } else { - res_url = base_seg->initialization_segment; - } - } - if (is_in_base_url) *is_in_base_url = 0; - /*no initialization segment / index, use base URL*/ - if (res_url && res_url->sourceURL) { - *out_url = gf_url_concatenate(url, res_url->sourceURL); - gf_free(url); - } else { - *out_url = url; - if (is_in_base_url) *is_in_base_url = 1; - } - if (res_url && res_url->byte_range) { - *out_range_start = res_url->byte_range->start_range; - *out_range_end = res_url->byte_range->end_range; - } else if (base_seg && base_seg->index_range && (resolve_type == GF_DASH_RESOLVE_URL_INDEX)) { - *out_range_start = base_seg->index_range->start_range; - *out_range_end = base_seg->index_range->end_range; - } - return GF_OK; - default: - break; - } - gf_free(url); - return GF_BAD_PARAM; + if (/*(!group->buffering || !group->min_bandwidth_selected) && */ total_size && bytes_per_sec && group->current_downloaded_segment_duration) { + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Downloaded segment %s %d bytes at %d bytes per seconds - skipping rate adaptation\n", dash->dash_io->get_url(dash->dash_io, group->segment_download), total_size, bytes_per_sec)); + return; } - /*segmentList*/ - if (rep->segment_list || set->segment_list || period->segment_list) { - GF_MPD_URL *init_url, *index_url; - GF_MPD_SegmentURL *segment; - GF_List *segments = NULL; - u32 segment_count; + bitrate = 8*total_size; + bitrate /= group->current_downloaded_segment_duration; + time = total_size; + time /= bytes_per_sec; - init_url = index_url = NULL; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Downloaded segment %s %d bytes in %g seconds - duration %g sec - Bandwidth (kbps): indicated %d - computed %d - download %d\n", dash->dash_io->get_url(dash->dash_io, group->segment_download), total_size, time, group->current_downloaded_segment_duration/1000.0, rep->bandwidth/1000, (u32) bitrate, 8*bytes_per_sec/1000)); - /*apply inheritance of attributes, lowest level having preceedence*/ - if (period->segment_list) { - if (period->segment_list->initialization_segment) init_url = period->segment_list->initialization_segment; - if (period->segment_list->representation_index) index_url = period->segment_list->representation_index; - if (period->segment_list->segment_URLs) segments = period->segment_list->segment_URLs; - if (period->segment_list->start_number != (u32) -1) start_number = period->segment_list->start_number; - if (period->segment_list->segment_timeline) timeline = period->segment_list->segment_timeline; - } - if (set->segment_list) { - if (set->segment_list->initialization_segment) init_url = set->segment_list->initialization_segment; - if (set->segment_list->representation_index) index_url = set->segment_list->representation_index; - if (set->segment_list->segment_URLs) segments = set->segment_list->segment_URLs; - if (set->segment_list->start_number != (u32) -1) start_number = set->segment_list->start_number; - if (set->segment_list->segment_timeline) timeline = set->segment_list->segment_timeline; - } - if (rep->segment_list) { - if (rep->segment_list->initialization_segment) init_url = rep->segment_list->initialization_segment; - if (rep->segment_list->representation_index) index_url = rep->segment_list->representation_index; - if (rep->segment_list->segment_URLs) segments = rep->segment_list->segment_URLs; - if (rep->segment_list->start_number != (u32) -1) start_number = rep->segment_list->start_number; - if (rep->segment_list->segment_timeline) timeline = rep->segment_list->segment_timeline; - } + //adjust the download rate according to the playback speed + speed = dash->speed; + if (speed<0) speed = -speed; + dl_rate = (u32) (8*bytes_per_sec / speed); + if (rep->bandwidth < dl_rate) { + go_up = 1; + } + if (dl_rate < group->min_representation_bitrate) + dl_rate = group->min_representation_bitrate; - segment_count = gf_list_count(segments); + /*find best bandwidth that fits our bitrate*/ + new_rep = NULL; - switch (resolve_type) { - case GF_DASH_RESOLVE_URL_INIT: - if (init_url) { - if (init_url->sourceURL) { - *out_url = gf_url_concatenate(url, init_url->sourceURL); - gf_free(url); - } else { - *out_url = url; - } - if (init_url->byte_range) { - *out_range_start = init_url->byte_range->start_range; - *out_range_end = init_url->byte_range->end_range; + for (k=0; k<gf_list_count(group->adaptation_set->representations); k++) { + GF_MPD_Representation *arep = gf_list_get(group->adaptation_set->representations, k); + if (arep->playback.disabled) continue; + + if (dl_rate >= arep->bandwidth) { + if (!new_rep) new_rep = arep; + else if (go_up) { + /*try to switch to highest bitrate below available download rate*/ + if (arep->bandwidth > new_rep->bandwidth) { + if (new_rep->bandwidth > rep->bandwidth) { + nb_inter_rep ++; + } + new_rep = arep; + } else if (arep->bandwidth > rep->bandwidth) { + nb_inter_rep ++; } } else { - gf_free(url); - } - return GF_OK; - case GF_DASH_RESOLVE_URL_MEDIA: - case GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE: - if (!url) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Media URL is not set in segment list\n")); - return GF_SERVICE_ERROR; - } - if (item_index >= segment_count) { - gf_free(url); - return GF_EOS; - } - *out_url = url; - segment = gf_list_get(segments, item_index); - if (segment->media) { - *out_url = gf_url_concatenate(url, segment->media); - gf_free(url); - } - if (segment->media_range) { - *out_range_start = segment->media_range->start_range; - *out_range_end = segment->media_range->end_range; - } - if (segment->duration) { - *segment_duration = (u32) ((Double) (segment->duration) * 1000.0 / timescale); - } - return GF_OK; - case GF_DASH_RESOLVE_URL_INDEX: - if (item_index >= segment_count) { - gf_free(url); - return GF_EOS; - } - *out_url = url; - segment = gf_list_get(segments, item_index); - if (segment->index) { - *out_url = gf_url_concatenate(url, segment->index); - gf_free(url); - } - if (segment->index_range) { - *out_range_start = segment->index_range->start_range; - *out_range_end = segment->index_range->end_range; + /*try to switch to highest bitrate below available download rate*/ + if (arep->bandwidth > new_rep->bandwidth) { + new_rep = arep; + } } - return GF_OK; - default: - break; } - gf_free(url); - return GF_BAD_PARAM; - } - - /*segmentTemplate*/ - media_url = init_template = index_template = NULL; - - /*apply inheritance of attributes, lowest level having preceedence*/ - if (period->segment_template) { - if (period->segment_template->initialization) init_template = period->segment_template->initialization; - if (period->segment_template->index) index_template = period->segment_template->index; - if (period->segment_template->media) media_url = period->segment_template->media; - if (period->segment_template->start_number != (u32) -1) start_number = period->segment_template->start_number; - if (period->segment_template->segment_timeline) timeline = period->segment_template->segment_timeline; - } - if (set->segment_template) { - if (set->segment_template->initialization) init_template = set->segment_template->initialization; - if (set->segment_template->index) index_template = set->segment_template->index; - if (set->segment_template->media) media_url = set->segment_template->media; - if (set->segment_template->start_number != (u32) -1) start_number = set->segment_template->start_number; - if (set->segment_template->segment_timeline) timeline = set->segment_template->segment_timeline; - } - if (rep->segment_template) { - if (rep->segment_template->initialization) init_template = rep->segment_template->initialization; - if (rep->segment_template->index) index_template = rep->segment_template->index; - if (rep->segment_template->media) media_url = rep->segment_template->media; - if (rep->segment_template->start_number != (u32) -1) start_number = rep->segment_template->start_number; - if (rep->segment_template->segment_timeline) timeline = rep->segment_template->segment_timeline; - } - - /*offset the start_number with the number of discarded segments (no longer in our lists)*/ - start_number += group->nb_segments_purged; - - if (!media_url) { - GF_MPD_BaseURL *base = gf_list_get(rep->base_URLs, 0); - if (!base) return GF_BAD_PARAM; - media_url = base->URL; - } - url_to_solve = NULL; - switch (resolve_type) { - case GF_DASH_RESOLVE_URL_INIT: - url_to_solve = init_template; - break; - case GF_DASH_RESOLVE_URL_MEDIA: - case GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE: - url_to_solve = media_url; - break; - case GF_DASH_RESOLVE_URL_INDEX: - url_to_solve = index_template; - break; - default: - gf_free(url); - return GF_BAD_PARAM; } - if (!url_to_solve) { - gf_free(url); - return GF_OK; - } - /*let's solve the template*/ - solved_template = gf_malloc(sizeof(char)*(strlen(url_to_solve) + (rep->id ? strlen(rep->id) : 0) ) * 2 ); - solved_template[0] = 0; - strcpy(solved_template, url_to_solve); - first_sep = strchr(solved_template, '$'); - if (first_sep) first_sep[0] = 0; - - first_sep = strchr(url_to_solve, '$'); - while (first_sep) { - char szPrintFormat[50]; - char szFormat[100]; - char *format_tag; - char *second_sep = strchr(first_sep+1, '$'); - if (!second_sep) { - gf_free(url); - gf_free(solved_template); - return GF_NON_COMPLIANT_BITSTREAM; - } - second_sep[0] = 0; - format_tag = strchr(first_sep+1, '%'); - if (format_tag) { - strcpy(szPrintFormat, format_tag); - format_tag[0] = 0; - if (!strchr(format_tag, 'd') && !strchr(format_tag, 'i') && !strchr(format_tag, 'u')) - strcat(szPrintFormat, "d"); - } else { - strcpy(szPrintFormat, "%d"); - } - /* identifier is $$ -> replace by $*/ - if (!strlen(first_sep+1)) { - strcat(solved_template, "$"); - } - else if (!strcmp(first_sep+1, "RepresentationID")) { - strcat(solved_template, rep->id); - } - else if (!strcmp(first_sep+1, "Number")) { - if (resolve_type==GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE) { - strcat(solved_template, "$Number$"); + if (!dash->disable_switching && new_rep && (new_rep!=rep)) { + Bool do_switch = GF_TRUE; + //if we're switching to the next upper bitrate (no intermediate bitrates), do not immediately switch + //but for a given number of segments - this avoids fluctuation in the quality + if (go_up && ! nb_inter_rep) { + new_rep->playback.probe_switch_count++; + if (new_rep->playback.probe_switch_count > dash->probe_times_before_switch) { + new_rep->playback.probe_switch_count = 0; } else { - sprintf(szFormat, szPrintFormat, start_number + item_index); - strcat(solved_template, szFormat); + do_switch = 0; } } - else if (!strcmp(first_sep+1, "Index")) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Wrong template identifier Index detected - using Number instead\n\n")); - sprintf(szFormat, szPrintFormat, start_number + item_index); - strcat(solved_template, szFormat); - } - else if (!strcmp(first_sep+1, "Bandwidth")) { - sprintf(szFormat, szPrintFormat, rep->bandwidth); - strcat(solved_template, szFormat); - } - else if (!strcmp(first_sep+1, "Time")) { - if (resolve_type==GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE) { - strcat(solved_template, "$Time$"); - } else if (timeline) { - /*uses segment timeline*/ - u32 k, nb_seg, cur_idx, nb_repeat; - u64 time, start_time; - nb_seg = gf_list_count(timeline->entries); - cur_idx = 0; - start_time=0; - for (k=0; k<nb_seg; k++) { - GF_MPD_SegmentTimelineEntry *ent = gf_list_get(timeline->entries, k); - if (item_index>cur_idx+ent->repeat_count) { - cur_idx += 1 + ent->repeat_count; - if (ent->start_time) start_time = ent->start_time; - - start_time += ent->duration * (1 + ent->repeat_count); - continue; - } - *segment_duration = ent->duration; - *segment_duration = (u32) ((Double) (*segment_duration) * 1000.0 / timescale); - nb_repeat = item_index - cur_idx; - time = ent->start_time ? ent->start_time : start_time; - time += nb_repeat * ent->duration; - - /*replace final 'd' with LLD (%lld or I64d)*/ - szPrintFormat[strlen(szPrintFormat)-1] = 0; - strcat(szPrintFormat, &LLD[1]); - sprintf(szFormat, szPrintFormat, time); - strcat(solved_template, szFormat); - break; - } - } + if (do_switch) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("\n\n[DASH] Download rate %d - switching representation %s from bandwidth %d bps to %d bps at UTC "LLU" ms\n\n", dl_rate, go_up ? "up" : "down", rep->bandwidth, new_rep->bandwidth, gf_net_get_utc() )); + gf_dash_set_group_representation(group, new_rep); } - else { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unknown template identifier %s - disabling rep\n\n", first_sep+1)); - *out_url = NULL; - gf_free(url); - gf_free(solved_template); - group->selection = GF_DASH_GROUP_NOT_SELECTABLE; - return GF_NON_COMPLIANT_BITSTREAM; + + for (k=0; k<gf_list_count(group->adaptation_set->representations); k++) { + GF_MPD_Representation *arep = gf_list_get(group->adaptation_set->representations, k); + if (new_rep==arep) continue; + arep->playback.probe_switch_count = 0; } - if (format_tag) format_tag[0] = '%'; - second_sep[0] = '$'; - /*look for next keyword - copy over remaining text if any*/ - first_sep = strchr(second_sep+1, '$'); - if (first_sep) first_sep[0] = 0; - if (strlen(second_sep+1)) - strcat(solved_template, second_sep+1); - if (first_sep) first_sep[0] = '$'; - } - *out_url = gf_url_concatenate(url, solved_template); - gf_free(url); - gf_free(solved_template); - return GF_OK; + } } static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group *group) { GF_Err e; char *base_init_url; + char *init_segment_local_url; GF_MPD_Representation *rep; u64 start_range, end_range; + char mime[128]; + const char *mime_type; /* This variable is 0 if there is a initURL, the index of first segment downloaded otherwise */ u32 nb_segment_read = 0; + char *key_url=NULL; + bin128 key_iv; + if (!dash || !group) return GF_BAD_PARAM; gf_mx_p(dash->dl_mutex); - assert( group->adaptation_set && group->adaptation_set->representations ); + assert(group->adaptation_set && group->adaptation_set->representations); rep = gf_list_get(group->adaptation_set->representations, group->active_rep_index); if (!rep) { gf_mx_v(dash->dl_mutex); @@ -2412,7 +2252,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * } start_range = end_range = 0; - e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL); + e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_MPD_RESOLVE_URL_INIT, 0, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL, &key_url, &key_iv); if (e) { gf_mx_v(dash->dl_mutex); GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unable to resolve initialization URL: %s\n", gf_error_to_string(e) )); @@ -2422,7 +2262,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * /*no error and no init segment, go for media segment - this is needed for TS so that the set of media streams can be declared to the player */ if (!base_init_url) { - e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL); + e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_MPD_RESOLVE_URL_MEDIA, group->download_segment_index, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL, &key_url, &key_iv); if (e) { gf_mx_v(dash->dl_mutex); GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unable to resolve media URL: %s\n", gf_error_to_string(e) )); @@ -2439,6 +2279,10 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * group->cached[0].url = gf_strdup(base_init_url); group->cached[0].representation_index = group->active_rep_index; group->prev_active_rep_index = group->active_rep_index; + if (key_url) { + group->cached[0].key_url = key_url; + memcpy(group->cached[0].key_IV, key_iv, sizeof(bin128)); + } group->nb_cached_segments = 1; /*do not erase local files*/ @@ -2448,12 +2292,16 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * } group->download_segment_index += nb_segment_read; - group->segment_local_url = group->cached[0].cache; - group->local_url_start_range = start_range; - group->local_url_end_range = end_range; - rep->playback.cached_init_segment_url = gf_strdup(group->segment_local_url); - rep->playback.init_start_range = start_range; - rep->playback.init_end_range = end_range; + init_segment_local_url = group->cached[0].cache; + if (group->bitstream_switching) { + group->bs_switching_init_segment_url = gf_strdup(init_segment_local_url); + group->bs_switching_init_segment_url_start_range = start_range; + group->bs_switching_init_segment_url_end_range = end_range; + } else { + rep->playback.cached_init_segment_url = gf_strdup(init_segment_local_url); + rep->playback.init_start_range = start_range; + rep->playback.init_end_range = end_range; + } /*finally download all init segments if any*/ @@ -2461,12 +2309,12 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * u32 k; for (k=0; k<gf_list_count(group->adaptation_set->representations); k++) { char *a_base_init_url = NULL; - u64 a_start, a_end, a_dur; + u64 a_start = 0, a_end = 0, a_dur = 0; GF_MPD_Representation *a_rep = gf_list_get(group->adaptation_set->representations, k); if (a_rep==rep) continue; if (a_rep->playback.disabled) continue; - e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur, NULL); + e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_MPD_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur, NULL, &a_rep->playback.key_url, &a_rep->playback.key_IV); if (!e && a_base_init_url) { a_rep->playback.cached_init_segment_url = a_base_init_url; a_rep->playback.init_start_range = a_start; @@ -2477,7 +2325,7 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * } } } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] First segment is %s \n", group->segment_local_url)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] First segment is %s \n", init_segment_local_url)); gf_mx_v(dash->dl_mutex); gf_free(base_init_url); return GF_OK; @@ -2486,149 +2334,184 @@ static GF_Err gf_dash_download_init_segment(GF_DashClient *dash, GF_DASH_Group * group->max_bitrate = 0; group->min_bitrate = (u32)-1; /*use persistent connection for segment downloads*/ - e = gf_dash_download_resource(dash->dash_io, &(group->segment_download), base_init_url, start_range, end_range, 1, group); + e = gf_dash_download_resource(dash, &(group->segment_download), base_init_url, start_range, end_range, 1, group); if ((e==GF_OK) && group->force_switch_bandwidth && !dash->auto_switch_count) { + gf_free(base_init_url); + if (key_url) gf_free(key_url); gf_dash_switch_group_representation(dash, group); gf_mx_v(dash->dl_mutex); return gf_dash_download_init_segment(dash, group); } - if (e == GF_URL_ERROR && !base_init_url) { /* We have a 404 and started with segments */ + if ((e==GF_URL_ERROR) && base_init_url && !group->download_abort_type) { /* We have a 404 and started with segments */ /* It is possible that the first segment has been deleted while we made the first request... - * so we try with the next segment on some M3U8 servers */ - + * so we try with the next segment on some M3U8 servers */ gf_free(base_init_url); - - e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index + 1, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL); - if (!e) { + if (key_url) gf_free(key_url); + e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_MPD_RESOLVE_URL_MEDIA, group->download_segment_index + 1, &base_init_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL, &key_url, &key_iv); + if (e != GF_OK) { gf_mx_v(dash->dl_mutex); return e; } GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Download of first segment failed... retrying with second one : %s\n", base_init_url)); nb_segment_read = 2; /*use persistent connection for segment downloads*/ - e = gf_dash_download_resource(dash->dash_io, &(group->segment_download), base_init_url, 0, 0, 1, group); + e = gf_dash_download_resource(dash, &(group->segment_download), base_init_url, 0, 0, 1, group); } /* end of 404 */ + + if ((e==GF_IP_CONNECTION_CLOSED) && group->download_abort_type) { + group->download_abort_type = 0; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Aborted while downloading init segment (seek ?)%s \n", base_init_url)); + gf_free(base_init_url); + if (key_url) gf_free(key_url); + return GF_OK; + } + if (e!= GF_OK && !group->segment_must_be_streamed) { dash->mpd_stop_request = 1; gf_mx_v(dash->dl_mutex); gf_free(base_init_url); + if (key_url) gf_free(key_url); return e; - } else { - char mime[128]; - const char *mime_type; - if (!group->nb_segments_in_rep) { - if (dash->mpd->type==GF_MPD_TYPE_STATIC) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] 0 segments in static representation, aborting\n")); - gf_free(base_init_url); - gf_mx_v(dash->dl_mutex); - return GF_BAD_PARAM; - } - } else if (group->nb_segments_in_rep < group->max_cached_segments) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Resizing to %u max_cached_segments elements instead of %u.\n", group->nb_segments_in_rep, group->max_cached_segments)); - /* OK, we have a problem, it may ends download */ - group->max_cached_segments = group->nb_segments_in_rep; - } - - /* Mime-Type check */ - mime_type = dash->dash_io->get_mime(dash->dash_io, group->segment_download) ; - strcpy(mime, mime_type ? mime_type : ""); - strlwr(mime); + } - if (dash->mimeTypeForM3U8Segments) - gf_free(dash->mimeTypeForM3U8Segments); - dash->mimeTypeForM3U8Segments = gf_strdup( mime ); - mime_type = gf_dash_get_mime_type(NULL, rep, group->adaptation_set); - if (!rep->mime_type) { - rep->mime_type = gf_strdup( mime_type ? mime_type : mime ); - mime_type = gf_dash_get_mime_type(NULL, rep, group->adaptation_set); + if (!group->nb_segments_in_rep) { + if (dash->mpd->type==GF_MPD_TYPE_STATIC) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] 0 segments in static representation, aborting\n")); + gf_free(base_init_url); + gf_mx_v(dash->dl_mutex); + if (key_url) gf_free(key_url); + return GF_BAD_PARAM; } + } else if (group->nb_segments_in_rep < group->max_cached_segments) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Resizing to %u max_cached_segments elements instead of %u.\n", group->nb_segments_in_rep, group->max_cached_segments)); + /* OK, we have a problem, it may ends download */ + group->max_cached_segments = group->nb_segments_in_rep; + } - if (stricmp(mime, mime_type)) { - Bool valid = 0; - char *stype1, *stype2; - stype1 = strchr(mime_type, '/'); - stype2 = strchr(mime, '/'); - if (stype1 && stype2 && !strcmp(stype1, stype2)) valid = 1; - - if (!valid && 0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Mime '%s' is not correct for '%s', it should be '%s'\n", mime, base_init_url, mime_type)); - dash->mpd_stop_request = 0; - gf_mx_v(dash->dl_mutex); - gf_free(base_init_url); - base_init_url = NULL; - return GF_BAD_PARAM; - } - } + /* Mime-Type check */ + mime_type = dash->dash_io->get_mime(dash->dash_io, group->segment_download) ; + strcpy(mime, mime_type ? mime_type : ""); + strlwr(mime); - if (group->segment_must_be_streamed ) { - group->segment_local_url = dash->dash_io->get_url(dash->dash_io, group->segment_download); - e = GF_OK; - } else { - group->segment_local_url = dash->dash_io->get_cache_name(dash->dash_io, group->segment_download); - } + if (dash->mimeTypeForM3U8Segments) + gf_free(dash->mimeTypeForM3U8Segments); + dash->mimeTypeForM3U8Segments = gf_strdup( mime ); + mime_type = gf_dash_get_mime_type(NULL, rep, group->adaptation_set); - if ((e!=GF_OK) || !group->segment_local_url) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error with initialization segment: download result:%s, cache file:%s\n", gf_error_to_string(e), group->segment_local_url)); - dash->mpd_stop_request = 1; + if (!rep->mime_type) { + rep->mime_type = gf_strdup( mime_type ? mime_type : mime ); + mime_type = gf_dash_get_mime_type(NULL, rep, group->adaptation_set); + } + //disable mime type check +#if 0 + if (stricmp(mime, mime_type)) { + Bool valid = GF_FALSE; + char *stype1, *stype2; + stype1 = strchr(mime_type, '/'); + stype2 = strchr(mime, '/'); + if (stype1 && stype2 && !strcmp(stype1, stype2)) valid = 1; + + if (!valid) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Mime '%s' is not correct for '%s', it should be '%s'\n", mime, base_init_url, mime_type)); + dash->mpd_stop_request = 0; gf_mx_v(dash->dl_mutex); gf_free(base_init_url); + if (key_url) gf_free(key_url); return GF_BAD_PARAM; } + } +#endif - assert(!group->nb_cached_segments); - group->cached[0].cache = gf_strdup(group->segment_local_url); - group->cached[0].url = gf_strdup( dash->dash_io->get_url(dash->dash_io, group->segment_download) ); - group->cached[0].representation_index = group->active_rep_index; - group->cached[0].duration = (u32) group->current_downloaded_segment_duration; - rep->playback.cached_init_segment_url = gf_strdup(group->segment_local_url); - rep->playback.init_start_range = 0; - rep->playback.init_end_range = 0; + if (group->segment_must_be_streamed ) { + init_segment_local_url = (char *) dash->dash_io->get_url(dash->dash_io, group->segment_download); + e = GF_OK; + } else { + init_segment_local_url = (char *) dash->dash_io->get_cache_name(dash->dash_io, group->segment_download); + } - group->nb_cached_segments = 1; - group->download_segment_index += nb_segment_read; - gf_dash_update_buffering(group, dash); - - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Adding initialization segment %s to cache: %s\n", group->segment_local_url, group->cached[0].url )); + if ((e!=GF_OK) || !init_segment_local_url) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error with initialization segment: download result:%s, cache file: %s\n", gf_error_to_string(e), init_segment_local_url ? init_segment_local_url : "UNKNOWN")); + dash->mpd_stop_request = 1; gf_mx_v(dash->dl_mutex); gf_free(base_init_url); + if (key_url) gf_free(key_url); + return GF_BAD_PARAM; + } - /*finally download all init segments if any*/ - if (!group->bitstream_switching) { - u32 k; - for (k=0; k<gf_list_count(group->adaptation_set->representations); k++) { - char *a_base_init_url = NULL; - u64 a_start, a_end, a_dur; - GF_MPD_Representation *a_rep = gf_list_get(group->adaptation_set->representations, k); - if (a_rep==rep) continue; - if (a_rep->playback.disabled) continue; + assert(!group->nb_cached_segments); + group->cached[0].cache = gf_strdup(init_segment_local_url); + group->cached[0].url = gf_strdup( dash->dash_io->get_url(dash->dash_io, group->segment_download) ); + group->cached[0].representation_index = group->active_rep_index; + group->cached[0].duration = (u32) group->current_downloaded_segment_duration; + + if (group->bitstream_switching) { + group->bs_switching_init_segment_url = gf_strdup(init_segment_local_url); + group->bs_switching_init_segment_url_start_range = 0; + group->bs_switching_init_segment_url_end_range = 0; + } else { + rep->playback.cached_init_segment_url = gf_strdup(init_segment_local_url); + rep->playback.init_start_range = 0; + rep->playback.init_end_range = 0; + } + + group->nb_cached_segments = 1; + group->download_segment_index += nb_segment_read; + gf_dash_update_buffering(group, dash); + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Adding initialization segment %s to cache: %s\n", init_segment_local_url, group->cached[0].url )); + gf_mx_v(dash->dl_mutex); + gf_free(base_init_url); + + /*download all init segments if any*/ + if (!group->bitstream_switching) { + u32 k; + for (k=0; k<gf_list_count(group->adaptation_set->representations); k++) { + char *a_base_init_url = NULL; + u64 a_start, a_end, a_dur; + GF_MPD_Representation *a_rep = gf_list_get(group->adaptation_set->representations, k); + if (a_rep==rep) continue; + if (a_rep->playback.disabled) continue; + + e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_MPD_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur, NULL, &a_rep->playback.key_url, &a_rep->playback.key_IV); + if (!e && a_base_init_url) { + e = gf_dash_download_resource(dash, &(group->segment_download), a_base_init_url, a_start, a_end, 1, group); + + if ((e==GF_IP_CONNECTION_CLOSED) && group->download_abort_type) { + group->download_abort_type = 0; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Aborted while downloading init segment (seek ?)%s \n", a_base_init_url)); - e = gf_dash_resolve_url(dash->mpd, a_rep, group, dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &a_base_init_url, &a_start, &a_end, &a_dur, NULL); - if (!e && a_base_init_url) { - e = gf_dash_download_resource(dash->dash_io, &(group->segment_download), a_base_init_url, a_start, a_end, 1, group); - if (e) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot retrieve initialization segment %s for representation: %s - discarding representation\n", a_base_init_url, gf_error_to_string(e) )); - a_rep->playback.disabled = 1; - } else { - a_rep->playback.cached_init_segment_url = gf_strdup( dash->dash_io->get_cache_name(dash->dash_io, group->segment_download) ); - a_rep->playback.init_start_range = 0; - a_rep->playback.init_end_range = 0; - } gf_free(a_base_init_url); - } else if (e) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot solve initialization segment for representation: %s - discarding representation\n", gf_error_to_string(e) )); - a_rep->playback.disabled = 1; + return GF_OK; } + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot retrieve initialization segment %s for representation: %s - discarding representation\n", a_base_init_url, gf_error_to_string(e) )); + a_rep->playback.disabled = 1; + } else { + a_rep->playback.cached_init_segment_url = gf_strdup( dash->dash_io->get_cache_name(dash->dash_io, group->segment_download) ); + a_rep->playback.init_start_range = 0; + a_rep->playback.init_end_range = 0; + } + gf_free(a_base_init_url); + } else if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot solve initialization segment for representation: %s - discarding representation\n", gf_error_to_string(e) )); + a_rep->playback.disabled = 1; } + } + } - return GF_OK; + /*if this was not an init segment, perform rate adaptation*/ + if (nb_segment_read) { + dash_do_rate_adaptation(dash, group, rep); } + + return GF_OK; } static void gf_dash_skip_disabled_representation(GF_DASH_Group *group, GF_MPD_Representation *rep, Bool for_autoswitch) @@ -2657,6 +2540,15 @@ static void gf_dash_skip_disabled_representation(GF_DASH_Group *group, GF_MPD_Re gf_dash_set_group_representation(group, rep); } + +static void gf_dash_group_reset_cache_entry(segment_cache_entry *cached) +{ + gf_free(cached->cache); + gf_free(cached->url); + if (cached->key_url) gf_free(cached->key_url); + memset(cached, 0, sizeof(segment_cache_entry)); +} + static void gf_dash_group_reset(GF_DashClient *dash, GF_DASH_Group *group) { if (group->buffering) { @@ -2678,8 +2570,7 @@ static void gf_dash_group_reset(GF_DashClient *dash, GF_DASH_Group *group) if (!dash->keep_files && !group->local_files) gf_delete_file(group->cached[group->nb_cached_segments].cache); - gf_free(group->cached[group->nb_cached_segments].cache); - gf_free(group->cached[group->nb_cached_segments].url); + gf_dash_group_reset_cache_entry(&group->cached[group->nb_cached_segments]); } group->timeline_setup = 0; } @@ -2736,7 +2627,7 @@ GF_Err gf_dash_setup_groups(GF_DashClient *dash) for (i=0; i<count; i++) { Double seg_dur; GF_DASH_Group *group; - Bool found = 0; + Bool found = GF_FALSE; Bool has_dependent_representations = GF_FALSE; GF_MPD_AdaptationSet *set = gf_list_get(period->adaptation_sets, i); for (j=0; j<gf_list_count(dash->groups); j++) { @@ -2749,6 +2640,11 @@ GF_Err gf_dash_setup_groups(GF_DashClient *dash) if (found) continue; + if (! gf_list_count(set->representations)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Empty adaptation set found (ID %s) - ignoring\n", set->id)); + continue; + } + GF_SAFEALLOC(group, GF_DASH_Group); if (!group) return GF_OUT_OF_MEM; @@ -2756,7 +2652,7 @@ GF_Err gf_dash_setup_groups(GF_DashClient *dash) group->adaptation_set = set; group->period = period; - group->bitstream_switching = (set->bitstream_switching || period->bitstream_switching) ? 1 : 0; + group->bitstream_switching = (set->bitstream_switching || period->bitstream_switching) ? GF_TRUE : GF_FALSE; seg_dur = 0; nb_dependant_rep = 0; @@ -2768,6 +2664,19 @@ GF_Err gf_dash_setup_groups(GF_DashClient *dash) gf_dash_get_segment_duration(rep, set, period, dash->mpd, &nb_seg, &dur); if (dur>seg_dur) seg_dur = dur; + if (group->bitstream_switching && (set->segment_base || period->segment_base || rep->segment_base) ) { + group->bitstream_switching = GF_FALSE; + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] bitstreamSwitching set for onDemand content - ignoring flag\n")); + } + + if (dash->dash_io->dash_codec_supported) { + Bool res = dash->dash_io->dash_codec_supported(dash->dash_io, rep->codecs, rep->width, rep->height, (rep->scan_type==GF_MPD_SCANTYPE_INTERLACED) ? 1 : 0, rep->framerate ? rep->framerate->num : 0, rep->framerate ? rep->framerate->den : 0, rep->samplerate); + if (!res) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Representation not supported by playback engine - ignoring\n")); + rep->playback.disabled = 1; + continue; + } + } if (dash->max_width && dash->max_height) { if ((rep->width>dash->max_width) || (rep->height>dash->max_height)) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Representation size %dx%d exceeds max display size allowed %dx%d - ignoring\n", rep->width, rep->height, dash->max_width, dash->max_height)); @@ -2982,7 +2891,7 @@ static GF_Err gf_dash_load_representation_sidx(GF_DASH_Group *group, GF_MPD_Repr } bs = gf_bs_new(mem_address, size, GF_BITSTREAM_READ); } else { - FILE *f = gf_f64_open(cache_name, "rb"); + FILE *f = gf_fopen(cache_name, "rb"); if (!f) return GF_IO_ERR; bs = gf_bs_from_file(f, GF_BITSTREAM_READ); } @@ -3006,7 +2915,7 @@ static GF_Err gf_dash_load_representation_sidx(GF_DASH_Group *group, GF_MPD_Repr break; } gf_bs_del(bs); - if (f) fclose(f); + if (f) gf_fclose(f); return e; } @@ -3026,9 +2935,9 @@ static GF_Err dash_load_box_type(const char *cache_name, u32 offset, u32 *box_ty *box_type = GF_4CC(mem_address[4], mem_address[5], mem_address[6], mem_address[7]); } else { unsigned char data[4]; - FILE *f = gf_f64_open(cache_name, "rb"); + FILE *f = gf_fopen(cache_name, "rb"); if (!f) return GF_IO_ERR; - if (gf_f64_seek(f, offset, SEEK_SET)) + if (gf_fseek(f, offset, SEEK_SET)) return GF_IO_ERR; if (fread(data, 1, 4, f) == 4) { *box_size = GF_4CC(data[0], data[1], data[2], data[3]); @@ -3036,7 +2945,7 @@ static GF_Err dash_load_box_type(const char *cache_name, u32 offset, u32 *box_ty *box_type = GF_4CC(data[0], data[1], data[2], data[3]); } } - fclose(f); + gf_fclose(f); } return GF_OK; } @@ -3044,7 +2953,7 @@ static GF_Err dash_load_box_type(const char *cache_name, u32 offset, u32 *box_ty static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) { u32 i; - GF_Err e; + GF_Err e = GF_OK; char *init_url = NULL; char *index_url = NULL; GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, 0); @@ -3055,18 +2964,18 @@ static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) /*OK we are in single-file mode, download all required indexes & co*/ for (i=0; i<gf_list_count(group->adaptation_set->representations); i++) { char *sidx_file = NULL; - u64 duration, index_start_range, index_end_range, init_start_range, init_end_range; + u64 duration, index_start_range = 0, index_end_range = 0, init_start_range, init_end_range; Bool index_in_base, init_in_base; - Bool init_needs_byte_range = 0; - Bool has_seen_sidx = 0; - Bool is_isom = 1; + Bool init_needs_byte_range = GF_FALSE; + Bool has_seen_sidx = GF_FALSE; + Bool is_isom = GF_TRUE; rep = gf_list_get(group->adaptation_set->representations, i); - index_in_base = init_in_base = 0; - e = gf_dash_resolve_url(group->dash->mpd, rep, group, group->dash->base_url, GF_DASH_RESOLVE_URL_INIT, 0, &init_url, &init_start_range, &init_end_range, &duration, &init_in_base); + index_in_base = init_in_base = GF_FALSE; + e = gf_dash_resolve_url(group->dash->mpd, rep, group, group->dash->base_url, GF_MPD_RESOLVE_URL_INIT, 0, &init_url, &init_start_range, &init_end_range, &duration, &init_in_base, NULL, NULL); if (e) goto exit; - - e = gf_dash_resolve_url(group->dash->mpd, rep, group, group->dash->base_url, GF_DASH_RESOLVE_URL_INDEX, 0, &index_url, &index_start_range, &index_end_range, &duration, &index_in_base); + + e = gf_dash_resolve_url(group->dash->mpd, rep, group, group->dash->base_url, GF_MPD_RESOLVE_URL_INDEX, 0, &index_url, &index_start_range, &index_end_range, &duration, &index_in_base, NULL, NULL); if (e) goto exit; @@ -3078,6 +2987,7 @@ static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) if (init_in_base) { GF_SAFEALLOC(rep->segment_list->initialization_segment, GF_MPD_URL); rep->segment_list->initialization_segment->sourceURL = gf_strdup(init_url); + rep->segment_list->initialization_segment->is_resolved = GF_TRUE; /*we don't want to load the entire movie */ init_needs_byte_range = 1; } @@ -3095,7 +3005,7 @@ static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Downloading init segment and SIDX for representation %s\n", init_url)); /*download first 8 bytes and check if we do have a box starting there*/ - e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), init_url, offset, 7, 1, group); + e = gf_dash_download_resource(group->dash, &(group->segment_download), init_url, offset, 7, 1, group); if (e) goto exit; cache_name = group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download); e = dash_load_box_type(cache_name, offset, &box_type, &box_size); @@ -3103,10 +3013,10 @@ static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) while (box_type) { /*we got the moov , stop here */ if (!index_in_base && (box_type==GF_4CC('m','o','o','v'))) { - e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), init_url, offset, offset+box_size-8, 2, group); + e = gf_dash_download_resource(group->dash, &(group->segment_download), init_url, offset, offset+box_size-8, 2, group); break; } else { - e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), init_url, offset, offset+box_size-1, 2, group); + e = gf_dash_download_resource(group->dash, &(group->segment_download), init_url, offset, offset+box_size-1, 2, group); offset += box_size; /*we need to refresh the cache name because of our memory astorage thing ...*/ cache_name = group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download); @@ -3129,12 +3039,49 @@ static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Done downloading init segment and SIDX\n")); GF_SAFEALLOC(rep->segment_list, GF_MPD_SegmentList); - rep->segment_list->segment_URLs =gf_list_new(); + rep->segment_list->segment_URLs = gf_list_new(); cache_name = group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download); if (init_in_base) { + char szName[100]; GF_SAFEALLOC(rep->segment_list->initialization_segment, GF_MPD_URL); - rep->segment_list->initialization_segment->sourceURL = gf_strdup(cache_name); + //we need to store the init segment since it has the same name as the rest of the segments and will be destroyed when cleaning up the cache .. + if (!strnicmp(cache_name, "gmem://", 7)) { + char *mem_address; + if (sscanf(cache_name, "gmem://%d@%p", &rep->playback.init_segment_size, &mem_address) != 2) { + e = GF_IO_ERR; + goto exit; + } + rep->playback.init_segment_data = gf_malloc(sizeof(char) * rep->playback.init_segment_size); + memcpy(rep->playback.init_segment_data, mem_address, sizeof(char) * rep->playback.init_segment_size); + + sprintf(szName, "gmem://%d@%p", rep->playback.init_segment_size, rep->playback.init_segment_data); + rep->segment_list->initialization_segment->sourceURL = gf_strdup(szName); + rep->segment_list->initialization_segment->is_resolved = GF_TRUE; + } else { + FILE *t = gf_fopen(cache_name, "rb"); + if (t) { + u32 res; + fseek(t, 0, SEEK_END); + rep->playback.init_segment_size = (u32) gf_ftell(t); + fseek(t, 0, SEEK_SET); + + rep->playback.init_segment_data = gf_malloc(sizeof(char) * rep->playback.init_segment_size); + res = (u32) fread(rep->playback.init_segment_data, sizeof(char), rep->playback.init_segment_size, t); + if (res != rep->playback.init_segment_size) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Failed to store init segment\n")); + } else { + sprintf(szName, "gmem://%d@%p", rep->playback.init_segment_size, rep->playback.init_segment_data); + rep->segment_list->initialization_segment->sourceURL = gf_strdup(szName); + rep->segment_list->initialization_segment->is_resolved = GF_TRUE; + } + } + } + + cache_name = rep->segment_list->initialization_segment->sourceURL; + //cleanup cache right away + group->dash->dash_io->delete_cache_file(group->dash->dash_io, group->segment_download, init_url); + } if (index_in_base) { sidx_file = (char *)cache_name; @@ -3143,7 +3090,7 @@ static GF_Err gf_dash_setup_single_index_mode(GF_DASH_Group *group) } /*we have index url, download it*/ if (! index_in_base) { - e = gf_dash_download_resource(group->dash->dash_io, &(group->segment_download), index_url, index_start_range, index_end_range, 1, group); + e = gf_dash_download_resource(group->dash, &(group->segment_download), index_url, index_start_range, index_end_range, 1, group); if (e) goto exit; sidx_file = (char *)group->dash->dash_io->get_cache_name(group->dash->dash_io, group->segment_download); } @@ -3178,10 +3125,137 @@ exit: return e; } +static void gf_dash_solve_period_xlink(GF_DashClient *dash, u32 period_idx) +{ + u32 count, i; + GF_Err e; + Bool is_local=GF_FALSE; + const char *local_url; + char *url; + GF_DOMParser *parser; + GF_MPD *new_mpd; + GF_MPD_Period *period; + + gf_mx_p(dash->dl_mutex); + + period = gf_list_get(dash->mpd->periods, period_idx); + if (!period->xlink_href) { + gf_mx_v(dash->dl_mutex); + return; + } + + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Resolving period XLINK %s\n", period->xlink_href)); + + if (!strcmp(period->xlink_href, "urn:mpeg:dash:resolve-to-zero:2013")) { + //spec is not very clear here, I suppose it means "remove the element" + gf_list_rem(dash->mpd->periods, period_idx); + gf_mpd_period_free(period); + gf_mx_v(dash->dl_mutex); + return; + } + + //xlink relative to our MPD base URL + url = gf_url_concatenate(dash->base_url, period->xlink_href); + + if (!strstr(url, "://") || !strnicmp(url, "file://", 7) ) { + local_url = url; + is_local=GF_TRUE; + e = GF_OK; + } else { + /*use non-persistent connection for MPD*/ + e = gf_dash_download_resource(dash, &(dash->mpd_dnload), url ? url : period->xlink_href, 0, 0, 0, NULL); + + gf_free(url); + } + + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot download xlink from periods %s: error %s\n", period->xlink_href, gf_error_to_string(e))); + gf_free(period->xlink_href); + period->xlink_href = NULL; + gf_mx_v(dash->dl_mutex); + return; + } + + if (!is_local) { + /*in case the session has been restarted, local_url may have been destroyed - get it back*/ + local_url = dash->dash_io->get_cache_name(dash->dash_io, dash->mpd_dnload); + } + + /* parse the MPD */ + parser = gf_xml_dom_new(); + e = gf_xml_dom_parse(parser, local_url, NULL, NULL); + if (is_local) gf_free(url); + + if (e != GF_OK) { + gf_xml_dom_del(parser); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot parse xlink periods: error in XML parsing %s\n", gf_error_to_string(e))); + gf_free(period->xlink_href); + period->xlink_href = NULL; + gf_mx_v(dash->dl_mutex); + return; + } + new_mpd = gf_mpd_new(); + + count = gf_xml_dom_get_root_nodes_count(parser); + for (i=0; i<count; i++) { + GF_XMLNode *root = gf_xml_dom_get_root_idx(parser, i); + if (i) { + e = gf_mpd_complete_from_dom(root, new_mpd, period->xlink_href); + } else { + e = gf_mpd_init_from_dom(root, new_mpd, period->xlink_href); + } + if (e) break; + } + gf_xml_dom_del(parser); + if (e) { + gf_free(period->xlink_href); + period->xlink_href = NULL; + gf_mpd_del(new_mpd); + gf_mx_v(dash->dl_mutex); + return; + } + + gf_list_rem(dash->mpd->periods, period_idx); + //insert all periods + while (gf_list_count(new_mpd->periods)) { + GF_MPD_Period *inserted_period = gf_list_get(new_mpd->periods, 0); + gf_list_rem(new_mpd->periods, 0); + //forbiden + if (inserted_period->xlink_href && inserted_period->xlink_actuate_on_load) { + gf_mpd_period_free(period); + continue; + } + gf_list_insert(dash->mpd->periods, inserted_period, period_idx); + period_idx++; + } + //this will do the garbage collection + gf_list_add(new_mpd->periods, period); + + gf_mpd_del(new_mpd); + + gf_mx_v(dash->dl_mutex); + +} + static GF_Err gf_dash_setup_period(GF_DashClient *dash) { GF_MPD_Period *period; u32 rep_i, group_i, j, nb_groups_ok; + u32 retry = 10; + + //solve xlink - if + while (retry) { + period = gf_list_get(dash->mpd->periods, dash->active_period_index); + if (!period->xlink_href) break; + gf_dash_solve_period_xlink(dash, dash->active_period_index); + retry --; + } + period = gf_list_get(dash->mpd->periods, dash->active_period_index); + if (period->xlink_href) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Too many xlink indirections on the same period - not supported\n")); + return GF_NOT_SUPPORTED; + } + /*setup all groups*/ gf_dash_setup_groups(dash); @@ -3191,8 +3265,9 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) u32 active_rep, nb_rep; const char *mime_type; u32 nb_rep_ok = 0; - Bool disabled = 0; - Bool cp_supported = 0; + Bool group_has_video = GF_FALSE; + Bool disabled = GF_FALSE; + Bool cp_supported = GF_FALSE; GF_DASH_Group *group = gf_list_get(dash->groups, group_i); if ((dash->debug_group_index>=0) && (group_i != (u32) dash->debug_group_index)) { @@ -3244,12 +3319,22 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) gf_dash_setup_single_index_mode(group); /* Select the appropriate representation in the given period */ + for (rep_i = 0; rep_i < nb_rep; rep_i++) { + GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, rep_i); + if (rep->width && rep->height) group_has_video = GF_TRUE; + } + + group->min_representation_bitrate = (u32) -1; active_rep = 0; for (rep_i = 0; rep_i < nb_rep; rep_i++) { GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, rep_i); rep_sel = gf_list_get(group->adaptation_set->representations, active_rep); + if (group_has_video && !rep_sel->width && !rep_sel->height && rep->width && rep->height) { + rep_sel = rep; + } + if (rep->bandwidth < group->min_representation_bitrate) { group->min_representation_bitrate = rep->bandwidth; } @@ -3264,7 +3349,7 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) ok = !strnicmp(rep->codecs, rep_sel->codecs, strlen(rep_sel->codecs) ); if (sep) sep[0] = '.'; if (!ok) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Different codec types (%s vs %s) in same AdaptationSet - disabling %s\n", rep_sel->codecs, rep->codecs, rep->codecs)); + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Different codec types (%s vs %s) in same AdaptationSet\n", rep_sel->codecs, rep->codecs)); //rep->playback.disabled = 1; //continue; } @@ -3283,8 +3368,10 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) break; }/*fallthrough if quality is not indicated*/ case GF_DASH_SELECT_BANDWIDTH_LOWEST: - if (rep->bandwidth < rep_sel->bandwidth) { - active_rep = rep_i; + if ((rep->width&&rep->height) || !group_has_video) { + if (rep->bandwidth < rep_sel->bandwidth) { + active_rep = rep_i; + } } break; case GF_DASH_SELECT_QUALITY_HIGHEST: @@ -3318,8 +3405,10 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) gf_dash_set_group_representation(group, rep_sel); - if (dash->playback_start_range>=0) - gf_dash_seek_group(dash, group); + //adjust seek + if (dash->start_range_period) { + gf_dash_seek_group(dash, group, dash->start_range_period, 0); + } mime_type = gf_dash_get_mime_type(NULL, rep_sel, group->adaptation_set); @@ -3341,6 +3430,7 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) group->selection = GF_DASH_GROUP_NOT_SELECTED; nb_groups_ok++; } + dash->start_range_period = 0; period = gf_list_get(dash->mpd->periods, dash->active_period_index); @@ -3358,75 +3448,72 @@ static GF_Err gf_dash_setup_period(GF_DashClient *dash) return GF_OK; } -static void dash_do_rate_adaptation(GF_DashClient *dash, GF_DASH_Group *group, GF_MPD_Representation *rep) +static Bool gf_dash_is_seamless_period_switch(GF_DashClient *dash) { - GF_MPD_Representation *new_rep; - u32 total_size, bytes_per_sec; + return 0; +} - if (group->dash->disable_switching) return; - total_size = dash->dash_io->get_total_size(dash->dash_io, group->segment_download); - bytes_per_sec = dash->dash_io->get_bytes_per_sec(dash->dash_io, group->segment_download); - group->last_segment_time = gf_sys_clock(); +static void gf_dash_group_check_time(GF_DASH_Group *group) +{ + s64 check_time; + u32 nb_dropped; - if (/*(!group->buffering || !group->min_bandwidth_selected) && */ total_size && bytes_per_sec && group->current_downloaded_segment_duration) { - Double bitrate, time; - u32 k, dl_rate; - Bool go_up = 0; - bitrate = 8*total_size; - bitrate /= group->current_downloaded_segment_duration; - time = total_size; - time /= bytes_per_sec; + if (group->dash->is_m3u8) return; + if (! group->timeline_setup) return; - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Downloaded segment %d bytes in %g seconds - duration %g sec - Bandwidth (kbps): indicated %d - computed %d - download %d\n", total_size, time, group->current_downloaded_segment_duration/1000.0, rep->bandwidth/1000, (u32) bitrate, 8*bytes_per_sec/1000)); + check_time = (s64) gf_net_get_utc(); + nb_dropped = 0; - dl_rate = 8*bytes_per_sec; - if (rep->bandwidth < dl_rate) { - go_up = 1; - } - if (dl_rate < group->min_representation_bitrate) - dl_rate = group->min_representation_bitrate; + while (1) { + u32 seg_dur_ms; + u64 seg_ast = gf_dash_get_segment_availability_start_time(group->dash->mpd, group, group->download_segment_index, &seg_dur_ms); - /*find best bandwidth that fits our bitrate*/ - new_rep = NULL; + s64 now = check_time + (s64) seg_dur_ms; + if (now <= (s64) seg_ast) { + group->dash->tsb_exceeded = (u32) -1; + return; + } - for (k=0; k<gf_list_count(group->adaptation_set->representations); k++) { - GF_MPD_Representation *arep = gf_list_get(group->adaptation_set->representations, k); - if (arep->playback.disabled) continue; - - if (dl_rate >= arep->bandwidth) { - if (!new_rep) new_rep = arep; - else if (go_up) { - /*try to switch to highest bitrate below availble download rate*/ - if (arep->bandwidth > new_rep->bandwidth) { - new_rep = arep; - } - } else { - /*try to switch to highest bitrate below availble download rate*/ - if (arep->bandwidth > new_rep->bandwidth) { - new_rep = arep; - } - } - } + now -= (s64) seg_ast; + if (now <= (s64) seg_dur_ms) { + group->dash->tsb_exceeded = (u32) -1; + return; + } + if (((s32) group->time_shift_buffer_depth > 0) && (now > group->time_shift_buffer_depth)) { + group->download_segment_index ++; + nb_dropped ++; + group->dash->time_in_tsb = 0; + continue; } - if (!dash->disable_switching && new_rep && (new_rep!=rep)) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("\n\n[DASH] Download rate %d - switching representation %s from bandwidth %d bps to %d bps at UTC "LLU" ms\n\n", dl_rate, go_up ? "up" : "down", rep->bandwidth, new_rep->bandwidth, gf_net_get_utc() )); - gf_dash_set_group_representation(group, new_rep); + if (nb_dropped > group->dash->tsb_exceeded) { + group->dash->tsb_exceeded = nb_dropped; } + + now -= group->dash->user_buffer_ms; + if (now<0) return; + + if (now>group->dash->time_in_tsb) + group->dash->time_in_tsb = (u32) now; + return; } } + static u32 dash_main_thread_proc(void *par) { GF_Err e; GF_DashClient *dash = (GF_DashClient*) par; GF_MPD_Representation *rep; u32 i, group_count, ret = 0; - Bool go_on = 1; + Bool go_on = GF_TRUE; u32 min_wait = 0; - Bool first_period_in_mpd = 1; + Bool first_period_in_mpd = GF_TRUE; char *new_base_seg_url; + char *key_url=NULL; + bin128 key_iv; + assert(dash); if (!dash->mpd) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Incorrect state, no dash->mpd for URL=%s, already stopped ?\n", dash->base_url)); @@ -3465,7 +3552,6 @@ restart_period: e = gf_dash_download_init_segment(dash, group); if (e) break; } - dash->mpd_stop_request=0; first_period_in_mpd = 0; /*if error signal to the user*/ @@ -3513,17 +3599,21 @@ restart_period: u32 diff = gf_sys_clock(); dash->force_mpd_update = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] At %d Time to update the playlist (%u ms elapsed since last refresh and min reload rate is %u)\n", gf_sys_clock() , timer, dash->mpd->minimum_update_period)); + gf_mx_p(dash->dl_mutex); e = gf_dash_update_manifest(dash); + gf_mx_v(dash->dl_mutex); group_count = gf_list_count(dash->groups); diff = gf_sys_clock() - diff; if (e) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error updating MPD %s\n", gf_error_to_string(e))); + if (!dash->in_error) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error updating MPD %s\n", gf_error_to_string(e))); + } } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Updated MPD in %d ms\n", diff)); } } else { - Bool all_groups_done = 1; - Bool cache_full = 1; + Bool all_groups_done = GF_TRUE; + Bool cache_full = GF_TRUE; /*wait if nothing is ready to be downloaded*/ if (min_wait>1) { @@ -3534,10 +3624,15 @@ restart_period: /*check if cache is not full*/ gf_mx_p(dash->dl_mutex); + dash->tsb_exceeded = 0; + dash->time_in_tsb = 0; for (i=0; i<group_count; i++) { GF_DASH_Group *group = gf_list_get(dash->groups, i); if ((group->selection != GF_DASH_GROUP_SELECTED) || group->done) continue; all_groups_done = 0; + if (dash->mpd->type==GF_MPD_TYPE_DYNAMIC) { + gf_dash_group_check_time(group); + } if (group->nb_cached_segments<group->max_cached_segments) { cache_full = 0; break; @@ -3545,17 +3640,41 @@ restart_period: } gf_mx_v(dash->dl_mutex); + if (dash->tsb_exceeded) { + dash->dash_io->on_dash_event(dash->dash_io, GF_DASH_EVENT_TIMESHIFT_OVERFLOW, (s32) dash->tsb_exceeded, GF_OK); + dash->tsb_exceeded = 0; + } else if (dash->time_in_tsb != dash->prev_time_in_tsb) { + dash->prev_time_in_tsb = dash->time_in_tsb; + dash->dash_io->on_dash_event(dash->dash_io, GF_DASH_EVENT_TIMESHIFT_UPDATE, 0, GF_OK); + } + + if (!cache_full) break; + //seek request if (dash->request_period_switch==2) all_groups_done = 1; + if (all_groups_done && dash->next_period_checked) { + dash->next_period_checked = 1; + //check if we can continue next period with the same groups + if (gf_dash_is_seamless_period_switch(dash)) { + all_groups_done = 0; + } + } if (all_groups_done && dash->request_period_switch) { gf_dash_reset_groups(dash); - if (dash->request_period_switch == 1) - dash->active_period_index++; + if (dash->request_period_switch == 1) { + if (dash->speed<0) { + if (dash->active_period_index) { + dash->active_period_index--; + } + } else { + dash->active_period_index++; + } + } dash->request_period_switch = 0; - + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Switching to period #%d\n", dash->active_period_index+1)); goto restart_period; } @@ -3575,7 +3694,7 @@ restart_period: for (i=0; i<group_count; i++) { //commented out as we end up doing too many requets #if 0 - Bool in_segment_avail_time=0; + Bool in_segment_avail_time = GF_FALSE; #endif u64 start_range, end_range; Bool use_byterange; @@ -3606,8 +3725,12 @@ restart_period: if (group->nb_segments_in_rep && (group->download_segment_index >= (s32) group->nb_segments_in_rep)) { u32 timer = gf_sys_clock() - dash->last_update_time; Bool update_playlist = 0; + + /* this period is done*/ + if ((dash->mpd->type==GF_MPD_TYPE_DYNAMIC) && group->period->duration) { + } /* update of the playlist, only if indicated */ - if (dash->mpd->minimum_update_period && (timer > dash->mpd->minimum_update_period)) { + else if (dash->mpd->minimum_update_period && (timer > dash->mpd->minimum_update_period)) { update_playlist = 1; } /* if media_presentation_duration is 0 and we are in live, force a refresh (not in the spec but safety check*/ @@ -3624,13 +3747,19 @@ restart_period: group_count = gf_list_count(dash->groups); rep = gf_list_get(group->adaptation_set->representations, group->active_rep_index); } else { - gf_sleep(16); + gf_sleep(1); } /* Now that the playlist is up to date, we can check again */ if (group->download_segment_index >= (s32) group->nb_segments_in_rep) { /* if there is a specified update period, we redo the whole process */ if (dash->mpd->minimum_update_period || dash->mpd->type==GF_MPD_TYPE_DYNAMIC) { - if (! group->maybe_end_of_stream) { + + if ((dash->mpd->type==GF_MPD_TYPE_DYNAMIC) && group->period->duration) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Last segment in period (dynamic mode) - group is done\n")); + group->done = 1; + break; + } + else if (! group->maybe_end_of_stream) { u32 now = gf_sys_clock(); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] End of segment list reached (%d segments but idx is %d), waiting for next MPD update\n", group->nb_segments_in_rep, group->download_segment_index)); if (group->nb_cached_segments) @@ -3642,14 +3771,16 @@ restart_period: } if (now - group->time_at_first_reload_required < group->cache_duration) continue; + if (dash->mpd->minimum_update_period && (now - group->time_at_first_reload_required < dash->mpd->minimum_update_period)) + continue; - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Segment list has not been updated for more than %d ms - assuming end of stream\n", now - group->time_at_first_reload_required)); + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Segment list has not been updated for more than %d ms - assuming end of period\n", now - group->time_at_first_reload_required)); group->done = 1; break; } } else { /* if not, we are really at the end of the playlist, we can quit */ - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] End of playlist reached... downloading remaining elements...")); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] End of period reached for group\n")); group->done = 1; break; } @@ -3689,6 +3820,7 @@ restart_period: /*if segment AST is greater than now, it is not yet available - we would need an estimate on how long the request takes to be sent to the server in order to be more reactive ...*/ if (to_wait > 1) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Set #%d At %d Next segment %d (AST "LLD" - sec in period %g) is not yet available on server - requesting later in %d ms\n", i+1, gf_sys_clock(), group->download_segment_index + start_number, segment_ast, (segment_ast - group->period->start - group->ast_at_init)/1000.0, to_wait)); if (group->last_segment_time) { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] %d ms elapsed since previous segment download\n", clock_time - group->last_segment_time)); @@ -3696,6 +3828,7 @@ restart_period: gf_mx_v(dash->dl_mutex); if (!min_wait || ((u32) to_wait < min_wait)) min_wait = to_wait; + continue; } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Set #%d At %d Next segment %d (AST "LLD" - sec in period %g) should now be available on server since %d ms - requesting it\n", i+1, gf_sys_clock(), group->download_segment_index + start_number, segment_ast, (segment_ast - group->period->start - group->ast_at_init)/1000.0, -to_wait)); @@ -3714,7 +3847,7 @@ restart_period: /* At this stage, there are some segments left to be downloaded */ - e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA, group->download_segment_index, &new_base_seg_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL); + e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_MPD_RESOLVE_URL_MEDIA, group->download_segment_index, &new_base_seg_url, &start_range, &end_range, &group->current_downloaded_segment_duration, NULL, &key_url, &key_iv); gf_mx_v(dash->dl_mutex); if (e) { /*do something!!*/ @@ -3745,11 +3878,22 @@ restart_period: /*use persistent connection for segment downloads*/ if (use_byterange) { - e = gf_dash_download_resource(dash->dash_io, &(group->segment_download), new_base_seg_url, start_range, end_range, 1, group); + e = gf_dash_download_resource(dash, &(group->segment_download), new_base_seg_url, start_range, end_range, 1, group); } else { - e = gf_dash_download_resource(dash->dash_io, &(group->segment_download), new_base_seg_url, 0, 0, 1, group); + e = gf_dash_download_resource(dash, &(group->segment_download), new_base_seg_url, 0, 0, 1, group); } + if ((e==GF_IP_CONNECTION_CLOSED) && group->download_abort_type) { + group->download_abort_type = 0; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Aborted while downloading segment (seek ?)%s \n", new_base_seg_url)); + gf_free(new_base_seg_url); + gf_free(key_url); + new_base_seg_url = NULL; + key_url = NULL; + continue; + } + + /*TODO decide what is the best, fetch from another representation or ignore ...*/ if (e != GF_OK) { clock_time = gf_sys_clock(); @@ -3758,14 +3902,21 @@ restart_period: if (group->maybe_end_of_stream) { if (group->maybe_end_of_stream==2) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Couldn't get segment %s (error %s) and end of period was guessed during last update - stoping playback\n", new_base_seg_url, gf_error_to_string(e))); + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Couldn't get segment %s (error %s) and end of period was guessed during last update - stopping playback\n", new_base_seg_url, gf_error_to_string(e))); group->maybe_end_of_stream = 0; group->done = 1; } group->maybe_end_of_stream++; } else if (group->segment_in_valid_range) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error in downloading new segment: %s %s - segment was lost at server/proxy side\n", new_base_seg_url, gf_error_to_string(e))); - group->download_segment_index++; + if (dash->speed >= 0) { + group->download_segment_index++; + } else if (group->download_segment_index) { + group->download_segment_index--; + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Playing in backward - start of playlist reached - assuming end of stream\n")); + group->done = 1; + } group->segment_in_valid_range=0; } else if (group->prev_segment_ok && !group->time_at_first_failure) { if (!group->loop_detected) { @@ -3792,11 +3943,20 @@ restart_period: #endif { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error in downloading new segment: %s %s\n", new_base_seg_url, gf_error_to_string(e))); - group->download_segment_index++; + if (dash->speed >= 0) { + group->download_segment_index++; + } else if (group->download_segment_index) { + group->download_segment_index--; + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Playing in backward - start of playlist reached - assuming end of stream\n")); + group->done = 1; + } } } gf_free(new_base_seg_url); + gf_free(key_url); new_base_seg_url = NULL; + key_url = NULL; continue; } @@ -3814,6 +3974,8 @@ restart_period: i--; gf_free(new_base_seg_url); new_base_seg_url = NULL; + gf_free(key_url); + key_url = NULL; continue; } if (rep->playback.disabled) { @@ -3822,6 +3984,8 @@ restart_period: i--; gf_free(new_base_seg_url); new_base_seg_url = NULL; + gf_free(key_url); + key_url = NULL; continue; } } @@ -3834,15 +3998,16 @@ restart_period: } resource_name = dash->dash_io->get_url(dash->dash_io, group->segment_download); - if (!dash->auto_switch_count) - dash_do_rate_adaptation(dash, group, rep); + dash_do_rate_adaptation(dash, group, rep); } if (local_file_name && (e == GF_OK || group->segment_must_be_streamed )) { gf_mx_p(dash->dl_mutex); + assert(group->nb_cached_segments<group->max_cached_segments); - assert( local_file_name ); - if (! empty_file) { + assert(local_file_name); + + if (!empty_file) { group->cached[group->nb_cached_segments].cache = gf_strdup(local_file_name); group->cached[group->nb_cached_segments].url = gf_strdup( resource_name ); @@ -3851,6 +4016,12 @@ restart_period: group->cached[group->nb_cached_segments].representation_index = representation_index; group->cached[group->nb_cached_segments].duration = (u32) group->current_downloaded_segment_duration; group->cached[group->nb_cached_segments].loop_detected = group->loop_detected; + if (key_url) { + group->cached[group->nb_cached_segments].key_url = key_url; + memcpy(group->cached[group->nb_cached_segments].key_IV, key_iv, sizeof(bin128)); + key_url = NULL; + } + group->loop_detected = GF_FALSE; if (group->local_files && use_byterange) { @@ -3863,12 +4034,22 @@ restart_period: } /* download enhancement representation of this segment*/ - if ((representation_index != group->force_max_rep_index) && rep->enhancement_rep_index_plus_one) + if ((representation_index != group->force_max_rep_index) && rep->enhancement_rep_index_plus_one) { group->active_rep_index = rep->enhancement_rep_index_plus_one - 1; + group->has_pending_enhancement = GF_TRUE; + } /* if we have downloaded all enhancement representations of this segment, restart from base representation and increase dowloaded segment index by 1*/ else { if (group->base_rep_index_plus_one) group->active_rep_index = group->base_rep_index_plus_one - 1; - group->download_segment_index++; + if (dash->speed >= 0) { + group->download_segment_index++; + } else if (group->download_segment_index) { + group->download_segment_index--; + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Playing in backward - start of playlist reached - assuming end of stream\n")); + group->done = 1; + } + group->has_pending_enhancement = GF_FALSE; } if (dash->auto_switch_count) { group->nb_segments_done++; @@ -3877,14 +4058,21 @@ restart_period: gf_dash_skip_disabled_representation(group, rep, GF_TRUE); } } - gf_mx_v(dash->dl_mutex); + //do not notify segments if there is a pending period switch - since these are decided by the user, we don't + //want to notify old segments + if (!dash->request_period_switch && !group->has_pending_enhancement) + dash->dash_io->on_dash_event(dash->dash_io, GF_DASH_EVENT_SEGMENT_AVAILABLE, gf_list_find(dash->groups, group), GF_OK); - dash->dash_io->on_dash_event(dash->dash_io, GF_DASH_EVENT_SEGMENT_AVAILABLE, gf_list_find(dash->groups, group), GF_OK); + gf_mx_v(dash->dl_mutex); } gf_free(new_base_seg_url); new_base_seg_url = NULL; + if (key_url) { + gf_free(key_url); + key_url = NULL; + } } } @@ -3905,13 +4093,25 @@ static u32 gf_dash_period_index_from_time(GF_DashClient *dash, u32 time) { u32 i, count, cumul_start=0; GF_MPD_Period *period; + +restart: count = gf_list_count(dash->mpd->periods); for (i = 0; i<count; i++) { period = gf_list_get(dash->mpd->periods, i); + + if (period->xlink_href) { + gf_dash_solve_period_xlink(dash, i); + goto restart; + } + if ((period->start > time) || (cumul_start > time)) { break; } cumul_start+=period->duration; + + if (time < cumul_start) { + break; + } } return (i>=1 ? (i-1) : 0); } @@ -3919,11 +4119,11 @@ static u32 gf_dash_period_index_from_time(GF_DashClient *dash, u32 time) static void gf_dash_download_stop(GF_DashClient *dash) { u32 i; - assert( dash ); + assert(dash); if (dash->groups) { for (i=0; i<gf_list_count(dash->groups); i++) { GF_DASH_Group *group = gf_list_get(dash->groups, i); - assert( group ); + assert(group); if ((group->selection == GF_DASH_GROUP_SELECTED) && group->segment_download) { if (group->segment_download) dash->dash_io->abort(dash->dash_io, group->segment_download); @@ -3933,6 +4133,7 @@ static void gf_dash_download_stop(GF_DashClient *dash) } /* stop the download thread */ gf_mx_p(dash->dl_mutex); + dash->mpd_stop_request = GF_TRUE; if (dash->dash_state != GF_DASH_STATE_STOPPED) { dash->mpd_stop_request = 1; gf_mx_v(dash->dl_mutex); @@ -3940,7 +4141,7 @@ static void gf_dash_download_stop(GF_DashClient *dash) /* waiting for the download thread to stop */ gf_sleep(16); gf_mx_p(dash->dl_mutex); - if (dash->dash_state != GF_DASH_STATE_RUNNING) { + if (dash->dash_state == GF_DASH_STATE_STOPPED) { /* it's stopped we can continue */ gf_mx_v(dash->dl_mutex); break; @@ -3950,26 +4151,42 @@ static void gf_dash_download_stop(GF_DashClient *dash) } else { gf_mx_v(dash->dl_mutex); } + dash->mpd_stop_request = GF_TRUE; } -Bool gf_dash_seek_periods(GF_DashClient *dash) +static Bool gf_dash_seek_periods(GF_DashClient *dash, Double seek_time) { Double start_time; u32 i, period_idx; - + u32 nb_retry = 10; gf_mx_p(dash->dl_mutex); - dash->start_range_in_segment_at_next_period = 0; + dash->start_range_period = 0; start_time = 0; period_idx = 0; - for (i=0; i<=gf_list_count(dash->mpd->periods); i++) { + for (i=0; i<gf_list_count(dash->mpd->periods); i++) { GF_MPD_Period *period = gf_list_get(dash->mpd->periods, i); - Double dur = period->duration; + Double dur; + + if (period->xlink_href) { + gf_dash_solve_period_xlink(dash, i); + if (nb_retry) { + nb_retry --; + i--; + continue; + } + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Period still resolves to XLINK %s for more than 10 consecutive retry, ignoring it ...\n", period->xlink_href)); + gf_free(period->xlink_href); + period->xlink_href = NULL; + } else { + nb_retry = 10; + } + dur = period->duration; dur /= 1000; - if (dash->playback_start_range >= start_time) { - if ((i+1==gf_list_count(dash->mpd->periods)) || (dash->playback_start_range < start_time + dur) ) { + if (seek_time >= start_time) { + if ((i+1==gf_list_count(dash->mpd->periods)) || (seek_time < start_time + dur) ) { period_idx = i; break; } @@ -3977,61 +4194,64 @@ Bool gf_dash_seek_periods(GF_DashClient *dash) start_time += dur; } if (period_idx != dash->active_period_index) { - dash->playback_start_range -= start_time; + seek_time -= start_time; dash->active_period_index = period_idx; dash->request_period_switch = 2; - /*figure out default segment duration and substract from our start range request*/ - if (dash->playback_start_range) { - Double duration; - u32 nb_segs; - GF_MPD_Period *period = gf_list_get(dash->mpd->periods, period_idx); - GF_MPD_AdaptationSet *set = gf_list_get(period->adaptation_sets, 0); - GF_MPD_Representation *rep = gf_list_get(set->representations, 0); - - gf_dash_get_segment_duration(rep, set, period, dash->mpd, &nb_segs, &duration); - - if (duration) { - while (dash->playback_start_range - dash->start_range_in_segment_at_next_period >= duration) - dash->start_range_in_segment_at_next_period += duration; - } - - } + dash->start_range_period = seek_time; } gf_mx_v(dash->dl_mutex); return dash->request_period_switch ? 1 : 0; } -static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group) +static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group, Double seek_to, Bool is_dynamic) { Double seg_start; - u32 first_downloaded, last_downloaded, segment_idx; + u32 first_downloaded, last_downloaded, segment_idx, orig_idx; group->force_segment_switch = 0; - if (!group->segment_duration) return; + if (!is_dynamic) { - /*figure out where to seek*/ - segment_idx = 0; - seg_start = 0.0; - while (1) { - if ((dash->playback_start_range >= seg_start) && (dash->playback_start_range < seg_start + group->segment_duration)) - break; - seg_start += group->segment_duration; - segment_idx++; - } - /*todo - seek to given duration*/ - dash->playback_start_range -= seg_start; + /*figure out where to seek*/ + orig_idx = group->download_segment_index; + segment_idx = 0; + seg_start = 0.0; + while (1) { + Double dur = group->segment_duration; + if (!dur) { + group->download_segment_index = segment_idx; + //TODO this could be further optimized by directly querying the index for this start time ... + seg_start = gf_dash_get_segment_start_time(group, &dur); + } + if (!dur) + break; + if ((seek_to >= seg_start) && (seek_to < seg_start + dur)) + break; + seg_start += dur; + segment_idx++; + } + group->download_segment_index = orig_idx; - first_downloaded = last_downloaded = group->download_segment_index; - if (group->download_segment_index + 1 >= (s32) group->nb_cached_segments) { - first_downloaded = group->download_segment_index + 1 - group->nb_cached_segments; + /*remember to seek to given duration*/ + group->start_playback_range = seek_to; + + first_downloaded = last_downloaded = group->download_segment_index; + if (group->download_segment_index + 1 >= (s32) group->nb_cached_segments) { + first_downloaded = group->download_segment_index + 1 - group->nb_cached_segments; + } + /*we are seeking in our download range, just go on*/ + if ((segment_idx >= first_downloaded) && (segment_idx<=last_downloaded)) return; + + group->force_segment_switch = 1; + group->download_segment_index = segment_idx; + } else { + group->start_number_at_last_ast = 0; + /*remember to adjust time in timeline steup*/ + group->start_playback_range = seek_to; + group->timeline_setup = 0; } - /*we are seeking in our download range, just go on*/ - if ((segment_idx >= first_downloaded) && (segment_idx<=last_downloaded)) return; - group->force_segment_switch = 1; - group->download_segment_index = segment_idx; if (group->segment_download) dash->dash_io->abort(dash->dash_io, group->segment_download); @@ -4043,7 +4263,9 @@ static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group) gf_free(group->urlToDeleteNext); group->urlToDeleteNext = NULL; } + if (group->segment_download) { + dash->dash_io->abort(dash->dash_io, group->segment_download); dash->dash_io->del(dash->dash_io, group->segment_download); group->segment_download = NULL; } @@ -4052,13 +4274,12 @@ static void gf_dash_seek_group(GF_DashClient *dash, GF_DASH_Group *group) if (!dash->keep_files && !group->local_files && !group->segment_must_be_streamed) gf_delete_file(group->cached[group->nb_cached_segments].cache); - gf_free(group->cached[group->nb_cached_segments].cache); - gf_free(group->cached[group->nb_cached_segments].url); - memset(&group->cached[group->nb_cached_segments], 0, sizeof(segment_cache_entry)); + gf_dash_group_reset_cache_entry(&group->cached[group->nb_cached_segments]); } + group->done = 0; } -void gf_dash_seek_groups(GF_DashClient *dash) +static void gf_dash_seek_groups(GF_DashClient *dash, Double seek_time, Bool is_dynamic) { u32 i; @@ -4071,12 +4292,13 @@ void gf_dash_seek_groups(GF_DashClient *dash) GF_MPD_Period *period = gf_list_get(dash->mpd->periods, dash->active_period_index-1); dur += period->duration/1000.0; } - dash->playback_start_range -= dur; + seek_time -= dur; } for (i=0; i<gf_list_count(dash->groups); i++) { GF_DASH_Group *group = gf_list_get(dash->groups, i); - gf_dash_seek_group(dash, group); + gf_dash_seek_group(dash, group, seek_time, is_dynamic); } + gf_mx_v(dash->dl_mutex); } @@ -4089,7 +4311,10 @@ static GF_Err http_ifce_get(GF_FileDownload *getter, char *url) if (!sess) return GF_IO_ERR; getter->session = sess; e = dash->dash_io->init(dash->dash_io, sess); - if (e) return e; + if (e) { + dash->dash_io->del(dash->dash_io, sess); + return e; + } return dash->dash_io->run(dash->dash_io, sess); } @@ -4112,18 +4337,23 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url) { char local_path[GF_MAX_PATH]; const char *local_url; + char *sep_cgi = NULL; + char *sep_frag = NULL; GF_Err e; GF_MPD_Period *period; GF_DOMParser *mpd_parser; - Bool is_local = 0; + Bool is_local = GF_FALSE; if (!dash || !manifest_url) return GF_BAD_PARAM; - memset( dash->lastMPDSignature, 0, sizeof(dash->last_update_time)); + memset( dash->lastMPDSignature, 0, GF_SHA1_DIGEST_SIZE); dash->reload_count = 0; if (dash->base_url) gf_free(dash->base_url); + sep_cgi = strrchr(manifest_url, '?'); + if (sep_cgi) sep_cgi[0] = 0; dash->base_url = gf_strdup(manifest_url); + if (sep_cgi) sep_cgi[0] = '?'; dash->getter.udta = dash; dash->getter.new_session = http_ifce_get; @@ -4141,12 +4371,12 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url) local_url = manifest_url + 7; is_local = 1; if (strstr(manifest_url, ".m3u8")) { - dash->is_m3u8 = 1; + dash->is_m3u8 = GF_TRUE; } } else if (strstr(manifest_url, "://")) { const char *reloc_url, *mtype; char mime[128]; - e = gf_dash_download_resource(dash->dash_io, &(dash->mpd_dnload), manifest_url, 0, 0, 1, NULL); + e = gf_dash_download_resource(dash, &(dash->mpd_dnload), manifest_url, 0, 0, 1, NULL); if (e!=GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot connect service: MPD downloading problem %s for %s\n", gf_error_to_string(e), manifest_url)); dash->dash_io->del(dash->dash_io, dash->mpd_dnload); @@ -4190,9 +4420,21 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url) } if (is_local) { - FILE *f = fopen(local_url, "rt"); - if (!f) return GF_URL_ERROR; - fclose(f); + FILE *f = gf_fopen(local_url, "rt"); + if (!f) { + sep_cgi = strrchr(local_url, '?'); + if (sep_cgi) sep_cgi[0] = 0; + sep_frag = strrchr(local_url, '#'); + if (sep_frag) sep_frag[0] = 0; + + f = gf_fopen(local_url, "rt"); + if (!f) { + if (sep_cgi) sep_cgi[0] = '?'; + if (sep_frag) sep_frag[0] = '#'; + return GF_URL_ERROR; + } + } + gf_fclose(f); } dash->mpd_fetch_time = dash_get_fetch_time(dash); @@ -4207,7 +4449,10 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url) gf_m3u8_to_mpd(local_url, manifest_url, local_path, dash->reload_count, dash->mimeTypeForM3U8Segments, 0, M3U8_TO_MPD_USE_TEMPLATE, &dash->getter); local_url = local_path; } else { - gf_m3u8_to_mpd(local_url, manifest_url, NULL, dash->reload_count, dash->mimeTypeForM3U8Segments, 0, M3U8_TO_MPD_USE_TEMPLATE, &dash->getter); + const char *redirected_url = dash->dash_io->get_url(dash->dash_io, dash->mpd_dnload); + if (!redirected_url) redirected_url=manifest_url; + + gf_m3u8_to_mpd(local_url, redirected_url, NULL, dash->reload_count, dash->mimeTypeForM3U8Segments, 0, M3U8_TO_MPD_USE_TEMPLATE, &dash->getter); } } @@ -4223,6 +4468,10 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url) /* parse the MPD */ mpd_parser = gf_xml_dom_new(); e = gf_xml_dom_parse(mpd_parser, local_url, NULL, NULL); + + if (sep_cgi) sep_cgi[0] = '?'; + if (sep_frag) sep_frag[0] = '#'; + if (e != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error - cannot connect service: MPD parsing problem %s\n", gf_xml_dom_get_error(mpd_parser) )); gf_xml_dom_del(mpd_parser); @@ -4263,6 +4512,7 @@ GF_Err gf_dash_open(GF_DashClient *dash, const char *manifest_url) goto exit; } + dash->mpd_stop_request = 0; e = gf_th_run(dash->dash_thread, dash_main_thread_proc, dash); return e; @@ -4279,8 +4529,7 @@ exit: GF_EXPORT void gf_dash_close(GF_DashClient *dash) { - assert( dash ); - + assert(dash); gf_dash_download_stop(dash); gf_mx_p(dash->dl_mutex); @@ -4304,7 +4553,9 @@ GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, u32 max_cache_duration, u32 a GF_DashClient *dash; GF_SAFEALLOC(dash, GF_DashClient); dash->dash_io = dash_io; - + dash->speed = 1.0; + //wait one segment to validate we have enough bandwidth + dash->probe_times_before_switch = 1; dash->dash_thread = gf_th_new("MPD Segment Downloader Thread"); dash->dl_mutex = gf_mx_new("MPD Segment Downloader Mutex"); dash->mimeTypeForM3U8Segments = gf_strdup( "video/mp2t" ); @@ -4320,6 +4571,7 @@ GF_DashClient *gf_dash_new(GF_DASHFileIO *dash_io, u32 max_cache_duration, u32 a dash->idle_interval = 1000; dash->min_timeout_between_404 = 500; dash->segment_lost_after_ms = 100; + dash->debug_group_index = -1; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Client created\n")); return dash; @@ -4351,6 +4603,12 @@ void gf_dash_enable_utc_drift_compensation(GF_DashClient *dash, Bool estimate_ut dash->estimate_utc_drift = estimate_utc_drift; } +GF_EXPORT +void gf_dash_set_switching_probe_count(GF_DashClient *dash, u32 switch_probe_count) +{ + dash->probe_times_before_switch = switch_probe_count; +} + GF_EXPORT u32 gf_dash_get_group_count(GF_DashClient *dash) @@ -4402,6 +4660,7 @@ void gf_dash_get_info(GF_DashClient *dash, const char **title, const char **sour } } + GF_EXPORT void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool immediate_switch) { @@ -4450,6 +4709,8 @@ void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool immediate_ group->force_representation_idx_plus_one = switch_to_rep_idx; else group->force_max_rep_index = switch_to_rep_idx-1; + + if (group->local_files || immediate_switch) { u32 keep_seg_index = 0; //keep all scalable enhancements of the first segment @@ -4474,16 +4735,12 @@ void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool immediate_ group->nb_cached_segments--; gf_dash_update_buffering(group, dash); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Switching quality - delete cached segment: %s\n", group->cached[group->nb_cached_segments].url)); - gf_free(group->cached[group->nb_cached_segments].url); - group->cached[group->nb_cached_segments].url = NULL; + if (!group->local_files && group->cached[group->nb_cached_segments].cache) { gf_delete_file( group->cached[group->nb_cached_segments].cache ); - gf_free(group->cached[group->nb_cached_segments].cache); - group->cached[group->nb_cached_segments].cache = NULL; } - group->cached[group->nb_cached_segments].representation_index = 0; - group->cached[group->nb_cached_segments].start_range = 0; - group->cached[group->nb_cached_segments].end_range = 0; + gf_dash_group_reset_cache_entry(&group->cached[group->nb_cached_segments]); + group->cached[group->nb_cached_segments].duration = (u32) group->current_downloaded_segment_duration; if (group->download_segment_index>1) group->download_segment_index--; @@ -4510,16 +4767,15 @@ void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool immediate_ group->nb_cached_segments--; gf_dash_update_buffering(group, dash); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Switching quality - delete cached segment: %s\n", group->cached[group->nb_cached_segments].url)); - gf_free(group->cached[group->nb_cached_segments].url); - group->cached[group->nb_cached_segments].url = NULL; + if (!group->local_files && group->cached[group->nb_cached_segments].cache) { gf_delete_file( group->cached[group->nb_cached_segments].cache ); - gf_free(group->cached[group->nb_cached_segments].cache); - group->cached[group->nb_cached_segments].cache = NULL; } - group->cached[group->nb_cached_segments].representation_index = 0; - group->cached[group->nb_cached_segments].start_range = 0; + + gf_dash_group_reset_cache_entry(&group->cached[group->nb_cached_segments]); + group->cached[group->nb_cached_segments].duration = (u32) group->current_downloaded_segment_duration; + if (decrease_download_segment_index && group->download_segment_index>1) group->download_segment_index--; } @@ -4528,7 +4784,7 @@ void gf_dash_switch_quality(GF_DashClient *dash, Bool switch_up, Bool immediate_ group->active_rep_index = switch_to_rep_idx - 1; group->download_segment_index--; } - else { + else if (group->nb_cached_segments) { /* we remove highest scalable enhancements of the dowloaded segments, and keep another segments*/ for (k = group->nb_cached_segments - 1; k > keep_seg_index; k--) { if (group->cached[k].representation_index != current_idx) @@ -4568,12 +4824,25 @@ Double gf_dash_get_duration(GF_DashClient *dash) return duration; } +GF_EXPORT +u32 gf_dash_group_get_time_shift_buffer_depth(GF_DashClient *dash, u32 idx) +{ + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group) return 0; + return group->time_shift_buffer_depth; +} + GF_EXPORT const char *gf_dash_get_url(GF_DashClient *dash) { return dash->base_url; } +GF_EXPORT +Bool gf_dash_is_m3u8(GF_DashClient *dash) { + return dash->is_m3u8; +} + GF_EXPORT const char *gf_dash_group_get_segment_mime(GF_DashClient *dash, u32 idx) { @@ -4588,18 +4857,52 @@ const char *gf_dash_group_get_segment_mime(GF_DashClient *dash, u32 idx) GF_EXPORT const char *gf_dash_group_get_segment_init_url(GF_DashClient *dash, u32 idx, u64 *start_range, u64 *end_range) { + GF_MPD_Representation *rep; + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group) return NULL; + + if (group->bs_switching_init_segment_url) { + if (start_range) *start_range = group->bs_switching_init_segment_url_start_range; + if (end_range) *end_range = group->bs_switching_init_segment_url_end_range; + return group->bs_switching_init_segment_url; + } + + rep = gf_list_get(group->adaptation_set->representations, group->active_rep_index); + //no rep found or no init for the rep, check all reps + //this may happen when the adaptation rate algo changed the rep between the init (TS) and the next segment + if (!rep || !rep->playback.cached_init_segment_url) { + u32 i, count; + count = gf_list_count(group->adaptation_set->representations); + for (i=0; i<count; i++) { + rep = gf_list_get(group->adaptation_set->representations, i); + if (rep->playback.cached_init_segment_url) break; + rep = NULL; + } + } + if (!rep) return NULL; + if (start_range) *start_range = rep->playback.init_start_range; + if (end_range) *end_range = rep->playback.init_end_range; + return rep->playback.cached_init_segment_url; +} + +GF_EXPORT +const char *gf_dash_group_get_segment_init_keys(GF_DashClient *dash, u32 idx, bin128 *key_IV) +{ + GF_MPD_Representation *rep; GF_DASH_Group *group = gf_list_get(dash->groups, idx); if (!group) return NULL; - if (start_range) *start_range = group->local_url_start_range; - if (end_range) *end_range = group->local_url_end_range; - return group->segment_local_url; + rep = gf_list_get(group->adaptation_set->representations, group->active_rep_index); + if (!rep) return NULL; + + if (key_IV) memcpy(*key_IV, rep->playback.key_IV, sizeof(bin128)); + return rep->playback.key_url; } GF_EXPORT void gf_dash_group_select(GF_DashClient *dash, u32 idx, Bool select) { - Bool needs_resetup = 0; + Bool needs_resetup = GF_FALSE; GF_DASH_Group *group = gf_list_get(dash->groups, idx); if (!group) return; if (group->selection == GF_DASH_GROUP_NOT_SELECTABLE) @@ -4631,17 +4934,76 @@ void gf_dash_group_select(GF_DashClient *dash, u32 idx, Bool select) } GF_EXPORT -void gf_dash_groups_set_language(GF_DashClient *dash, const char *lang_3cc) +void gf_dash_groups_set_language(GF_DashClient *dash, const char *lang_code_rfc_5646) { - u32 i; - if (!lang_3cc) return; + u32 i, len; + s32 lang_idx; + char *sep; + GF_List *groups_selected; + if (!lang_code_rfc_5646) return; + + groups_selected = gf_list_new(); + + gf_mx_p(dash->dl_mutex); + + //first pass, check exact match for (i=0; i<gf_list_count(dash->groups); i++) { GF_DASH_Group *group = gf_list_get(dash->groups, i); if (group->selection==GF_DASH_GROUP_NOT_SELECTABLE) continue; - if (group->adaptation_set->lang && !stricmp(group->adaptation_set->lang, lang_3cc)) { + if (!group->adaptation_set->lang) continue; + + if (!stricmp(group->adaptation_set->lang, lang_code_rfc_5646)) { gf_dash_group_select(dash, i, 1); + gf_list_add(groups_selected, group); } } + + lang_idx = gf_lang_find(lang_code_rfc_5646); + if (lang_idx>=0) { + const char *n2cc = gf_lang_get_2cc(lang_idx); + const char *n3cc = gf_lang_get_3cc(lang_idx); + + for (i=0; i<gf_list_count(dash->groups); i++) { + GF_DASH_Group *group = gf_list_get(dash->groups, i); + if (group->selection==GF_DASH_GROUP_NOT_SELECTABLE) continue; + if (!group->adaptation_set->lang) continue; + if (gf_list_find(groups_selected, group) >= 0) continue; + + //check we didn't select one AS in this group in the previous pass or in this pass + if (group->adaptation_set->group>=0) { + u32 k; + Bool found = GF_FALSE; + for (k=0; k<gf_list_count(groups_selected); k++) { + GF_DASH_Group *ag = gf_list_get(groups_selected, k); + + if (ag->adaptation_set->group == group->adaptation_set->group) { + found = 1; + break; + } + } + if (found) continue; + } + //get the 2 or 3 land code + sep = strchr(group->adaptation_set->lang, '-'); + if (sep) { + sep[0] = 0; + } + len = (u32) strlen(group->adaptation_set->lang); + //compare with what we found + if ( ((len==3) && !stricmp(group->adaptation_set->lang, n3cc)) + || ((len==2) && !stricmp(group->adaptation_set->lang, n2cc)) + ) { + gf_dash_group_select(dash, i, 1); + gf_list_add(groups_selected, group); + } + + if (sep) sep[0] = '-'; + } + } + + gf_mx_v(dash->dl_mutex); + + gf_list_del(groups_selected); } GF_EXPORT @@ -4658,6 +5020,7 @@ u32 gf_dash_get_period_switch_status(GF_DashClient *dash) GF_EXPORT void gf_dash_request_period_switch(GF_DashClient *dash) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Period switch has been requested\n")); dash->request_period_switch = 1; } GF_EXPORT @@ -4671,6 +5034,12 @@ Bool gf_dash_in_period_setup(GF_DashClient *dash) return dash->in_period_setup; } +GF_EXPORT +void gf_dash_set_speed(GF_DashClient *dash, Double speed) +{ + if (dash) dash->speed = speed ? speed : 1.0; +} + GF_EXPORT u32 gf_dash_group_get_max_segments_in_cache(GF_DashClient *dash, u32 idx) { @@ -4718,13 +5087,13 @@ discard_segment: } if (group->cached[0].cache) { if (group->urlToDeleteNext) { - if (!group->local_files && !dash->keep_files) + if (!group->local_files && !dash->keep_files && strncmp(group->urlToDeleteNext, "gmem://", 7) ) dash->dash_io->delete_cache_file(dash->dash_io, group->segment_download, group->urlToDeleteNext); - gf_free( group->urlToDeleteNext); + gf_free(group->urlToDeleteNext); group->urlToDeleteNext = NULL; } - assert( group->cached[0].url ); + assert(group->cached[0].url); if (group->dont_delete_first_segment) { group->dont_delete_first_segment = 0; @@ -4737,13 +5106,7 @@ discard_segment: //remember the representation index of the last segment group->prev_active_rep_index = group->cached[0].representation_index; - gf_free(group->cached[0].cache); - gf_free(group->cached[0].url); - group->cached[0].url = NULL; - group->cached[0].cache = NULL; - group->cached[0].representation_index = 0; - group->cached[0].duration = 0; - + gf_dash_group_reset_cache_entry(&group->cached[0]); } memmove(&group->cached[0], &group->cached[1], sizeof(segment_cache_entry)*(group->nb_cached_segments-1)); memset(&(group->cached[group->nb_cached_segments-1]), 0, sizeof(segment_cache_entry)); @@ -4763,8 +5126,13 @@ void gf_dash_set_group_done(GF_DashClient *dash, u32 idx, Bool done) { GF_DASH_Group *group = gf_list_get(dash->groups, idx); if (group) { + gf_mx_p(dash->dl_mutex); group->done = done; - if (done && group->segment_download) dash->dash_io->abort(dash->dash_io, group->segment_download); + if (done && group->segment_download) { + group->download_abort_type = 1; + dash->dash_io->abort(dash->dash_io, group->segment_download); + } + gf_mx_v(dash->dl_mutex); } } @@ -4782,7 +5150,7 @@ GF_Err gf_dash_group_get_presentation_time_offset(GF_DashClient *dash, u32 idx, } GF_EXPORT -GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32 dependent_representation_index, const char **url, u64 *start_range, u64 *end_range, s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range, const char **original_url, Bool *has_next_segment) +GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32 dependent_representation_index, const char **url, u64 *start_range, u64 *end_range, s32 *switching_index, const char **switching_url, u64 *switching_start_range, u64 *switching_end_range, const char **original_url, Bool *has_next_segment, const char **key_url, bin128 *key_IV) { GF_DASH_Group *group; u32 index; @@ -4828,6 +5196,8 @@ GF_Err gf_dash_group_get_next_segment_location(GF_DashClient *dash, u32 idx, u32 if (end_range) *end_range = group->cached[index].end_range; if (original_url) *original_url = group->cached[index].url; + if (key_url) *key_url = group->cached[index].key_url; + if (key_IV) memcpy((*key_IV), group->cached[index].key_IV, sizeof(bin128)); if (!group->base_rep_index_plus_one && (group->cached[index].representation_index != group->prev_active_rep_index)) { GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, group->cached[0].representation_index); @@ -4877,8 +5247,8 @@ GF_Err gf_dash_group_probe_current_download_segment_location(GF_DashClient *dash } *switched = GF_FALSE; - if (group->download_aborted) { - group->download_aborted = 0; + if (group->download_abort_type==2) { + group->download_abort_type = 0; *switched = GF_TRUE; } @@ -4899,23 +5269,39 @@ GF_Err gf_dash_group_probe_current_download_segment_location(GF_DashClient *dash GF_EXPORT void gf_dash_seek(GF_DashClient *dash, Double start_range) { + Bool is_dynamic = GF_FALSE; gf_mx_p(dash->dl_mutex); - dash->playback_start_range = start_range; + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Seek request - playing from %g\n", start_range)); + + //are we live ? if so adjust start range + if (dash->mpd->type==GF_MPD_TYPE_DYNAMIC) { + u64 now, availabilityStartTime; + availabilityStartTime = dash->mpd->availabilityStartTime + dash->utc_shift; + if (dash->estimate_utc_drift) availabilityStartTime += dash->utc_drift_estimate; + + now = dash->mpd_fetch_time + (gf_sys_clock() - dash->last_update_time) - availabilityStartTime; + + if (dash->initial_time_shift_value<=100) { + now -= dash->mpd->time_shift_buffer_depth * dash->initial_time_shift_value / 100; + } else { + now -= dash->initial_time_shift_value; + } +// now += (u64) (start_range*1000); + start_range = (Double) now; + start_range /= 1000; + + is_dynamic = 1; + } + /*first check if we seek to another period*/ - if (! gf_dash_seek_periods(dash)) { + if (! gf_dash_seek_periods(dash, start_range)) { /*if no, seek in group*/ - gf_dash_seek_groups(dash); + gf_dash_seek_groups(dash, start_range, is_dynamic); } gf_mx_v(dash->dl_mutex); } -GF_EXPORT -Double gf_dash_get_playback_start_range(GF_DashClient *dash) -{ - return dash->playback_start_range; -} - GF_EXPORT Bool gf_dash_group_segment_switch_forced(GF_DashClient *dash, u32 idx) { @@ -5028,7 +5414,7 @@ GF_Err gf_dash_resync_to_segment(GF_DashClient *dash, const char *latest_segment for (j=0; j<gf_list_count(group->adaptation_set->representations); j++) { GF_Err e; rep = gf_list_get(group->adaptation_set->representations, j); - e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_DASH_RESOLVE_URL_MEDIA_TEMPLATE, i, &seg_url, &start_range, &end_range, ¤t_dur, NULL); + e = gf_dash_resolve_url(dash->mpd, rep, group, dash->base_url, GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE, i, &seg_url, &start_range, &end_range, ¤t_dur, NULL, NULL, NULL); if (e) GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unable to resolve media template URL: %s\n", gf_error_to_string(e))); @@ -5164,7 +5550,7 @@ GF_Err gf_dash_resync_to_segment(GF_DashClient *dash, const char *latest_segment //we are too late resync... } - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Sync to live was lost - reloading MPD\n")); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Sync to live was lost - reloading MPD (loop detected %d)\n", loop_detected)); for (i=0; i< gf_list_count(dash->groups); i++) { group = gf_list_get(dash->groups, i); //force reinit of timeline for this group @@ -5177,7 +5563,7 @@ GF_Err gf_dash_resync_to_segment(GF_DashClient *dash, const char *latest_segment return GF_OK; } - //TODO segment list adressing: + //TODO segment list addressing: return GF_OK; } @@ -5205,6 +5591,238 @@ void gf_dash_set_user_buffer(GF_DashClient *dash, u32 buffer_time_ms) if (dash) dash->user_buffer_ms = buffer_time_ms; } +/*returns active period start in ms*/ +GF_EXPORT +u32 gf_dash_get_period_start(GF_DashClient *dash) +{ + u32 start; + u32 i; + GF_MPD_Period *period; + if (!dash || !dash->mpd) return 0; -#endif //GPAC_DISABLE_DASH_CLIENT + start = 0; + for (i=0; i<=dash->active_period_index; i++) { + period = gf_list_get(dash->mpd->periods, i); + if (period->start) start = period->start; + + if (i<dash->active_period_index) start += period->duration; + } + return start; +} + + +/*returns active period duration in ms*/ +GF_EXPORT +u32 gf_dash_get_period_duration(GF_DashClient *dash) +{ + u32 start; + u32 i; + GF_MPD_Period *period = NULL; + if (!dash || !dash->mpd) return 0; + + start = 0; + for (i=0; i<=dash->active_period_index; i++) { + period = gf_list_get(dash->mpd->periods, i); + if (period->start) start = period->start; + if (i<dash->active_period_index) start += period->duration; + } + if (!period) return 0; + if (period->duration) return period->duration; + period = gf_list_get(dash->mpd->periods, dash->active_period_index+1); + + if (!period) { + //infered from MPD duration + if (dash->mpd->media_presentation_duration) return dash->mpd->media_presentation_duration - start; + //duration is not known (live) + if (dash->mpd->type==GF_MPD_TYPE_STATIC) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Period duration is not computable: last period without duration and no MPD duration !\n")); + } + return 0; + } + if (!period->start) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Period duration is not computable, paeriod has no duration and next period has no start !\n")); + return 0; + } + return period->start - start; +} +GF_EXPORT +const char *gf_dash_group_get_language(GF_DashClient *dash, u32 idx) +{ + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group) return NULL; + return group->adaptation_set->lang; +} + +GF_EXPORT +u32 gf_dash_group_get_audio_channels(GF_DashClient *dash, u32 idx) +{ + GF_MPD_Descriptor *mpd_desc; + u32 i=0; + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group) return 0; + + while ((mpd_desc=gf_list_enum(group->adaptation_set->audio_channels, &i))) { + if (!strcmp(mpd_desc->scheme_id_uri, "urn:mpeg:dash:23003:3:audio_channel_configuration:2011")) { + return atoi(mpd_desc->value); + } + } + return 0; +} + +GF_EXPORT +u32 gf_dash_group_get_num_qualities(GF_DashClient *dash, u32 idx) +{ + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group) return 0; + return gf_list_count(group->adaptation_set->representations); +} + +GF_EXPORT +GF_Err gf_dash_group_get_quality_info(GF_DashClient *dash, u32 idx, u32 quality_idx, GF_DASHQualityInfo *quality) +{ + GF_MPD_Fractional *sar; + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + GF_MPD_Representation *rep; + if (!group || !quality) return GF_BAD_PARAM; + rep = gf_list_get(group->adaptation_set->representations, quality_idx); + if (!rep) return GF_BAD_PARAM; + + memset(quality, 0, sizeof(GF_DASHQualityInfo)); + quality->mime = rep->mime_type ? rep->mime_type : group->adaptation_set->mime_type; + quality->codec = rep->codecs ? rep->codecs : group->adaptation_set->codecs; + quality->disabled = rep->playback.disabled; + sar = rep->framerate ? rep->framerate : group->adaptation_set->framerate; + if (sar) { + quality->fps_den = sar->den; + quality->fps_num = sar->num; + } + quality->height = rep->height ? rep->height : group->adaptation_set->height; + quality->width = rep->width ? rep->width : group->adaptation_set->width; + quality->nb_channels = gf_dash_group_get_audio_channels(dash, idx); + sar = rep->sar ? rep->sar : group->adaptation_set->sar; + if (sar) { + quality->par_num = sar->num; + quality->par_den = sar->den; + } + quality->sample_rate = rep->samplerate ? rep->samplerate : group->adaptation_set->samplerate; + quality->bandwidth = rep->bandwidth; + quality->ID = rep->id; + quality->interlaced = (rep->scan_type == GF_MPD_SCANTYPE_INTERLACED) ? 1 : ( (group->adaptation_set->scan_type == GF_MPD_SCANTYPE_INTERLACED) ? 1 : 0); + quality->is_selected = (quality_idx==group->active_rep_index) ? 1 : 0; + + return GF_OK; +} + + +static Bool gf_dash_group_enum_descriptor_list(GF_DashClient *dash, u32 idx, GF_List *descs, const char **desc_id, const char **desc_scheme, const char **desc_value) +{ + GF_MPD_Descriptor *mpd_desc; + if (idx>=gf_list_count(descs)) return 0; + mpd_desc = gf_list_get(descs, idx); + if (desc_value) *desc_value = mpd_desc->value; + if (desc_scheme) *desc_scheme = mpd_desc->scheme_id_uri; + if (desc_id) *desc_id = mpd_desc->id; + return 1; +} + +GF_EXPORT +Bool gf_dash_group_enum_descriptor(GF_DashClient *dash, u32 group_idx, GF_DashDescriptorType desc_type, u32 desc_idx, const char **desc_id, const char **desc_scheme, const char **desc_value) +{ + GF_List *descs = NULL; + GF_DASH_Group *group = gf_list_get(dash->groups, group_idx); + if (!group) return 0; + switch (desc_type) { + case GF_MPD_DESC_ACCESSIBILITY: + descs = group->adaptation_set->accessibility; + break; + case GF_MPD_DESC_AUDIOCONFIG: + descs = group->adaptation_set->audio_channels; + break; + case GF_MPD_DESC_CONTENT_PROTECTION: + descs = group->adaptation_set->content_protection; + break; + case GF_MPD_DESC_ESSENTIAL_PROPERTIES: + descs = group->adaptation_set->essential_properties; + break; + case GF_MPD_DESC_SUPPLEMENTAL_PROPERTIES: + descs = group->adaptation_set->supplemental_properties; + break; + case GF_MPD_DESC_FRAME_PACKING: + descs = group->adaptation_set->frame_packing; + break; + case GF_MPD_DESC_ROLE: + descs = group->adaptation_set->role; + break; + case GF_MPD_DESC_RATING: + descs = group->adaptation_set->rating; + break; + case GF_MPD_DESC_VIEWPOINT: + descs = group->adaptation_set->viewpoint; + break; + default: + return 0; + } + return gf_dash_group_enum_descriptor_list(dash, desc_idx, descs, desc_id, desc_scheme, desc_value); +} + +GF_EXPORT +Bool gf_dash_get_automatic_switching(GF_DashClient *dash) +{ + return (dash && dash->disable_switching) ? 0 : 1; +} + +GF_EXPORT +GF_Err gf_dash_set_automatic_switching(GF_DashClient *dash, Bool enable_switching) +{ + if (!dash) return GF_BAD_PARAM; + dash->disable_switching = !enable_switching; + return GF_OK; +} + +GF_EXPORT +GF_Err gf_dash_group_select_quality(GF_DashClient *dash, u32 idx, const char *ID) +{ + u32 i, count; + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group || !ID) return GF_BAD_PARAM; + + count = gf_list_count(group->adaptation_set->representations); + for (i=0; i<count; i++) { + GF_MPD_Representation *rep = gf_list_get(group->adaptation_set->representations, i); + if (rep->id && !strcmp(rep->id, ID)) { + group->force_representation_idx_plus_one = i+1; + group->force_switch_bandwidth = 1; + return GF_OK; + } + } + return GF_BAD_PARAM; +} + + + +GF_EXPORT +u32 gf_dash_group_get_download_rate(GF_DashClient *dash, u32 idx) +{ + GF_DASH_Group *group = gf_list_get(dash->groups, idx); + if (!group || !group->segment_download) return 0; + + return dash->dash_io->get_bytes_per_sec(dash->dash_io, group->segment_download); +} + + +GF_EXPORT +GF_Err gf_dash_set_timeshift(GF_DashClient *dash, u32 ms_in_timeshift) +{ + if (!dash) return GF_BAD_PARAM; + dash->initial_time_shift_value = ms_in_timeshift; + return GF_OK; +} + +GF_EXPORT +Double gf_dash_get_timeshift_buffer_pos(GF_DashClient *dash) +{ + return dash ? dash->prev_time_in_tsb / 1000.0 : 0.0; +} + +#endif //GPAC_DISABLE_DASH_CLIENT diff --git a/src/media_tools/dash_segmenter.c b/src/media_tools/dash_segmenter.c index 3fa3631..5673233 100644 --- a/src/media_tools/dash_segmenter.c +++ b/src/media_tools/dash_segmenter.c @@ -55,7 +55,7 @@ struct _dash_component /*for audio*/ u32 sample_rate, channels; /*apply to any media. We use 5 bytes because we may use copy data converted from gf_4cc_to_str which is 5 bytes*/ - char szLang[5]; + char *lang; }; typedef struct @@ -73,11 +73,13 @@ typedef struct Bool daisy_chain_sidx; u32 use_url_template; Bool use_segment_timeline; + Bool segment_alignment_disabled; u32 single_file_mode; u32 segment_marker_4cc; s32 time_shift_depth; const char *bs_switch_segment_file; Bool inband_param_set; + Bool force_period_end; /*set if seg_rad_name depends on input file name (had %s in it). In this case, SegmentTemplate cannot be used at adaptation set level*/ Bool variable_seg_rad_name; @@ -92,15 +94,24 @@ typedef struct u64 initial_tfdt; Bool no_fragments_defaults; Bool samplegroups_in_traf; + Bool single_traf_per_moof; + Bool content_protection_in_rep; + Bool insert_utc; + Bool real_time; + + Double max_segment_duration; + s32 ast_offset_ms; } GF_DASHSegmenterOptions; struct _dash_segment_input { char *file_name; char representationID[100]; - char periodID[100]; - char xlink[100]; - char role[100]; + char *periodID; + u32 nb_baseURL; + char **baseURL; + char *xlink; + char *role; u32 nb_rep_descs; char **rep_descs; u32 nb_as_descs; @@ -111,7 +122,7 @@ struct _dash_segment_input char **p_descs; u32 bandwidth; u32 dependency_bandwidth; - char dependencyID[100]; + char *dependencyID; /*if 0, input is disabled*/ u32 adaptation_set; @@ -126,7 +137,7 @@ struct _dash_segment_input /*assigns the different media to the same adaptation set or group than the input_idx one*/ GF_Err (* dasher_input_classify) (GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 input_idx, u32 *current_group_id, u32 *max_sap_type); GF_Err ( *dasher_get_components_info) (GF_DashSegInput *dash_input, GF_DASHSegmenterOptions *opts); - GF_Err ( *dasher_create_init_segment) (GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 adaptation_set, char *szInitName, const char *tmpdir, GF_DASHSegmenterOptions *dash_opts, Bool *disable_bs_switching); + GF_Err ( *dasher_create_init_segment) (GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 adaptation_set, char *szInitName, const char *tmpdir, GF_DASHSegmenterOptions *dash_opts, GF_DashSwitchingMode bs_switch_mode, Bool *disable_bs_switching); GF_Err ( *dasher_segment_file) (GF_DashSegInput *dash_input, const char *szOutName, GF_DASHSegmenterOptions *opts, Bool first_in_set); /*shall be set after call to dasher_input_classify*/ @@ -140,6 +151,7 @@ struct _dash_segment_input u32 protection_scheme_type; + Double segment_duration; /*all these shall be set after call to dasher_get_components_info*/ Double duration; struct _dash_component components[20]; @@ -148,6 +160,8 @@ struct _dash_segment_input //spatial info for tiling u32 x, y, w, h; + Bool disable_inband_param_set; + }; @@ -180,30 +194,28 @@ GF_Err gf_media_mpd_format_segment_name(GF_DashTemplateSegmentType seg_type, Boo char tmp[100]; strcpy(segment_name, ""); - if (seg_rad_name && (strstr(seg_rad_name, "$RepresentationID$") || strstr(seg_rad_name, "$ID$") || strstr(seg_rad_name, "$Bandwidth$"))) + if (seg_rad_name && (strstr(seg_rad_name, "$RepresentationID$") || strstr(seg_rad_name, "$Bandwidth$"))) needs_init = GF_FALSE; if (!seg_rad_name) { strcpy(segment_name, output_file_name); } else { + char c; + const size_t seg_rad_name_len = strlen(seg_rad_name); + while (char_template <= seg_rad_name_len) { + c = seg_rad_name[char_template]; - while (1) { - char c = seg_rad_name[char_template]; - if (!c) break; - - if (!is_template && !is_init_template - && (!strnicmp(& seg_rad_name[char_template], "$RepresentationID$", 18) || !strnicmp(& seg_rad_name[char_template], "$ID$", 4)) - ) { - char_template+=18; + if (!is_template && !is_init_template && !strnicmp(& seg_rad_name[char_template], "$RepresentationID$", 18) ) { + char_template += 18; strcat(segment_name, rep_id); - needs_init=GF_FALSE; + needs_init = GF_FALSE; } else if (!is_template && !is_init_template && !strnicmp(& seg_rad_name[char_template], "$Bandwidth", 10)) { EXTRACT_FORMAT(10); sprintf(tmp, szFmt, bandwidth); strcat(segment_name, tmp); - needs_init=GF_FALSE; + needs_init = GF_FALSE; } else if (!is_template && !strnicmp(& seg_rad_name[char_template], "$Time", 5)) { EXTRACT_FORMAT(5); @@ -213,7 +225,7 @@ GF_Err gf_media_mpd_format_segment_name(GF_DashTemplateSegmentType seg_type, Boo strcat(szFmt, &LLD[1]); sprintf(tmp, szFmt, start_time); strcat(segment_name, tmp); - has_number=1; + has_number = GF_TRUE; } else if (!is_template && !strnicmp(& seg_rad_name[char_template], "$Number", 7)) { EXTRACT_FORMAT(7); @@ -221,14 +233,14 @@ GF_Err gf_media_mpd_format_segment_name(GF_DashTemplateSegmentType seg_type, Boo if (is_init || is_init_template) continue; sprintf(tmp, szFmt, segment_number); strcat(segment_name, tmp); - has_number=GF_TRUE; + has_number = GF_TRUE; } else if (!strnicmp(& seg_rad_name[char_template], "$Init=", 6)) { char *sep = strchr(seg_rad_name + char_template+6, '$'); if (sep) sep[0] = 0; if (is_init || is_init_template) { strcat(segment_name, seg_rad_name + char_template+6); - needs_init=GF_FALSE; + needs_init = GF_FALSE; } char_template += (u32) strlen(seg_rad_name + char_template)+1; if (sep) sep[0] = '$'; @@ -238,7 +250,7 @@ GF_Err gf_media_mpd_format_segment_name(GF_DashTemplateSegmentType seg_type, Boo if (sep) sep[0] = 0; if (is_index) { strcat(segment_name, seg_rad_name + char_template+6); - needs_init=GF_FALSE; + needs_init = GF_FALSE; } char_template += (u32) strlen(seg_rad_name + char_template)+1; if (sep) sep[0] = '$'; @@ -246,13 +258,15 @@ GF_Err gf_media_mpd_format_segment_name(GF_DashTemplateSegmentType seg_type, Boo else { char_template+=1; + if (c=='\\') c = '/'; + sprintf(tmp, "%c", c); strcat(segment_name, tmp); } } } - if (is_template && ! use_segment_timeline && !strstr(seg_rad_name, "$Number")) + if (is_template && ( ! use_segment_timeline || !strstr(seg_rad_name, "$Time")) && !strstr(seg_rad_name, "$Number")) strcat(segment_name, "$Number$"); if (needs_init) @@ -266,15 +280,46 @@ GF_Err gf_media_mpd_format_segment_name(GF_DashTemplateSegmentType seg_type, Boo strcat(segment_name, "."); strcat(segment_name, seg_ext); } + + if ((seg_type != GF_DASH_TEMPLATE_TEMPLATE) && (seg_type != GF_DASH_TEMPLATE_INITIALIZATION_TEMPLATE)) { + char *sep = strrchr(segment_name, '/'); + if (sep) { + char c = sep[0]; + sep[0] = 0; + if (!gf_dir_exists(segment_name)) { + gf_mkdir(segment_name); + } + sep[0] = c; + } + } + return GF_OK; } -GF_Err gf_dasher_store_segment_info(GF_DASHSegmenterOptions *dash_cfg, const char *SegmentName, Double segStartTime) +const char *gf_dasher_strip_output_dir(const char *mpd_url, const char *path) +{ + char c; + const char *res; + char *sep = strrchr(mpd_url, '/'); + if (!sep) sep = strrchr(mpd_url, '\\'); + if (!sep) return path; + c = sep[0]; + sep[0] = 0; + if (!strncmp(mpd_url, path, strlen(mpd_url))) { + res = path + strlen(mpd_url) + 1; + } else { + res = path; + } + sep[0] = c; + return res; +} + +GF_Err gf_dasher_store_segment_info(GF_DASHSegmenterOptions *dash_cfg, const char *representationID, const char *SegmentName, u64 segStartTime, u64 segDuration) { char szKey[512]; if (!dash_cfg->dash_ctx) return GF_OK; - sprintf(szKey, "%g", segStartTime); + sprintf(szKey, ""LLU"-"LLU"@%s", segStartTime, segDuration, representationID); return gf_cfg_set_key(dash_cfg->dash_ctx, "SegmentsStartTimes", SegmentName, szKey); } @@ -282,7 +327,7 @@ GF_Err gf_dasher_store_segment_info(GF_DASHSegmenterOptions *dash_cfg, const cha #ifndef GPAC_DISABLE_ISOM GF_EXPORT -GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCodec) +GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCodec, Bool force_inband, Bool force_sbr) { GF_ESD *esd; GF_AVCConfig *avcc; @@ -321,6 +366,19 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCo if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { /*5 first bits of AAC config*/ u8 audio_object_type = (esd->decoderConfig->decoderSpecificInfo->data[0] & 0xF8) >> 3; +#ifndef GPAC_DISABLE_AV_PARSERS + if (force_sbr && (audio_object_type==2) ) { + GF_M4ADecSpecInfo a_cfg; + GF_Err e = gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg); + if (e==GF_OK) { + if (a_cfg.sbr_sr) + audio_object_type = a_cfg.sbr_object_type; + if (a_cfg.has_ps) + audio_object_type = 29; + } + } +#endif + sprintf(szCodec, "mp4a.%02x.%01d", esd->decoderConfig->objectTypeIndication, audio_object_type); } else { sprintf(szCodec, "mp4a.%02x", esd->decoderConfig->objectTypeIndication); @@ -350,6 +408,10 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCo case GF_ISOM_SUBTYPE_AVC3_H264: case GF_ISOM_SUBTYPE_AVC4_H264: avcc = gf_isom_avc_config_get(movie, track, 1); + if (force_inband) { + if (subtype==GF_ISOM_SUBTYPE_AVC_H264) subtype = GF_ISOM_SUBTYPE_AVC3_H264; + else if (subtype==GF_ISOM_SUBTYPE_AVC2_H264) subtype = GF_ISOM_SUBTYPE_AVC4_H264; + } sprintf(szCodec, "%s.%02x%02x%02x", gf_4cc_to_str(subtype), avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication); gf_odf_avc_cfg_del(avcc); return GF_OK; @@ -359,9 +421,27 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCo gf_odf_avc_cfg_del(avcc); return GF_OK; #ifndef GPAC_DISABLE_HEVC - case GF_4CC('h','v','c','1'): - case GF_4CC('h','e','v','1'): + case GF_ISOM_SUBTYPE_HVC1: + case GF_ISOM_SUBTYPE_HEV1: + case GF_ISOM_SUBTYPE_HVC2: + case GF_ISOM_SUBTYPE_HEV2: + case GF_ISOM_SUBTYPE_HVT1: + case GF_ISOM_SUBTYPE_SHC1: + case GF_ISOM_SUBTYPE_SHV1: + + if (force_inband) { + if (subtype==GF_ISOM_SUBTYPE_HVC1) subtype = GF_ISOM_SUBTYPE_HEV1; + else if (subtype==GF_ISOM_SUBTYPE_HVC2) subtype = GF_ISOM_SUBTYPE_HEV2; + } hvcc = gf_isom_hevc_config_get(movie, track, 1); + if (!hvcc) { + hvcc = gf_isom_shvc_config_get(movie, track, 1); + } + if (subtype==GF_ISOM_SUBTYPE_HVT1) { + u32 refTrack; + gf_isom_get_reference(movie, track, GF_ISOM_REF_TBAS, 1, &refTrack); + hvcc = gf_isom_hevc_config_get(movie, refTrack, 1); + } if (hvcc) { u8 c; char szTemp[40]; @@ -378,6 +458,7 @@ GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCo u32 i, res = 0; for (i=0; i<32; i++) { res |= val & 1; + if (i==31) break; res <<= 1; val >>=1; } @@ -450,11 +531,12 @@ typedef struct u64 FragmentLength; u32 OriginalTrack; u32 finalSampleDescriptionIndex; - u32 TimeScale, MediaType, DefaultDuration, InitialTSOffset; - u64 last_sample_cts, next_sample_dts; + u32 TimeScale, MediaType, DefaultDuration; + u64 last_sample_cts, next_sample_dts, InitialTSOffset; Bool all_sample_raps, splitable; u32 split_sample_dts_shift; s32 media_time_to_pres_time_shift; + u64 min_cts_in_segment; } GF_ISOMTrackFragmenter; static u64 isom_get_next_sap_time(GF_ISOFile *input, u32 track, u32 sample_count, u32 sample_num) @@ -483,35 +565,95 @@ static u64 isom_get_next_sap_time(GF_ISOFile *input, u32 track, u32 sample_count return time; } -typedef struct +static GF_Err gf_isom_write_content_protection(GF_ISOFile *input, FILE *mpd, u32 protected_track, u8 indent) { - u32 nb_segment; - u64 segment_duration; -} GF_DASHSegmentDuration; + u32 prot_scheme = gf_isom_is_media_encrypted(input, protected_track, 1); + if (gf_isom_is_cenc_media(input, protected_track, 1)) { + bin128 default_KID; + u8 i; + gf_isom_cenc_get_default_info(input, protected_track, 1, NULL, NULL, &default_KID); + for (i=0; i<indent; i++) + fprintf(mpd, " "); + fprintf(mpd, "<ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\" value=\"%s\" cenc:default_KID=\"", gf_4cc_to_str(prot_scheme) ); + /* Output canonical UIID form */ + for (i=0; i<4; i++) fprintf(mpd, "%02x", default_KID[i]); + fprintf(mpd, "-"); + for (i=4; i<6; i++) fprintf(mpd, "%02x", default_KID[i]); + fprintf(mpd, "-"); + for (i=6; i<8; i++) fprintf(mpd, "%02x", default_KID[i]); + fprintf(mpd, "-"); + for (i=8; i<10; i++) fprintf(mpd, "%02x", default_KID[i]); + fprintf(mpd, "-"); + for (i=10; i<16; i++) fprintf(mpd, "%02x", default_KID[i]); + fprintf(mpd, "\"/>\n"); + } + //todo for ISMA or OMA DRM -static void store_segment_duration(GF_List **segment_duration, u64 SegmentDuration) -{ - u32 k; - GF_DASHSegmentDuration *entry; + return GF_OK; +} - if (! *segment_duration) *segment_duration = gf_list_new(); +static void gf_dash_append_segment_timeline(GF_BitStream *mpd_timeline_bs, u64 segment_start, u64 segment_dur, u64 *previous_segment_duration , Bool *first_segment_in_timeline,u32 *segment_timeline_repeat_count) +{ + char szMPDTempLine[2048]; + if (*previous_segment_duration == segment_dur) { + *segment_timeline_repeat_count = *segment_timeline_repeat_count + 1; + return; + } - for (k = 0; k < gf_list_count(*segment_duration); k++) { - entry = (GF_DASHSegmentDuration *)gf_list_get(*segment_duration, k); - if (SegmentDuration == entry->segment_duration) { - entry->nb_segment++; - return; + if (*previous_segment_duration) { + if (*segment_timeline_repeat_count) { + sprintf(szMPDTempLine, " r=\"%d\"/>\n", *segment_timeline_repeat_count); + } else { + sprintf(szMPDTempLine, "/>\n"); } + gf_bs_write_data(mpd_timeline_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); + } + *previous_segment_duration = segment_dur; + if (*first_segment_in_timeline) { + sprintf(szMPDTempLine, " <S t=\""LLU"\" d=\""LLU"\"", segment_start, segment_dur); + *first_segment_in_timeline = GF_FALSE; + } else { + sprintf(szMPDTempLine, " <S d=\""LLU"\"", segment_dur); } + gf_bs_write_data(mpd_timeline_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); + *segment_timeline_repeat_count = 0; +} + +static void gf_dash_load_segment_timeline(GF_DASHSegmenterOptions *dash_cfg, GF_BitStream *mpd_timeline_bs, const char *representationID, u64 *previous_segment_duration , Bool *first_segment_in_timeline,u32 *segment_timeline_repeat_count) +{ + u32 i, count; + char szRepID[100]; - GF_SAFEALLOC(entry, GF_DASHSegmentDuration); - entry->segment_duration = SegmentDuration; - entry->nb_segment = 1; - gf_list_add(*segment_duration, entry); + *first_segment_in_timeline = GF_TRUE; + *segment_timeline_repeat_count = 0; + *previous_segment_duration = 0; + + count = gf_cfg_get_key_count(dash_cfg->dash_ctx, "SegmentsStartTimes"); + for (i=0; i<count; i++) { + u64 start, dur; + const char *fileName = gf_cfg_get_key_name(dash_cfg->dash_ctx, "SegmentsStartTimes", i); + const char *MPDTime = gf_cfg_get_key(dash_cfg->dash_ctx, "SegmentsStartTimes", fileName); + if (!fileName) + break; + + sscanf(MPDTime, ""LLU"-"LLU"@%s", &start, &dur, szRepID); + if (strcmp(representationID, szRepID)) continue; + + gf_dash_append_segment_timeline(mpd_timeline_bs, start, dur, previous_segment_duration, first_segment_in_timeline, segment_timeline_repeat_count); + } } +static u64 get_presentation_time(u64 media_time, s32 ts_shift) +{ + if ((ts_shift<0) && (media_time < -ts_shift)) { + media_time = 0; + } else { + media_time += ts_shift; + } + return media_time ; +} -static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_file, Double max_duration_sec, GF_DASHSegmenterOptions *dash_cfg, GF_DashSegInput *dash_input, Bool first_in_set) +static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_file, GF_DASHSegmenterOptions *dash_cfg, GF_DashSegInput *dash_input, Bool first_in_set) { u8 NbBits; u32 i, TrackNum, descIndex, j, count, nb_sync, ref_track_id, nb_tracks_done; @@ -526,11 +668,11 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f GF_ISOFile *output, *bs_switch_segment; GF_ISOSample *sample, *next; GF_List *fragmenters; - u64 MaxFragmentDuration, MaxSegmentDuration, SegmentDuration, maxFragDurationOverSegment; - u32 presentationTimeOffset = 0; - Double segment_start_time, file_duration, period_duration, max_segment_duration; + u64 MaxFragmentDuration, MaxSegmentDuration, SegmentDuration, maxFragDurationOverSegment, segment_start_time, period_duration; + u64 presentationTimeOffset = 0; + Double file_duration, max_segment_duration; u32 nb_segments, width, height, sample_rate, nb_channels, sar_w, sar_h, fps_num, fps_denum, startNumber; - char langCode[5]; + char *langCode = NULL; u32 index_start_range, index_end_range; Bool force_switch_segment = GF_FALSE; Bool switch_segment = GF_FALSE; @@ -542,6 +684,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f Bool simulation_pass = GF_FALSE; Bool init_segment_deleted = GF_FALSE; Bool first_segment_in_timeline = GF_TRUE; + Bool store_utc = GF_FALSE; u64 previous_segment_duration = 0; u32 segment_timeline_repeat_count = 0; //u64 last_ref_cts = 0; @@ -565,26 +708,37 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f u32 *segments_info = NULL; u32 nb_segments_info = 0; u32 protected_track = 0; + u64 min_seg_dur, max_seg_dur, total_seg_dur, last_seg_dur; Bool audio_only = GF_TRUE; Bool is_bs_switching = GF_FALSE; Bool use_url_template = dash_cfg->use_url_template; const char *seg_rad_name = dash_cfg->seg_rad_name; const char *seg_ext = dash_cfg->seg_ext; const char *bs_switching_segment_name = NULL; - GF_List *segment_duration = NULL; - + u64 generation_start_ntp = 0; + SegmentName[0] = 0; SegmentDuration = 0; nb_samp = 0; fragmenters = NULL; if (!seg_ext) seg_ext = "m4s"; + + if (dash_cfg->real_time && dash_cfg->dash_ctx) { + u32 sec, frac; + opt = gf_cfg_get_key(dash_cfg->dash_ctx, "DASH", "GenerationNTP"); + sscanf(opt, "%u:%u", &sec, &frac); + generation_start_ntp = sec; + generation_start_ntp <<= 32; + generation_start_ntp |= frac; + } + bs_switch_segment = NULL; if (dash_cfg->bs_switch_segment_file) { bs_switch_segment = gf_isom_open(dash_cfg->bs_switch_segment_file, GF_ISOM_OPEN_READ, NULL); if (bs_switch_segment) { - bs_switching_segment_name = gf_url_get_resource_name(dash_cfg->bs_switch_segment_file); - is_bs_switching = 1; + bs_switching_segment_name = gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->bs_switch_segment_file); + is_bs_switching = GF_TRUE; } } @@ -619,11 +773,11 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f opt = dash_cfg->dash_ctx ? gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "InitializationSegment") : NULL; if (opt) { - output = gf_isom_open(opt, GF_ISOM_OPEN_CAT_FRAGMENTS, NULL); - dash_moov_setup = 1; + output = gf_isom_open(opt, GF_ISOM_OPEN_CAT_FRAGMENTS, dash_cfg->tmpdir); + dash_moov_setup = GF_TRUE; } else { gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION, is_bs_switching, SegmentName, output_file, dash_input->representationID, seg_rad_name, !stricmp(seg_ext, "null") ? NULL : "mp4", 0, bandwidth, 0, dash_cfg->use_segment_timeline); - output = gf_isom_open(SegmentName, GF_ISOM_OPEN_WRITE, NULL); + output = gf_isom_open(SegmentName, GF_ISOM_OPEN_WRITE, dash_cfg->tmpdir); } if (!output) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISOBMF DASH] Cannot open %s for writing\n", opt ? opt : SegmentName)); @@ -649,22 +803,36 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f } else if (dash_cfg->dash_ctx) { opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "BitstreamSwitching"); if (opt && !strcmp(opt, "yes")) { - is_bs_switching = 1; + is_bs_switching = GF_TRUE; if (bs_switch_segment) gf_isom_delete(bs_switch_segment); bs_switch_segment = output; - bs_switching_is_output = 1; - bs_switching_segment_name = gf_url_get_resource_name(gf_isom_get_filename(bs_switch_segment)); + bs_switching_is_output = GF_TRUE; + bs_switching_segment_name = gf_dasher_strip_output_dir(dash_cfg->mpd_name, gf_isom_get_filename(bs_switch_segment)); } opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "Bandwidth"); if (opt) sscanf(opt, "%u", &bandwidth); + + if (dash_cfg->use_segment_timeline) { + opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "NbSegmentsRemoved"); + if (opt) { + u32 nb_removed = atoi(opt); + startNumber = 1 + nb_removed; + } + } } + mpd_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); - if (first_in_set && dash_cfg->use_segment_timeline) { + //if segment alignment not set or if first in AS, create SegmentTimeline + if (dash_cfg->use_segment_timeline && (first_in_set || dash_cfg->segment_alignment_disabled) ) { mpd_timeline_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); sprintf(szMPDTempLine, " <SegmentTimeline>\n"); gf_bs_write_data(mpd_timeline_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); + + if (dash_cfg->dash_ctx) { + gf_dash_load_segment_timeline(dash_cfg, mpd_timeline_bs, dash_input->representationID, &previous_segment_duration, &first_segment_in_timeline, &segment_timeline_repeat_count); + } } nb_sync = 0; @@ -686,7 +854,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f } - MaxFragmentDuration = (u32) (dash_cfg->dash_scale * max_duration_sec); + MaxFragmentDuration = (u32) (dash_cfg->dash_scale * dash_cfg->fragment_duration); MaxSegmentDuration = (u32) (dash_cfg->dash_scale * dash_cfg->segment_duration); /*in single segment mode, only one big SIDX is written between the end of the moov and the first fragment. @@ -706,15 +874,14 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f tf = tfref = NULL; file_duration = 0; width = height = sample_rate = nb_channels = sar_w = sar_h = fps_num = fps_denum = 0; - langCode[0]=0; - langCode[4]=0; + langCode = NULL; szCodecs[0] = 0; mpd_timescale = nb_video = nb_audio = nb_text = nb_scene = 0; //duplicates all tracks for (i=0; i<gf_isom_get_track_count(input); i++) { - u32 _w, _h, _sr, _nb_ch, avctype; + u32 _w, _h, _sr, _nb_ch, vidtype; u32 mtype = gf_isom_get_media_type(input, i+1); if (mtype == GF_ISOM_MEDIA_HINT) continue; @@ -725,13 +892,13 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f if (dash_input->single_track_num && ((i+1) != dash_input->single_track_num)) continue; - if (! dash_moov_setup) { + if (!dash_moov_setup) { e = gf_isom_clone_track(input, i+1, output, GF_FALSE, &TrackNum); if (e) goto err_exit; if (gf_isom_is_track_in_root_od(input, i+1)) gf_isom_add_track_to_root_od(output, TrackNum); - /*remove sgpd in stbl; it wuold be in traf*/ + /*remove sgpd in stbl; it would be in traf*/ if (dash_cfg->samplegroups_in_traf) { GF_TrackBox *trak = (GF_TrackBox *)gf_isom_get_track_from_file(output, TrackNum); if (!trak) continue; @@ -759,24 +926,31 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f } /*set extraction mode whether setup or not*/ - avctype = gf_isom_get_avc_svc_type(input, i+1, 1); - if (avctype==GF_ISOM_AVCTYPE_AVC_ONLY) { + vidtype = gf_isom_get_avc_svc_type(input, i+1, 1); + if (vidtype==GF_ISOM_AVCTYPE_AVC_ONLY) { /*for AVC we concatenate SPS/PPS unless SVC base*/ - if (!dash_input->trackNum && dash_cfg->inband_param_set) + if (!dash_input->trackNum && dash_cfg->inband_param_set && !dash_input->disable_inband_param_set) gf_isom_set_nalu_extract_mode(input, i+1, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG); } - else if (avctype > GF_ISOM_AVCTYPE_AVC_ONLY) { + else if (vidtype > GF_ISOM_AVCTYPE_AVC_ONLY) { /*for SVC we don't want any rewrite of extractors, and we don't concatenate SPS/PPS*/ gf_isom_set_nalu_extract_mode(input, i+1, GF_ISOM_NALU_EXTRACT_INSPECT); } - if (gf_isom_get_media_subtype(input, i+1, 1)==GF_ISOM_SUBTYPE_HVC1) { - u32 mode = GF_ISOM_NALU_EXTRACT_INSPECT; - if (dash_cfg->inband_param_set) { + vidtype = gf_isom_get_hevc_shvc_type(input, i+1, 1); + if (vidtype == GF_ISOM_HEVCTYPE_HEVC_ONLY) { + + u32 mode = GF_ISOM_NALU_EXTRACT_INSPECT; //because of tile tracks + + /*concatenate SPS/PPS unless SHVC base*/ + if (!dash_input->trackNum && dash_cfg->inband_param_set && !dash_input->disable_inband_param_set) mode |= GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG; - } + gf_isom_set_nalu_extract_mode(input, i+1, mode); } + else if (vidtype > GF_ISOM_HEVCTYPE_HEVC_ONLY) { + gf_isom_set_nalu_extract_mode(input, i+1, GF_ISOM_NALU_EXTRACT_INSPECT); + } if (mtype == GF_ISOM_MEDIA_VISUAL) nb_video++; else if (mtype == GF_ISOM_MEDIA_AUDIO) nb_audio++; @@ -807,7 +981,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f &defaultDuration, &defaultSize, &defaultDescriptionIndex, &defaultRandomAccess, &defaultPadding, &defaultDegradationPriority); } - gf_media_get_rfc_6381_codec_name(bs_switch_segment ? bs_switch_segment : input, i+1, szCodec); + gf_media_get_rfc_6381_codec_name(input, i+1, szCodec, bs_switch_segment ? GF_TRUE : GF_FALSE, GF_TRUE); if (strlen(szCodecs)) strcat(szCodecs, ","); strcat(szCodecs, szCodec); @@ -903,7 +1077,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f /*more than one sampleDesc, we will need to indicate all the sample descs in the file in case we produce a single file, otherwise the file would not be compliant*/ if (s_count > 1) { - gf_isom_clone_sample_descriptions(output, TrackNum, bs_switch_segment, sample_descs_track, 1); + gf_isom_clone_sample_descriptions(output, TrackNum, bs_switch_segment, sample_descs_track, GF_TRUE); } /*and search in new ones the new index*/ @@ -925,7 +1099,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f char *opt, sKey[100]; sprintf(sKey, "TKID_%d_NextDecodingTime", tf->TrackID); opt = (char *)gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey); - if (opt) tf->InitialTSOffset = atoi(opt); + if (opt) sscanf(opt, LLU, & tf->InitialTSOffset); /*store presentationTimeOffset on the first rep*/ if (store_dash_params) @@ -938,19 +1112,24 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f case GF_ISOM_MEDIA_SUBT: case GF_ISOM_MEDIA_MPEG_SUBT: tf->splitable = GF_TRUE; - gf_isom_get_media_language(input, i+1, langCode); + gf_isom_get_media_language(input, i+1, &langCode); case GF_ISOM_MEDIA_VISUAL: case GF_ISOM_MEDIA_SCENE: case GF_ISOM_MEDIA_DIMS: - gf_isom_get_track_layout_info(input, i+1, &_w, &_h, NULL, NULL, NULL); - if (_w>width) width = _w; - if (_h>height) height = _h; + e = gf_isom_get_visual_info(input, i+1, 1, &_w, &_h); + if (e == GF_OK) { + if (_w>width) width = _w; + if (_h>height) height = _h; + } else { + width = 0; + height = 0; + } break; case GF_ISOM_MEDIA_AUDIO: gf_isom_get_audio_info(input, i+1, 1, &_sr, &_nb_ch, NULL); if (_sr>sample_rate) sample_rate=_sr; if (_nb_ch>nb_channels) nb_channels = _nb_ch; - gf_isom_get_media_language(input, i+1, langCode); + gf_isom_get_media_language(input, i+1, &langCode); break; } @@ -1022,7 +1201,7 @@ static GF_Err gf_media_isom_segment_file(GF_ISOFile *input, const char *output_f if (store_dash_params) { char szVal[1024]; sprintf(szVal, LLU, init_seg_size); - gf_cfg_set_key(dash_cfg->dash_ctx, RepSecName, "InitializationSegmentSize", szVal); + gf_cfg_set_key(dash_cfg->dash_ctx, RepSecName, "InitializationSegmentSize", szVal); } else { const char *opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "InitializationSegmentSize"); if (opt) init_seg_size = atoi(opt); @@ -1078,7 +1257,7 @@ restart_fragmentation_pass: opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "NextFragmentIndex"); if (opt) fragment_index = atoi(opt); opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, "CumulatedDuration"); - if (opt) period_duration = atof(opt); + if (opt) sscanf(opt, LLU, &period_duration); for (i=0; i<gf_list_count(fragmenters); i++) { tf = (GF_ISOMTrackFragmenter *)gf_list_get(fragmenters, i); @@ -1095,6 +1274,10 @@ restart_fragmentation_pass: if (opt) { sscanf(opt, LLU, &tf->next_sample_dts); } + + sprintf(sKey, "TKID_%d_MediaTimeToPresTime", tf->TrackID); + opt = gf_cfg_get_key(dash_cfg->dash_ctx, RepSecName, sKey); + if (opt) tf->media_time_to_pres_time_shift = atoi(opt); } } @@ -1102,12 +1285,13 @@ restart_fragmentation_pass: max_segment_duration = 0; + min_seg_dur = max_seg_dur = total_seg_dur = last_seg_dur = 0; while ( (count = gf_list_count(fragmenters)) ) { Bool store_pssh = GF_FALSE; if (switch_segment) { if (dash_cfg->subduration && (segment_start_time + MaxSegmentDuration/2 >= dash_cfg->dash_scale * dash_cfg->subduration)) { - /*done with file (next segment will exceppe of more than half the requested subduration : store all fragmenters state and abord*/ + /*done with file (next segment will exceed of more than half the requested subduration : store all fragmenters state and abord*/ break; } @@ -1123,21 +1307,19 @@ restart_fragmentation_pass: } else { start_range = gf_isom_get_file_size(output); if (seg_rad_name) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, is_bs_switching, SegmentName, output_file, dash_input->representationID, seg_rad_name, !stricmp(seg_ext, "null") ? NULL : seg_ext, (u64) ( period_duration * dash_cfg->dash_scale + segment_start_time), bandwidth, cur_seg, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, is_bs_switching, SegmentName, output_file, dash_input->representationID, seg_rad_name, !stricmp(seg_ext, "null") ? NULL : seg_ext, period_duration + segment_start_time, bandwidth, cur_seg, dash_cfg->use_segment_timeline); e = gf_isom_start_segment(output, SegmentName, dash_cfg->memory_mode); - gf_dasher_store_segment_info(dash_cfg, SegmentName, period_duration + segment_start_time / (Double) dash_cfg->dash_scale); - /*we are in bitstream switching mode, delete init segment*/ if (is_bs_switching && !init_segment_deleted) { init_segment_deleted = GF_TRUE; - if (strcmp(dash_cfg->bs_switch_segment_file, gf_isom_get_filename(output))) { + if (dash_cfg->bs_switch_segment_file && strcmp(dash_cfg->bs_switch_segment_file, gf_isom_get_filename(output))) { gf_delete_file(gf_isom_get_filename(output)); } } if (!use_url_template) { - const char *name = gf_url_get_resource_name(SegmentName); + const char *name = gf_dasher_strip_output_dir(dash_cfg->mpd_name, SegmentName); sprintf(szMPDTempLine, " <SegmentURL media=\"%s\"/>\n", name ); gf_bs_write_data(mpd_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); if (dash_cfg->dash_ctx) { @@ -1152,6 +1334,10 @@ restart_fragmentation_pass: } if (dash_cfg->pssh_moof) store_pssh = GF_TRUE; + + if (tfref && dash_cfg->insert_utc) { + store_utc = GF_TRUE; + } } cur_seg++; @@ -1166,21 +1352,24 @@ restart_fragmentation_pass: segments_info[nb_segments_info-1] ++; e = GF_OK; } else { - e = gf_isom_start_fragment(output, 1); + e = gf_isom_start_fragment(output, GF_TRUE); if (e) goto err_exit; - for (i=0; i<count; i++) { + u64 tfdt; tf = (GF_ISOMTrackFragmenter *)gf_list_get(fragmenters, i); if (tf->done) continue; if (dash_cfg->initial_tfdt && (tf->TimeScale != dash_cfg->dash_scale)) { Double scale = tf->TimeScale; scale /= dash_cfg->dash_scale; - gf_isom_set_traf_base_media_decode_time(output, tf->TrackID, (u64) (dash_cfg->initial_tfdt*scale) + tf->InitialTSOffset + tf->next_sample_dts); + tfdt = (u64) (dash_cfg->initial_tfdt*scale) + tf->InitialTSOffset + tf->next_sample_dts; } else { - gf_isom_set_traf_base_media_decode_time(output, tf->TrackID, tf->InitialTSOffset + tf->next_sample_dts); + tfdt = tf->InitialTSOffset + tf->next_sample_dts; } + gf_isom_set_traf_base_media_decode_time(output, tf->TrackID, tfdt); + if (!SegmentDuration) tf->min_cts_in_segment = (u64)-1; + } if (store_pssh) { store_pssh = GF_FALSE; @@ -1195,11 +1384,16 @@ restart_fragmentation_pass: u32 SAP_type = 0; tf = (GF_ISOMTrackFragmenter *)gf_list_get(fragmenters, i); - if (tf == tfref) + if (tf->is_ref_track) has_rap = GF_FALSE; if (tf->done) continue; - + //if not the first TRAF in our moof and single traf per moof is requested, start a new moof + if (!simulation_pass && dash_cfg->single_traf_per_moof && (i>0) ) { + e = gf_isom_start_fragment(output, GF_TRUE); + if (e) goto err_exit; + } + //ok write samples while (1) { Bool stop_frag = GF_FALSE; @@ -1220,9 +1414,9 @@ restart_fragmentation_pass: is_redundant_sample = GF_TRUE; } - /*also get SAP type - this is not needed if sample is not NULL as SAP tye was computed for "next sample" in previous loop*/ + /*also get SAP type - this is not needed if sample is not NULL as SAP type was computed for "next sample" in previous loop*/ if (sample->IsRAP) { - SAP_type = 1; + SAP_type = sample->IsRAP; } else { SAP_type = 0; e = gf_isom_get_sample_rap_roll_info(input, tf->OriginalTrack, tf->SampleNum + 1, &is_rap, &has_roll, &roll_distance); @@ -1239,23 +1433,24 @@ restart_fragmentation_pass: if (next) { defaultDuration = (u32) (next->DTS - sample->DTS); } else { - defaultDuration = (u32) (gf_isom_get_media_duration(input, tf->OriginalTrack)- sample->DTS); + defaultDuration = (u32) (gf_isom_get_media_duration(input, tf->OriginalTrack) - sample->DTS); } if (tf->splitable) { - if (tfref==tf) { + if (tf->is_ref_track) { u64 frag_dur = (tf->FragmentLength + defaultDuration) * dash_cfg->dash_scale / tf->TimeScale; /*if media segment about to be produced is longer than max segment length, force segment split*/ if (SegmentDuration + frag_dur > MaxSegmentDuration) { split_sample_duration = defaultDuration; defaultDuration = (u32) (tf->TimeScale * (MaxSegmentDuration - SegmentDuration) / dash_cfg->dash_scale - tf->FragmentLength); + assert(defaultDuration); split_sample_duration -= defaultDuration; + nb_samp++; } } else if (tfref /* tfref set to NULL after the last sample of tfref is processed */ /*&& next do not split if no next sample */ /*next sample DTS */ -// && ((tf->next_sample_dts /*+ 1 accuracy*/ ) * tfref_timescale < tfref->next_sample_dts * tf->TimeScale) && ((tf->next_sample_dts + defaultDuration) * tfref_timescale > tfref->next_sample_dts * tf->TimeScale)) { split_sample_duration = defaultDuration; defaultDuration = (u32) ( (tfref->next_sample_dts * tf->TimeScale)/tfref_timescale - tf->next_sample_dts ); @@ -1263,13 +1458,14 @@ restart_fragmentation_pass: /*since we split this sample we have to stop fragmenting afterwards*/ stop_frag = GF_TRUE; + nb_samp++; } } - if (tf==tfref) { - if (segments_start_with_sap && first_sample_in_segment ) { + if (tf->is_ref_track) { + if (segments_start_with_sap && first_sample_in_segment) { first_sample_in_segment = GF_FALSE; - if (! SAP_type) segments_start_with_sap = GF_FALSE; + if (!SAP_type) segments_start_with_sap = GF_FALSE; } if (ref_track_first_dts > sample->DTS) ref_track_first_dts = sample->DTS; @@ -1294,6 +1490,12 @@ restart_fragmentation_pass: if (simulation_pass) { e = GF_OK; } else { + if (tf->is_ref_track && store_utc) { + u64 ntpts = gf_net_get_ntp_ts(); + gf_isom_set_fragment_reference_time(output, tf->TrackID, ntpts, sample->DTS + sample->CTS_Offset + tf->media_time_to_pres_time_shift); + store_utc = GF_FALSE; + } + /*override descIndex with final index used in file*/ descIndex = tf->finalSampleDescriptionIndex; e = gf_isom_fragment_add_sample(output, tf->TrackID, sample, descIndex, @@ -1301,6 +1503,9 @@ restart_fragmentation_pass: if (e) goto err_exit; + if (sample->DTS + sample->CTS_Offset < tf->min_cts_in_segment) + tf->min_cts_in_segment = sample->DTS + sample->CTS_Offset; + e = gf_isom_fragment_add_sai(output, input, tf->TrackID, tf->SampleNum + 1); if (e) goto err_exit; @@ -1330,7 +1535,7 @@ restart_fragmentation_pass: /*compute SAP type*/ if (sample) { if (sample->IsRAP) { - SAP_type = 1; + SAP_type = sample->IsRAP; } else { SAP_type = 0; e = gf_isom_get_sample_rap_roll_info(input, tf->OriginalTrack, tf->SampleNum + 1, &is_rap, &has_roll, NULL); @@ -1344,7 +1549,7 @@ restart_fragmentation_pass: } if (next && SAP_type) { - if (tf==tfref) { + if (tf->is_ref_track) { if (split_sample_duration) { stop_frag = GF_TRUE; } @@ -1363,7 +1568,7 @@ restart_fragmentation_pass: /*this is the fragment duration from last sample added to next SAP*/ frag_dur += (s64) (next_sap_time - tf->next_sample_dts - next_dur) * dash_cfg->dash_scale / tf->TimeScale; /*if media segment about to be produced is longer than max segment length, force segment split*/ - if (SegmentDuration + frag_dur > MaxSegmentDuration) { + if (!tf->splitable && (SegmentDuration + frag_dur > MaxSegmentDuration)) { split_at_rap = GF_TRUE; /*force new segment*/ force_switch_segment = GF_TRUE; @@ -1390,26 +1595,42 @@ restart_fragmentation_pass: if (tf->SampleNum==tf->SampleCount) { stop_frag = GF_TRUE; - } else if (tf==tfref) { + } else if (tf->is_ref_track) { /*fragmenting on "clock" track: no drift control*/ - if (!dash_cfg->fragments_start_with_rap || ( (next && next->IsRAP) || split_at_rap) ) { - if (tf->FragmentLength * dash_cfg->dash_scale >= MaxFragmentDuration * tf->TimeScale) { + if (!dash_cfg->fragments_start_with_rap || ( tf->splitable && split_sample_duration ) || ( (next && next->IsRAP) || split_at_rap) ) { + if ((tf->FragmentLength * dash_cfg->dash_scale >= MaxFragmentDuration * tf->TimeScale) + /* if we don't split segment at rap and if the current fragment makes the segment longer than required, stop the current fragment */ + || (!split_seg_at_rap && (SegmentDuration + (tf->FragmentLength * dash_cfg->dash_scale / tf->TimeScale) >= MaxSegmentDuration)) + ) { stop_frag = GF_TRUE; } } } /*do not abort fragment if ref track is done, put everything in the last fragment*/ else if (!flush_all_samples) { + u64 ept_next; + u64 tref_ept_next = get_presentation_time(ref_track_next_cts, tfref->media_time_to_pres_time_shift); + /*get next sample dts: if greater than tref EPT, abort. This ensures that we have at most + one au wihth EPT less than ref EPT*/ + u64 next_dur = gf_isom_get_sample_duration(input, tf->OriginalTrack, tf->SampleNum + 1); + if (!next_dur) next_dur = defaultDuration; + ept_next = get_presentation_time(tf->next_sample_dts + next_dur, tf->media_time_to_pres_time_shift); /*fragmenting on "non-clock" track: drift control*/ - if ((tf->next_sample_dts /*+1 accuracy*/) * tfref_timescale >= ref_track_next_cts * tf->TimeScale) + if (ept_next * tfref_timescale > tref_ept_next * tf->TimeScale) stop_frag = GF_TRUE; } if (stop_frag) { gf_isom_sample_del(&sample); sample = next = NULL; - if (maxFragDurationOverSegment <= tf->FragmentLength * dash_cfg->dash_scale / tf->TimeScale) { - maxFragDurationOverSegment = tf->FragmentLength * dash_cfg->dash_scale / tf->TimeScale; + + //only compute max dur over segment for the track used for indexing / deriving MPD start time + if (!tfref || (tf->is_ref_track)) { + u64 f_dur; + f_dur = ( tf->FragmentLength ) * dash_cfg->dash_scale / tf->TimeScale; + if (maxFragDurationOverSegment <= f_dur) { + maxFragDurationOverSegment = f_dur; + } } tf->FragmentLength = 0; if (split_sample_duration) @@ -1425,7 +1646,7 @@ restart_fragmentation_pass: if (tf->SampleNum==tf->SampleCount) { tf->done = GF_TRUE; nb_tracks_done++; - if (tf == tfref) { + if (tf->is_ref_track) { tfref = NULL; flush_all_samples = GF_TRUE; } @@ -1435,45 +1656,92 @@ restart_fragmentation_pass: SegmentDuration += maxFragDurationOverSegment; maxFragDurationOverSegment=0; - /*if no simulation and no SIDX is used, flush fragments as we write them*/ - if (!simulation_pass && (dash_cfg->subsegs_per_sidx<0) ) { + /*if no simulation and no SIDX or realtime is used, flush fragments as we write them*/ + if (!simulation_pass && ((dash_cfg->subsegs_per_sidx<0) || dash_cfg->real_time) ) { + + if (tfref && dash_cfg->real_time) { + u64 end_time = tfref->InitialTSOffset + tfref->next_sample_dts - tfref->DefaultDuration; + end_time *= 1000; + end_time /= tfref->TimeScale; + + while (1) { + s32 diff_ms = gf_net_get_ntp_diff_ms(generation_start_ntp); + if (diff_ms >= end_time) break; + gf_sleep(1); + } + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH] Flushing fragment at "LLU" us\n", gf_sys_clock_high_res() )); + } + e = gf_isom_flush_fragments(output, flush_all_samples ? GF_TRUE : GF_FALSE); if (e) goto err_exit; } + //this is now disabled - we try to keep segment duration as constant and close to the requested duration as possible + //this code was producing much shorter segments in case segment duration was way greater than fragment duration + //this means we will typically end up with one shorter fragment at the end of the segment +#if 0 /*next fragment will exceed segment length, abort fragment now (all samples RAPs)*/ if (tfref && tfref->all_sample_raps && (SegmentDuration + MaxFragmentDuration >= MaxSegmentDuration)) { force_switch_segment = GF_TRUE; } +#endif - if (force_switch_segment || ((SegmentDuration >= MaxSegmentDuration) && (!split_seg_at_rap || next_sample_rap))) { - - store_segment_duration(&segment_duration, SegmentDuration); + if (force_switch_segment || ((SegmentDuration >= MaxSegmentDuration) && (!split_seg_at_rap || !next || next_sample_rap || tf->splitable))) { + if (!min_seg_dur || (min_seg_dur>SegmentDuration)) + min_seg_dur = SegmentDuration; + if (max_seg_dur < SegmentDuration) + max_seg_dur = SegmentDuration; + total_seg_dur += SegmentDuration; + last_seg_dur = SegmentDuration; if (mpd_timeline_bs) { - if (previous_segment_duration == SegmentDuration) { - segment_timeline_repeat_count ++; - } else { - if (previous_segment_duration) { - if (segment_timeline_repeat_count) { - sprintf(szMPDTempLine, " r=\"%d\"/>\n", segment_timeline_repeat_count); - } else { - sprintf(szMPDTempLine, "/>\n"); + u32 tick_adjust = 0; + + //since dash scale and ref track used for segmentation may not have the same timescale we will have drift in segment timelines. Adjust it + if (tfref) { + s64 seg_start_time_min_cts = (s64) (tfref->min_cts_in_segment + tfref->media_time_to_pres_time_shift) * dash_cfg->dash_scale; + u64 seg_start_time_mpd = (period_duration + segment_start_time) * tfref->TimeScale; + + //if first CTS in segment is less than 0, this means that we have AUs that are not presented due to edit list. + //adjust the segment duration accordingly. + if (seg_start_time_min_cts<0) { + s64 mpd_time_adjust = seg_start_time_min_cts / tfref->TimeScale; + if ((s64) SegmentDuration < - mpd_time_adjust) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error: Segment duration is less than media time from edit list (%d vs %d)\n", MaxSegmentDuration, -tfref->media_time_to_pres_time_shift)); + e = GF_BAD_PARAM; + goto err_exit; } - gf_bs_write_data(mpd_timeline_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); + SegmentDuration += mpd_time_adjust; + seg_start_time_min_cts=0; } - previous_segment_duration = SegmentDuration; - if (first_segment_in_timeline) { - sprintf(szMPDTempLine, " <S t=\""LLU"\" d=\""LLU"\"", (u64) (segment_start_time*dash_cfg->dash_scale), (u64) SegmentDuration ); - first_segment_in_timeline = GF_FALSE; - } else { - sprintf(szMPDTempLine, " <S d=\""LLU"\"", (u64) SegmentDuration); + + if (seg_start_time_mpd != seg_start_time_min_cts) { + //compute diff in dash timescale + Double diff = (Double) seg_start_time_min_cts; + diff -= (Double) seg_start_time_mpd; + diff /= tfref->TimeScale; + + //if we are ahead we will adjust keep track of how many ticks we miss + if (diff >= 1) { + tick_adjust = (u32) diff; + if (tick_adjust > 1) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Drift between minCTS of segment and MPD start time is %g s\n", diff/dash_cfg->dash_scale)); + } + } } - gf_bs_write_data(mpd_timeline_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); - segment_timeline_repeat_count = 0; - } + } + //adjust + gf_dash_append_segment_timeline(mpd_timeline_bs, period_duration + segment_start_time, SegmentDuration + tick_adjust, &previous_segment_duration, &first_segment_in_timeline, &segment_timeline_repeat_count); + period_duration += tick_adjust; } + if (dash_cfg->max_segment_duration * dash_cfg->dash_scale < SegmentDuration) { + dash_cfg->max_segment_duration = (Double) SegmentDuration; + dash_cfg->max_segment_duration /= dash_cfg->dash_scale; + } + + gf_dasher_store_segment_info(dash_cfg, dash_input->representationID, SegmentName, period_duration + segment_start_time, SegmentDuration); segment_start_time += SegmentDuration; nb_segments++; @@ -1487,12 +1755,20 @@ restart_fragmentation_pass: split_at_rap = GF_FALSE; has_rap = GF_FALSE; /*restore fragment duration*/ - MaxFragmentDuration = (u32) (max_duration_sec * dash_cfg->dash_scale); + MaxFragmentDuration = (u32) (dash_cfg->fragment_duration * dash_cfg->dash_scale); if (!simulation_pass) { u64 idx_start_range, idx_end_range; + Bool last_segment = flush_all_samples ? GF_TRUE : GF_FALSE; - gf_isom_close_segment(output, dash_cfg->subsegs_per_sidx, ref_track_id, ref_track_first_dts, tfref ? tfref->media_time_to_pres_time_shift : tf->media_time_to_pres_time_shift, ref_track_next_cts, dash_cfg->daisy_chain_sidx, flush_all_samples ? GF_TRUE : GF_FALSE, dash_cfg->segment_marker_4cc, &idx_start_range, &idx_end_range); + if (dash_cfg->subduration && (segment_start_time + MaxSegmentDuration/2 >= dash_cfg->dash_scale * dash_cfg->subduration)) { + //onDemand with subdur: if we are done dashing the content set last segment to TRUE to flush sidx + //live and end of period forced, force last segment + if (dash_cfg->force_period_end || (dash_cfg->single_file_mode==1) ) + last_segment = GF_TRUE; + } + + gf_isom_close_segment(output, dash_cfg->subsegs_per_sidx, ref_track_id, ref_track_first_dts, tfref ? tfref->media_time_to_pres_time_shift : tf->media_time_to_pres_time_shift, ref_track_next_cts, dash_cfg->daisy_chain_sidx, last_segment, dash_cfg->segment_marker_4cc, &idx_start_range, &idx_end_range); //take care of scalable reps if (dash_input->moof_seqnum_increase) { @@ -1560,19 +1836,10 @@ restart_fragmentation_pass: if (!switch_segment) { u64 idx_start_range, idx_end_range; - store_segment_duration(&segment_duration, SegmentDuration); + total_seg_dur += SegmentDuration; + last_seg_dur = SegmentDuration; - /*do not update on last segment, we're likely to have a different last GOP*/ -#if 0 - if (max_segment_duration * dash_cfg->dash_scale <= SegmentDuration) { - max_segment_duration = (Double) (s64) SegmentDuration; - max_segment_duration /= dash_cfg->dash_scale; - } -#endif - - segment_start_time += SegmentDuration; - - gf_isom_close_segment(output, dash_cfg->subsegs_per_sidx, ref_track_id, ref_track_first_dts, tfref ? tfref->media_time_to_pres_time_shift : tf->media_time_to_pres_time_shift, ref_track_next_cts, dash_cfg->daisy_chain_sidx, 1, dash_cfg->segment_marker_4cc, &idx_start_range, &idx_end_range); + gf_isom_close_segment(output, dash_cfg->subsegs_per_sidx, ref_track_id, ref_track_first_dts, tfref ? tfref->media_time_to_pres_time_shift : tf->media_time_to_pres_time_shift, ref_track_next_cts, dash_cfg->daisy_chain_sidx, GF_TRUE, dash_cfg->segment_marker_4cc, &idx_start_range, &idx_end_range); nb_segments++; if (!seg_rad_name) { @@ -1598,6 +1865,7 @@ restart_fragmentation_pass: file_size += gf_isom_get_file_size(output); } } + //close timeline if (mpd_timeline_bs) { if (previous_segment_duration == SegmentDuration) { segment_timeline_repeat_count ++; @@ -1614,7 +1882,7 @@ restart_fragmentation_pass: } if (SegmentDuration) { if (first_segment_in_timeline) { - sprintf(szMPDTempLine, " <S t=\""LLU"\" d=\""LLU"\"/>\n", (u64) (segment_start_time), (u64) SegmentDuration ); + sprintf(szMPDTempLine, " <S t=\""LLU"\" d=\""LLU"\"/>\n", segment_start_time, SegmentDuration ); first_segment_in_timeline = GF_FALSE; } else { sprintf(szMPDTempLine, " <S d=\""LLU"\"/>\n", (u64) SegmentDuration); @@ -1626,21 +1894,23 @@ restart_fragmentation_pass: sprintf(szMPDTempLine, " </SegmentTimeline>\n"); gf_bs_write_data(mpd_timeline_bs, szMPDTempLine, (u32) strlen(szMPDTempLine)); } - else { - u32 k; - u32 most_frequent_duration = 0; - - for (k = 0; k < gf_list_count(segment_duration); k++) { - GF_DASHSegmentDuration *entry; - entry = (GF_DASHSegmentDuration *)gf_list_get(segment_duration, k); - if (entry->nb_segment > most_frequent_duration) { - max_segment_duration = (Double) entry->segment_duration; - max_segment_duration /= dash_cfg->dash_scale; - most_frequent_duration = entry->nb_segment; + else if (!dash_cfg->use_segment_timeline) { + if (dash_cfg->dash_ctx) { + max_segment_duration = dash_cfg->segment_duration; + } else { + if (3*min_seg_dur < max_seg_dur) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Segment duration variation is higher than the +/- 50%% allowed by DASH-IF (min %g, max %g) - please reconsider encoding\n", (Double) min_seg_dur / dash_cfg->dash_scale, (Double) max_seg_dur / dash_cfg->dash_scale)); + } + if (nb_segments == 1) { + max_segment_duration = (Double) total_seg_dur; + max_segment_duration /= nb_segments * dash_cfg->dash_scale; + } else { + max_segment_duration = (Double) (total_seg_dur - last_seg_dur); + max_segment_duration /= (nb_segments - 1) * dash_cfg->dash_scale; } } } - + if (!bandwidth) bandwidth = (u32) (file_size * 8 / file_duration); @@ -1648,13 +1918,17 @@ restart_fragmentation_pass: bandwidth += dash_input->dependency_bandwidth; dash_input->bandwidth = bandwidth; + if (use_url_template) { /*segment template does not depend on file name, write the template at the adaptationSet level*/ if (!dash_cfg->variable_seg_rad_name && first_in_set) { - const char *rad_name = gf_url_get_resource_name(seg_rad_name); + const char *rad_name = gf_dasher_strip_output_dir(dash_cfg->mpd_name, seg_rad_name); gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_TEMPLATE, is_bs_switching, SegmentName, output_file, dash_input->representationID, rad_name, !stricmp(seg_ext, "null") ? NULL : seg_ext, 0, 0, 0, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " <SegmentTemplate timescale=\"%d\" media=\"%s\" startNumber=\"%d\"", mpd_timeline_bs ? dash_cfg->dash_scale : mpd_timescale, SegmentName, startNumber); - if (!mpd_timeline_bs) { + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } + if (!dash_cfg->use_segment_timeline) { if (!max_segment_duration) max_segment_duration = dash_cfg->segment_duration; fprintf(dash_cfg->mpd, " duration=\"%d\"", (u32) (max_segment_duration * mpd_timescale)); @@ -1667,7 +1941,7 @@ restart_fragmentation_pass: } fprintf(dash_cfg->mpd, " initialization=\"%s\"", SegmentName); if (presentationTimeOffset) - fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", presentationTimeOffset); + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset); if (mpd_timeline_bs) { char *mpd_seg_info = NULL; @@ -1683,15 +1957,23 @@ restart_fragmentation_pass: } } /*in BS switching we share the same IS for all reps, write the SegmentTemplate for the init segment*/ - else if (is_bs_switching && first_in_set) { - fprintf(dash_cfg->mpd, " <SegmentTemplate initialization=\"%s\"", bs_switching_segment_name); - if (presentationTimeOffset) - fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", presentationTimeOffset); + else if ((is_bs_switching || mpd_timeline_bs) && first_in_set && !dash_cfg->segment_alignment_disabled) { + fprintf(dash_cfg->mpd, " <SegmentTemplate"); + if (is_bs_switching) { + fprintf(dash_cfg->mpd, " initialization=\"%s\"", bs_switching_segment_name); + if (presentationTimeOffset) + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset); + } + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } if (mpd_timeline_bs) { char *mpd_seg_info = NULL; u32 size; - fprintf(dash_cfg->mpd, ">\n"); + + + fprintf(dash_cfg->mpd, " timescale=\"%d\">\n", dash_cfg->dash_scale); gf_bs_get_content(mpd_timeline_bs, &mpd_seg_info, &size); gf_fwrite(mpd_seg_info, 1, size, dash_cfg->mpd); @@ -1706,7 +1988,11 @@ restart_fragmentation_pass: char *mpd_seg_info = NULL; u32 size; - fprintf(dash_cfg->mpd, " <SegmentList timescale=\"%d\">\n", dash_cfg->dash_scale); + fprintf(dash_cfg->mpd, " <SegmentList timescale=\"%d\"", dash_cfg->dash_scale); + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } + fprintf(dash_cfg->mpd, "\n"); gf_bs_get_content(mpd_timeline_bs, &mpd_seg_info, &size); gf_fwrite(mpd_seg_info, 1, size, dash_cfg->mpd); @@ -1714,14 +2000,18 @@ restart_fragmentation_pass: fprintf(dash_cfg->mpd, " </SegmentList>\n"); } + /* Write adaptation set content protection element */ + if (protected_track && first_in_set && !dash_cfg->content_protection_in_rep) { + gf_isom_write_content_protection(input, dash_cfg->mpd, protected_track, 3); + } fprintf(dash_cfg->mpd, " <Representation "); - if (dash_input->representationID) fprintf(dash_cfg->mpd, "id=\"%s\"", dash_input->representationID); + if ( strlen(dash_input->representationID) ) fprintf(dash_cfg->mpd, "id=\"%s\"", dash_input->representationID); else fprintf(dash_cfg->mpd, "id=\"%p\"", output); fprintf(dash_cfg->mpd, " mimeType=\"%s/mp4\" codecs=\"%s\"", audio_only ? "audio" : "video", szCodecs); if (width && height) { - fprintf(dash_cfg->mpd, " width=\"%d\" height=\"%d\"", width, height); + fprintf(dash_cfg->mpd, " width=\"%u\" height=\"%u\"", width, height); /*this is a video track*/ if (fps_num || fps_denum) { @@ -1735,22 +2025,38 @@ restart_fragmentation_pass: if (!sar_h) sar_h = 1; fprintf(dash_cfg->mpd, " sar=\"%d:%d\"", sar_w, sar_h); } - } if (sample_rate) fprintf(dash_cfg->mpd, " audioSamplingRate=\"%d\"", sample_rate); - if (segments_start_with_sap || split_seg_at_rap) { - fprintf(dash_cfg->mpd, " startWithSAP=\"%d\"", max_sap_type); - } else { - fprintf(dash_cfg->mpd, " startWithSAP=\"0\""); + + //single segment (onDemand profiles, assumes we always start with an IDR) + if (dash_cfg->single_file_mode==1) { + fprintf(dash_cfg->mpd, " startWithSAP=\"1\""); + } + //regular segmenting + else { + if (segments_start_with_sap || split_seg_at_rap) { + fprintf(dash_cfg->mpd, " startWithSAP=\"%d\"", max_sap_type); + } else { + fprintf(dash_cfg->mpd, " startWithSAP=\"0\""); + } } + + //only appears at AdaptationSet level - need to rewrite the DASH segementer to allow writing this at the proper place // if ((single_file_mode==1) && segments_start_with_sap) fprintf(dash_cfg->mpd, " subsegmentStartsWithSAP=\"%d\"", max_sap_type); fprintf(dash_cfg->mpd, " bandwidth=\"%d\"", bandwidth); - if (strlen(dash_input->dependencyID)) + if (dash_input->dependencyID) fprintf(dash_cfg->mpd, " dependencyId=\"%s\"", dash_input->dependencyID); fprintf(dash_cfg->mpd, ">\n"); + /* baseURLs */ + if (dash_input->nb_baseURL) { + for (i=0; i<dash_input->nb_baseURL; i++) { + fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n", dash_input->baseURL[i]); + } + } + /* writing Representation level descriptors */ if (dash_input->nb_rep_descs) { for (i=0; i<dash_input->nb_rep_descs; i++) { @@ -1761,26 +2067,9 @@ restart_fragmentation_pass: if (nb_channels && !is_bs_switching) fprintf(dash_cfg->mpd, " <AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\"/>\n", nb_channels); - - if (protected_track) { - u32 prot_scheme = gf_isom_is_media_encrypted(input, protected_track, 1); - if (gf_isom_is_cenc_media(input, protected_track, 1)) { - bin128 default_KID; - gf_isom_cenc_get_default_info(input, protected_track, 1, NULL, NULL, &default_KID); - fprintf(dash_cfg->mpd, " <ContentProtection schemeIdUri=\"urn:mpeg:dash:mp4protection:2011\" value=\"%s\" cenc:default_KID=\"", gf_4cc_to_str(prot_scheme) ); - /* Output canonical UIID form */ - for (i=0; i<4; i++) fprintf(dash_cfg->mpd, "%02x", default_KID[i]); - fprintf(dash_cfg->mpd, "-"); - for (i=4; i<6; i++) fprintf(dash_cfg->mpd, "%02x", default_KID[i]); - fprintf(dash_cfg->mpd, "-"); - for (i=6; i<8; i++) fprintf(dash_cfg->mpd, "%02x", default_KID[i]); - fprintf(dash_cfg->mpd, "-"); - for (i=8; i<10; i++) fprintf(dash_cfg->mpd, "%02x", default_KID[i]); - fprintf(dash_cfg->mpd, "-"); - for (i=10; i<16; i++) fprintf(dash_cfg->mpd, "%02x", default_KID[i]); - fprintf(dash_cfg->mpd, "\"/>\n"); - } - //todo for ISMA or OMA DRM + /* Write content protection element in representation */ + if (protected_track && dash_cfg->content_protection_in_rep) { + gf_isom_write_content_protection(input, dash_cfg->mpd, protected_track, 4); } if (dash_cfg->dash_ctx) { @@ -1804,10 +2093,10 @@ restart_fragmentation_pass: if (use_url_template) { /*segment template depends on file name, but the template at the representation level*/ if (dash_cfg->variable_seg_rad_name) { - const char *rad_name = gf_url_get_resource_name(seg_rad_name); + const char *rad_name = gf_dasher_strip_output_dir(dash_cfg->mpd_name, seg_rad_name); gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_TEMPLATE, is_bs_switching, SegmentName, output_file, dash_input->representationID, rad_name, !stricmp(seg_ext, "null") ? NULL : seg_ext, 0, bandwidth, 0, dash_cfg->use_segment_timeline); - fprintf(dash_cfg->mpd, " <SegmentTemplate timescale=\"%d\" media=\"%s\" startNumber=\"%d\"", mpd_timescale, SegmentName, startNumber); - if (!mpd_timeline_bs) { + fprintf(dash_cfg->mpd, " <SegmentTemplate timescale=\"%d\" media=\"%s\" startNumber=\"%d\"", dash_cfg->use_segment_timeline ? dash_cfg->dash_scale : mpd_timescale, SegmentName, startNumber); + if (!dash_cfg->use_segment_timeline) { if (!max_segment_duration) max_segment_duration = dash_cfg->segment_duration; fprintf(dash_cfg->mpd, " duration=\"%d\"", (u32) (max_segment_duration * mpd_timescale)); @@ -1817,25 +2106,50 @@ restart_fragmentation_pass: fprintf(dash_cfg->mpd, " initialization=\"%s\"", SegmentName); } if (presentationTimeOffset) - fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", presentationTimeOffset); - fprintf(dash_cfg->mpd, "/>\n"); + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset); + + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } + + if (mpd_timeline_bs && (!first_in_set || dash_cfg->segment_alignment_disabled) ) { + char *mpd_seg_info = NULL; + u32 size; + fprintf(dash_cfg->mpd, ">\n"); + + gf_bs_get_content(mpd_timeline_bs, &mpd_seg_info, &size); + gf_fwrite(mpd_seg_info, 1, size, dash_cfg->mpd); + gf_free(mpd_seg_info); + fprintf(dash_cfg->mpd, " </SegmentTemplate>\n"); + } else { + fprintf(dash_cfg->mpd, "/>\n"); + } } } else if (dash_cfg->single_file_mode==1) { - fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n", gf_url_get_resource_name( gf_isom_get_filename(output) ) ); + fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n", gf_dasher_strip_output_dir(dash_cfg->mpd_name, gf_isom_get_filename(output) ) ); fprintf(dash_cfg->mpd, " <SegmentBase indexRangeExact=\"true\" indexRange=\"%d-%d\"", index_start_range, index_end_range); if (presentationTimeOffset) - fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", presentationTimeOffset); - fprintf(dash_cfg->mpd, "/>\n"); + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset); + if (!is_bs_switching) { + fprintf(dash_cfg->mpd, ">\n"); + fprintf(dash_cfg->mpd, " <Initialization range=\"%d-%d\"/>\n", 0, index_start_range-1); + fprintf(dash_cfg->mpd, " </SegmentBase>\n"); + } else { + fprintf(dash_cfg->mpd, "/>\n"); + } } else { if (!seg_rad_name) { - fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n", gf_url_get_resource_name( gf_isom_get_filename(output) ) ); + fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n", gf_dasher_strip_output_dir(dash_cfg->mpd_name, gf_isom_get_filename(output) ) ); } fprintf(dash_cfg->mpd, " <SegmentList"); if (!mpd_timeline_bs) { fprintf(dash_cfg->mpd, " timescale=\"%d\" duration=\"%d\"", mpd_timescale, (u32) (max_segment_duration * mpd_timescale)); } if (presentationTimeOffset) { - fprintf(dash_cfg->mpd, " presentationTimeOffset=\"%d\"", presentationTimeOffset); + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset); + } + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); } fprintf(dash_cfg->mpd, ">\n"); /*we are not in bitstreamSwitching mode*/ @@ -1844,7 +2158,7 @@ restart_fragmentation_pass: if (!seg_rad_name) { fprintf(dash_cfg->mpd, " range=\"0-"LLD"\"", init_seg_size-1); } else { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION, is_bs_switching, SegmentName, output_file, dash_input->representationID, gf_url_get_resource_name( seg_rad_name) , !stricmp(seg_ext, "null") ? NULL : "mp4", 0, bandwidth, 0, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION, is_bs_switching, SegmentName, output_file, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, seg_rad_name) , !stricmp(seg_ext, "null") ? NULL : "mp4", 0, bandwidth, 0, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " sourceURL=\"%s\"", SegmentName); } fprintf(dash_cfg->mpd, "/>\n"); @@ -1867,7 +2181,7 @@ restart_fragmentation_pass: /*store context*/ if (dash_cfg->dash_ctx) { - period_duration += (Double)segment_start_time / dash_cfg->dash_scale; + period_duration += segment_start_time; for (i=0; i<gf_list_count(fragmenters); i++) { tf = (GF_ISOMTrackFragmenter *)gf_list_get(fragmenters, i); @@ -1891,6 +2205,10 @@ restart_fragmentation_pass: sprintf(sKey, "TKID_%d_NextSampleDTS", tf->TrackID); sprintf(sOpt, LLU, tf->next_sample_dts); gf_cfg_set_key(dash_cfg->dash_ctx, RepSecName, sKey, tf->done ? NULL : sOpt); + + sprintf(sKey, "TKID_%d_MediaTimeToPresTime", tf->TrackID); + sprintf(sOpt, "%d", tf->media_time_to_pres_time_shift); + gf_cfg_set_key(dash_cfg->dash_ctx, RepSecName, sKey, sOpt); } } sprintf(sOpt, "%d", cur_seg); @@ -1901,7 +2219,7 @@ restart_fragmentation_pass: gf_cfg_set_key(dash_cfg->dash_ctx, RepSecName, "NextFragmentIndex", sOpt); - sprintf(sOpt, "%f", period_duration); + sprintf(sOpt, LLU, period_duration); gf_cfg_set_key(dash_cfg->dash_ctx, RepSecName, "CumulatedDuration", sOpt); if (store_dash_params) { @@ -1911,6 +2229,9 @@ restart_fragmentation_pass: } err_exit: + if (langCode) { + gf_free(langCode); + } if (fragmenters) { while (gf_list_count(fragmenters)) { tf = (GF_ISOMTrackFragmenter *)gf_list_get(fragmenters, 0); @@ -1928,14 +2249,6 @@ err_exit: gf_set_progress("ISO File Fragmenting", nb_samp, nb_samp); if (mpd_bs) gf_bs_del(mpd_bs); if (mpd_timeline_bs) gf_bs_del(mpd_timeline_bs); - if (segment_duration) { - while (gf_list_count(segment_duration)) { - GF_DASHSegmentDuration *entry = (GF_DASHSegmentDuration *)gf_list_last(segment_duration); - gf_free(entry); - gf_list_rem_last(segment_duration); - } - gf_list_del(segment_duration); - } return e; } @@ -1973,20 +2286,20 @@ static GF_Err dasher_isom_get_input_components_info(GF_DashSegInput *input, GF_D input->components[input->nb_components].ID = gf_isom_get_track_id(in, i+1); input->components[input->nb_components].media_type = mtype; + gf_isom_get_media_language(in, i+1, &input->components[input->nb_components].lang); + if (mtype == GF_ISOM_MEDIA_VISUAL) { gf_isom_get_visual_info(in, i+1, 1, &input->components[input->nb_components].width, &input->components[input->nb_components].height); input->components[input->nb_components].fps_num = gf_isom_get_media_timescale(in, i+1); /*get duration of 2nd sample*/ input->components[input->nb_components].fps_denum = gf_isom_get_sample_duration(in, i+1, 2); - } /*non-video tracks, get lang*/ else if (mtype == GF_ISOM_MEDIA_AUDIO) { u8 bps; gf_isom_get_audio_info(in, i+1, 1, &input->components[input->nb_components].sample_rate, &input->components[input->nb_components].channels, &bps); } - gf_isom_get_media_language(in, i+1, input->components[input->nb_components].szLang); input->nb_components++; } @@ -2005,8 +2318,8 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da for (i=input_idx+1; i<nb_dash_inputs; i++) { Bool has_same_desc = GF_TRUE; - Bool valid_in_adaptation_set = 1; - Bool assign_to_group = 1; + Bool valid_in_adaptation_set = GF_TRUE; + Bool assign_to_group = GF_TRUE; GF_ISOFile *in; if (dash_inputs[input_idx].period != dash_inputs[i].period) @@ -2015,13 +2328,13 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da if (strcmp(dash_inputs[input_idx].szMime, dash_inputs[i].szMime)) continue; - if (strcmp(dash_inputs[input_idx].role, dash_inputs[i].role)) + if (dash_inputs[input_idx].role && dash_inputs[i].role && strcmp(dash_inputs[input_idx].role, dash_inputs[i].role)) continue; /* if two inputs don't have the same (number and value) as_desc they don't belong to the same AdaptationSet (use c_as_desc for AdaptationSet descriptors common to all inputs in an AS) */ if (dash_inputs[input_idx].nb_as_descs != dash_inputs[i].nb_as_descs) - continue; + continue; for (j = 0; j < dash_inputs[input_idx].nb_as_descs; j++) { if (strcmp(dash_inputs[input_idx].as_descs[j], dash_inputs[i].as_descs[j])) { has_same_desc= GF_FALSE; @@ -2039,12 +2352,12 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da for (j=0; j<gf_isom_get_track_count(set_file); j++) { u32 mtype, msub_type; - Bool same_codec = 1; + Bool same_codec = GF_TRUE; u32 track = gf_isom_get_track_by_id(in, gf_isom_get_track_id(set_file, j+1)); if (!track) { - valid_in_adaptation_set = 0; - assign_to_group = 0; + valid_in_adaptation_set = GF_FALSE; + assign_to_group = GF_FALSE; break; } @@ -2057,12 +2370,12 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da mtype = gf_isom_get_media_type(set_file, j+1); if (mtype != gf_isom_get_media_type(in, track)) { - valid_in_adaptation_set = 0; - assign_to_group = 0; + valid_in_adaptation_set = GF_FALSE; + assign_to_group = GF_FALSE; break; } msub_type = gf_isom_get_media_subtype(set_file, j+1, 1); - if (msub_type != gf_isom_get_media_subtype(in, track, 1)) same_codec = 0; + if (msub_type != gf_isom_get_media_subtype(in, track, 1)) same_codec = GF_FALSE; if ((msub_type==GF_ISOM_SUBTYPE_MPEG4) || (msub_type==GF_ISOM_SUBTYPE_MPEG4_CRYP) || (msub_type==GF_ISOM_SUBTYPE_AVC_H264) @@ -2077,28 +2390,32 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da GF_DecoderConfig *dcd1 = gf_isom_get_decoder_config(set_file, j+1, 1); GF_DecoderConfig *dcd2 = gf_isom_get_decoder_config(in, track, 1); if (dcd1 && dcd2 && (dcd1->streamType==dcd2->streamType) && (dcd1->objectTypeIndication==dcd2->objectTypeIndication)) { - same_codec = 1; + same_codec = GF_TRUE; } else { - same_codec = 0; + same_codec = GF_FALSE; } if (dcd1) gf_odf_desc_del((GF_Descriptor *)dcd1); if (dcd2) gf_odf_desc_del((GF_Descriptor *)dcd2); } if (!same_codec) { - valid_in_adaptation_set = 0; + valid_in_adaptation_set = GF_FALSE; break; } if ((mtype!=GF_ISOM_MEDIA_VISUAL) && (mtype!=GF_ISOM_MEDIA_HINT)) { - char szLang1[4], szLang2[4]; - szLang1[3] = szLang2[3] = 0; - gf_isom_get_media_language(set_file, j+1, szLang1); - gf_isom_get_media_language(in, track, szLang2); - if (stricmp(szLang1, szLang2)) { - valid_in_adaptation_set = 0; + char *lang1, *lang2; + lang1 = lang2 = NULL; + gf_isom_get_media_language(set_file, j+1, &lang1); + gf_isom_get_media_language(in, track, &lang2); + if (lang1 && lang2 && stricmp(lang1, lang2)) { + valid_in_adaptation_set = GF_FALSE; + gf_free(lang1); + gf_free(lang2); break; } + if (lang1) gf_free(lang1); + if (lang2) gf_free(lang2); } if (mtype==GF_ISOM_MEDIA_VISUAL) { u32 w1, h1, w2, h2, sap_type; @@ -2109,8 +2426,29 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da gf_isom_get_track_layout_info(in, track, &w2, &h2, NULL, NULL, NULL); if (h1*w2 != h2*w1) { - valid_in_adaptation_set = 0; - break; + u32 hs1, hs2, vs1, vs2, vw1, vh1, vw2, vh2; + u64 ar1, ar2; + + //check same sample aspect ratio + gf_isom_get_pixel_aspect_ratio(set_file, j+1, 1, &hs1, &vs1); + gf_isom_get_pixel_aspect_ratio(in, track, 1, &hs2, &vs2); + + //check same image aspect ratio + gf_isom_get_visual_info(set_file, j+1, 1, &vw1, &vh1); + gf_isom_get_visual_info(in, track, 1, &vw2, &vh2); + + ar1 = vh1*vw2; + ar1*= hs2*vs1; + + ar2 = vh2*vw1; + ar2 *= hs1*vs2; + if (ar1 != ar2) { + gf_isom_get_track_layout_info(in, track, &w2, &h2, NULL, NULL, NULL); + valid_in_adaptation_set = GF_FALSE; + break; + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Files have non-proportional track layouts (%dx%d vs %dx%d) but sample size and aspect ratio match, assuming precision issue\n", w1, h1, w2, h2)); + } } gf_isom_get_sample_rap_roll_info(in, track, 0, &rap, &roll, &roll_dist); @@ -2137,18 +2475,26 @@ static GF_Err dasher_isom_classify_input(GF_DashSegInput *dash_inputs, u32 nb_da return GF_OK; } -static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 adaptation_set, char *szInitName, const char *tmpdir, GF_DASHSegmenterOptions *dash_opts, Bool *disable_bs_switching) +static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 adaptation_set, char *szInitName, const char *tmpdir, GF_DASHSegmenterOptions *dash_opts, GF_DashSwitchingMode bs_switch_mode, Bool *disable_bs_switching) { GF_Err e = GF_OK; u32 i; u32 single_track_id = 0; - Bool sps_merge_failed = 0; - Bool use_avc3 = 0; - Bool use_hevc = 0; + Bool sps_merge_failed = GF_FALSE; + Bool use_avc3 = GF_FALSE; + Bool use_hevc = GF_FALSE; Bool use_inband_param_set; - Bool single_segment = (dash_opts->single_file_mode==1) ? 1 : 0; - GF_ISOFile *init_seg = gf_isom_open(szInitName, GF_ISOM_OPEN_WRITE, tmpdir); + u32 probe_inband_param_set; + u32 first_track = 0; + Bool single_segment = (dash_opts->single_file_mode==1) ? GF_TRUE : GF_FALSE; + GF_ISOFile *init_seg; + + + probe_inband_param_set = dash_opts->inband_param_set ? 1 : 0; +restart_init: + + init_seg = gf_isom_open(szInitName, GF_ISOM_OPEN_WRITE, tmpdir); for (i=0; i<nb_dash_inputs; i++) { u32 j; GF_ISOFile *in; @@ -2157,7 +2503,7 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 continue; //no inband param set for scalable files - use_inband_param_set = dash_inputs[i].trackNum ? 0 : dash_opts->inband_param_set; + use_inband_param_set = dash_inputs[i].trackNum ? GF_FALSE : dash_opts->inband_param_set; in = gf_isom_open(dash_inputs[i].file_name, GF_ISOM_OPEN_READ, NULL); if (!in) { @@ -2166,6 +2512,14 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 return e; } + if (bs_switch_mode == GF_DASH_BSMODE_MULTIPLE_ENTRIES) { + if (gf_isom_get_track_count(in)>1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot use muli-stsd mode on files with multiple tracks\n")); + return GF_NOT_SUPPORTED; + } + } + + for (j=0; j<gf_isom_get_track_count(in); j++) { u32 track; @@ -2177,6 +2531,7 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 single_track_id = gf_isom_get_track_id(in, j+1); //if not the same ID between the two tracks we cannot create a legal file with bitstream switching enabled else if (single_track_id != gf_isom_get_track_id(in, j+1)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Track IDs different between representations, disabling bitstream switching\n")); *disable_bs_switching = GF_TRUE; gf_isom_delete(init_seg); gf_delete_file(szInitName); @@ -2195,35 +2550,46 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 gf_isom_delete(in); return e; } +retry_track: + + if (bs_switch_mode == GF_DASH_BSMODE_MULTIPLE_ENTRIES) { + gf_isom_clone_sample_description(init_seg, track, in, j+1, 1, NULL, NULL, &outDescIndex); + } /*if not the same sample desc we might need to clone it*/ - if (! gf_isom_is_same_sample_description(in, j+1, 1, init_seg, track, 1)) { + else if (! gf_isom_is_same_sample_description(in, j+1, 1, init_seg, track, 1)) { u32 merge_mode = 1; u32 stype1, stype2; stype1 = gf_isom_get_media_subtype(in, j+1, 1); stype2 = gf_isom_get_media_subtype(init_seg, track, 1); if (stype1 != stype2) merge_mode = 0; switch (stype1) { - case GF_4CC( 'a', 'v', 'c', '1'): - case GF_4CC( 'a', 'v', 'c', '2'): + case GF_ISOM_SUBTYPE_AVC_H264: + case GF_ISOM_SUBTYPE_AVC2_H264: + case GF_ISOM_SUBTYPE_MPEG4_CRYP: if (use_avc3) merge_mode = 2; break; - case GF_4CC( 's', 'v', 'c', '1'): + case GF_ISOM_SUBTYPE_SVC_H264: break; - case GF_4CC( 'a', 'v', 'c', '3'): - case GF_4CC( 'a', 'v', 'c', '4'): + case GF_ISOM_SUBTYPE_AVC3_H264: + case GF_ISOM_SUBTYPE_AVC4_H264: /*we don't want to clone SPS/PPS since they are already inside the samples*/ merge_mode = 2; break; - case GF_4CC( 'h', 'v', 'c', '1'): + case GF_ISOM_SUBTYPE_HVC1: if (use_hevc) merge_mode = 2; break; - case GF_4CC( 'h', 'e', 'v', '1'): + case GF_ISOM_SUBTYPE_HEV1: /*we don't want to clone SPS/PPS since they are already inside the samples*/ merge_mode = 2; break; + case GF_ISOM_SUBTYPE_SHC1: + break; + case GF_ISOM_SUBTYPE_SHV1: + merge_mode = 2; + break; default: merge_mode = 0; break; @@ -2262,15 +2628,46 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 } gf_isom_avc_config_update(init_seg, track, 1, avccfg2); } else { - sps_merge_failed = 1; + sps_merge_failed = GF_TRUE; } gf_odf_avc_cfg_del(avccfg1); gf_odf_avc_cfg_del(avccfg2); } + //check if we can get rid of inband params + if (!merge_mode && use_inband_param_set && probe_inband_param_set) { + probe_inband_param_set = 0; + + switch (gf_isom_get_media_subtype(init_seg, first_track, 1)) { + case GF_ISOM_SUBTYPE_HVC1: + gf_isom_hevc_set_inband_config(init_seg, track, 1); + use_hevc = GF_TRUE; + gf_isom_set_brand_info(init_seg, GF_4CC('i','s','o','6'), 1); + sps_merge_failed = GF_FALSE; + break; + case GF_ISOM_SUBTYPE_AVC_H264: + case GF_ISOM_SUBTYPE_AVC2_H264: + case GF_ISOM_SUBTYPE_SVC_H264: + gf_isom_avc_set_inband_config(init_seg, track, 1); + use_avc3 = GF_TRUE; + gf_isom_set_brand_info(init_seg, GF_4CC('i','s','o','6'), 1); + sps_merge_failed = GF_FALSE; + break; + } + goto retry_track; + } + + /*cannot merge, clone*/ - if (merge_mode==0) + if (merge_mode==0) { + + if (use_inband_param_set && (use_avc3 || use_hevc) ) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Couldn't merge %s parameter sets - using in-band config\n", use_hevc ? "HEVC" : "AVC" )); + gf_isom_delete(init_seg); + goto restart_init; + } gf_isom_clone_sample_description(init_seg, track, in, j+1, 1, NULL, NULL, &outDescIndex); + } } } else { u32 defaultDuration, defaultSize, defaultDescriptionIndex, defaultRandomAccess; @@ -2280,21 +2677,36 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 gf_isom_clone_track(in, j+1, init_seg, GF_FALSE, &track); switch (gf_isom_get_media_subtype(in, j+1, 1)) { - case GF_4CC( 'a', 'v', 'c', '1'): - case GF_4CC( 'a', 'v', 'c', '2'): - case GF_4CC( 's', 'v', 'c', '1'): - if (use_inband_param_set) { - gf_isom_avc_set_inband_config(init_seg, track, 1); - use_avc3 = GF_TRUE; + case GF_ISOM_SUBTYPE_AVC_H264: + case GF_ISOM_SUBTYPE_AVC2_H264: + case GF_ISOM_SUBTYPE_SVC_H264: + if (!probe_inband_param_set) { + if (use_inband_param_set) { + gf_isom_avc_set_inband_config(init_seg, track, 1); + use_avc3 = GF_TRUE; + } + } else { + first_track = track; } break; - case GF_4CC( 'h', 'v', 'c', '1'): + case GF_ISOM_SUBTYPE_HVC1: + //todo enble comparison of hevc xPS + probe_inband_param_set=0; + if (use_inband_param_set) { gf_isom_hevc_set_inband_config(init_seg, track, 1); } use_hevc = GF_TRUE; break; + + case GF_ISOM_SUBTYPE_AVC3_H264: + case GF_ISOM_SUBTYPE_AVC4_H264: + case GF_ISOM_SUBTYPE_HEV1: + probe_inband_param_set = 0; + break; } + if (gf_isom_has_sync_points(in, j+1)) + gf_isom_set_sync_table(init_seg, track); gf_isom_get_fragment_defaults(in, j+1, &defaultDuration, &defaultSize, @@ -2307,6 +2719,27 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 defaultPadding, defaultDegradationPriority); if (e) break; } + if (!e) { + u32 k, edit_count=gf_isom_get_edit_segment_count(in, j+1); + + /*remove all segments*/ + gf_isom_remove_edit_segments(init_seg, track); + //clone all edits before first nomal, and stop at first normal setting duration to 0 + for (k=0; k<edit_count; k++) { + u64 EditTime, SegDuration, MediaTime; + u8 EditMode; + + /*get first edit*/ + gf_isom_get_edit_segment(in, j+1, k+1, &EditTime, &SegDuration, &MediaTime, &EditMode); + + if (EditMode==GF_ISOM_EDIT_NORMAL) { + gf_isom_set_edit_segment(init_seg, track, EditTime, 0, MediaTime, EditMode); + break; + } + + gf_isom_set_edit_segment(init_seg, track, EditTime, SegDuration, MediaTime, EditMode); + } + } } if (!i) { if (use_hevc || use_avc3) { @@ -2322,7 +2755,7 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 } if (!dash_opts->pssh_moof) { - e = gf_isom_clone_pssh(init_seg, in, GF_TRUE); + e = gf_isom_clone_pssh(init_seg, in, GF_FALSE); } } gf_isom_close(in); @@ -2334,13 +2767,22 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 gf_delete_file(szInitName); return GF_OK; } else if (sps_merge_failed) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Couldnt merge AVC|H264 SPS from different files (same SPS ID used) - different sample descriptions will be used\n")); + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Could not merge AVC|H264 SPS from different files (same SPS ID used) - disabling bitstream switching\n")); *disable_bs_switching = GF_TRUE; gf_isom_delete(init_seg); gf_delete_file(szInitName); return GF_OK; } else { e = gf_isom_close(init_seg); + + if (probe_inband_param_set) { + for (i=0; i<nb_dash_inputs; i++) { + if (dash_inputs[i].adaptation_set != adaptation_set) + continue; + + dash_inputs[i].disable_inband_param_set = GF_TRUE; + } + } } return e; } @@ -2348,7 +2790,7 @@ static GF_Err dasher_isom_create_init_segment(GF_DashSegInput *dash_inputs, u32 static GF_Err dasher_isom_segment_file(GF_DashSegInput *dash_input, const char *szOutName, GF_DASHSegmenterOptions *dash_cfg, Bool first_in_set) { GF_ISOFile *in = gf_isom_open(dash_input->file_name, GF_ISOM_OPEN_READ, dash_cfg->tmpdir); - GF_Err e = gf_media_isom_segment_file(in, szOutName, dash_cfg->fragment_duration, dash_cfg, dash_input, first_in_set); + GF_Err e = gf_media_isom_segment_file(in, szOutName, dash_cfg, dash_input, first_in_set); gf_isom_close(in); return e; } @@ -2391,8 +2833,8 @@ static GF_Err dasher_generic_classify_input(GF_DashSegInput *dash_inputs, u32 nb e = gf_media_import(&probe); if (e) return e; - if (in.nb_progs != probe.nb_progs) valid_in_adaptation_set = 0; - if (in.nb_tracks != probe.nb_tracks) valid_in_adaptation_set = 0; + if (in.nb_progs != probe.nb_progs) valid_in_adaptation_set = GF_FALSE; + if (in.nb_tracks != probe.nb_tracks) valid_in_adaptation_set = GF_FALSE; for (j=0; j<in.nb_tracks; j++) { struct __track_import_info *src_tk, *probe_tk; @@ -2478,8 +2920,9 @@ static GF_Err dasher_generic_get_components_info(GF_DashSegInput *input, GF_DASH input->components[i].channels = in.tk_info[i].audio_info.nb_channels; input->components[i].sample_rate = in.tk_info[i].audio_info.sample_rate; input->components[i].ID = in.tk_info[i].track_num; - if (in.tk_info[i].lang) - strcpy(input->components[i].szLang, gf_4cc_to_str(in.tk_info[i].lang) ); + if (in.tk_info[i].lang) { + input->components[i].lang = gf_strdup( gf_4cc_to_str(in.tk_info[i].lang) ); + } strcpy(input->components[i].szCodec, in.tk_info[i].szCodecProfile); input->components[i].fps_denum = 1000; input->components[i].fps_num = (u32) (in.tk_info[i].video_info.FPS*1000); @@ -2622,7 +3065,7 @@ static void m2ts_sidx_finalize_size(GF_TSSegmenter *index_info, u64 file_size) static void m2ts_sidx_flush_entry(GF_TSSegmenter *index_info) { u32 end_offset, size, duration; - Bool store_segment = 1; + Bool store_segment = GF_TRUE; if (index_info->suspend_indexing) return; @@ -2664,17 +3107,17 @@ static void m2ts_sidx_flush_entry(GF_TSSegmenter *index_info) /* close the current index */ SAP_delta_time = (u32)(index_info->first_SAP_PTS - index_info->base_PTS); SAP_offset = (u32)(index_info->first_SAP_offset - index_info->base_offset); - m2ts_sidx_add_entry(index_info->sidx, 0, size, duration, index_info->first_pes_sap, index_info->SAP_type, SAP_delta_time); + m2ts_sidx_add_entry(index_info->sidx, GF_FALSE, size, duration, index_info->first_pes_sap, index_info->SAP_type, SAP_delta_time); /*add pcrb entry*/ index_info->pcrb->subsegment_count++; - index_info->pcrb->pcr_values = gf_realloc(index_info->pcrb->pcr_values, index_info->pcrb->subsegment_count*sizeof(u64)); + index_info->pcrb->pcr_values = (u64*)gf_realloc(index_info->pcrb->pcr_values, index_info->pcrb->subsegment_count*sizeof(u64)); index_info->pcrb->pcr_values[index_info->pcrb->subsegment_count-1] = index_info->interpolated_pcr_value; /* adjust the previous index duration */ if (index_info->sidx->nb_refs > 0 && (index_info->base_PTS < index_info->prev_last_PTS) ) { prev_duration = (u32)(index_info->base_PTS-index_info->prev_base_PTS); - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, (" time-range adj.: %.03f-%.03f / %.03f sec.\n", + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, (" time-range adj.: %.3f-%.3f / %.3f sec.\n", (index_info->prev_base_PTS - index_info->first_PTS)/90000.0, (index_info->base_PTS - index_info->first_PTS)/90000.0, prev_duration/90000.0)); @@ -2688,12 +3131,12 @@ static void m2ts_sidx_flush_entry(GF_TSSegmenter *index_info) /* Printing result */ GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Subsegment:")); //time-range:position-range: - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, (" %.03f-%0.3f / %.03f sec., %d-%d / %d bytes, ", + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, (" %.3f-%.3f / %.3f sec., %d-%d / %d bytes, ", (index_info->base_PTS - index_info->first_PTS)/90000.0, (index_info->last_PTS - index_info->first_PTS)/90000.0, duration/90000.0, index_info->base_offset, end_offset, size)); if (index_info->SAP_type) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("RAP @ %.03f sec. / %d bytes", (index_info->first_SAP_PTS - index_info->first_PTS)/90000.0, + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("RAP @ %.3f sec. / %d bytes", (index_info->first_SAP_PTS - index_info->first_PTS)/90000.0, SAP_offset)); } if (index_info->first_pat_position_valid) { @@ -2744,7 +3187,7 @@ static void m2ts_sidx_flush_entry(GF_TSSegmenter *index_info) index_info->nb_pes_in_segment = 1; index_info->base_PTS = index_info->first_SAP_PTS; - index_info->pes_after_last_pat_is_sap= 0; + index_info->pes_after_last_pat_is_sap = GF_FALSE; } else { index_info->SAP_type = 0; index_info->first_SAP_PTS = 0; @@ -2825,7 +3268,7 @@ static void dash_m2ts_event_check_pat(GF_M2TS_Demuxer *ts, u32 evt_type, void *p GF_M2TS_PES_PCK *pck; switch (evt_type) { case GF_M2TS_EVT_PAT_REPEAT: - ts_seg->has_seen_pat = 1; + ts_seg->has_seen_pat = GF_TRUE; break; case GF_M2TS_EVT_PMT_FOUND: { @@ -2841,7 +3284,7 @@ static void dash_m2ts_event_check_pat(GF_M2TS_Demuxer *ts, u32 evt_type, void *p case GF_M2TS_EVT_PMT_REPEAT: if (ts_seg->has_seen_pat) { u32 i, count; - Bool done = 1; + Bool done = GF_TRUE; GF_M2TS_Program *prog = (GF_M2TS_Program*)par; count = gf_list_count(prog->streams); for (i=0; i<count; i++) { @@ -2849,7 +3292,7 @@ static void dash_m2ts_event_check_pat(GF_M2TS_Demuxer *ts, u32 evt_type, void *p if (es->flags&GF_M2TS_ES_IS_PES) { GF_M2TS_PES *pes = (GF_M2TS_PES *)es; if (!pes->aud_sr && !pes->vid_w) { - done = 0; + done = GF_FALSE; break; } else { /*stream is configured, we only need PES header now*/ @@ -2892,56 +3335,56 @@ static void dash_m2ts_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) switch (evt_type) { case GF_M2TS_EVT_PAT_FOUND: if (!ts_seg->first_pat_position_valid) { - ts_seg->first_pat_position_valid = 1; + ts_seg->first_pat_position_valid = GF_TRUE; ts_seg->first_pat_position = (ts->pck_number-1)*188; } ts_seg->last_pat_position = (ts->pck_number-1)*188; - ts_seg->first_pes_after_last_pat = 0; - ts_seg->pes_after_last_pat_is_sap = 0; + ts_seg->first_pes_after_last_pat = GF_FALSE; + ts_seg->pes_after_last_pat_is_sap = GF_FALSE; break; case GF_M2TS_EVT_PAT_UPDATE: if (!ts_seg->first_pat_position_valid) { - ts_seg->first_pat_position_valid = 1; + ts_seg->first_pat_position_valid = GF_TRUE; ts_seg->first_pat_position = (ts->pck_number-1)*188; } ts_seg->last_pat_position = (ts->pck_number-1)*188; - ts_seg->first_pes_after_last_pat = 0; - ts_seg->pes_after_last_pat_is_sap = 0; + ts_seg->first_pes_after_last_pat = GF_FALSE; + ts_seg->pes_after_last_pat_is_sap = GF_FALSE; break; case GF_M2TS_EVT_PAT_REPEAT: if (!ts_seg->first_pat_position_valid) { - ts_seg->first_pat_position_valid = 1; + ts_seg->first_pat_position_valid = GF_TRUE; ts_seg->first_pat_position = (ts->pck_number-1)*188; } ts_seg->last_pat_position = (ts->pck_number-1)*188; - ts_seg->first_pes_after_last_pat = 0; - ts_seg->pes_after_last_pat_is_sap = 0; + ts_seg->first_pes_after_last_pat = GF_FALSE; + ts_seg->pes_after_last_pat_is_sap = GF_FALSE; break; case GF_M2TS_EVT_CAT_FOUND: if (!ts_seg->first_cat_position_valid) { - ts_seg->first_cat_position_valid = 1; + ts_seg->first_cat_position_valid = GF_TRUE; ts_seg->first_cat_position = (ts->pck_number-1)*188; } ts_seg->last_cat_position = (ts->pck_number-1)*188; break; case GF_M2TS_EVT_CAT_UPDATE: if (!ts_seg->first_cat_position_valid) { - ts_seg->first_cat_position_valid = 1; + ts_seg->first_cat_position_valid = GF_TRUE; ts_seg->first_cat_position = (ts->pck_number-1)*188; } break; case GF_M2TS_EVT_CAT_REPEAT: if (!ts_seg->first_cat_position_valid) { - ts_seg->first_cat_position_valid = 1; + ts_seg->first_cat_position_valid = GF_TRUE; ts_seg->first_cat_position = (ts->pck_number-1)*188; } ts_seg->last_cat_position = (ts->pck_number-1)*188; break; case GF_M2TS_EVT_PMT_FOUND: - ts_seg->has_seen_pat = 1; + ts_seg->has_seen_pat = GF_TRUE; prog = (GF_M2TS_Program*)par; if (!ts_seg->first_pmt_position_valid) { - ts_seg->first_pmt_position_valid = 1; + ts_seg->first_pmt_position_valid = GF_TRUE; ts_seg->first_pmt_position = (ts->pck_number-1)*188; } ts_seg->last_pmt_position = (ts->pck_number-1)*188; @@ -2958,14 +3401,14 @@ static void dash_m2ts_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) break; case GF_M2TS_EVT_PMT_UPDATE: if (!ts_seg->first_pmt_position_valid) { - ts_seg->first_pmt_position_valid = 1; + ts_seg->first_pmt_position_valid = GF_TRUE; ts_seg->first_pmt_position = (ts->pck_number-1)*188; } ts_seg->last_pmt_position = (ts->pck_number-1)*188; break; case GF_M2TS_EVT_PMT_REPEAT: if (!ts_seg->first_pmt_position_valid) { - ts_seg->first_pmt_position_valid = 1; + ts_seg->first_pmt_position_valid = GF_TRUE; ts_seg->first_pmt_position = (ts->pck_number-1)*188; } ts_seg->last_pmt_position = (ts->pck_number-1)*188; @@ -3002,7 +3445,7 @@ static void dash_m2ts_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) if (!ts_seg->first_pes_after_last_pat) { ts_seg->first_pes_after_last_pat = ts_seg->nb_pes_in_segment; - ts_seg->pes_after_last_pat_is_sap=0; + ts_seg->pes_after_last_pat_is_sap = GF_FALSE; } } @@ -3021,7 +3464,7 @@ static void dash_m2ts_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) ts_seg->first_pes_sap = GF_TRUE; } if ((ts_seg->nb_pes_in_segment>1) && (ts_seg->first_pes_after_last_pat==ts_seg->nb_pes_in_segment)) { - ts_seg->pes_after_last_pat_is_sap=1; + ts_seg->pes_after_last_pat_is_sap=GF_TRUE; } } /* we need to know the earliest PTS value (RAP or not) in the index*/ @@ -3059,7 +3502,7 @@ static void dash_m2ts_event(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) static GF_Err dasher_get_ts_demux(GF_TSSegmenter *ts_seg, const char *file, u32 probe_mode) { memset(ts_seg, 0, sizeof(GF_TSSegmenter)); - ts_seg->src = gf_f64_open(file, "rb"); + ts_seg->src = gf_fopen(file, "rb"); if (!ts_seg->src) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot open input %s: no such file\n", file)); return GF_URL_ERROR; @@ -3069,9 +3512,9 @@ static GF_Err dasher_get_ts_demux(GF_TSSegmenter *ts_seg, const char *file, u32 ts_seg->ts->notify_pes_timing = GF_TRUE; ts_seg->ts->user = ts_seg; - gf_f64_seek(ts_seg->src, 0, SEEK_END); - ts_seg->file_size = gf_f64_tell(ts_seg->src); - gf_f64_seek(ts_seg->src, 0, SEEK_SET); + gf_fseek(ts_seg->src, 0, SEEK_END); + ts_seg->file_size = gf_ftell(ts_seg->src); + gf_fseek(ts_seg->src, 0, SEEK_SET); if (probe_mode) { /* first loop to process all packets between two PAT, and assume all signaling was found between these 2 PATs */ @@ -3085,7 +3528,7 @@ static GF_Err dasher_get_ts_demux(GF_TSSegmenter *ts_seg, const char *file, u32 break; } gf_m2ts_reset_parsers(ts_seg->ts); - gf_f64_seek(ts_seg->src, 0, SEEK_SET); + gf_fseek(ts_seg->src, 0, SEEK_SET); } ts_seg->ts->on_event = dash_m2ts_event; return GF_OK; @@ -3094,7 +3537,7 @@ static GF_Err dasher_get_ts_demux(GF_TSSegmenter *ts_seg, const char *file, u32 static void dasher_del_ts_demux(GF_TSSegmenter *ts_seg) { if (ts_seg->ts) gf_m2ts_demux_del(ts_seg->ts); - if (ts_seg->src) fclose(ts_seg->src); + if (ts_seg->src) gf_fclose(ts_seg->src); memset(ts_seg, 0, sizeof(GF_TSSegmenter)); } @@ -3134,7 +3577,7 @@ static GF_Err dasher_mp2t_get_components_info(GF_DashSegInput *dash_input, GF_DA static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char *szOutName, GF_DASHSegmenterOptions *dash_cfg, Bool first_in_set) { GF_TSSegmenter ts_seg; - Bool rewrite_input = 0; + Bool rewrite_input = GF_FALSE; u8 is_pes[GF_M2TS_MAX_STREAMS]; char szOpt[100]; char SegName[GF_MAX_PATH], IdxName[GF_MAX_PATH]; @@ -3143,12 +3586,12 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * const char *opt; u32 i; GF_Err e; - u64 start, pcr_shift, next_pcr_shift; + u64 start, pcr_shift, next_pcr_shift, presentationTimeOffset; Double cumulated_duration = 0; u32 bandwidth = 0; u32 segment_index; /*compute name for indexed segments*/ - const char *basename = gf_url_get_resource_name(szOutName); + const char *basename = gf_dasher_strip_output_dir(dash_cfg->mpd_name, szOutName); /*perform indexation of the file, this info will be destroyed at the end of the segment file routine*/ e = dasher_get_ts_demux(&ts_seg, dash_input->file_name, 0); @@ -3164,13 +3607,14 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * segment_index = 1; ts_seg.index_file = NULL; ts_seg.index_bs = NULL; + presentationTimeOffset=0; if (!dash_cfg->dash_ctx && (dash_cfg->use_url_template != 2)) { #ifndef GPAC_DISABLE_ISOM_FRAGMENTS GF_SegmentTypeBox *styp; - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, 1, IdxName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, GF_TRUE, IdxName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0, dash_cfg->use_segment_timeline); - ts_seg.index_file = gf_f64_open(IdxName, "wb"); + ts_seg.index_file = gf_fopen(IdxName, "wb"); if (!ts_seg.index_file) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot create index file %s\n", IdxName)); e = GF_IO_ERR; @@ -3190,7 +3634,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * #endif } - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, 1, IdxName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, GF_TRUE, IdxName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0, dash_cfg->use_segment_timeline); ts_seg.PCR_DTS_initial_diff = (u64) -1; ts_seg.subduration = (u32) (dash_cfg->subduration * 90000); @@ -3215,7 +3659,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * } gf_m2ts_reset_parsers(ts_seg.ts); ts_seg.base_PTS = 0; - gf_f64_seek(ts_seg.src, offset, SEEK_SET); + gf_fseek(ts_seg.src, offset, SEEK_SET); ts_seg.base_offset = offset; ts_seg.ts->pck_number = (u32) (offset/188); } @@ -3223,6 +3667,12 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * opt = gf_cfg_get_key(dash_cfg->dash_ctx, szSectionName, "InitialDTSOffset"); if (opt) sscanf(opt, LLU, &ts_seg.PCR_DTS_initial_diff); + opt = gf_cfg_get_key(dash_cfg->dash_ctx, szSectionName, "PresentationTimeOffset"); + if (opt) { + sscanf(opt, LLU, &presentationTimeOffset); + presentationTimeOffset++; + } + opt = gf_cfg_get_key(dash_cfg->dash_ctx, szSectionName, "DurationAtLastPass"); if (opt) sscanf(opt, LLD, &ts_seg.duration_at_last_pass); } @@ -3236,6 +3686,14 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * } if (feof(ts_seg.src)) ts_seg.suspend_indexing = 0; + if (!presentationTimeOffset) { + presentationTimeOffset = 1 + ts_seg.first_PTS; + if (dash_cfg->dash_ctx) { + sprintf(szOpt, LLU, ts_seg.first_PTS); + gf_cfg_set_key(dash_cfg->dash_ctx, szSectionName, "PresentationTimeOffset", szOpt); + } + } + next_pcr_shift = 0; if (!ts_seg.suspend_indexing) { next_pcr_shift = ts_seg.last_DTS + ts_seg.last_frame_duration - ts_seg.PCR_DTS_initial_diff; @@ -3246,7 +3704,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * m2ts_sidx_finalize_size(&ts_seg, ts_seg.file_size); GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH]: Indexing done (1 sidx, %d entries).\n", ts_seg.sidx->nb_refs)); - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, 1, IdxName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "six", 0, 0, 0, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, GF_TRUE, IdxName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "six", 0, 0, 0, dash_cfg->use_segment_timeline); memset(is_pes, 0, sizeof(u8)*GF_M2TS_MAX_STREAMS); @@ -3277,18 +3735,29 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * if (opt) sscanf(opt, LLU, &pcr_shift); opt = gf_cfg_get_key(dash_cfg->dash_ctx, szSectionName, "CumulatedDuration"); - if (opt) cumulated_duration = atof(opt); + if (opt) { + u64 val; + sscanf(opt, LLU, &val); + cumulated_duration = ((Double) val) / dash_cfg->dash_scale; + } } } /*write segment template for all representations*/ if (first_in_set && dash_cfg->seg_rad_name && dash_cfg->use_url_template && !dash_cfg->variable_seg_rad_name) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_TEMPLATE, 1, SegName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_TEMPLATE, GF_TRUE, SegName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " <SegmentTemplate timescale=\"90000\" duration=\"%d\" startNumber=\"%d\" media=\"%s\"", (u32) (90000*dash_cfg->segment_duration), segment_index, SegName); + //the SIDX we have is not compatible with the spec - until fixed, disable this +#if 0 if (!dash_cfg->dash_ctx) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION_TEMPLATE, 1, IdxName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "six", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION_TEMPLATE, 1, IdxName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "six", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " index=\"%s\"", IdxName); } +#endif + + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } fprintf(dash_cfg->mpd, "/>\n"); } @@ -3302,7 +3771,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * strcat(szCodecs, dash_input->components[i].szCodec); if (dash_input->components[i].width && dash_input->components[i].height) - fprintf(dash_cfg->mpd, " width=\"%d\" height=\"%d\"", dash_input->components[i].width, dash_input->components[i].height); + fprintf(dash_cfg->mpd, " width=\"%u\" height=\"%u\"", dash_input->components[i].width, dash_input->components[i].height); if (dash_input->components[i].sample_rate) fprintf(dash_cfg->mpd, " audioSamplingRate=\"%d\"", dash_input->components[i].sample_rate); @@ -3321,8 +3790,18 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * } } + + for (i=0; i<ts_seg.sidx->nb_refs; i++) { + GF_SIDXReference *ref = &ts_seg.sidx->refs[i]; + if (dash_cfg->max_segment_duration * ts_seg.sidx->timescale < ref->subsegment_duration) { + dash_cfg->max_segment_duration = (Double) ref->subsegment_duration; + dash_cfg->max_segment_duration /= ts_seg.sidx->timescale; + } + } + + if (dash_cfg->single_file_mode==1) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, GF_TRUE, SegName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n", SegName); fprintf(dash_cfg->mpd, " <SegmentBase>\n"); @@ -3330,31 +3809,44 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * fprintf(dash_cfg->mpd, " </SegmentBase>\n"); /*we rewrite the file*/ - rewrite_input = 1; + rewrite_input = GF_TRUE; } else { if (dash_cfg->seg_rad_name && dash_cfg->use_url_template) { if (dash_cfg->variable_seg_rad_name) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_TEMPLATE, 1, SegName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_TEMPLATE, GF_TRUE, SegName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " <SegmentTemplate timescale=\"90000\" duration=\"%d\" startNumber=\"%d\" media=\"%s\"", (u32) (90000*dash_cfg->segment_duration), segment_index, SegName); + + //the SIDX we have is not compatible with the spec - until fixed, disable this +#if 0 if (!dash_cfg->dash_ctx) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION_TEMPLATE, 1, IdxName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "six", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_INITIALIZATION_TEMPLATE, 1, IdxName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "six", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " index=\"%s\"", IdxName); } +#endif + + if (presentationTimeOffset > 1) + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset - 1); - if (dash_cfg->time_shift_depth>=0) - fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", ts_seg.sidx->earliest_presentation_time + pcr_shift); + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } fprintf(dash_cfg->mpd, "/>\n"); - } else if (dash_cfg->time_shift_depth>=0) { - fprintf(dash_cfg->mpd, " <SegmentTemplate presentationTimeOffset=\""LLD"\"/>\n", ts_seg.sidx->earliest_presentation_time + pcr_shift); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH]: PTSOffset "LLD" - startNumber %d - time %g\n", ts_seg.sidx->earliest_presentation_time + pcr_shift, segment_index, (Double) (s64) (ts_seg.sidx->earliest_presentation_time + pcr_shift) / 90000.0)); + } else if (presentationTimeOffset > 1) { + fprintf(dash_cfg->mpd, " <SegmentTemplate presentationTimeOffset=\""LLD"\"/>\n", presentationTimeOffset - 1); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DASH]: PTSOffset "LLD" - startNumber %d - time %g\n", presentationTimeOffset - 1, segment_index, (Double) (s64) (ts_seg.sidx->earliest_presentation_time + pcr_shift) / 90000.0)); } } else { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, GF_TRUE, SegName, basename, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); if (dash_cfg->single_file_mode) fprintf(dash_cfg->mpd, " <BaseURL>%s</BaseURL>\n",SegName); fprintf(dash_cfg->mpd, " <SegmentList timescale=\"90000\" duration=\"%d\"", (u32) (90000*dash_cfg->segment_duration)); - if (dash_cfg->time_shift_depth>=0) - fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", ts_seg.sidx->earliest_presentation_time + pcr_shift); + + if (presentationTimeOffset > 1) + fprintf(dash_cfg->mpd, " presentationTimeOffset=\""LLD"\"", presentationTimeOffset - 1); + + if (dash_cfg->ast_offset_ms<0) { + fprintf(dash_cfg->mpd, " availabilityTimeOffset=\"%g\"", - (Double) dash_cfg->ast_offset_ms / 1000.0); + } fprintf(dash_cfg->mpd, ">\n"); if (!dash_cfg->dash_ctx) { @@ -3389,31 +3881,33 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * FILE *src, *dst; u64 pos, end; Double current_time = cumulated_duration, dur; - src = gf_f64_open(dash_input->file_name, "rb"); + src = gf_fopen(dash_input->file_name, "rb"); start = ts_seg.sidx->first_offset; for (i=0; i<ts_seg.sidx->nb_refs; i++) { char buf[NB_TSPCK_IO_BYTES]; GF_SIDXReference *ref = &ts_seg.sidx->refs[i]; - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, GF_TRUE, SegName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); /*warning - we may introduce repeated sequence number when concatenating files. We should use switching segments to force reset of the continuity counter for all our pids - we don't because most players don't car ...*/ if (dash_cfg->use_url_template != 2) { - dst = gf_f64_open(SegName, "wb"); + dst = gf_fopen(SegName, "wb"); if (!dst) { - fclose(src); + gf_fclose(src); GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot create segment file %s\n", SegName)); e = GF_IO_ERR; goto exit; } - gf_dasher_store_segment_info(dash_cfg, SegName, current_time); dur = ref->subsegment_duration; dur /= 90000; + + gf_dasher_store_segment_info(dash_cfg, dash_input->representationID, SegName, (u64) (current_time*dash_cfg->dash_scale), (u64) (dur*dash_cfg->dash_scale)); + current_time += dur; - gf_f64_seek(src, start, SEEK_SET); + gf_fseek(src, start, SEEK_SET); pos = start; end = start+ref->reference_size; while (pos<end) { @@ -3433,12 +3927,12 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * } pos += res; } - fclose(dst); + gf_fclose(dst); } start += ref->reference_size; if (!dash_cfg->use_url_template) { - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, 1, SegName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, GF_TRUE, SegName, basename, dash_input->representationID, dash_cfg->seg_rad_name, "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); fprintf(dash_cfg->mpd, " <SegmentURL media=\"%s\"/>\n", SegName); if (dash_cfg->dash_ctx) { @@ -3452,7 +3946,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * segment_index++; gf_set_progress("Extracting segment ", i+1, ts_seg.sidx->nb_refs); } - fclose(src); + gf_fclose(src); cumulated_duration = current_time; } if (!dash_cfg->seg_rad_name || !dash_cfg->use_url_template) { @@ -3465,17 +3959,17 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * u64 fsize, done; char buf[NB_TSPCK_IO_BYTES]; - gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, GF_TRUE, SegName, dash_cfg->seg_rad_name ? basename : szOutName, dash_input->representationID, gf_url_get_resource_name(dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); - out = gf_f64_open(SegName, "wb"); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_SEGMENT, GF_TRUE, SegName, dash_cfg->seg_rad_name ? basename : szOutName, dash_input->representationID, gf_dasher_strip_output_dir(dash_cfg->mpd_name, dash_cfg->seg_rad_name), "ts", 0, bandwidth, segment_index, dash_cfg->use_segment_timeline); + out = gf_fopen(SegName, "wb"); if (!out) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: Cannot create segment file %s\n", SegName)); e = GF_IO_ERR; goto exit; } - in = gf_f64_open(dash_input->file_name, "rb"); - gf_f64_seek(in, 0, SEEK_END); - fsize = gf_f64_tell(in); - gf_f64_seek(in, 0, SEEK_SET); + in = gf_fopen(dash_input->file_name, "rb"); + gf_fseek(in, 0, SEEK_END); + fsize = gf_ftell(in); + gf_fseek(in, 0, SEEK_SET); done = 0; while (1) { u32 read = (u32) fread(buf, 1, NB_TSPCK_IO_BYTES, in); @@ -3485,8 +3979,8 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * gf_set_progress("Extracting segment ", done/188, fsize/188); if (read<NB_TSPCK_IO_BYTES) break; } - fclose(in); - fclose(out); + gf_fclose(in); + gf_fclose(out); } fprintf(dash_cfg->mpd, " </Representation>\n"); @@ -3498,7 +3992,7 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * sprintf(szOpt, "%u", segment_index); gf_cfg_set_key(dash_cfg->dash_ctx, szSectionName, "StartIndex", szOpt); - sprintf(szOpt, "%g", ts_seg.segment_duration); + sprintf(szOpt, LLU, (u64) (dash_cfg->dash_scale*ts_seg.segment_duration) ); gf_cfg_set_key(dash_cfg->dash_ctx, szSectionName, "CumulatedDuration", szOpt); sprintf(szOpt, LLU, next_pcr_shift + pcr_shift); @@ -3512,9 +4006,6 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * sprintf(szOpt, LLU, ts_seg.PCR_DTS_initial_diff); gf_cfg_set_key(dash_cfg->dash_ctx, szSectionName, "InitialDTSOffset", ts_seg.suspend_indexing ? szOpt : NULL); - - sprintf(szOpt, "%g", cumulated_duration); - gf_cfg_set_key(dash_cfg->dash_ctx, szSectionName, "CumulatedDuration", szOpt); } if (ts_seg.sidx && ts_seg.index_bs) { @@ -3529,8 +4020,12 @@ static GF_Err dasher_mp2t_segment_file(GF_DashSegInput *dash_input, const char * exit: if (ts_seg.sidx) gf_isom_box_del((GF_Box *)ts_seg.sidx); if (ts_seg.pcrb) gf_isom_box_del((GF_Box *)ts_seg.pcrb); - if (ts_seg.index_file) fclose(ts_seg.index_file); if (ts_seg.index_bs) gf_bs_del(ts_seg.index_bs); + if (ts_seg.index_file) { + gf_fclose(ts_seg.index_file); + gf_media_mpd_format_segment_name(GF_DASH_TEMPLATE_REPINDEX, GF_TRUE, IdxName, szOutName, dash_input->representationID, dash_cfg->seg_rad_name, "six", 0, 0, 0, dash_cfg->use_segment_timeline); + gf_delete_file(IdxName); + } dasher_del_ts_demux(&ts_seg); return e; } @@ -3555,13 +4050,13 @@ GF_Err gf_dash_segmenter_probe_input(GF_DashSegInput **io_dash_inputs, u32 *nb_d GF_DashSegInput *dash_inputs = *io_dash_inputs; GF_DashSegInput *dash_input = & dash_inputs[idx]; char *uri_frag = strchr(dash_input->file_name, '#'); - FILE *t = gf_f64_open(dash_input->file_name, "rb"); - + FILE *t; + if (uri_frag) uri_frag[0] = 0; - t = gf_f64_open(dash_input->file_name, "rb"); + t = gf_fopen(dash_input->file_name, "rb"); if (!t) return GF_URL_ERROR; - fclose(t); + gf_fclose(t); #ifndef GPAC_DISABLE_ISOM_FRAGMENTS if (gf_isom_probe_file(dash_input->file_name)) { @@ -3588,7 +4083,7 @@ GF_Err gf_dash_segmenter_probe_input(GF_DashSegInput **io_dash_inputs, u32 *nb_d else if (!strnicmp(uri_frag+1, "ID=", 3)) id = atoi(uri_frag+4); else if (!stricmp(uri_frag+1, "audio") || !stricmp(uri_frag+1, "video")) { - Bool check_video = !stricmp(uri_frag+1, "video") ? 1 : 0; + Bool check_video = !stricmp(uri_frag+1, "video") ? GF_TRUE : GF_FALSE; u32 i; for (i=0; i<nb_track; i++) { switch (gf_isom_get_media_type(file, i+1)) { @@ -3665,6 +4160,10 @@ GF_Err gf_dash_segmenter_probe_input(GF_DashSegInput **io_dash_inputs, u32 *nb_d u32 default_sample_group_index, id, independent; Bool full_frame; gf_isom_get_tile_info(file, di->trackNum, 1, &default_sample_group_index, &id, &independent, &full_frame, &di->x, &di->y, &di->w, &di->h); + + if (!dash_input->w) { + gf_isom_get_visual_info(file, dash_input->trackNum, 1, &dash_input->w, &dash_input->h); + } } } @@ -3673,21 +4172,32 @@ GF_Err gf_dash_segmenter_probe_input(GF_DashSegInput **io_dash_inputs, u32 *nb_d for (j = idx; j < *nb_dash_inputs; j++) { GF_DashSegInput *di; u32 count, t, ref_track; + char *depID = gf_malloc(2); di = &dash_inputs[j]; count = gf_isom_get_reference_count(file, di->trackNum, GF_ISOM_REF_SCAL); if (!count) continue; di->lower_layer_track = dash_input->trackNum; - strcpy(di->dependencyID, ""); + strcpy(depID, ""); for (t=0; t < count; t++) { - gf_isom_get_reference(file, di->trackNum, GF_ISOM_REF_SCAL, t+1, &ref_track); - if (t) strcat(di->dependencyID, " "); - strcat(di->dependencyID, gf_dash_get_representationID(dash_inputs, *nb_dash_inputs, di->file_name, ref_track)); + u32 al_len = 0; + char *rid; + if (t) al_len++; + gf_isom_get_reference(file, di->trackNum, GF_ISOM_REF_SCAL, t+1, &ref_track); + rid = gf_dash_get_representationID(dash_inputs, *nb_dash_inputs, di->file_name, ref_track); + + if (!rid) continue; + al_len += (u32) strlen(rid); + al_len += (u32) strlen(depID)+1; + + depID = gf_realloc(depID, sizeof(char)*al_len); + if (t) strcat(depID, " "); + strcat(depID, gf_dash_get_representationID(dash_inputs, *nb_dash_inputs, di->file_name, ref_track)); di->lower_layer_track = ref_track; } - + di->dependencyID = depID; } gf_isom_close(file); return GF_OK; @@ -3723,9 +4233,12 @@ GF_Err gf_dash_segmenter_probe_input(GF_DashSegInput **io_dash_inputs, u32 *nb_d return GF_NOT_SUPPORTED; } -static GF_Err write_mpd_header(FILE *mpd, const char *mpd_name, GF_Config *dash_ctx, GF_DashProfile profile, Bool is_mpeg2, const char *title, const char *source, const char *copyright, const char *moreInfoURL, const char **mpd_base_urls, u32 nb_mpd_base_urls, Bool dash_dynamic, u32 time_shift_depth, Double mpd_duration, Double mpd_update_period, Double min_buffer, u32 ast_shift_sec, Bool use_cenc, Bool use_xlink) +static GF_Err write_mpd_header(FILE *mpd, const char *mpd_name, GF_Config *dash_ctx, GF_DashProfile profile, Bool is_mpeg2, const char *title, const char *source, const char *copyright, const char *moreInfoURL, const char **mpd_base_urls, + u32 nb_mpd_base_urls, GF_DashDynamicMode dash_mode, u32 time_shift_depth, Double mpd_duration, Double mpd_update_period, Double min_buffer, s32 ast_shift_ms, Bool use_cenc, Bool use_xlink, Double max_seg_dur, const char *dash_profile_extension) { u32 sec, frac; + u64 time_ms; + Double msec; #ifdef _WIN32_WCE SYSTEMTIME syst; FILETIME filet; @@ -3737,7 +4250,18 @@ static GF_Err write_mpd_header(FILE *mpd, const char *mpd_name, GF_Config *dash_ Double s; gf_net_get_ntp(&sec, &frac); - sec += ast_shift_sec; + time_ms = sec; + time_ms *= 1000; + msec = frac*1000.0; + msec /= 0xFFFFFFFF; + + time_ms += (u32) msec; + if (ast_shift_ms>0) { + time_ms += (u32) ast_shift_ms; + } + sec = (u32) (time_ms/1000); + time_ms -= ((u64)sec)*1000; + assert(time_ms<1000); fprintf(mpd, "<?xml version=\"1.0\"?>\n"); fprintf(mpd, "<!-- MPD file Generated with GPAC version "GPAC_FULL_VERSION" "); @@ -3745,72 +4269,111 @@ static GF_Err write_mpd_header(FILE *mpd, const char *mpd_name, GF_Config *dash_ #ifndef _WIN32_WCE gtime = sec - GF_NTP_SEC_1900_TO_1970; t = gmtime(>ime); - fprintf(mpd, " on %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); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Generating MPD at time %d-%02d-%02dT%02d:%02d:%02dZ\n", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec) ); + fprintf(mpd, " at %d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (u32) time_ms); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Generating MPD at time %d-%02d-%02dT%02d:%02d:%02d.%03dZ\n", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (u32) time_ms) ); #else GetSystemTime(&syst); - fprintf(mpd, " on %d-%02d-%02dT%02d:%02d:%02dZ", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Generating MPD at time %d-%02d-%02dT%02d:%02d:%02dZ\n", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond) ); + fprintf(mpd, " at %d-%02d-%02dT%02d:%02d:%02dZ", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Generating MPD at time %d-%02d-%02dT%02d:%02d:%02dZ\n", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond); #endif fprintf(mpd, "-->\n"); /*TODO what should we put for minBufferTime */ - fprintf(mpd, "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" minBufferTime=\"PT%fS\" type=\"%s\"", min_buffer, dash_dynamic ? "dynamic" : "static"); - if (dash_dynamic) { + fprintf(mpd, "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" minBufferTime=\"PT%.3fS\" type=\"%s\"", min_buffer, dash_mode ? "dynamic" : "static"); + + + if (dash_mode != GF_DASH_STATIC) { + //set publish time +#ifndef _WIN32_WCE + gtime = sec - GF_NTP_SEC_1900_TO_1970; + t = gmtime(>ime); + fprintf(mpd, " 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); +#else + GetSystemTime(&syst); + fprintf(mpd, " publishTime=\"%d-%02d-%02dT%02d:%02d:%02dZ\"", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond); +#endif + if (dash_ctx) { //we only support profiles for which AST has to be the same const char *opt = gf_cfg_get_key(dash_ctx, "DASH", "GenerationNTP"); - sscanf(opt, "%u", &sec); - sec += ast_shift_sec; + sscanf(opt, "%u:%u", &sec, &frac); + + msec = frac*1000.0; + msec /= 0xFFFFFFFF; + time_ms = (u32) msec; } #ifdef _WIN32_WCE *(LONGLONG *) &filet = (sec - GF_NTP_SEC_1900_TO_1970) * 10000000 + TIMESPEC_TO_FILETIME_OFFSET; FileTimeToSystemTime(&filet, &syst); - fprintf(mpd, " on %d-%02d-%02dT%02d:%02d:%02dZ", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond); - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Generating MPD at time %d-%02d-%02dT%02d:%02d:%02dZ\n", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond) ); + fprintf(mpd, " " availabilityStartTime=\"%d-%02d-%02dT%02d:%02d:%02d.%03dZ\"", syst.wYear, syst.wMonth, syst.wDay, syst.wHour, syst.wMinute, syst.wSecond, (u32) time_ms); #else gtime = sec - GF_NTP_SEC_1900_TO_1970; t = gmtime(>ime); - fprintf(mpd, " availabilityStartTime=\"%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); - if (ast_shift_sec) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] MPD AvailabilityStartTime %d-%02d-%02dT%02d:%02d:%02dZ\n", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec) ); - } + fprintf(mpd, " availabilityStartTime=\"%d-%02d-%02dT%02d:%02d:%02d.%03dZ\"", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (u32) time_ms); #endif if ((s32)time_shift_depth>=0) { h = (u32) (time_shift_depth/3600); m = (u32) (time_shift_depth/60 - h*60); s = time_shift_depth - h*3600 - m*60; - fprintf(mpd, " timeShiftBufferDepth=\"PT%dH%dM%.2fS\"", h, m, s); + fprintf(mpd, " timeShiftBufferDepth=\"PT%dH%dM%.3fS\"", h, m, s); } if (mpd_update_period) { h = (u32) (mpd_update_period/3600); m = (u32) (mpd_update_period/60 - h*60); s = mpd_update_period - h*3600 - m*60; - fprintf(mpd, " minimumUpdatePeriod=\"PT%dH%dM%.2fS\"", h, m, s); + fprintf(mpd, " minimumUpdatePeriod=\"PT%dH%dM%.3fS\"", h, m, s); + } else { + h = (u32) (mpd_duration/3600); + m = (u32) (mpd_duration/60 - h*60); + s = mpd_duration - h*3600 - m*60; + fprintf(mpd, " mediaPresentationDuration=\"PT%dH%dM%.3fS\"", h, m, s); } } else { h = (u32) (mpd_duration/3600); m = (u32) (mpd_duration/60 - h*60); s = mpd_duration - h*3600 - m*60; - fprintf(mpd, " mediaPresentationDuration=\"PT%dH%dM%.2fS\"", h, m, s); + fprintf(mpd, " mediaPresentationDuration=\"PT%dH%dM%.3fS\"", h, m, s); + } + + if (max_seg_dur) { + h = (u32) (max_seg_dur/3600); + m = (u32) (max_seg_dur/60 - h*60); + s = max_seg_dur - h*3600 - m*60; + fprintf(mpd, " maxSegmentDuration=\"PT%dH%dM%.3fS\"", h, m, s); } if (profile==GF_DASH_PROFILE_LIVE) { - fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:%s:2011\"", is_mpeg2 ? "mp2t-simple" : "isoff-live"); + if (use_xlink && !is_mpeg2) { + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-ext-live:2014"); + } else { + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:%s:2011", is_mpeg2 ? "mp2t-simple" : "isoff-live"); + } } else if (profile==GF_DASH_PROFILE_ONDEMAND) { - fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011\""); + if (use_xlink) { + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-ext-on-demand:2014"); + } else { + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011"); + } } else if (profile==GF_DASH_PROFILE_MAIN) { - fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:%s:2011\"", is_mpeg2 ? "mp2t-main" : "isoff-main"); + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:%s:2011", is_mpeg2 ? "mp2t-main" : "isoff-main"); + } else if (profile==GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE) { + fprintf(mpd, " profiles=\"urn:hbbtv:dash:profile:isoff-live:2012"); } else if (profile==GF_DASH_PROFILE_AVC264_LIVE) { - fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-live:2011, http://dashif.org/guildelines/dash264\""); + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash264"); } else if (profile==GF_DASH_PROFILE_AVC264_ONDEMAND) { - fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011, http://dashif.org/guildelines/dash264\""); + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:isoff-on-demand:2011,http://dashif.org/guidelines/dash264"); } else { - fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:full:2011\""); + fprintf(mpd, " profiles=\"urn:mpeg:dash:profile:full:2011"); } + + if (dash_profile_extension) { + fprintf(mpd, ",%s", dash_profile_extension); + } + fprintf(mpd, "\""); + if (use_cenc) { fprintf(mpd, " xmlns:cenc=\"urn:mpeg:cenc:2013\""); } @@ -3839,33 +4402,37 @@ static GF_Err write_mpd_header(FILE *mpd, const char *mpd_name, GF_Config *dash_ return GF_OK; } -static GF_Err write_period_header(FILE *mpd, const char *szID, Double period_start, Double period_duration, - Bool dash_dynamic, const char *xlink, - GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 period_num) +static GF_Err write_period_header(FILE *mpd, const char *szID, Double period_start, Double period_duration, + GF_DashDynamicMode dash_mode, const char *xlink, + GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 period_num, Bool insert_xmlns) { u32 h, m; Double s; u32 i,j; - fprintf(mpd, " <Period"); + + if (insert_xmlns) { + fprintf(mpd, " xmlns=\"urn:mpeg:dash:schema:mpd:2011\" "); + } if (szID && strlen(szID)) fprintf(mpd, " id=\"%s\"", szID); - if (period_start || dash_dynamic) { + if (period_start || dash_mode) { h = (u32) (period_start/3600); m = (u32) (period_start/60 - h*60); s = period_start - h*3600 - m*60; - fprintf(mpd, " start=\"PT%dH%dM%.2fS\"", h, m, s); + fprintf(mpd, " start=\"PT%dH%dM%.3fS\"", h, m, s); } - if (!dash_dynamic && period_duration) { + if (!dash_mode && period_duration) { h = (u32) (period_duration/3600); m = (u32) (period_duration/60 - h*60); s = period_duration - h*3600 - m*60; - fprintf(mpd, " duration=\"PT%dH%dM%.2fS\"", h, m, s); + fprintf(mpd, " duration=\"PT%dH%dM%.3fS\"", h, m, s); } if (xlink) { fprintf(mpd, " xlink:href=\"%s\"", xlink); } + fprintf(mpd, ">\n"); /* writing Period level descriptors */ @@ -3877,16 +4444,23 @@ static GF_Err write_period_header(FILE *mpd, const char *szID, Double period_sta } } + if (xlink) { + fprintf(mpd, " </Period>\n"); + } + return GF_OK; } -static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool use_url_template, u32 single_file_mode, - GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 period_num, u32 adaptation_set_num, u32 first_rep_in_set, - Bool bitstream_switching_mode, u32 max_width, u32 max_height, char *szMaxFPS, char *szLang, const char *szInitSegment) +static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool use_url_template, u32 single_file_mode, + GF_DashSegInput *dash_inputs, u32 nb_dash_inputs, u32 period_num, u32 adaptation_set_num, u32 first_rep_in_set, + Bool bitstream_switching_mode, u32 max_width, u32 max_height, char *szMaxFPS, char *szLang, const char *szInitSegment, Bool segment_alignment_disabled, const char *mpd_name) { u32 i, j; + Bool is_on_demand = ((profile==GF_DASH_PROFILE_ONDEMAND) || (profile==GF_DASH_PROFILE_AVC264_ONDEMAND)); GF_DashSegInput *first_rep = &dash_inputs[first_rep_in_set]; - fprintf(mpd, " <AdaptationSet segmentAlignment=\"true\""); + + //force segmentAlignment in onDemand + fprintf(mpd, " <AdaptationSet segmentAlignment=\"%s\"", (!is_on_demand && segment_alignment_disabled) ? "false" : "true"); if (bitstream_switching_mode) { fprintf(mpd, " bitstreamSwitching=\"true\""); } @@ -3900,26 +4474,35 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us gf_media_reduce_aspect_ratio(&max_width, &max_height); fprintf(mpd, " par=\"%d:%d\"", max_width, max_height); } - if (szLang && szLang[0] && strcmp(szLang, "und")) { + //add lang even if "und" to comply with dash-if + if (szLang) { fprintf(mpd, " lang=\"%s\"", szLang); } - /*this should be fixed to use info collected during segmentation process*/ - if (profile==GF_DASH_PROFILE_ONDEMAND) - fprintf(mpd, " subsegmentStartsWithSAP=\"1\""); - - if (!strcmp(first_rep->szMime, "video/mp2t")) - fprintf(mpd, " subsegmentAlignment=\"true\""); - + if ((profile==GF_DASH_PROFILE_ONDEMAND) || (profile==GF_DASH_PROFILE_AVC264_ONDEMAND)) { + fprintf(mpd, " subsegmentAlignment=\"%s\"", segment_alignment_disabled ? "false" : "true"); + //FIXME - we need inspection of the segments to figure out the SAP type ! + fprintf(mpd, " subsegmentStartsWithSAP=\"1\""); + } fprintf(mpd, ">\n"); /* writing AdaptationSet level descriptors specified only on one input (non discriminating during classification)*/ for (i=0; i< nb_dash_inputs; i++) { - if (dash_inputs[i].adaptation_set == adaptation_set_num && dash_inputs[i].period == period_num) { + if ((dash_inputs[i].adaptation_set == adaptation_set_num) && (dash_inputs[i].period == period_num)) { for (j = 0; j < dash_inputs[i].nb_as_c_descs; j++) { fprintf(mpd, " %s\n", dash_inputs[i].as_c_descs[j]); } } } + + //check SRD + for (i=0; i< nb_dash_inputs; i++) { + if ((dash_inputs[i].adaptation_set == adaptation_set_num) && (dash_inputs[i].period == period_num)) { + if (dash_inputs[i].w && dash_inputs[i].h) { + fprintf(mpd, " <SupplementalProperty schemeIdURI=\"urn:mpeg:dash:srd:2014\" value=\"1,%d,%d,%d,%d\"/>\n", dash_inputs[i].x, dash_inputs[i].y, dash_inputs[i].w, dash_inputs[i].h); + } + } + } + if (first_rep) { @@ -3938,13 +4521,14 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us } /*set role*/ - if (strlen(first_rep->role)) { + if (first_rep->role) { if (!strcmp(first_rep->role, "caption") || !strcmp(first_rep->role, "subtitle") || !strcmp(first_rep->role, "main") || !strcmp(first_rep->role, "alternate") || !strcmp(first_rep->role, "supplementary") || !strcmp(first_rep->role, "commentary") || !strcmp(first_rep->role, "dub") ) { fprintf(mpd, " <Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"%s\"/>\n", first_rep->role); } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Unrecognized role %s - using GPAC urn for schemaID\n", first_rep->role)); fprintf(mpd, " <Role schemeIdUri=\"urn:gpac:dash:role:2013\" value=\"%s\"/>\n", first_rep->role); } } @@ -3971,8 +4555,8 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us break; } /*if lang not specified at adaptationSet level, put it here*/ - if ((!szLang || !szLang[0]) && (comp->szLang[0] && strcmp(comp->szLang, "und"))) { - fprintf(mpd, " lang=\"%s\"", comp->szLang); + if ((!szLang) && (comp->lang && strcmp(comp->lang, "und"))) { + fprintf(mpd, " lang=\"%s\"", comp->lang); } fprintf(mpd, "/>\n"); } @@ -3980,14 +4564,14 @@ static GF_Err write_adaptation_header(FILE *mpd, GF_DashProfile profile, Bool us if (bitstream_switching_mode && !use_url_template && (single_file_mode!=1) && strlen(szInitSegment) ) { fprintf(mpd, " <SegmentList>\n"); - fprintf(mpd, " <Initialization sourceURL=\"%s\"/>\n", gf_url_get_resource_name( szInitSegment )); + fprintf(mpd, " <Initialization sourceURL=\"%s\"/>\n", gf_dasher_strip_output_dir(mpd_name, szInitSegment )); fprintf(mpd, " </SegmentList>\n"); } } return GF_OK; } -static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, u32 *dynamic, u32 *timeShiftBufferDepth, const char *periodID, u32 ast_shift_sec) +static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, GF_DashDynamicMode *dash_mode, u32 *timeShiftBufferDepth, const char *periodID, s32 ast_shift_ms) { const char *opt; char szVal[100]; @@ -4004,17 +4588,17 @@ static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, u32 *dynamic, u32 *tim if (!opt) { first_run = GF_TRUE; sprintf(szVal, "%d", *timeShiftBufferDepth); - gf_cfg_set_key(dash_ctx, "DASH", "SessionType", (*dynamic==2) ? "dynamic-debug" : ( *dynamic ? "dynamic" : "static" ) ); + gf_cfg_set_key(dash_ctx, "DASH", "SessionType", (*dash_mode == GF_DASH_DYNAMIC_DEBUG) ? "dynamic-debug" : ( *dash_mode ? "dynamic" : "static" ) ); gf_cfg_set_key(dash_ctx, "DASH", "TimeShiftBufferDepth", szVal); gf_cfg_set_key(dash_ctx, "DASH", "StoreParams", "yes"); } //switching from live to static - else if (! (*dynamic) && !strncmp(opt, "dynamic", 7)) { + else if (! (*dash_mode) && !strncmp(opt, "dynamic", 7)) { gf_cfg_set_key(dash_ctx, "DASH", "SessionType", "static"); } else { - *dynamic = 0; - if (!strcmp(opt, "dynamic")) *dynamic = 1; - else if (!strcmp(opt, "dynamic-debug")) *dynamic = 2; + *dash_mode = 0; + if (!strcmp(opt, "dynamic")) *dash_mode = GF_DASH_DYNAMIC; + else if (!strcmp(opt, "dynamic-debug")) *dash_mode = GF_DASH_DYNAMIC_DEBUG; opt = gf_cfg_get_key(dash_ctx, "DASH", "TimeShiftBufferDepth"); *timeShiftBufferDepth = atoi(opt); @@ -4030,10 +4614,8 @@ static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, u32 *dynamic, u32 *tim gtime = sec - GF_NTP_SEC_1900_TO_1970; gf_cfg_set_key(dash_ctx, "DASH", "GenerationTime", asctime(gmtime(>ime))); #endif - sprintf(szVal, "%u", sec); + sprintf(szVal, "%u:%d", sec, frac); gf_cfg_set_key(dash_ctx, "DASH", "GenerationNTP", szVal); - sprintf(szVal, "%u", frac); - gf_cfg_set_key(dash_ctx, "DASH", "GenerationNTPFraction", szVal); if (periodID) gf_cfg_set_key(dash_ctx, "DASH", "PeriodID", periodID); @@ -4055,26 +4637,28 @@ static GF_Err gf_dasher_init_context(GF_Config *dash_ctx, u32 *dynamic, u32 *tim } GF_EXPORT -u32 gf_dasher_next_update_time(GF_Config *dash_ctx, u32 mpd_update_time) +u32 gf_dasher_next_update_time(GF_Config *dash_ctx, Double mpd_update_time) { Double max_dur = 0; Double safety_dur; Double ms_elapsed; - u32 i, ntp_sec, frac, prev_sec, prev_frac; + u32 i, ntp_sec, frac, prev_sec, prev_frac, dash_scale; const char *opt, *section; opt = gf_cfg_get_key(dash_ctx, "DASH", "MaxSegmentDuration"); if (!opt) return 0; - safety_dur = atof(opt); - if (safety_dur > (Double) mpd_update_time) - safety_dur = (Double) mpd_update_time; + safety_dur = atof(opt) / 2; + if (safety_dur > mpd_update_time) + safety_dur = mpd_update_time; + safety_dur = 0; opt = gf_cfg_get_key(dash_ctx, "DASH", "GenerationNTP"); - sscanf(opt, "%u", &prev_sec); - opt = gf_cfg_get_key(dash_ctx, "DASH", "GenerationNTPFraction"); - sscanf(opt, "%u", &prev_frac); + sscanf(opt, "%u:%u", &prev_sec, &prev_frac); + + opt = gf_cfg_get_key(dash_ctx, "DASH", "TimeScale"); + sscanf(opt, "%u", &dash_scale); /*compute cumulated duration*/ for (i=0; i<gf_cfg_get_section_count(dash_ctx); i++) { @@ -4082,7 +4666,11 @@ u32 gf_dasher_next_update_time(GF_Config *dash_ctx, u32 mpd_update_time) section = gf_cfg_get_section_name(dash_ctx, i); if (section && !strncmp(section, "Representation_", 15)) { opt = gf_cfg_get_key(dash_ctx, section, "CumulatedDuration"); - if (opt) dur = atof(opt); + if (opt) { + u64 val; + sscanf(opt, LLU, &val); + dur = ((Double) val) / dash_scale; + } if (dur>max_dur) max_dur = dur; } } @@ -4104,23 +4692,23 @@ u32 gf_dasher_next_update_time(GF_Config *dash_ctx, u32 mpd_update_time) } /*peform all file cleanup*/ -static Bool gf_dasher_cleanup(GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double dash_duration, u32 ast_shift_sec) +static Bool gf_dasher_cleanup(GF_Config *dash_ctx, GF_DashDynamicMode dash_mode, Double mpd_update_time, u32 time_shift_depth, Double dash_duration, s32 ast_shift_ms, u32 dash_scale) { Double max_dur = 0; Double elapsed = 0; - Double safety_dur = MAX(mpd_update_time, (u32) dash_duration); - u32 i, ntp_sec, frac, prev_sec; + Double safety_dur = MAX(mpd_update_time, dash_duration); + u32 i, ntp_sec, frac, prev_sec, prev_frac; const char *opt, *section; GF_Err e; - if (!dash_dynamic) return 1; + if (!dash_mode) return GF_TRUE; opt = gf_cfg_get_key(dash_ctx, "DASH", "StoreParams"); - if (opt && !strcmp(opt, "yes")) return 1; + if (opt && !strcmp(opt, "yes")) return GF_TRUE; opt = gf_cfg_get_key(dash_ctx, "DASH", "GenerationNTP"); - if (!opt) return 1; - sscanf(opt, "%u", &prev_sec); + if (!opt) return GF_TRUE; + sscanf(opt, "%u:%u", &prev_sec, &prev_frac); /*compute cumulated duration*/ for (i=0; i<gf_cfg_get_section_count(dash_ctx); i++) { @@ -4128,22 +4716,28 @@ static Bool gf_dasher_cleanup(GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_upd section = gf_cfg_get_section_name(dash_ctx, i); if (section && !strncmp(section, "Representation_", 15)) { opt = gf_cfg_get_key(dash_ctx, section, "CumulatedDuration"); - if (opt) dur = atof(opt); + if (opt) { + u64 val; + sscanf(opt, LLU, &val); + dur = ((Double) val) / dash_scale; + } if (dur>max_dur) max_dur = dur; } } - if (!max_dur) return 1; + if (!max_dur) return GF_TRUE; gf_net_get_ntp(&ntp_sec, &frac); - if (dash_dynamic==2) { + if (dash_mode == GF_DASH_DYNAMIC_DEBUG) { elapsed = (u32)-1; } else { elapsed = ntp_sec; + elapsed += (frac*1.0)/0xFFFFFFFF; elapsed -= prev_sec; + elapsed -= (prev_frac*1.0)/0xFFFFFFFF; /*check if we need to generate */ - if (!dash_dynamic && elapsed < max_dur - safety_dur ) { + if (!dash_mode && elapsed < max_dur - safety_dur ) { GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Asked to regenerate segments before expiration of the current segment list, please wait %g seconds - ignoring\n", max_dur + prev_sec - ntp_sec )); - return 0; + return GF_FALSE; } if (elapsed > max_dur) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Generating segments and MPD %g seconds too late\n", elapsed - (u32) max_dur)); @@ -4157,23 +4751,28 @@ static Bool gf_dasher_cleanup(GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_upd if ((s32) time_shift_depth >= 0) { for (i=0; i<gf_cfg_get_key_count(dash_ctx, "SegmentsStartTimes"); i++) { Double seg_time; - Bool found=0; + u64 start, dur; + char szRepID[100]; + char szSecName[200]; u32 j; const char *fileName = gf_cfg_get_key_name(dash_ctx, "SegmentsStartTimes", i); - const char *MPDTime = gf_cfg_get_key(dash_ctx, "SegmentsStartTimes", fileName); + const char *opt = gf_cfg_get_key(dash_ctx, "SegmentsStartTimes", fileName); if (!fileName) break; - seg_time = atof(MPDTime); - seg_time += ast_shift_sec; - seg_time += dash_duration + time_shift_depth; + sscanf(opt, ""LLU"-"LLU"@%s", &start, &dur, szRepID); + seg_time = (Double) start; + seg_time /= dash_scale; + if (ast_shift_ms>0) + seg_time += ((Double) ast_shift_ms) / 1000; + + + seg_time += 2*dash_duration + time_shift_depth; seg_time -= elapsed; - /*safety gard of one second*/ - if (seg_time >= -1) - break; + if (seg_time >= 0) break; - if (dash_dynamic!=2) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Removing segment %s - %g sec too late\n", fileName, -seg_time)); + if (! (dash_mode == GF_DASH_DYNAMIC_DEBUG) ) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Removing segment %s - %g sec too late\n", fileName, -seg_time - dash_duration)); } e = gf_delete_file(fileName); @@ -4182,28 +4781,32 @@ static Bool gf_dasher_cleanup(GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_upd break; } - /*check all reps*/ - for (j=0; j<gf_cfg_get_section_count(dash_ctx); j++) { - u32 k; - const char *secName = gf_cfg_get_section_name(dash_ctx, j); - if (!strstr(secName, "URLs_")) continue; - for (k=0; k<gf_cfg_get_key_count(dash_ctx, secName); k++) { - const char *entry = gf_cfg_get_key_name(dash_ctx, secName, k); - const char *name = gf_cfg_get_key(dash_ctx, secName, entry); - if (strstr(name, fileName)) { - gf_cfg_set_key(dash_ctx, secName, entry, NULL); - found=1; - break; - } + sprintf(szSecName, "URLs_%s", szRepID); + + /*remove URLs*/ + for (j=0; j<gf_cfg_get_key_count(dash_ctx, szSecName); j++) { + const char *entry = gf_cfg_get_key_name(dash_ctx, szSecName, j); + const char *name = gf_cfg_get_key(dash_ctx, szSecName, entry); + if (strstr(name, fileName)) { + gf_cfg_set_key(dash_ctx, szSecName, entry, NULL); + break; } - if (found) break; } + /*adjust seg removed count - this is needed to adjust startNumber for SegmentTimeline case*/ + sprintf(szSecName, "Representation_%s", szRepID); + j = 1; + opt = gf_cfg_get_key(dash_ctx, szSecName, "NbSegmentsRemoved"); + if (opt) j += atoi(opt); + sprintf(szRepID, "%d", j); + gf_cfg_set_key(dash_ctx, szSecName, "NbSegmentsRemoved", szRepID); + + gf_cfg_set_key(dash_ctx, "SegmentsStartTimes", fileName, NULL); i--; } } - return 1; + return GF_TRUE; } static u32 gf_dash_get_dependency_bandwidth(GF_DashSegInput *inputs, u32 nb_dash_inputs, const char *file_name, u32 trackNum) { @@ -4222,14 +4825,14 @@ static GF_Err dash_insert_period_xml(FILE *mpd, char *szPeriodXML) FILE *period_mpd; u32 xml_size; - period_mpd = gf_f64_open(szPeriodXML, "rb"); + period_mpd = gf_fopen(szPeriodXML, "rb"); if (!period_mpd) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Error opening period MPD file %s\n", szPeriodXML)); return GF_IO_ERR; } - gf_f64_seek(period_mpd, 0, SEEK_END); - xml_size = (u32) gf_f64_tell(period_mpd); - gf_f64_seek(period_mpd, 0, SEEK_SET); + gf_fseek(period_mpd, 0, SEEK_END); + xml_size = (u32) gf_ftell(period_mpd); + gf_fseek(period_mpd, 0, SEEK_SET); while (xml_size) { char buf[4096]; @@ -4238,14 +4841,15 @@ static GF_Err dash_insert_period_xml(FILE *mpd, char *szPeriodXML) read = (u32) fread(buf, 1, size, period_mpd); if (read != size) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Error reading from period MPD file: got %d but requested %d bytes\n", read, size )); - fclose(period_mpd); + gf_fclose(period_mpd); return GF_IO_ERR; } fwrite(buf, 1, size, mpd); xml_size -= size; } - fclose(period_mpd); + gf_fclose(period_mpd); + //we cannot delet the file because we don't know if we will be called again with a new period, in which case we need to reinsert this XML ... return GF_OK; } @@ -4265,6 +4869,15 @@ static void purge_dash_context(GF_Config *dash_ctx) } } +typedef struct +{ + char szPeriodXML[GF_MAX_PATH]; + Double period_duration; + Bool is_xlink; + u32 period_idx; + const char *id; +} PeriodEntry; + /*dash segmenter*/ GF_EXPORT GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *inputs, u32 nb_inputs, GF_DashProfile dash_profile, @@ -4273,12 +4886,13 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input u32 use_url_template, Bool use_segment_timeline, Bool single_segment, Bool single_file, GF_DashSwitchingMode bitstream_switching, Bool seg_at_rap, Double dash_duration, char *seg_name, char *seg_ext, u32 segment_marker_4cc, Double frag_duration, s32 subsegs_per_sidx, Bool daisy_chain_sidx, Bool frag_at_rap, const char *tmpdir, - GF_Config *dash_ctx, u32 dash_dynamic, u32 mpd_update_time, u32 time_shift_depth, Double subduration, Double min_buffer, - u32 ast_shift_sec, u32 dash_scale, Bool fragments_in_memory, u32 initial_moof_sn, u64 initial_tfdt, Bool no_fragments_defaults, Bool pssh_moof, Bool samplegroups_in_traf) + GF_Config *dash_ctx, GF_DashDynamicMode dash_mode, Double mpd_update_time, u32 time_shift_depth, Double subduration, Double min_buffer, + s32 ast_offset_ms, u32 dash_scale, Bool fragments_in_memory, u32 initial_moof_sn, u64 initial_tfdt, Bool no_fragments_defaults, + Bool pssh_moof, Bool samplegroups_in_traf, Bool single_traf_per_moof, Double mpd_live_duration, Bool insert_utc, Bool real_time, const char *dash_profile_extension) { - u32 i, j, k, segment_mode; + u32 i, j, segment_mode; char *sep, szSegName[GF_MAX_PATH], szSolvedSegName[GF_MAX_PATH], szTempMPD[GF_MAX_PATH], szOpt[GF_MAX_PATH]; - char szPeriodXML[GF_MAX_PATH]; +// char szPeriodXML[GF_MAX_PATH]; const char *opt; u32 cur_adaptation_set; u32 max_adaptation_set = 0; @@ -4286,11 +4900,13 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input u32 max_period = 0; u32 cur_group_id = 0; u32 max_sap_type = 0; + u32 max_comp_per_input; u32 last_period_rep_idx_plus_one = 0; Bool use_cenc = GF_FALSE; Bool none_supported = GF_TRUE; Bool has_mpeg2 = GF_FALSE; Bool has_role = GF_FALSE; + Bool content_protection_in_rep = GF_TRUE; /*if not in rep, then in the adptation set*/ Double presentation_duration = 0; Double active_period_start = 0; GF_Err e = GF_OK; @@ -4299,30 +4915,46 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input GF_DASHSegmenterOptions dash_opts; u32 nb_dash_inputs; Bool uses_xlink = GF_FALSE; + PeriodEntry *p; + Bool force_period_end = GF_FALSE; + Bool segment_alignment = GF_TRUE; + GF_List *period_links = NULL; + + if (dash_mode && !mpd_update_time && !mpd_live_duration) { + if (dash_mode == GF_DASH_DYNAMIC_LAST) { + force_period_end = GF_TRUE; + dash_mode = GF_DASH_DYNAMIC; + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Either MPD refresh (update) period or MPD duration shall be set in dynamic mode.\n")); + return GF_BAD_PARAM; + } + } + if (real_time && (nb_inputs>1)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] real-time simulation is only supported with a single representation.\n")); + return GF_BAD_PARAM; + } /*init dash context if needed*/ if (dash_ctx) { - e = gf_dasher_init_context(dash_ctx, &dash_dynamic, &time_shift_depth, NULL, ast_shift_sec); - if (e) return e; - if (dash_ctx) { + e = gf_dasher_init_context(dash_ctx, &dash_mode, &time_shift_depth, NULL, ast_offset_ms); + if (e) { + return e; + } else { Bool regenerate; + char sOpt[100]; const char *opt = gf_cfg_get_key(dash_ctx, "DASH", "MaxSegmentDuration"); if (opt) { Double seg_dur = atof(opt); - /* - if (seg_dur != dash_duration) { - return GF_NOT_SUPPORTED; - } - */ dash_duration = seg_dur; } else { - char sOpt[100]; sprintf(sOpt, "%f", dash_duration); gf_cfg_set_key(dash_ctx, "DASH", "MaxSegmentDuration", sOpt); } + sprintf(sOpt, "%u", dash_scale); + gf_cfg_set_key(dash_ctx, "DASH", "TimeScale", sOpt); /*peform all file cleanup*/ - regenerate = gf_dasher_cleanup(dash_ctx, dash_dynamic, mpd_update_time, time_shift_depth, dash_duration, ast_shift_sec); + regenerate = gf_dasher_cleanup(dash_ctx, dash_mode, mpd_update_time, time_shift_depth, dash_duration, ast_offset_ms, dash_scale); if (!regenerate) return GF_OK; opt = gf_cfg_get_key(dash_ctx, "DASH", "HasXLINK"); @@ -4334,62 +4966,66 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input max_period = 0; /* first, we assume that nb_dash_inputs is equal to nb_inputs. This value will be recompute then*/ nb_dash_inputs = nb_inputs; - dash_inputs = gf_malloc(sizeof(GF_DashSegInput)*nb_dash_inputs); + dash_inputs = (GF_DashSegInput *)gf_malloc(sizeof(GF_DashSegInput)*nb_dash_inputs); memset(dash_inputs, 0, sizeof(GF_DashSegInput)*nb_dash_inputs); j = 0; for (i=0; i<nb_inputs; i++) { s32 nb_diff; dash_inputs[j].file_name = inputs[i].file_name; - strcpy(dash_inputs[j].representationID, inputs[i].representationID); - strcpy(dash_inputs[j].periodID, inputs[i].periodID); - strcpy(dash_inputs[j].xlink, inputs[i].xlink); - if (strlen(dash_inputs[j].xlink)) uses_xlink = GF_TRUE; - strcpy(dash_inputs[j].role, inputs[i].role); + if (inputs[i].representationID) + strcpy(dash_inputs[j].representationID, inputs[i].representationID); + dash_inputs[j].periodID = inputs[i].periodID; + dash_inputs[j].nb_baseURL = inputs[i].nb_baseURL; + dash_inputs[j].baseURL = inputs[i].baseURL; + dash_inputs[j].xlink = inputs[i].xlink; + if (dash_inputs[j].xlink) uses_xlink = GF_TRUE; + dash_inputs[j].role = inputs[i].role; + dash_inputs[j].nb_rep_descs = inputs[i].nb_rep_descs; - dash_inputs[j].rep_descs = (char **)gf_malloc(dash_inputs[j].nb_rep_descs*sizeof(char *)); - for (k = 0; k < dash_inputs[j].nb_rep_descs; k++) { - dash_inputs[j].rep_descs[k] = inputs[i].rep_descs[k]; - } + dash_inputs[j].rep_descs = inputs[i].rep_descs; dash_inputs[j].nb_as_descs = inputs[i].nb_as_descs; - dash_inputs[j].as_descs = (char **)gf_malloc(dash_inputs[j].nb_as_descs*sizeof(char *)); - for (k = 0; k < dash_inputs[j].nb_as_descs; k++) { - dash_inputs[j].as_descs[k] = inputs[i].as_descs[k]; - } + dash_inputs[j].as_descs = inputs[i].as_descs; dash_inputs[j].nb_as_c_descs = inputs[i].nb_as_c_descs; - dash_inputs[j].as_c_descs = (char **)gf_malloc(dash_inputs[j].nb_as_c_descs*sizeof(char *)); - for (k = 0; k < dash_inputs[j].nb_as_c_descs; k++) { - dash_inputs[j].as_c_descs[k] = inputs[i].as_c_descs[k]; - } + dash_inputs[j].as_c_descs = inputs[i].as_c_descs; dash_inputs[j].nb_p_descs = inputs[i].nb_p_descs; - dash_inputs[j].p_descs = (char **)gf_malloc(dash_inputs[j].nb_p_descs*sizeof(char *)); - for (k = 0; k < dash_inputs[j].nb_p_descs; k++) { - dash_inputs[j].p_descs[k] = inputs[i].p_descs[k]; - } + dash_inputs[j].p_descs = inputs[i].p_descs; + dash_inputs[j].bandwidth = inputs[i].bandwidth; - if (strlen(inputs[i].role) && strcmp(inputs[i].role, "main")) - has_role = 1; + if (inputs[i].role && strcmp(inputs[i].role, "main")) + has_role = GF_TRUE; - if (!strlen(dash_inputs[j].periodID)) { + if (! dash_inputs[j].periodID) { max_period = 1; dash_inputs[j].period = 1; //assign ID if dynamic - if dash_ctx also assign ID since we could have moved from dynamic to static - if (dash_dynamic || dash_ctx) { - strcpy(dash_inputs[j].periodID, "GENID_DEF"); + if (dash_mode || dash_ctx) { + dash_inputs[j].periodID = "GENID_DEF"; } } - nb_diff = nb_dash_inputs; - dash_inputs[j].moof_seqnum_increase = 2 + (u32) (dash_duration/frag_duration); - e = gf_dash_segmenter_probe_input(&dash_inputs, &nb_dash_inputs, j); - nb_diff = nb_dash_inputs - nb_diff; - if (e) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Cannot open file %s for dashing: %s\n", dash_inputs[i].file_name, gf_error_to_string(e) )); - nb_diff--; - } + if (!strcmp(dash_inputs[j].file_name, "NULL") || !strcmp(dash_inputs[j].file_name, "") || !dash_inputs[j].file_name) { + if (!strcmp(dash_inputs[j].xlink, "")) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH]: No input file specified and no xlink set - cannot dash\n")); + e = GF_BAD_PARAM; + goto exit; + } + dash_inputs[j].duration = inputs[i].period_duration; + j += 1; + } else { + nb_diff = nb_dash_inputs; + dash_inputs[j].segment_duration = inputs[i].period_duration; + dash_inputs[j].moof_seqnum_increase = 2 + (u32) (dash_duration/frag_duration); + e = gf_dash_segmenter_probe_input(&dash_inputs, &nb_dash_inputs, j); + nb_diff = nb_dash_inputs - nb_diff; + if (e) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Cannot open file %s for dashing: %s\n", dash_inputs[i].file_name, gf_error_to_string(e) )); + nb_diff--; + } - if (!strcmp(dash_inputs[j].szMime, "video/mp2t")) has_mpeg2 = 1; + if (!strcmp(dash_inputs[j].szMime, "video/mp2t")) has_mpeg2 = GF_TRUE; - j += 1+nb_diff; + j += 1+nb_diff; + } } if (!j) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Error: no suitable file found for dashing.\n")); @@ -4397,20 +5033,22 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input goto exit; } + period_links = gf_list_new(); + memset(&dash_opts, 0, sizeof(GF_DASHSegmenterOptions)); /*set all default roles to main if needed*/ if (has_role) { for (i=0; i<nb_dash_inputs; i++) { - if (!strlen(dash_inputs[i].role)) - strcpy(dash_inputs[i].role, "main"); + if (!dash_inputs[i].role) + dash_inputs[i].role = "main"; } } for (i=0; i<nb_dash_inputs; i++) { if (dash_inputs[i].period) continue; - if (strlen(dash_inputs[i].periodID)) { + if (dash_inputs[i].periodID) { max_period++; dash_inputs[i].period = max_period; @@ -4420,33 +5058,46 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input } } } - if (dash_dynamic && max_period>1) { + if (dash_mode && max_period>1) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Multiple periods in live mode not supported\n")); e = GF_NOT_SUPPORTED; goto exit; } for (cur_period=0; cur_period<max_period; cur_period++) { + Double seg_duration_in_period = 0; /*classify all input in possible adaptation sets*/ for (i=0; i<nb_dash_inputs; i++) { /*this file does not belong to our current period*/ if (dash_inputs[i].period != cur_period+1) continue; + if (!seg_duration_in_period) { + seg_duration_in_period = dash_inputs[i].segment_duration ? dash_inputs[i].segment_duration : dash_duration*dash_scale; + } else if (dash_inputs[i].segment_duration && (dash_inputs[i].segment_duration != seg_duration_in_period)) { + segment_alignment = GF_FALSE; + } + /*this file already belongs to an adaptation set*/ if (dash_inputs[i].adaptation_set) continue; /*we cannot fragment the input file*/ if (!dash_inputs[i].dasher_input_classify || !dash_inputs[i].dasher_segment_file) { + //this is a remote period insertion + if (dash_inputs[i].xlink) { + //assign a AS for this fake source (otherwise first active period detection will fail) + dash_inputs[i].adaptation_set = 1; + none_supported = GF_FALSE; + } continue; } - max_adaptation_set ++; + max_adaptation_set++; dash_inputs[i].adaptation_set = max_adaptation_set; dash_inputs[i].nb_rep_in_adaptation_set = 1; e = dash_inputs[i].dasher_input_classify(dash_inputs, nb_dash_inputs, i, &cur_group_id, &max_sap_type); if (e) goto exit; - none_supported = 0; + none_supported = GF_FALSE; } if (none_supported) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: None of the input types are supported for DASHing - nothing to do ...\n")); @@ -4460,57 +5111,94 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (dash_profile) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: WARNING! Max SAP type %d detected\n\tswitching to FULL profile\n", max_sap_type)); } - dash_profile = 0; - } - if ((dash_profile==GF_DASH_PROFILE_LIVE) && !seg_name) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: WARNING! DASH Live profile requested but no -segment-name\n\tusing \"%%s_dash\" by default\n\n")); - seg_name = "%s_dash"; - } - - /*if output id not in the current working dir, concatenate output path to segment name*/ - szSegName[0] = 0; - if (seg_name) { - if (gf_url_get_resource_path(mpdfile, szSegName)) { - strcat(szSegName, seg_name); - seg_name = szSegName; - } + dash_profile = GF_DASH_PROFILE_FULL; } /*adjust params based on profiles*/ switch (dash_profile) { case GF_DASH_PROFILE_LIVE: - seg_at_rap = 1; + seg_at_rap = GF_TRUE; use_url_template = 1; - single_segment = single_file = 0; + single_segment = single_file = GF_FALSE; break; + case GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE: { + bitstream_switching = GF_DASH_BSMODE_MULTIPLE_ENTRIES; + for (i=0; i<nb_dash_inputs; i++) { + if (dash_inputs[i].role && !strcmp(dash_inputs[i].role, "main")) + break; + } + if (i == nb_dash_inputs) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] HbbTV 1.5 ISO live profile requires to have at least one Adaptation Set\nlabelled with a Role@value of \"main\". Consider adding \":role=main\" to your inputs.\n")); + e = GF_BAD_PARAM; + goto exit; + } + } case GF_DASH_PROFILE_AVC264_LIVE: - seg_at_rap = 1; - no_fragments_defaults = 1; + seg_at_rap = GF_TRUE; + no_fragments_defaults = GF_TRUE; use_url_template = 1; - single_segment = single_file = 0; + single_segment = single_file = GF_FALSE; + content_protection_in_rep = GF_FALSE; break; case GF_DASH_PROFILE_AVC264_ONDEMAND: - seg_at_rap = 1; - no_fragments_defaults = 1; + seg_at_rap = GF_TRUE; + no_fragments_defaults = GF_TRUE; + content_protection_in_rep = GF_FALSE; if (seg_name) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Segment-name not allowed in DASH-AVC/264 onDemand profile.\n")); - e = GF_NOT_SUPPORTED; + e = GF_BAD_PARAM; goto exit; } case GF_DASH_PROFILE_ONDEMAND: - seg_at_rap = 1; - single_segment = 1; + seg_at_rap = GF_TRUE; + single_segment = GF_TRUE; + if ((bitstream_switching != GF_DASH_BSMODE_DEFAULT) && (bitstream_switching != GF_DASH_BSMODE_NONE)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] onDemand profile, bitstream switching mode cannot be used.\n")); + e = GF_BAD_PARAM; + goto exit; + } /*BS switching is meaningless in onDemand profile*/ bitstream_switching = GF_DASH_BSMODE_NONE; - use_url_template = single_file = 0; + use_url_template = single_file = GF_FALSE; break; case GF_DASH_PROFILE_MAIN: - seg_at_rap = 1; - single_segment = 0; + seg_at_rap = GF_TRUE; + single_segment = GF_FALSE; break; default: break; } + if (bitstream_switching == GF_DASH_BSMODE_DEFAULT) { + bitstream_switching = GF_DASH_BSMODE_INBAND; + } + + //we allow using inband param set when not time aligned. set the option now before overriding flags for non time aligned + dash_opts.inband_param_set = ((bitstream_switching == GF_DASH_BSMODE_INBAND) || (bitstream_switching == GF_DASH_BSMODE_SINGLE) ) ? GF_TRUE : GF_FALSE; + + if (!segment_alignment) { + if (dash_profile) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Segments are not time-aligned in each representation of each period\n\tswitching to FULL profile\n", max_sap_type)); + dash_profile = GF_DASH_PROFILE_FULL; + } + if (bitstream_switching != GF_DASH_BSMODE_NONE) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: Segments are not time-aligned in each representation of each period\n\tdisabling bitstream switching\n", max_sap_type)); + bitstream_switching = GF_DASH_BSMODE_NONE; + } + } + + if (use_url_template && !seg_name) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH]: WARNING! DASH Live profile requested but no -segment-name\n\tusing \"%%s_dash\" by default\n\n")); + seg_name = "%s_dash"; + } + /*if output id not in the current working dir, concatenate output path to segment name*/ + szSegName[0] = 0; + if (seg_name) { + if (gf_url_get_resource_path(mpdfile, szSegName)) { + strcat(szSegName, seg_name); + seg_name = szSegName; + } + } + segment_mode = single_segment ? 1 : (single_file ? 2 : 0); @@ -4530,10 +5218,10 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input } GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("\n")); } - if (frag_at_rap) seg_at_rap = 1; + if (frag_at_rap) seg_at_rap = GF_TRUE; if (seg_at_rap) { - GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Spliting segments %sat GOP boundaries\n", frag_at_rap ? "and fragments " : "")); + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Splitting segments %sat GOP boundaries\n", frag_at_rap ? "and fragments " : "")); } dash_opts.mpd_name = mpdfile; @@ -4550,10 +5238,13 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input dash_opts.dash_ctx = dash_ctx; dash_opts.time_shift_depth = (s32) time_shift_depth; dash_opts.segment_marker_4cc = segment_marker_4cc; - dash_opts.inband_param_set = ((bitstream_switching == GF_DASH_BSMODE_INBAND) || (bitstream_switching == GF_DASH_BSMODE_SINGLE) ) ? 1 : 0; dash_opts.memory_mode = fragments_in_memory; dash_opts.pssh_moof = pssh_moof; dash_opts.samplegroups_in_traf = samplegroups_in_traf; + dash_opts.single_traf_per_moof = single_traf_per_moof; + dash_opts.content_protection_in_rep = content_protection_in_rep; + dash_opts.ast_offset_ms = ast_offset_ms; + dash_opts.force_period_end = force_period_end; dash_opts.segment_duration = dash_duration * 1000 / dash_scale; dash_opts.subduration = subduration * 1000 / dash_scale; @@ -4561,13 +5252,17 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input dash_opts.initial_moof_sn = initial_moof_sn; dash_opts.initial_tfdt = initial_tfdt; dash_opts.no_fragments_defaults = no_fragments_defaults; + dash_opts.insert_utc = insert_utc; + dash_opts.real_time = real_time; + dash_opts.mpd_name = mpdfile; - + max_comp_per_input = 0; for (cur_period=0; cur_period<max_period; cur_period++) { u32 first_in_period = 0; Double period_duration=0; for (i=0; i<nb_dash_inputs; i++) { + Double dur = 0; /*this file does not belongs to any adaptation set*/ if (dash_inputs[i].period != cur_period+1) continue; @@ -4583,8 +5278,13 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input e = dash_inputs[i].dasher_get_components_info(&dash_inputs[i], &dash_opts); if (e) goto exit; } - if (dash_inputs[i].duration > period_duration) - period_duration = dash_inputs[i].duration; + dur = dash_inputs[i].duration; + if (subduration && (subduration < dur) ) { + dur = dash_opts.subduration; + } + + if (dur > period_duration) + period_duration = dur; switch (dash_inputs[i].protection_scheme_type) { case GF_ISOM_CENC_SCHEME: @@ -4592,6 +5292,8 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input use_cenc = GF_TRUE; break; } + if (max_comp_per_input < dash_inputs[i].nb_components) + max_comp_per_input = dash_inputs[i].nb_components; } if (first_in_period) { dash_inputs[first_in_period-1].period_duration = period_duration; @@ -4599,6 +5301,39 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input presentation_duration += period_duration; } + if (max_comp_per_input > 1) { + if (dash_profile == GF_DASH_PROFILE_AVC264_LIVE) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Muxed representations not allowed in DASH-IF AVC264 live profile\n\tswitching to regular live profile\n")); + dash_profile = GF_DASH_PROFILE_LIVE; + } else if (dash_profile == GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Muxed representations not allowed in HbbTV 1.5 ISOBMF live profile\n\tswitching to regular live profile\n")); + dash_profile = GF_DASH_PROFILE_LIVE; + } else if (dash_profile == GF_DASH_PROFILE_AVC264_ONDEMAND) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Muxed representations not allowed in DASH-IF AVC264 onDemand profile\n\tswitching to regular onDemand profile\n")); + dash_profile = GF_DASH_PROFILE_ONDEMAND; + } + } + + /*HbbTV 1.5 ISO live specific checks*/ + if (dash_profile == GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE) { + if (max_adaptation_set > 16) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Max 16 adaptation sets in HbbTV 1.5 ISO live profile\n\tswitching to DASH AVC/264 live profile\n")); + dash_profile = GF_DASH_PROFILE_AVC264_LIVE; + } + if (max_period > 32) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Max 32 periods in HbbTV 1.5 ISO live profile\n\tswitching to regular DASH AVC/264 live profile\n")); + dash_profile = GF_DASH_PROFILE_AVC264_LIVE; + } + if (dash_duration < 1.0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Min segment duration 1s in HbbTV 1.5 ISO live profile\n\tcapping to 1s\n")); + dash_duration = 1.0; + } + if (dash_duration > 15.0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Max segment duration 15s in HbbTV 1.5 ISO live profile\n\tcapping to 15s\n")); + dash_duration = 15.0; + } + } + active_period_start = 0; if (dash_ctx) { Double duration; @@ -4606,6 +5341,10 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (last_period_rep_idx_plus_one) id = dash_inputs[last_period_rep_idx_plus_one-1].periodID; if (!id) id = ""; + //restore max segment duration + opt = gf_cfg_get_key(dash_ctx, "DASH", "MaxSegmentDuration"); + if (opt) dash_opts.max_segment_duration = atof(opt); + opt = gf_cfg_get_key(dash_ctx, "DASH", "LastActivePeriod"); //period has changed if (opt && strcmp(opt, id)) { @@ -4617,7 +5356,12 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input opt = gf_cfg_get_key(dash_ctx, "DASH", "LastPeriodDuration"); if (opt) last_period_dur = atof(opt); - presentation_duration += last_period_dur; + + if (!last_period_dur) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] last period has no known duration, cannot insert new period. Try re-dashing previous period and specifying its duration\n")); + e = GF_BAD_PARAM; + goto exit; + } //we may have called the segmenter with the end of the previous active period and the start of the new one - locate the //previous period and update cumulated duration @@ -4626,6 +5370,7 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (!p_id) p_id = ""; if (!strcmp(p_id, prev_id)) { last_period_dur += dash_inputs[last_period_rep_idx_plus_one-1].period_duration; + presentation_duration -= dash_inputs[last_period_rep_idx_plus_one-1].period_duration;; prev_period_not_done = GF_TRUE; break; } @@ -4633,6 +5378,8 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input gf_cfg_set_key(dash_ctx, "DASH", "LastPeriodDuration", NULL); duration += last_period_dur; + presentation_duration += duration; + sprintf(szOpt, "%g", duration); gf_cfg_set_key(dash_ctx, "DASH", "CumulatedPastPeriodsDuration", szOpt); @@ -4641,10 +5388,14 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (opt) active_period_start = atof(opt); active_period_start += last_period_dur; - //and add period to past periods, storing their start time + //and add period to past periods, storing their duration and xlink if (! prev_period_not_done) { - sprintf(szOpt, "%g", presentation_duration - last_period_dur); + opt = gf_cfg_get_key(dash_ctx, "DASH", "LastPeriodXLINK"); + sprintf(szOpt, "%g,%s", last_period_dur, opt ? opt : "INLINE"); gf_cfg_set_key(dash_ctx, "PastPeriods", prev_id, szOpt); + if (opt) { + gf_cfg_set_key(dash_ctx, "DASH", "LastPeriodXLINK", NULL); + } //update active period start sprintf(szOpt, "%g", active_period_start); @@ -4675,43 +5426,47 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input } strcpy(szTempMPD, mpdfile); - if (dash_dynamic) strcat(szTempMPD, ".tmp"); + if (dash_mode) strcat(szTempMPD, ".tmp"); - mpd = gf_f64_open(szTempMPD, "wt"); + mpd = gf_fopen(szTempMPD, "wt"); if (!mpd) { GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[MPD] Cannot open MPD file %s for writing\n", szTempMPD)); e = GF_IO_ERR; goto exit; } - dash_opts.mpd = mpd; - - e = write_mpd_header(mpd, mpdfile, dash_ctx, dash_profile, has_mpeg2, mpd_title, mpd_source, mpd_copyright, mpd_moreInfoURL, (const char **) mpd_base_urls, nb_mpd_base_urls, dash_dynamic, time_shift_depth, presentation_duration, mpd_update_time, min_buffer, ast_shift_sec,use_cenc, uses_xlink); - if (e) goto exit; - if (dash_ctx) { u32 count = gf_cfg_get_key_count(dash_ctx, "PastPeriods"); for (i=0; i<count; i++) { - const char *xlink = NULL; - const char *p_id = gf_cfg_get_key_name(dash_ctx, "PastPeriods", i); - - strcpy(szPeriodXML, mpdfile); - sep = strrchr(szPeriodXML, '.'); - if (sep) sep[0] = 0; - strcat(szPeriodXML, "-Period_"); - strcat(szPeriodXML, p_id); - strcat(szPeriodXML, ".mpd"); - - if (xlink) { - //TODOD ! - //write_period_header(mpd, id, 0.0, period_duration, dash_dynamic, xlink); + const char *id = gf_cfg_get_key_name(dash_ctx, "PastPeriods", i); + const char *xlink = gf_cfg_get_key(dash_ctx, "PastPeriods", id); + char *sep = (char *)strchr(xlink, ','); + if (!sep) continue; + + GF_SAFEALLOC(p, PeriodEntry); + gf_list_add(period_links, p); + p->id = id; + + sep[0] = 0; + p->period_duration = (Double) atof(xlink); + sep[0]=','; + xlink = &sep[1]; + if (!strcmp(xlink, "INLINE")) { + strcpy(p->szPeriodXML, mpdfile); + sep = strrchr(p->szPeriodXML, '.'); + if (sep) sep[0] = 0; + strcat(p->szPeriodXML, "-Period_"); + strcat(p->szPeriodXML, id); + strcat(p->szPeriodXML, ".mpd"); } else { - dash_insert_period_xml(mpd, szPeriodXML); + strcpy(p->szPeriodXML, xlink); + p->is_xlink = GF_TRUE; } } } for (cur_period=0; cur_period<max_period; cur_period++) { + Bool flush_period = GF_FALSE; FILE *period_mpd; Double period_duration = 0; const char *id=NULL; @@ -4722,25 +5477,49 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (dash_inputs[i].adaptation_set && (dash_inputs[i].period==cur_period+1)) { period_duration = dash_inputs[i].period_duration; id = dash_inputs[i].periodID; - if (strlen(dash_inputs[i].xlink)) + if (dash_inputs[i].xlink) xlink = dash_inputs[i].xlink; break; } } - strcpy(szPeriodXML, mpdfile); - sep = strrchr(szPeriodXML, '.'); - if (sep) sep[0] = 0; - strcat(szPeriodXML, "-Period_"); - strcat(szPeriodXML, id ? id : ""); - strcat(szPeriodXML, ".mpd"); + GF_SAFEALLOC(p, PeriodEntry); + gf_list_add(period_links, p); + p->period_duration = period_duration; + p->period_idx = cur_period+1; + p->id = id; - period_mpd = gf_f64_open(szPeriodXML, "wb"); - dash_opts.mpd = period_mpd; + if (xlink) { + strcpy(p->szPeriodXML, xlink); + p->is_xlink = GF_TRUE; + } else { + strcpy(p->szPeriodXML, mpdfile); + sep = strrchr(p->szPeriodXML, '.'); + if (sep) sep[0] = 0; + strcat(p->szPeriodXML, "-Period_"); + strcat(p->szPeriodXML, id ? id : ""); + strcat(p->szPeriodXML, ".mpd"); + } - e = write_period_header(period_mpd, id, 0.0, period_duration, dash_dynamic, NULL, dash_inputs, nb_dash_inputs, cur_period+1); - if (e) goto exit; + period_mpd = NULL; + //only open file if we are to dash something (max_adaptation_set=0: no source file, only period xlink insertion) + if (max_adaptation_set) { + period_mpd = gf_fopen(p->szPeriodXML, "wb"); + + if (!period_mpd) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Cannot open period MPD %s for writing, aborintg\n", p->szPeriodXML)); + e = GF_IO_ERR; + goto exit; + } + + dash_opts.mpd = period_mpd; + + e = write_period_header(period_mpd, id, 0.0, period_duration, dash_mode, NULL, dash_inputs, nb_dash_inputs, cur_period+1, (xlink!=NULL) ? 1 : 0 ); + if (e) goto exit; + } + //keep track of the last period xlink + gf_cfg_set_key(dash_ctx, "DASH", "LastPeriodXLINK", xlink); /*for each identified adaptationSets, write MPD and perform segmentation of input files*/ for (cur_adaptation_set=0; cur_adaptation_set < max_adaptation_set; cur_adaptation_set++) { @@ -4750,11 +5529,13 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input u32 max_height = 0; u32 fps_num = 0; u32 fps_denum = 0; - Bool use_bs_switching = bitstream_switching ? 1 : 0; - char szLang[4]; + Bool use_bs_switching = (bitstream_switching==GF_DASH_BSMODE_NONE) ? GF_FALSE : GF_TRUE; + char *lang; char szFPS[100]; - Bool is_first_rep=0; - Bool skip_init_segment_creation = 0; + Bool is_first_rep = GF_FALSE; + Bool skip_init_segment_creation = GF_FALSE; + + dash_opts.segment_alignment_disabled = GF_FALSE; while (dash_inputs[first_rep_in_set].adaptation_set!=cur_adaptation_set+1) first_rep_in_set++; @@ -4775,13 +5556,13 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input } /*unless asked to do BS switching on single rep, don't do it ...*/ if ((bitstream_switching < GF_DASH_BSMODE_SINGLE) && dash_inputs[first_rep_in_set].nb_rep_in_adaptation_set==1) - use_bs_switching = 0; + use_bs_switching = GF_FALSE; if (! use_bs_switching) { - skip_init_segment_creation = 1; + skip_init_segment_creation = GF_TRUE; } else if (! dash_inputs[first_rep_in_set].dasher_create_init_segment) { - skip_init_segment_creation = 1; + skip_init_segment_creation = GF_TRUE; strcpy(szInit, ""); } /*if we already wrote the InitializationSegment, get rid of it (no overwrite) and let the dashing routine open it*/ @@ -4790,23 +5571,23 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input const char *init_seg_name; sprintf(RepSecName, "Representation_%s", dash_inputs[first_rep_in_set].representationID); if ((init_seg_name = gf_cfg_get_key(dash_ctx, RepSecName, "InitializationSegment")) != NULL) { - skip_init_segment_creation = 1; + skip_init_segment_creation = GF_TRUE; } } if (!skip_init_segment_creation) { - Bool disable_bs_switching = 0; - e = dash_inputs[first_rep_in_set].dasher_create_init_segment(dash_inputs, nb_dash_inputs, cur_adaptation_set+1, szInit, tmpdir, &dash_opts, &disable_bs_switching); + Bool disable_bs_switching = GF_FALSE; + e = dash_inputs[first_rep_in_set].dasher_create_init_segment(dash_inputs, nb_dash_inputs, cur_adaptation_set+1, szInit, tmpdir, &dash_opts, bitstream_switching, &disable_bs_switching); if (e) goto exit; if (disable_bs_switching) - use_bs_switching = 0; + use_bs_switching = GF_FALSE; } dash_opts.bs_switch_segment_file = use_bs_switching ? szInit : NULL; dash_opts.use_url_template = seg_name ? use_url_template : 0; szFPS[0] = 0; - szLang[0] = 0; + lang = NULL; /*compute some max defaults*/ for (i=0; i<nb_dash_inputs && !e; i++) { @@ -4828,13 +5609,18 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input fps_denum = dash_inputs[i].components[j].fps_denum; } - if (dash_inputs[i].components[j].szLang && dash_inputs[i].components[j].szLang[0] && strncmp(szLang, dash_inputs[i].components[j].szLang, 3) ) { - if (szLang[0]) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] two languages in adaptation set: %s will be kept %s will be ignored\n", szLang, dash_inputs[i].components[j].szLang)); - } else { - memcpy(szLang, dash_inputs[i].components[j].szLang, 4*sizeof(char)); + if (dash_inputs[i].components[j].lang) { + if (lang && strcmp(lang, dash_inputs[i].components[j].lang) ) { + if (!strcmp(lang, "und") || !strcmp(dash_inputs[i].components[j].lang, "lang")) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] two languages in adaptation set: %s will be kept %s will be ignored\n", lang, dash_inputs[i].components[j].lang)); + } + } else if (!lang) { + lang = gf_strdup(dash_inputs[i].components[j].lang); } } + + if (dash_inputs[i].segment_duration && (dash_inputs[i].segment_duration != dash_scale*dash_duration)) + dash_opts.segment_alignment_disabled = GF_TRUE; } } @@ -4846,10 +5632,10 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input sprintf(szFPS, "%d", fps_num); } - e = write_adaptation_header(period_mpd, dash_profile, use_url_template, segment_mode, dash_inputs, nb_dash_inputs, cur_period+1, cur_adaptation_set+1, first_rep_in_set, use_bs_switching, max_width, max_height, szFPS, szLang, szInit); + e = write_adaptation_header(period_mpd, dash_profile, use_url_template, segment_mode, dash_inputs, nb_dash_inputs, cur_period+1, cur_adaptation_set+1, first_rep_in_set, use_bs_switching, max_width, max_height, szFPS, lang, szInit, dash_opts.segment_alignment_disabled, dash_opts.mpd_name); if (e) goto exit; - is_first_rep = 1; + is_first_rep = GF_TRUE; for (i=0; i<nb_dash_inputs && !e; i++) { char szOutName[GF_MAX_PATH], *segment_name; @@ -4863,11 +5649,11 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (sep) sep[0] = 0; /*in scalable case: seg_name is variable*/ - dash_opts.variable_seg_rad_name = (nb_dash_inputs != nb_inputs) ? 1 : 0; + dash_opts.variable_seg_rad_name = (nb_dash_inputs != nb_inputs) ? GF_TRUE : GF_FALSE; if (seg_name) { if (strstr(seg_name, "%s")) { sprintf(szSolvedSegName, seg_name, szOutName); - dash_opts.variable_seg_rad_name = 1; + dash_opts.variable_seg_rad_name = GF_TRUE; if (dash_inputs[i].single_track_num) { char szTkNum[50]; sprintf(szTkNum, "_track%d_", dash_inputs[i].single_track_num); @@ -4876,11 +5662,30 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input } else { strcpy(szSolvedSegName, seg_name); } + + /* user added a relative-path baseURL */ + if (dash_inputs[i].nb_baseURL) { + if (gf_url_is_local(dash_inputs[i].baseURL[0])) { + const char *name; + char tmp_segment_name[GF_MAX_PATH]; + if (dash_inputs[i].nb_baseURL > 1) + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Several relative path baseURL for input %s: selecting \"%s\"\n", dash_inputs[i].file_name, dash_inputs[i].baseURL[0])); + name = gf_url_get_resource_name(szSolvedSegName); + strcpy(tmp_segment_name, name); + gf_url_get_resource_path(dash_inputs[i].baseURL[0], szSolvedSegName); + if (szSolvedSegName[strlen(szSolvedSegName)] != GF_PATH_SEPARATOR) { + char ext[2]; ext[0] = GF_PATH_SEPARATOR; ext[1] = 0; + strcat(szSolvedSegName, ext); + } + strcat(szSolvedSegName, tmp_segment_name); + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Found baseURL for input %s but not a relative path (%s)\n", dash_inputs[i].file_name, dash_inputs[i].baseURL[0])); + } + } + segment_name = szSolvedSegName; } - if ((dash_inputs[i].trackNum || dash_inputs[i].single_track_num) - && (!seg_name || (!strstr(seg_name, "$RepresentationID$") && !strstr(seg_name, "$ID$"))) - ) { + if ((dash_inputs[i].trackNum || dash_inputs[i].single_track_num) && (!seg_name || !strstr(seg_name, "$RepresentationID$") ) ) { char tmp[10]; sprintf(tmp, "_track%d", dash_inputs[i].trackNum ? dash_inputs[i].trackNum : dash_inputs[i].single_track_num); strcat(szOutName, tmp); @@ -4891,7 +5696,7 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input strcat(tmp, szOutName); strcpy(szOutName, tmp); } - if (segment_name && dash_inputs[i].trackNum && !strstr(seg_name, "$RepresentationID$") && !strstr(seg_name, "$ID$")) { + if (segment_name && dash_inputs[i].trackNum && !strstr(seg_name, "$RepresentationID$") ) { char tmp[10]; sprintf(tmp, "_track%d_", dash_inputs[i].trackNum); strcat(segment_name, tmp); @@ -4899,10 +5704,17 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input dash_opts.seg_rad_name = segment_name; /*in scalable case, we need also the bandwidth of dependent representation*/ - if (strlen(dash_inputs[i].dependencyID)) { + if (dash_inputs[i].dependencyID) { dash_inputs[i].dependency_bandwidth = gf_dash_get_dependency_bandwidth(dash_inputs, nb_dash_inputs, dash_inputs[i].file_name, dash_inputs[i].lower_layer_track); } + dash_opts.segment_duration = dash_inputs[i].segment_duration ? dash_inputs[i].segment_duration / dash_scale : dash_duration * 1000 / dash_scale; + if (dash_inputs[i].segment_duration && (frag_duration*dash_scale > dash_inputs[i].segment_duration)) { + dash_opts.fragment_duration = dash_opts.segment_duration; + } else { + dash_opts.fragment_duration = frag_duration * 1000 / dash_scale; + } + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("DASHing file %s\n", dash_inputs[i].file_name)); e = dash_inputs[i].dasher_segment_file(&dash_inputs[i], szOutName, &dash_opts, is_first_rep); @@ -4910,30 +5722,28 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while DASH-ing file: %s\n", gf_error_to_string(e))); goto exit; } - is_first_rep = 0; + is_first_rep = GF_FALSE; } /*close adaptation set*/ fprintf(period_mpd, " </AdaptationSet>\n"); } - - fprintf(period_mpd, " </Period>\n"); - fclose(period_mpd); - - if (xlink) { - write_period_header(mpd, id, 0.0, period_duration, dash_dynamic, xlink, dash_inputs, nb_dash_inputs, cur_period+1); - } else { - dash_insert_period_xml(mpd, szPeriodXML); - } - - if (!dash_ctx && !xlink) { - gf_delete_file(szPeriodXML); + + if (period_mpd) { + fprintf(period_mpd, " </Period>\n"); + gf_fclose(period_mpd); } dash_opts.mpd = period_mpd; //and add periods done to past periods, storing their start time if (!id) id=""; - if (last_period_rep_idx_plus_one && strcmp(id, dash_inputs[last_period_rep_idx_plus_one-1].periodID) ) { + if (last_period_rep_idx_plus_one && dash_inputs[last_period_rep_idx_plus_one-1].periodID && strcmp(id, dash_inputs[last_period_rep_idx_plus_one-1].periodID) ) { + flush_period = GF_TRUE; + } + else if (force_period_end) { + flush_period = GF_TRUE; + } + if (flush_period) { sprintf(szOpt, "%g", active_period_start); gf_cfg_set_key(dash_ctx, "PastPeriods", id, szOpt); active_period_start += period_duration; @@ -4944,12 +5754,73 @@ GF_Err gf_dasher_segment_files(const char *mpdfile, GF_DashSegmenterInput *input if (dash_ctx) purge_dash_context(dash_ctx); } } + + if (dash_ctx) { + sprintf(szOpt, "%g", dash_opts.max_segment_duration); + gf_cfg_set_key(dash_ctx, "DASH", "MaxSegmentDuration", szOpt); + } + + + /*ready to write the MPD*/ + dash_opts.mpd = mpd; + + if (dash_mode && !mpd_update_time) { + presentation_duration = mpd_live_duration; + } + + if (force_period_end && !mpd_update_time && !presentation_duration) { + presentation_duration = 0; + i=0; + while ((p = (PeriodEntry *) gf_list_enum(period_links, &i))) { + presentation_duration = p->period_duration; + } + } + + e = write_mpd_header(mpd, mpdfile, dash_ctx, dash_profile, has_mpeg2, mpd_title, mpd_source, mpd_copyright, mpd_moreInfoURL, (const char **) mpd_base_urls, nb_mpd_base_urls, dash_mode, time_shift_depth, presentation_duration, mpd_update_time, min_buffer, ast_offset_ms, use_cenc, uses_xlink, dash_opts.max_segment_duration, dash_profile_extension); + if (e) goto exit; + + + i=0; + while ((p = (PeriodEntry *) gf_list_enum(period_links, &i))) { + if (!p->period_idx) { + if (p->is_xlink) { + write_period_header(mpd, p->id, 0.0, p->period_duration, dash_mode, p->szPeriodXML, NULL, 0, 0, GF_FALSE); + } else { + dash_insert_period_xml(mpd, p->szPeriodXML); + } + } else { + if (p->is_xlink) { + write_period_header(mpd, p->id, 0.0, p->period_duration, dash_mode, p->szPeriodXML, dash_inputs, nb_dash_inputs, p->period_idx, GF_FALSE); + } else { + dash_insert_period_xml(mpd, p->szPeriodXML); + } + + if (!dash_ctx && !p->is_xlink) { + gf_delete_file(p->szPeriodXML); + } + + } + } + fprintf(mpd, "</MPD>"); + + if (dash_ctx && dash_mode) { + const char *opt = gf_cfg_get_key(dash_ctx, "DASH", "LastPeriodDuration"); + if (opt) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DASH] Current Period Duration: %s\n", opt) ); + } + } + + if (dash_profile == GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE) { + if (gf_ftell(mpd) > 100*1024) + GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[DASH] Manifest MPD is too big for HbbTV 1.5. Limit is 100kB, current size is "LLU"kB\n", gf_ftell(mpd)/1024)); + } + exit: if (mpd) { - fclose(mpd); - if (!e && dash_dynamic) { + gf_fclose(mpd); + if (!e && dash_mode) { gf_delete_file(mpdfile); e = gf_move_file(szTempMPD, mpdfile); if (e) { @@ -4957,14 +5828,22 @@ exit: } } } - /* TODO free descriptors */ - for (i=0; i < nb_dash_inputs; i++) { - if (dash_inputs[i].as_descs) gf_free(dash_inputs[i].as_descs); - if (dash_inputs[i].as_c_descs) gf_free(dash_inputs[i].as_c_descs); - if (dash_inputs[i].p_descs) gf_free(dash_inputs[i].p_descs); - if (dash_inputs[i].rep_descs) gf_free(dash_inputs[i].rep_descs); + for (i=0; i < nb_inputs; i++) { + for (j = 0; j < dash_inputs[i].nb_components; j++) { + if (dash_inputs[i].components[j].lang) { + gf_free(dash_inputs[i].components[j].lang); + } + } + if (dash_inputs[i].dependencyID) gf_free(dash_inputs[i].dependencyID); } gf_free(dash_inputs); + + if (period_links) { + while (gf_list_count(period_links)) { + PeriodEntry *p = (PeriodEntry *) gf_list_pop_back(period_links); + if (p) gf_free(p); + } + } return e; } diff --git a/src/media_tools/dsmcc.c b/src/media_tools/dsmcc.c index 93d9309..7fefd2a 100644 --- a/src/media_tools/dsmcc.c +++ b/src/media_tools/dsmcc.c @@ -1015,10 +1015,10 @@ static GF_Err dsmcc_process_biop_file(GF_BitStream* bs,GF_M2TS_DSMCC_BIOP_HEADER File = dsmcc_get_file(ServiceGateway->File,moduleId,downloadId,BIOP_File->Header->objectKey_data); if(File) { GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Fichier: %s module_Id %d place :%d \n",File->Path,moduleId,File->objectKey_data)); - pFile = fopen(File->Path,"wb"); + pFile = gf_fopen(File->Path,"wb"); if (pFile!=NULL) { gf_fwrite(BIOP_File->content_byte,1,BIOP_File->content_length ,pFile); - fclose(pFile); + gf_fclose(pFile); GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Fichier créé \n\n")); if(!strcmp(File->name,"index.html")) { dsmcc_overlord->get_index = 1; diff --git a/src/media_tools/dvb_mpe.c b/src/media_tools/dvb_mpe.c index 5bba971..93ef0fa 100644 --- a/src/media_tools/dvb_mpe.c +++ b/src/media_tools/dvb_mpe.c @@ -310,7 +310,7 @@ void gf_m2ts_process_ipdatagram(MPE_FEC_FRAME *mff,GF_M2TS_Demuxer *ts) u32 i, i_holes; MPE_Error_Holes *mff_holes; u32 offset; /* offset to get through the datagram */ - u8 ip_adress_bootstrap[4]; + u8 ip_address_bootstrap[4]; Bool Boostrap_ip; offset =0; @@ -342,18 +342,18 @@ void gf_m2ts_process_ipdatagram(MPE_FEC_FRAME *mff,GF_M2TS_Demuxer *ts) /* 224.0.23.14 IP Bosstrap */ - ip_adress_bootstrap[0]=224; - ip_adress_bootstrap[1]=0; - ip_adress_bootstrap[2]=23; - ip_adress_bootstrap[3]=14; + ip_address_bootstrap[0]=224; + ip_address_bootstrap[1]=0; + ip_address_bootstrap[2]=23; + ip_address_bootstrap[3]=14; socket_simu(ip_packet,ts, 1); if(ip_packet->u8_rx_adr[3] == 8) { fprintf(stderr, "\n"); } - /* compare the destination ip adress and the ESG Bootstrap adress */ - Boostrap_ip = gf_m2ts_compare_ip(ip_packet->u8_rx_adr,ip_adress_bootstrap); + /* compare the destination ip address and the ESG Bootstrap address */ + Boostrap_ip = gf_m2ts_compare_ip(ip_packet->u8_rx_adr,ip_address_bootstrap); if(Boostrap_ip) { fprintf(stderr, "ESG Bootstrap found !\n"); } @@ -422,12 +422,12 @@ void gf_m2ts_mpe_send_datagram(GF_M2TS_Demuxer *ts, u32 mpe_pid, unsigned char * } -Bool gf_m2ts_compare_ip(u8 rx_ip_adress[4], u8 ip_adress_bootstrap[4]) +Bool gf_m2ts_compare_ip(u8 rx_ip_address[4], u8 ip_address_bootstrap[4]) { u8 i; for (i=0; i<4; i++) { - if (rx_ip_adress[i] != ip_adress_bootstrap[i]) + if (rx_ip_address[i] != ip_address_bootstrap[i]) return 0; } return 1; @@ -936,7 +936,7 @@ void gf_m2ts_print_mpe_info(GF_M2TS_Demuxer *ts) u32 i_streams, i_targets,i,j,l; GF_M2TS_IP_Stream *ip_stream_buff; GF_M2TS_IP_Target *ip_targets; - u8 *ip_adress; + u8 *ip_address; GF_M2TS_IP_PLATFORM * ip_platform = ts->ip_platform; assert( ts ); if (!ts->ip_platform) return; @@ -955,7 +955,7 @@ void gf_m2ts_print_mpe_info(GF_M2TS_Demuxer *ts) ip_stream_buff=gf_list_get(ip_platform->ip_streams, i); fprintf(stderr, "PID:%d \n",ip_stream_buff->PID); fprintf(stderr, "Target IP Adress : \n"); - /*Print the target IP adress */ + /*Print the target IP address */ i_targets = gf_list_count(ip_stream_buff->targets); for(j=0; j<i_targets; j++) { @@ -963,8 +963,8 @@ void gf_m2ts_print_mpe_info(GF_M2TS_Demuxer *ts) l=0; - ip_adress = ip_targets->address; - fprintf(stderr, "%d.%d.%d.%d/%d ",ip_adress[0],ip_adress[1],ip_adress[2],ip_adress[3],ip_targets->slash_mask); + ip_address = ip_targets->address; + fprintf(stderr, "%d.%d.%d.%d/%d ",ip_address[0],ip_address[1],ip_address[2],ip_address[3],ip_targets->slash_mask); fprintf(stderr, "RX port :"); while(ip_targets->rx_port[l] != 0) { @@ -1087,8 +1087,8 @@ void socket_simu(GF_M2TS_IP_Packet *ip_packet, GF_M2TS_Demuxer *ts, Bool yield) } else { /* binding of the socket to send data to port 4600 on the local machine - the first adress / port parameters are NULL or 0 because there are not needed for sending UDP datagrams - the second adress is "localhost" and the port is the destination port on localhost + the first address / port parameters are NULL or 0 because there are not needed for sending UDP datagrams + the second address is "localhost" and the port is the destination port on localhost */ e = gf_sk_bind(Sock_Struct->sock, "127.0.0.1", ip_packet->u32_rx_udp_port,/*name*/"127.0.0.1", ip_packet->u32_rx_udp_port, 0); GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Setting up socket for MPE on 127.0.0.1:%d\n", ip_packet->u32_rx_udp_port )); diff --git a/src/media_tools/filestreamer.c b/src/media_tools/filestreamer.c index 877d85d..495f05d 100644 --- a/src/media_tools/filestreamer.c +++ b/src/media_tools/filestreamer.c @@ -25,7 +25,7 @@ #include <gpac/internal/media_dev.h> #include <gpac/constants.h> -#include <gpac/math.h> +#include <gpac/maths.h> #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_STREAMING) @@ -101,7 +101,7 @@ static GF_Err gf_isom_streamer_setup_sdp(GF_ISOMRTPStreamer *streamer, char*sdpf u8 *payload_type; strcpy(filename, sdpfilename ? sdpfilename : "videosession.sdp"); - sdp_out = gf_f64_open(filename, "wt"); + sdp_out = gf_fopen(filename, "wt"); if (!sdp_out) return GF_IO_ERR; if (!out_sdp_buffer) { @@ -188,17 +188,17 @@ static GF_Err gf_isom_streamer_setup_sdp(GF_ISOMRTPStreamer *streamer, char*sdpf } fprintf(sdp_out, "\n"); - fclose(sdp_out); + gf_fclose(sdp_out); if (out_sdp_buffer) { u64 size; - sdp_out = gf_f64_open(filename, "r"); - gf_f64_seek(sdp_out, 0, SEEK_END); - size = gf_f64_tell(sdp_out); - gf_f64_seek(sdp_out, 0, SEEK_SET); + sdp_out = gf_fopen(filename, "r"); + gf_fseek(sdp_out, 0, SEEK_END); + size = gf_ftell(sdp_out); + gf_fseek(sdp_out, 0, SEEK_SET); if (*out_sdp_buffer) gf_free(*out_sdp_buffer); *out_sdp_buffer = gf_malloc(sizeof(char)*(size_t)(size+1)); size = fread(*out_sdp_buffer, 1, (size_t)size, sdp_out); - fclose(sdp_out); + gf_fclose(sdp_out); (*out_sdp_buffer)[size]=0; } @@ -374,12 +374,12 @@ GF_Err gf_isom_streamer_send_next_packet(GF_ISOMRTPStreamer *streamer, s32 send_ remain -= size; au_end = remain ? 0 : 1; - e = gf_rtp_streamer_send_data(to_send->rtp, ptr, size, to_send->au->dataLength, cts, dts, to_send->au->IsRAP, au_start, au_end, to_send->current_au, duration, to_send->sample_desc_index); + e = gf_rtp_streamer_send_data(to_send->rtp, ptr, size, to_send->au->dataLength, cts, dts, (to_send->au->IsRAP==RAP) ? 1 : 0, au_start, au_end, to_send->current_au, duration, to_send->sample_desc_index); ptr += size; au_start = 0; } } else { - e = gf_rtp_streamer_send_data(to_send->rtp, to_send->au->data, to_send->au->dataLength, to_send->au->dataLength, cts, dts, to_send->au->IsRAP, 1, 1, to_send->current_au, duration, to_send->sample_desc_index); + e = gf_rtp_streamer_send_data(to_send->rtp, to_send->au->data, to_send->au->dataLength, to_send->au->dataLength, cts, dts, (to_send->au->IsRAP==RAP) ? 1 : 0, 1, 1, to_send->current_au, duration, to_send->sample_desc_index); } /*delete sample*/ gf_isom_sample_del(&to_send->au); diff --git a/src/media_tools/html5_mse.c b/src/media_tools/html5_mse.c index ddfd55a..0a37e8c 100644 --- a/src/media_tools/html5_mse.c +++ b/src/media_tools/html5_mse.c @@ -24,7 +24,8 @@ */ #include <gpac/setup.h> -#ifdef GPAC_HAS_SPIDERMONKEY +#ifndef GPAC_DISABLE_MSE + #include <gpac/html5_mse.h> #include <gpac/internal/isomedia_dev.h> @@ -826,7 +827,9 @@ void gf_mse_source_buffer_append_arraybuffer(GF_HTML_SourceBuffer *sb, GF_HTML_A buffer->url = (char *)gf_malloc(256); sprintf(buffer->url, "gmem://%d@%p", buffer->length, buffer->data); buffer->reference_count++; +#ifndef GPAC_DISABLE_ISOM buffer->is_init = (gf_isom_probe_file(buffer->url) == 2 ? GF_TRUE : GF_FALSE); +#endif GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Appending segment %s to SourceBuffer %p\n", buffer->url, sb)); gf_list_add(sb->input_buffer, buffer); @@ -1054,4 +1057,4 @@ GF_Err gf_mse_track_buffer_get_next_packet(GF_HTML_Track *track, } -#endif +#endif //GPAC_DISABLE_MSE diff --git a/src/media_tools/img.c b/src/media_tools/img.c index 79e60eb..e0ec978 100644 --- a/src/media_tools/img.c +++ b/src/media_tools/img.c @@ -462,8 +462,8 @@ GF_Err gf_img_png_dec(char *png, u32 png_size, u32 *width, u32 *height, u32 *pix png_set_tRNS_to_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } - *width = png_get_image_width(png_ptr, info_ptr); - *height = png_get_image_height(png_ptr, info_ptr); + *width = (u32) png_get_image_width(png_ptr, info_ptr); + *height = (u32) png_get_image_height(png_ptr, info_ptr); switch (png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_GRAY: @@ -485,7 +485,7 @@ GF_Err gf_img_png_dec(char *png, u32 png_size, u32 *width, u32 *height, u32 *pix } - out_size = png_get_rowbytes(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr); + out_size = (u32) (png_get_rowbytes(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr)); /*new cfg, reset*/ if (*dst_size != out_size) { *dst_size = out_size; @@ -494,9 +494,10 @@ GF_Err gf_img_png_dec(char *png, u32 png_size, u32 *width, u32 *height, u32 *pix return GF_BUFFER_TOO_SMALL; } *dst_size = out_size; + if (!dst) return GF_BAD_PARAM; /*read*/ - stride = png_get_rowbytes(png_ptr, info_ptr); + stride = (u32) png_get_rowbytes(png_ptr, info_ptr); rows = (png_bytepp) gf_malloc(sizeof(png_bytep) * png_get_image_height(png_ptr, info_ptr)); for (i=0; i<png_get_image_height(png_ptr, info_ptr); i++) { rows[i] = (png_bytep)dst + i*stride; @@ -671,14 +672,14 @@ GF_Err gf_img_png_enc_file(char *data, u32 width, u32 height, s32 stride, u32 pi goto exit; } - png = gf_f64_open(dst_file, "wb"); + png = gf_fopen(dst_file, "wb"); if (!png) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[PNG]: Error opening destination file %s\n", dst_file )); goto exit; } gf_fwrite(dst, dst_size, 1, png); - fclose(png); + gf_fclose(png); exit: gf_free(dst); @@ -703,14 +704,14 @@ GF_Err gf_img_png_enc_file(char *data, u32 width, u32 height, s32 stride, u32 pi } #endif /*GPAC_HAS_PNG*/ - +GF_EXPORT GF_Err gf_img_file_dec(char *png_filename, u32 *hint_oti, u32 *width, u32 *height, u32 *pixel_format, char **dst, u32 *dst_size) { u32 fsize, read, oti; FILE *f; char *data; GF_Err e; - f = gf_f64_open(png_filename, "rb"); + f = gf_fopen(png_filename, "rb"); if (!f) return GF_URL_ERROR; oti = 0; @@ -719,13 +720,15 @@ GF_Err gf_img_file_dec(char *png_filename, u32 *hint_oti, u32 *width, u32 *heigh if (!ext) return GF_NOT_SUPPORTED; if (!stricmp(ext, ".png")) oti = GPAC_OTI_IMAGE_PNG; else if (!stricmp(ext, ".jpg") || !stricmp(ext, ".jpeg")) oti = GPAC_OTI_IMAGE_JPEG; + } else if (hint_oti) { + oti = *hint_oti; } - gf_f64_seek(f, 0, SEEK_END); - fsize = (u32)gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + fsize = (u32)gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); data = gf_malloc(fsize); read = (u32) fread(data, sizeof(char), fsize, f); - fclose( f ); + gf_fclose( f ); if (read != fsize) return GF_IO_ERR; e = GF_NOT_SUPPORTED; @@ -735,7 +738,7 @@ GF_Err gf_img_file_dec(char *png_filename, u32 *hint_oti, u32 *width, u32 *heigh e = gf_img_jpeg_dec(data, fsize, width, height, pixel_format, NULL, dst_size, 0); if (*dst_size) { *dst = gf_malloc(*dst_size); - return gf_img_jpeg_dec(data, fsize, width, height, pixel_format, NULL, dst_size, 0); + return gf_img_jpeg_dec(data, fsize, width, height, pixel_format, *dst, dst_size, 0); } #endif } else if (oti == GPAC_OTI_IMAGE_PNG) { diff --git a/src/media_tools/ismacryp.c b/src/media_tools/ismacryp.c index ca2d164..d9a0cff 100644 --- a/src/media_tools/ismacryp.c +++ b/src/media_tools/ismacryp.c @@ -302,7 +302,7 @@ Bool gf_ismacryp_mpeg4ip_get_info(char *kms_uri, char *key, char *salt) strcpy(szPath, getenv("HOME")); strcat(szPath , "/.kms_data"); got_it = 0; - kms = gf_f64_open(szPath, "r"); + kms = gf_fopen(szPath, "r"); while (kms && !feof(kms)) { if (!fgets(szPath, 1024, kms)) break; szPath[strlen(szPath) - 1] = 0; @@ -314,7 +314,7 @@ Bool gf_ismacryp_mpeg4ip_get_info(char *kms_uri, char *key, char *salt) if (i==24) got_it = 1; break; } - if (kms) fclose(kms); + if (kms) gf_fclose(kms); if (got_it) { /*watchout, MPEG4IP stores SALT|KEY, NOT KEY|SALT*/ memcpy(key, catKey+8, sizeof(char)*16); @@ -786,74 +786,39 @@ GF_Err gf_ismacryp_encrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void ( } /*Common Encryption*/ -static void cenc_resync_IV(GF_Crypt *mc, char IV[16], u64 BSO, u8 IV_size, Bool isNewSample) { - char next_IV[17]; - GF_BitStream *bs, *tmp; - u64 prev_block_count; - u32 remain; - /*for log*/ - u8 digest[33]; - char t[3]; +static void increase_counter(char *x, int x_size) { + register int i, y=0; - if (isNewSample) { - prev_block_count = BSO % 16 ? BSO / 16 + 1 : BSO / 16; - remain = 0; - } - else { - prev_block_count = BSO / 16; - remain = (u32) (BSO % 16); - } + for (i=x_size-1; i>=0; i--) { + y = 0; + if ((u8) x[i] == 0xFF) { + x[i] = 0; + y = 1; + } else x[i]++; - tmp = gf_bs_new(IV, 16, GF_BITSTREAM_READ); - bs = gf_bs_new(next_IV, 17, GF_BITSTREAM_WRITE); - gf_bs_write_u8(bs, 0); /*begin of counter*/ - if (isNewSample && (IV_size == 8)) { - u64 IV_value; - IV_value = gf_bs_read_u64(tmp); - if (IV_value == 0xFFFFFFFFFFFFFFFFULL) - IV_value = 0x0; - else - IV_value++; - gf_bs_write_u64(bs, IV_value); - gf_bs_write_u64(bs, 0x0); - } - else { - u64 salt_portion, block_count_portion; - salt_portion = gf_bs_read_u64(tmp); - block_count_portion = gf_bs_read_u64(tmp); - /*reset the block counter to zero without affecting the other 64 bits of the IV*/ - if (prev_block_count > 0xFFFFFFFFFFFFFFFFULL - block_count_portion) - block_count_portion = prev_block_count - (0xFFFFFFFFFFFFFFFFULL - block_count_portion) - 1; - else - block_count_portion += prev_block_count; - gf_bs_write_u64(bs, salt_portion); - gf_bs_write_u64(bs, block_count_portion); - } - - gf_crypt_set_state(mc, next_IV, 17); - /*decrypt remain bytes*/ - if (remain) { - char dummy[20]; - gf_crypt_decrypt(mc, dummy, remain); + if (y==0) break; } - /* IV for subsequence sample*/ - if (isNewSample) { - memset(IV, 0, 16*sizeof(char)); - memmove(IV, next_IV+1, 16*sizeof(char)); - } - else { - u32 j; - digest[0] = 0; - for ( j=0; j<16; j++ ) { - t[2] = 0; - sprintf ( t, "%02X", (u8) next_IV[j+1] ); - strcat ( (char*)digest, t ); - } - GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("[CENC] \t next NALU: %s \n", digest) ); + return; +} + +static void cenc_resync_IV(GF_Crypt *mc, char IV[16], u8 IV_size) { + char next_IV[17]; + int size = 17; + + gf_crypt_get_state(mc, &next_IV, &size); + if (next_IV[0]) { + increase_counter(&next_IV[1], IV_size); + next_IV[0] = 0; } - gf_bs_del(bs); - gf_bs_del(tmp); + + if (IV_size == 8) + memset(&next_IV[9], 0, 8*sizeof(char)); + + gf_crypt_set_state(mc, next_IV, size); + + memset(IV, 0, 16*sizeof(char)); + memcpy(IV, next_IV+1, 16*sizeof(char)); } static GF_Err gf_cenc_encrypt_sample_ctr(GF_Crypt *mc, GF_ISOSample *samp, Bool is_nalu_video, u32 nalu_size_length, char IV[16], u32 IV_size, char **sai, u32 *saiz, u32 bytes_in_nalhr) { @@ -914,11 +879,6 @@ static GF_Err gf_cenc_encrypt_sample_ctr(GF_Crypt *mc, GF_ISOSample *samp, Bool gf_list_add(subsamples, entry); - - - /*update IV for next sub-samples*/ - if (gf_bs_available(pleintext_bs)) - cenc_resync_IV(mc, IV, BSO, IV_size, GF_FALSE); } if (samp->data) { @@ -937,7 +897,7 @@ static GF_Err gf_cenc_encrypt_sample_ctr(GF_Crypt *mc, GF_ISOSample *samp, Bool } gf_list_del(subsamples); gf_bs_get_content(sai_bs, sai, saiz); - cenc_resync_IV(mc, IV, BSO, IV_size, GF_TRUE); + cenc_resync_IV(mc, IV, IV_size); exit: if (buffer) gf_free(buffer); @@ -1263,7 +1223,6 @@ GF_Err gf_cenc_decrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void (*pro { GF_Err e; u32 track, count, i, j, si, max_size, subsample_count, nb_samp_decrypted; - u64 BSO; GF_ISOSample *samp = NULL; GF_Crypt *mc; char IV[17]; @@ -1323,7 +1282,6 @@ GF_Err gf_cenc_decrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void (*pro memset(IV, 0, 17); memset(buffer, 0, max_size); - BSO = 0; samp = gf_isom_get_sample(mp4, track, i+1, &si); if (!samp) @@ -1403,13 +1361,6 @@ GF_Err gf_cenc_decrypt_track(GF_ISOFile *mp4, GF_TrackCryptInfo *tci, void (*pro gf_crypt_decrypt(mc, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); gf_bs_write_data(pleintext_bs, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); - /*update IV for next subsample*/ - if (tci->enc_type == 2) { - BSO += sai->subsamples[subsample_count].bytes_encrypted_data; - if (gf_bs_available(cyphertext_bs)) - cenc_resync_IV(mc, (char *)sai->IV, BSO, tci->IV_size, GF_FALSE); - } - subsample_count++; } } @@ -1813,13 +1764,13 @@ GF_Err gf_decrypt_file(GF_ISOFile *mp4, const char *drm_file) } } else if (!drm_file) { FILE *test = NULL; - if (!stricmp(scheme_URI, "urn:gpac:isma:encryption_scheme")) test = gf_f64_open(KMS_URI, "rt"); + if (!stricmp(scheme_URI, "urn:gpac:isma:encryption_scheme")) test = gf_fopen(KMS_URI, "rt"); if (!test) { GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[CENC/ISMA] TrackID %d does not contain decryption keys - skipping\n", trackID)); continue; } - fclose(test); + gf_fclose(test); if (gf_ismacryp_gpac_get_info(tci.trackID, (char *) KMS_URI, (char *) tci.key, (char *) tci.salt) != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC/ISMA] Couldn't load TrackID %d keys in GPAC DRM file %s\n", tci.trackID, KMS_URI)); continue; diff --git a/src/media_tools/isom_hinter.c b/src/media_tools/isom_hinter.c index 3e35d9f..00dfeb3 100644 --- a/src/media_tools/isom_hinter.c +++ b/src/media_tools/isom_hinter.c @@ -27,7 +27,7 @@ #include <gpac/base_coding.h> #include <gpac/mpeg4_odf.h> #include <gpac/constants.h> -#include <gpac/math.h> +#include <gpac/maths.h> #include <gpac/ietf.h> #ifndef GPAC_DISABLE_ISOM @@ -130,7 +130,7 @@ void MP4T_DumpSDP(GF_ISOFile *file, const char *name) u32 size, i; FILE *f; - f = gf_f64_open(name, "wt"); + f = gf_fopen(name, "wt"); //get the movie SDP gf_isom_sdp_get(file, &sdp, &size); gf_fwrite(sdp, size, 1, f); @@ -142,7 +142,7 @@ void MP4T_DumpSDP(GF_ISOFile *file, const char *name) gf_isom_sdp_track_get(file, i+1, &sdp, &size); gf_fwrite(sdp, size, 1, f); } - fclose(f); + gf_fclose(f); } @@ -505,6 +505,18 @@ GF_RTPHinter *gf_hinter_track_new(GF_ISOFile *file, u32 TrackNum, streamType = GF_STREAM_AUDIO; gf_isom_get_audio_info(file, TrackNum, 1, NULL, &nb_ch, NULL); break; + case GF_ISOM_SUBTYPE_MP3: + { + GF_ISOSample *samp = gf_isom_get_sample(file, TrackNum, 1, NULL); + u32 hdr = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]); + nb_ch = gf_mp3_num_channels(hdr); + gf_isom_sample_del(&samp); + hintType = GF_RTP_PAYT_MPEG12_AUDIO; + /*use official RTP/AVP payload type*/ + OfficialPayloadID = 14; + required_rate = 90000; + } + break; default: /*ERROR*/ hintType = 0; @@ -695,9 +707,9 @@ GF_Err gf_hinter_track_process(GF_RTPHinter *tkHint) /*keep same AU indicator if sync shadow - TODO FIXME: this assumes shadows are placed interleaved with the track content which is the case for GPAC scene carousel generation, but may not always be true*/ - if (samp->IsRAP==2) { + if (samp->IsRAP==RAP_REDUNDANT) { tkHint->rtp_p->sl_header.AU_sequenceNumber -= 1; - samp->IsRAP = 1; + samp->IsRAP = RAP; } ts = (u64) (ft * (s64) (samp->DTS+samp->CTS_Offset)); diff --git a/src/media_tools/isom_tools.c b/src/media_tools/isom_tools.c index 56c4f29..415f36f 100644 --- a/src/media_tools/isom_tools.c +++ b/src/media_tools/isom_tools.c @@ -151,10 +151,10 @@ GF_Err gf_media_get_file_hash(const char *file, u8 hash[20]) Bool is_isom = gf_isom_probe_file(file); #endif - in = gf_f64_open(file, "rb"); - gf_f64_seek(in, 0, SEEK_END); - size = gf_f64_tell(in); - gf_f64_seek(in, 0, SEEK_SET); + in = gf_fopen(file, "rb"); + gf_fseek(in, 0, SEEK_END); + size = gf_ftell(in); + gf_fseek(in, 0, SEEK_SET); ctx = gf_sha1_starts(); tot = 0; @@ -199,7 +199,7 @@ GF_Err gf_media_get_file_hash(const char *file, u8 hash[20]) #ifndef GPAC_DISABLE_ISOM if (bs) gf_bs_del(bs); #endif - fclose(in); + gf_fclose(in); return GF_OK; #endif } @@ -214,8 +214,6 @@ static const u32 ISMA_AUDIO_OD_ID = 10; static const u32 ISMA_VIDEO_ES_ID = 201; static const u32 ISMA_AUDIO_ES_ID = 101; -static const char ISMA_BIFS_CONFIG[] = {0x00, 0x00, 0x60 }; - /*ISMA audio*/ static const u8 ISMA_BIFS_AUDIO[] = { @@ -453,7 +451,7 @@ GF_Err gf_media_make_isma(GF_ISOFile *mp4file, Bool keepESIDs, Bool keepImage, B gf_odf_codec_del(codec); samp->CTS_Offset = 0; samp->DTS = 0; - samp->IsRAP = 1; + samp->IsRAP = RAP; /*create the OD track*/ odT = gf_isom_new_track(mp4file, odID, GF_ISOM_MEDIA_OD, gf_isom_get_timescale(mp4file)); @@ -477,7 +475,7 @@ GF_Err gf_media_make_isma(GF_ISOFile *mp4file, Bool keepESIDs, Bool keepImage, B if (!bifsT) return gf_isom_last_error(mp4file); _esd = gf_odf_desc_esd_new(SLPredef_MP4); - _esd->decoderConfig->bufferSizeDB = sizeof(ISMA_BIFS_CONFIG); + _esd->decoderConfig->bufferSizeDB = 20; _esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS_V2; _esd->decoderConfig->streamType = GF_STREAM_SCENE; _esd->ESID = bifsID; @@ -530,7 +528,7 @@ GF_Err gf_media_make_isma(GF_ISOFile *mp4file, Bool keepESIDs, Bool keepImage, B break; } - samp->IsRAP = 1; + samp->IsRAP = RAP; gf_isom_add_sample(mp4file, bifsT, 1, samp); samp->data = NULL; @@ -880,6 +878,18 @@ GF_ESD *gf_media_map_esd(GF_ISOFile *mp4, u32 track) return esd; } + if (subtype == GF_ISOM_SUBTYPE_MP3) { + esd = gf_odf_desc_esd_new(0); + esd->slConfig->timestampResolution = gf_isom_get_media_timescale(mp4, track); + esd->ESID = gf_isom_get_track_id(mp4, track); + esd->OCRESID = esd->ESID; + esd->decoderConfig->streamType = GF_STREAM_AUDIO; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1; + gf_odf_desc_del((GF_Descriptor*)esd->decoderConfig->decoderSpecificInfo); + esd->decoderConfig->decoderSpecificInfo = NULL; + return esd; + } + if ( (subtype == GF_4CC('j','p','e','g')) || (subtype == GF_4CC('p','n','g',' ')) ) { esd = gf_odf_desc_esd_new(0); @@ -1071,7 +1081,7 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll) char *buffer; s32 *sps_track, *sps, *pps; u64 offset; - Bool is_splited; + Bool is_splitted; Bool *first_sample_track, *is_subseq_pps; u64 *first_DTS_track; s8 sample_offset; @@ -1103,12 +1113,12 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll) } num_pps = gf_list_count(svccfg->pictureParameterSets); if ((gf_isom_get_avc_svc_type(file, track, 1) == GF_ISOM_AVCTYPE_SVC_ONLY) && !gf_isom_has_svc_explicit(file, track)) - is_splited = 1; + is_splitted = 1; else - is_splited = 0; + is_splitted = 0; num_subseq = gf_isom_has_svc_explicit(file, track) ? num_sps - 1 : num_sps; - if (is_splited) + if (is_splitted) { /*this track has only one SVC ...*/ if (num_sps == 1) @@ -1171,7 +1181,7 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll) } pps[j] = pps_id; } - if (!is_splited) + if (!is_splitted) ref_trackID = gf_isom_get_track_id(file, track); else { @@ -1556,7 +1566,7 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll) } /*if this is a merged file*/ - if (!is_splited) + if (!is_splitted) { /*a normal stream: delete SVC config*/ if (!gf_isom_has_svc_explicit(file, track)) @@ -1606,7 +1616,7 @@ GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll) goto exit; } } - /*if this is as splited file: delete this track*/ + /*if this is as splitted file: delete this track*/ else { gf_isom_remove_track(file, track); @@ -1995,7 +2005,7 @@ static GF_Err gf_isom_adjust_visual_info(GF_ISOFile *file, u32 track) { } if (shvccfg) gf_odf_hevc_cfg_del(shvccfg); - + return gf_isom_set_visual_info(file, track, 1, width, height); } @@ -2107,9 +2117,12 @@ GF_Err gf_media_split_shvc(GF_ISOFile *file, u32 track, Bool splitAll, Bool use_ GF_BitStream *bs; u32 di; GF_ISOSample *sample; + Bool is_irap, has_roll; + s32 roll_distance; u8 cur_max_layer_id = 0; sample = gf_isom_get_sample(file, track, i+1, &di); + gf_isom_get_sample_rap_roll_info(file, track, i+1, &is_irap, &has_roll, &roll_distance); bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ); while (gf_bs_available(bs)) { @@ -2220,7 +2233,7 @@ GF_Err gf_media_split_shvc(GF_ISOFile *file, u32 track, Bool splitAll, Bool use_ gf_bs_write_int(xbs, trefidx, 8); // no sample offset gf_bs_write_int(xbs, 0, 8); - // data offset: we start from begining of the sample data, not the extractor + // data offset: we start from beginning of the sample data, not the extractor gf_bs_write_int(xbs, sti[k].data_offset, 8*shvccfg->nal_unit_size); gf_bs_write_int(xbs, sti[k].data_size, 8*shvccfg->nal_unit_size); } @@ -2264,6 +2277,15 @@ GF_Err gf_media_split_shvc(GF_ISOFile *file, u32 track, Bool splitAll, Bool use_ gf_bs_del(sti[j].bs); sti[j].bs = NULL; + if (sample->IsRAP>SAP_TYPE_1) { + if (is_irap) { + gf_isom_set_sample_rap_group(file, sti[j].track_num, i+1, 0); + } + else if (has_roll) { + gf_isom_set_sample_roll_group(file, sti[j].track_num, i+1, (s16) roll_distance); + } + } + if (sample->data) { gf_free(sample->data); sample->data = NULL; @@ -2328,21 +2350,20 @@ static u32 hevc_get_tile_id(HEVCState *hevc, u32 *tile_x, u32 *tile_y, u32 *tile { HEVCSliceInfo *si = &hevc->s_info; u32 i, tbX, tbY, PicWidthInCtbsY, PicHeightInCtbsY, tileX, tileY, oX, oY, val; - PicWidthInCtbsY = si->sps->width / si->sps->max_CU_width; - PicHeightInCtbsY = si->sps->height / si->sps->max_CU_width; + + PicWidthInCtbsY = si->sps->width / si->sps->max_CU_width; + if (PicWidthInCtbsY * si->sps->max_CU_width < si->sps->width) PicWidthInCtbsY++; + PicHeightInCtbsY = si->sps->height / si->sps->max_CU_width; + if (PicHeightInCtbsY * si->sps->max_CU_width < si->sps->height) PicHeightInCtbsY++; tbX = si->slice_segment_address % PicWidthInCtbsY; tbY = si->slice_segment_address / PicWidthInCtbsY; tileX = tileY = 0; oX = oY = 0; - for (i=0; i<si->pps->num_tile_columns; i++) { + for (i=0; i < si->pps->num_tile_columns; i++) { if (si->pps->uniform_spacing_flag) { - if (i<si->pps->num_tile_columns-1) { - val = (i+1)*PicWidthInCtbsY / si->pps->num_tile_columns - (i)*PicWidthInCtbsY / si->pps->num_tile_columns; - } else { - val = (i)*PicWidthInCtbsY / si->pps->num_tile_columns - (i-1)*PicWidthInCtbsY / si->pps->num_tile_columns; - } + val = (i+1)*PicWidthInCtbsY / si->pps->num_tile_columns - (i)*PicWidthInCtbsY / si->pps->num_tile_columns; } else { if (i<si->pps->num_tile_columns-1) { val = si->pps->column_width[i]; @@ -2359,11 +2380,7 @@ static u32 hevc_get_tile_id(HEVCState *hevc, u32 *tile_x, u32 *tile_y, u32 *tile } for (i=0; i<si->pps->num_tile_rows; i++) { if (si->pps->uniform_spacing_flag) { - if (i<si->pps->num_tile_rows-1) { - val = (i+1)*PicHeightInCtbsY / si->pps->num_tile_rows - (i)*PicHeightInCtbsY / si->pps->num_tile_rows; - } else { - val = (i)*PicHeightInCtbsY / si->pps->num_tile_rows - (i-1)*PicHeightInCtbsY / si->pps->num_tile_rows; - } + val = (i+1)*PicHeightInCtbsY / si->pps->num_tile_rows - (i)*PicHeightInCtbsY / si->pps->num_tile_rows; } else { if (i<si->pps->num_tile_rows-1) { val = si->pps->row_height[i]; @@ -2545,8 +2562,13 @@ GF_Err gf_media_split_hevc_tiles(GF_ISOFile *file) gf_bs_write_int(bs, 0, 8); // data offset: we start from last NAL written in this sample in this tile track gf_bs_write_int(bs, tiles[cur_tile].data_offset, 8*nalu_size_length); - gf_bs_write_int(bs, nalu_size + nalu_size_length, 8*nalu_size_length); - tiles[cur_tile].data_offset += nalu_size + nalu_size_length; + + //we always write 0 to force complete NAL referencing. This avoids size issues when mixing tile tracks + //at different rates :) + //gf_bs_write_int(bs, nalu_size + nalu_size_length, 8*nalu_size_length); + gf_bs_write_int(bs, 0, 8*nalu_size_length); + + tiles[cur_tile].data_offset += nalu_size + nalu_size_length; break; default: @@ -2695,9 +2717,17 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, Double e = gf_isom_clone_track(input, i+1, output, 0, &TrackNum); if (e) goto err_exit; - //if few samples don't fragment track + for (j = 0; j < gf_isom_get_track_kind_count(input, i+1); j++) { + char *scheme, *value; + gf_isom_get_track_kind(input, i+1, j, &scheme, &value); + gf_isom_add_track_kind(output, TrackNum, scheme, value); + } + count = gf_isom_get_sample_count(input, i+1); - if (count<=2) { + //we always fragment each track regardless of the sample count +#if 0 + //if few samples don't fragment track + if (count<=1) { for (j=0; j<count; j++) { sample = gf_isom_get_sample(input, i+1, j+1, &descIndex); e = gf_isom_add_sample(output, TrackNum, 1, sample); @@ -2706,7 +2736,9 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, Double } } //otherwise setup fragmented - else { + else +#endif + { gf_isom_get_fragment_defaults(input, i+1, &defaultDuration, &defaultSize, &defaultDescriptionIndex, &defaultRandomAccess, &defaultPadding, &defaultDegradationPriority); //otherwise setup fragmentation @@ -2718,7 +2750,7 @@ GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, Double GF_SAFEALLOC(tf, GF_TrackFragmenter); tf->TrackID = gf_isom_get_track_id(output, TrackNum); - tf->SampleCount = gf_isom_get_sample_count(input, i+1); + tf->SampleCount = count; tf->OriginalTrack = i+1; tf->TimeScale = gf_isom_get_media_timescale(input, i+1); tf->MediaType = gf_isom_get_media_type(input, i+1); diff --git a/src/media_tools/m2ts_mux.c b/src/media_tools/m2ts_mux.c index 73ac537..1809b58 100644 --- a/src/media_tools/m2ts_mux.c +++ b/src/media_tools/m2ts_mux.c @@ -468,7 +468,7 @@ static u32 gf_m2ts_add_adaptation(GF_M2TS_Mux_Program *prog, GF_BitStream *bs, u gf_bs_write_int(bs, 0, 1); // piecewise_rate_flag gf_bs_write_int(bs, 0, 1); // seamless_splice_flag gf_bs_write_int(bs, 0, 1); // af_descriptor_not_present_flag - gf_bs_write_int(bs, 1, 4); // reserved + gf_bs_write_int(bs, 0xF, 4); // reserved gf_bs_write_data(bs, af_descriptors, af_descriptors_size); } @@ -936,7 +936,7 @@ static void id3_tag_create(char **input, u32 *len) gf_bs_del(bs); } -u32 gf_m2ts_stream_process_stream(GF_M2TS_Mux *muxer, GF_M2TS_Mux_Stream *stream) +static u32 gf_m2ts_stream_process_pes(GF_M2TS_Mux *muxer, GF_M2TS_Mux_Stream *stream) { u64 time_inc; Bool ret = 0; @@ -1211,9 +1211,14 @@ u32 gf_m2ts_stream_process_stream(GF_M2TS_Mux *muxer, GF_M2TS_Mux_Stream *stream /*compute next interesting time in TS unit: this will be DTS of next packet*/ stream->time = stream->program->ts_time_at_pcr_init; time_inc = stream->curr_pck.dts - stream->program->pcr_offset; + + //this is disabled nd controled through stream->program->pcr_offset #if 0 - if (stream->bit_rate) { - u64 send_time = ((u64)stream->curr_pck.data_len)*720000/*8*90000*/ / stream->bit_rate; + //CBR mux: how long does it take to send our data ? + if (stream->program->mux->fixed_rate) { + u32 nb_pck = 1 + (stream->curr_pck.data_len / 184); + u64 send_time = nb_pck * 135360000 /* 188 * 8 * 90000*/ / stream->program->mux->bit_rate; + //send_time += stream->max_send_delay; if (send_time<time_inc) { time_inc -= send_time; } else { @@ -1221,6 +1226,7 @@ u32 gf_m2ts_stream_process_stream(GF_M2TS_Mux *muxer, GF_M2TS_Mux_Stream *stream } } #endif + gf_m2ts_time_inc(&stream->time, time_inc, 90000); /*PCR injection is now decided when building TS packet*/ @@ -1276,6 +1282,8 @@ void gf_m2ts_stream_update_data_following(GF_M2TS_Mux_Stream *stream) { Bool ignore_next=0; stream->next_payload_size = 0; + stream->next_next_payload_size = 0; + stream->next_pck_flags = 0; stream->copy_from_next_packets = 0; @@ -1309,6 +1317,12 @@ void gf_m2ts_stream_update_data_following(GF_M2TS_Mux_Stream *stream) stream->next_pck_cts = stream->pck_first->cts; stream->next_pck_dts = stream->pck_first->dts; stream->next_pck_flags = stream->pck_first->flags; + + if (!stream->pck_first->next && stream->ifce->input_ctrl) stream->ifce->input_ctrl(stream->ifce, GF_ESI_INPUT_DATA_FLUSH, NULL); + if (stream->pck_first->next) { + stream->next_next_payload_size = stream->pck_first->next->data_len; + } + } } /*consider we don't have the next AU if: @@ -1331,6 +1345,8 @@ void gf_m2ts_stream_update_data_following(GF_M2TS_Mux_Stream *stream) if (stream->next_payload_size) { stream->next_payload_size += stream->reframe_overhead; + if (stream->next_next_payload_size) + stream->next_next_payload_size += stream->reframe_overhead; gf_m2ts_remap_timestamps_for_pes(stream, stream->next_pck_flags, &stream->next_pck_dts, &stream->next_pck_cts, NULL); @@ -1372,8 +1388,11 @@ Bool gf_m2ts_stream_compute_pes_length(GF_M2TS_Mux_Stream *stream, u32 payload_l while (ts_bytes < pck_size + stream->next_payload_size) { ts_bytes += 184; } - /*don't end next AU in next PES if we don't want to start 2 AUs in one PES*/ - if (stream->prevent_two_au_start_in_pes && (ts_bytes>pck_size + stream->next_payload_size)) { + /*don't end next AU in next PES if we don't want to start 2 AUs in one PES + if we don't have the N+2 AU size, don't try to pack it*/ + if ((stream->prevent_two_au_start_in_pes && (ts_bytes>pck_size + stream->next_payload_size)) + || !stream->next_next_payload_size + ) { if (ts_bytes>184) ts_bytes -= 184; else @@ -1391,7 +1410,7 @@ Bool gf_m2ts_stream_compute_pes_length(GF_M2TS_Mux_Stream *stream, u32 payload_l } if (stream->min_bytes_copy_from_next && stream->copy_from_next_packets) { - /*if we don't have enough space in the PES to store begining of new AU, don't copy it and ask + /*if we don't have enough space in the PES to store beginning of new AU, don't copy it and ask to recompute header (we might no longer have DTS/CTS signaled)*/ if (stream->copy_from_next_packets < stream->min_bytes_copy_from_next) { stream->copy_from_next_packets = 0; @@ -1466,7 +1485,7 @@ u32 gf_m2ts_stream_add_pes_header(GF_BitStream *bs, GF_M2TS_Mux_Stream *stream) dts = stream->next_pck_dts; cts = stream->next_pck_cts; } - /*we already sent the begining of the AU*/ + /*we already sent the beginning of the AU*/ else if (stream->pck_offset) { use_pts = use_dts = 0; dts = cts = 0; @@ -1540,6 +1559,7 @@ void gf_m2ts_mux_pes_get_next_packet(GF_M2TS_Mux_Stream *stream, char *packet) hdr_len = gf_m2ts_stream_get_pes_header_length(stream); + adaptation_field_control = GF_M2TS_ADAPTATION_NONE; /*we may need two pass in case we first compute hdr len and TS payload size by considering we concatenate next au start in this PES but finally couldn't do it when computing PES len and AU alignment constraint of the stream*/ @@ -1554,7 +1574,6 @@ void gf_m2ts_mux_pes_get_next_packet(GF_M2TS_Mux_Stream *stream, char *packet) adaptation_field_control = GF_M2TS_ADAPTATION_NONE; payload_length = 184 - hdr_len; payload_to_copy = padding_length = 0; -// is_rap = (hdr_len && (stream->curr_pck.flags & GF_ESI_DATA_AU_RAP)) ? GF_TRUE : GF_FALSE; needs_pcr = 0; if (stream == stream->program->pcr) { @@ -1731,23 +1750,23 @@ void gf_m2ts_mux_pes_get_next_packet(GF_M2TS_Mux_Stream *stream, char *packet) if (stream->pck_offset == stream->curr_pck.data_len) { u64 pcr = gf_m2ts_get_pcr(stream)/300; if (stream->program->mux->real_time && !stream->program->mux->fixed_rate && gf_m2ts_time_less(&stream->time, &stream->program->mux->time) ) { - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Done sending PES TOO LATE: PID %d - DTS "LLD" - PCR "LLD" - stream time %d:%09d - mux time %d:%09d - current mux rate %d\n", + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Sent PES TOO LATE: PID %d - DTS "LLD" - PCR "LLD" - stream time %d:%09d - mux time %d:%09d - current mux rate %d\n", stream->pid, stream->curr_pck.dts, pcr, stream->time.sec, stream->time.nanosec, stream->program->mux->time.sec, stream->program->mux->time.nanosec, stream->program->mux->bit_rate )); } else if (stream->curr_pck.dts < pcr) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Done sending PES %d us TOO LATE: PID %d - DTS "LLD" - size %d - PCR "LLD" - - stream time %d:%09d - mux time %d:%09d \n", - pcr - stream->curr_pck.dts, stream->pid, stream->curr_pck.dts, stream->curr_pck.data_len, pcr, + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Sent PES %d us TOO LATE: PID %d - DTS "LLD" - size %d\n\tPCR "LLD" - stream time %d:%09d - mux time %d:%09d \n", + (pcr - stream->curr_pck.dts)*100/9, stream->pid, stream->curr_pck.dts, stream->curr_pck.data_len, pcr, stream->time.sec, stream->time.nanosec, stream->program->mux->time.sec, stream->program->mux->time.nanosec )); } else if (stream->curr_pck.cts < pcr) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Done sending PES %d us TOO LATE: PID %d - DTS "LLD" - size %d - PCR "LLD" - - stream time %d:%09d - mux time %d:%09d \n", + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Sent PES %d us TOO LATE: PID %d - DTS "LLD" - size %d\n\tPCR "LLD" - stream time %d:%09d - mux time %d:%09d \n", pcr - stream->curr_pck.dts, stream->pid, stream->curr_pck.dts, stream->curr_pck.data_len, pcr, stream->time.sec, stream->time.nanosec, stream->program->mux->time.sec, stream->program->mux->time.nanosec )); } else { - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Done sending PES: PID %d - DTS "LLD" - PCR "LLD" - stream time %d:%09d - mux time %d:%09d \n", + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Sent PES: PID %d - DTS "LLD" - PCR "LLD" - stream time %d:%09d - mux time %d:%09d \n", stream->pid, stream->curr_pck.dts, pcr, stream->time.sec, stream->time.nanosec, stream->program->mux->time.sec, stream->program->mux->time.nanosec )); @@ -1831,7 +1850,7 @@ GF_M2TS_Mux_Stream *gf_m2ts_stream_new(u32 pid) { GF_SAFEALLOC(stream, GF_M2TS_Mux_Stream); stream->pid = pid; - stream->process = gf_m2ts_stream_process_stream; + stream->process = gf_m2ts_stream_process_pes; return stream; } @@ -1906,17 +1925,13 @@ static void gf_m2ts_stream_set_default_slconfig(GF_M2TS_Mux_Stream *stream) static u32 gf_m2ts_stream_get_pid(GF_M2TS_Mux_Program *program, u32 stream_id) { - GF_M2TS_Mux_Stream *st; - - st = program->streams; - + GF_M2TS_Mux_Stream *st = program->streams; while (st) { if (st->ifce->stream_id == stream_id) return st->pid; st = st->next; } - return 0; } @@ -2019,7 +2034,7 @@ GF_M2TS_Mux_Stream *gf_m2ts_program_stream_add(GF_M2TS_Mux_Program *program, str stream->loop_descriptors = gf_list_new(); if (program->streams) { - /*if PCR keep stream at the begining*/ + /*if PCR keep stream at the beginning*/ if (is_pcr) { stream->next = program->streams; program->streams = stream; @@ -2653,7 +2668,7 @@ send_pck: ret = muxer->dst_pck; *status = GF_M2TS_STATE_DATA; - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Send %s from PID %d at %d:%09d - mux time %d:%09d\n", stream_to_process->tables ? "table" : "PES", stream_to_process->pid, time.sec, time.nanosec, muxer->time.sec, muxer->time.nanosec)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG2-TS Muxer] Sending %s from PID %d at %d:%09d - mux time %d:%09d\n", stream_to_process->tables ? "table" : "PES", stream_to_process->pid, time.sec, time.nanosec, muxer->time.sec, muxer->time.nanosec)); if (nb_streams && (nb_streams==nb_streams_done)) *status = GF_M2TS_STATE_EOS; diff --git a/src/media_tools/m3u8.c b/src/media_tools/m3u8.c index 14a4119..db2fcce 100644 --- a/src/media_tools/m3u8.c +++ b/src/media_tools/m3u8.c @@ -1,49 +1,44 @@ /** -* GPAC - Multimedia Framework C SDK -* -* Authors: Pierre Souchay, Jean Le Feuvre -* Copyright (c) Telecom ParisTech 2010-2012 -* All rights reserved -* -* This file is part of GPAC -* -* 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. -* -*/ + * GPAC - Multimedia Framework C SDK + * + * Authors: Pierre Souchay, Jean Le Feuvre, Romain Bouqueau + * Copyright (c) Telecom ParisTech 2010-2012, Romain Bouqueau + * All rights reserved + * + * This file is part of GPAC + * + * 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. + * + */ #define _GNU_SOURCE #include <gpac/internal/m3u8.h> -#include <string.h> -#include <stdio.h> #include <gpac/network.h> -/*#define MYLOG(xx) GF_LOG(GF_LOG_INFO, GF_LOG_DASH, xx )*/ -#define MYLOG(xx) +/********** playlist_element **********/ -#if defined(WIN32) || defined(_WIN32_WCE) -#define bzero(a, b) memset(a, 0x0, b) -#endif +GF_Err playlist_element_del(PlaylistElement * e); -GF_Err cleanup_list_of_elements(GF_List * list) { +static GF_Err cleanup_list_of_elements(GF_List *list) { GF_Err result = GF_OK; if (list == NULL) return result; while (gf_list_count(list)) { - PlaylistElement * pl = (PlaylistElement *) gf_list_get(list, 0); + PlaylistElement *pl = (PlaylistElement *) gf_list_get(list, 0); if (pl) result |= playlist_element_del(pl); gf_list_rem(list, 0); @@ -52,6 +47,9 @@ GF_Err cleanup_list_of_elements(GF_List * list) { return result; } +/** + * Deletes an Playlist element + */ GF_Err playlist_element_del(PlaylistElement * e) { GF_Err result = GF_OK; if (e == NULL) @@ -64,16 +62,33 @@ GF_Err playlist_element_del(PlaylistElement * e) { gf_free(e->codecs); e->codecs = NULL; } - assert( e->url); + if (e->language) { + gf_free(e->language); + e->language = NULL; + } + if (e->audio_group) { + gf_free(e->audio_group); + e->audio_group = NULL; + } + if (e->video_group) { + gf_free(e->video_group); + e->video_group = NULL; + } + if (e->key_uri) { + gf_free(e->key_uri); + e->key_uri = NULL; + } + memset(e->key_iv, 0, sizeof(bin128) ); + assert(e->url); gf_free(e->url); e->url = NULL; - switch (e->elementType) { + switch (e->element_type) { case TYPE_UNKNOWN: - case TYPE_STREAM: + case TYPE_MEDIA: break; case TYPE_PLAYLIST: - assert( e->element.playlist.elements); + assert(e->element.playlist.elements); result |= cleanup_list_of_elements(e->element.playlist.elements); e->element.playlist.elements = NULL; default: @@ -83,343 +98,301 @@ GF_Err playlist_element_del(PlaylistElement * e) { return result; } -Program * program_new(int programId) { - Program * program = (Program*)gf_malloc(sizeof(Program)); - if (program == NULL) { - return NULL; - } - program->programId = programId; - program->bitrates = gf_list_new(); - if (program->bitrates == NULL) { - gf_free(program); - return NULL; - } - return program; -} - -GF_Err program_del(Program * program) { - GF_Err e = GF_OK; - if (program == NULL) - return e; - if ( program->bitrates) { - while (gf_list_count(program->bitrates)) { - GF_List * l = gf_list_get(program->bitrates, 0); - cleanup_list_of_elements(l); - gf_list_rem(program->bitrates, 0); - } - gf_list_del(program->bitrates); - } - program->bitrates = NULL; - gf_free(program); - return e; -} - -/* -GF_Err playlist_del(Playlist * pl){ -GF_Err result = GF_OK; -if (pl == NULL) -return result; -if (pl->elements){ -result|= cleanup_list_of_elements(pl->elements); -pl->elements = NULL; -} -gf_free(pl); -return result; -}*/ - -PlaylistElement * playlist_element_new(PlaylistElementType elementType, const char * url, const char * title, const char *codecs, int durationInfo, u64 byteRangeStart, u64 byteRangeEnd) { - PlaylistElement * e = gf_malloc(sizeof(PlaylistElement)); - bzero(e, sizeof(PlaylistElement)); - assert( url ); +/** + * Creates an Playlist element. + * This element can be either a playlist of a stream according to first parameter. + * \return NULL if element could not be created. Elements will be deleted recursively. + */ +static PlaylistElement* playlist_element_new(PlaylistElementType element_type, const char *url, const char *title, const char *codecs, const char *language, double duration_info, u64 byte_range_start, u64 byte_range_end, PlaylistElementDRMMethod drm_method, const char *key_uri, const unsigned char *iv) { + PlaylistElement *e = gf_malloc(sizeof(PlaylistElement)); + memset(e, 0, sizeof(PlaylistElement)); if (e == NULL) return NULL; - e->durationInfo = durationInfo; - e->byteRangeStart = byteRangeStart; - e->byteRangeEnd = byteRangeEnd; + e->duration_info = duration_info; + e->byte_range_start = byte_range_start; + e->byte_range_end = byte_range_end; e->title = (title ? gf_strdup(title) : NULL); e->codecs = (codecs ? gf_strdup(codecs) : NULL); - assert( url); + e->language = (language ? gf_strdup(language) : NULL); + e->drm_method = drm_method; + e->key_uri = (key_uri ? gf_strdup(key_uri) : NULL); + memcpy(e->key_iv, iv, sizeof(bin128)); + + assert(url); e->url = gf_strdup(url); e->bandwidth = 0; - e->elementType = elementType; - if (elementType == TYPE_PLAYLIST) { - e->element.playlist.is_ended = 0; - e->element.playlist.target_duration = durationInfo; - e->element.playlist.currentMediaSequence = 0; - e->element.playlist.mediaSequenceMin = 0; - e->element.playlist.mediaSequenceMax = 0; + e->element_type = element_type; + if (element_type == TYPE_PLAYLIST) { + e->element.playlist.is_ended = GF_FALSE; + e->element.playlist.target_duration = duration_info; + e->element.playlist.current_media_seq = 0; + e->element.playlist.media_seq_min = 0; + e->element.playlist.media_seq_max = 0; e->element.playlist.elements = gf_list_new(); if (NULL == (e->element.playlist.elements)) { if (e->title) gf_free(e->title); if (e->codecs) gf_free(e->codecs); + if (e->language) + gf_free(e->language); + if (e->audio_group) + gf_free(e->audio_group); + if (e->video_group) + gf_free(e->video_group); if (e->url) gf_free(e->url); + if (e->key_uri) + gf_free(e->key_uri); e->url = NULL; e->title = NULL; e->codecs = NULL; + e->language = NULL; + e->audio_group = NULL; + e->video_group = NULL; + e->key_uri = NULL; + memset(e->key_iv, 0, sizeof(bin128)); gf_free(e); return NULL; } } else { - /* Nothing to do, stream is an empty structure */ + /* Nothing to do, media is an empty structure */ } assert(e->bandwidth == 0); assert(e->url); return e; } -/* -Playlist * playlist_new(){ -Playlist * pl = gf_malloc(sizeof(Playlist)); -if (pl == NULL) -return NULL; -pl->currentMediaSequence = 1; -pl->target_duration = 0; -pl->mediaSequenceMin = 0; -pl->mediaSequenceMax = 0; -pl->is_ended = 0; -pl->elements = gf_list_new(); -if (pl->elements == NULL){ -gf_free(pl); -return NULL; -} -return pl; -} -*/ -VariantPlaylist * variant_playlist_new () -{ - VariantPlaylist * pl = (VariantPlaylist*)gf_malloc( sizeof(VariantPlaylist) ); - if (pl == NULL) - return NULL; - pl->programs = gf_list_new(); - if (! pl->programs) { - gf_free( pl ); + +/********** stream **********/ + +/** + * Creates a new stream properly initialized + */ +static Stream* stream_new(int stream_id) { + Stream *program = (Stream *) gf_malloc(sizeof(Stream)); + if (program == NULL) { return NULL; } - pl->currentProgram = -1; - pl->playlistNeedsRefresh = 1; - return pl; -} - -GF_Err variant_playlist_del (VariantPlaylist * playlist) { - if (playlist == NULL) - return GF_OK; - assert( playlist->programs); - while (gf_list_count(playlist->programs)) { - Program * p = gf_list_get(playlist->programs, 0); - assert(p); - while (gf_list_count( p->bitrates )) { - PlaylistElement * pl = gf_list_get(p->bitrates, 0); - assert( pl ); - playlist_element_del(pl); - gf_list_rem(p->bitrates, 0); - } - gf_list_del(p->bitrates); - p->bitrates = NULL; - program_del(p); - gf_list_rem(playlist->programs, 0); + program->stream_id = stream_id; + program->variants = gf_list_new(); + if (program->variants == NULL) { + gf_free(program); + return NULL; } - gf_list_del(playlist->programs); - playlist->programs = NULL; - gf_free(playlist); - return GF_OK; -} - -GF_Err playlist_element_dump(const PlaylistElement * e, int indent) { - int i; - GF_Err r = GF_OK; - for (i = 0 ; i < indent; i++) - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, (" ") ); - if (e == NULL) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] NULL PlaylistElement\n")); - return r; - } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] PlayListElement[%p, title=%s, codecs=%s, duration=%d, bandwidth=%d, url=%s, type=%s]\n", - (void*)e, - e->title, - e->codecs, - e->durationInfo, - e->bandwidth, - e->url, - e->elementType == TYPE_STREAM ? "stream" : "playlist")); - if (TYPE_PLAYLIST == e->elementType) { - int sz; - assert( e->element.playlist.elements); - sz = gf_list_count(e->element.playlist.elements); - indent+=2; - for (i = 0 ; i < sz ; i++) { - PlaylistElement * el = gf_list_get(e->element.playlist.elements, i); - assert( el); - r|= playlist_element_dump( el, indent); - } - } - return r; + return program; } -GF_Err variant_playlist_dump(const VariantPlaylist * pl) { - int i, count; +/** + * Deletes the specified stream + */ +static GF_Err stream_del(Stream *stream) { GF_Err e = GF_OK; - if (pl == NULL) { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] VariantPlaylist = NULL\n")); + if (stream == NULL) return e; + if (stream->variants) { + while (gf_list_count(stream->variants)) { + GF_List *l = gf_list_get(stream->variants, 0); + cleanup_list_of_elements(l); + gf_list_rem(stream->variants, 0); + } + gf_list_del(stream->variants); } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] VariantPlaylist = {\n")); - assert( pl->programs); - count = gf_list_count( pl->programs); - for (i = 0 ; i < count ; i++) { - int j, countj; - Program * p = gf_list_get(pl->programs, i); - assert( p ); - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] program[programId=%d]{\n", p->programId)); - assert( p->bitrates ); - countj = gf_list_count(p->bitrates); - for (j = 0; j < countj; j++) { - PlaylistElement * el = gf_list_get(p->bitrates, j); - assert(el); - e |= playlist_element_dump( el, 4); - } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] }\n")); - } - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8]}\n")); + stream->variants = NULL; + gf_free(stream); return e; } -Program * variant_playlist_find_matching_program(const VariantPlaylist * pl, const u32 programId) { - u32 count, i; - assert( pl); - assert( pl->programs); - assert(programId >= 0); - count = gf_list_count(pl->programs); - for (i = 0 ; i < count ; i++) { - Program * cur = gf_list_get(pl->programs, i); - assert( cur ); - if (programId == cur->programId) { - /* We found the program */ - return cur; - } - } - return NULL; -} -Program * variant_playlist_get_current_program(const VariantPlaylist * pl) { - assert( pl ); - return variant_playlist_find_matching_program(pl, pl->currentProgram); -} +/********** accumulated_attributes **********/ +typedef enum _e_MediaType { + MEDIA_TYPE_UNKNOWN = 0, + MEDIA_TYPE_AUDIO = 0x100000, + MEDIA_TYPE_VIDEO = 0x200000, + MEDIA_TYPE_SUBTITLES = 0x300000, + MEDIA_TYPE_CLOSED_CAPTIONS = 0x400000 +} MediaType; +static GFINLINE int string2num(const char *s) { + u64 ret=0, i, shift=2; + u8 hash[GF_SHA1_DIGEST_SIZE]; + gf_sha1_csum((u8*)s, (u32)strlen(s), hash); + assert(shift*GF_SHA1_DIGEST_SIZE < 64); + for (i=0; i<GF_SHA1_DIGEST_SIZE; ++i) + ret += (ret << shift) + hash[i]; + return (int)(ret % MEDIA_TYPE_AUDIO); +} -typedef struct _s_accumulated_attributes { - char * title; - int durationInSeconds; - int bandwidth; - int width, height; - int programId; - char * codecs; - int targetDurationInSeconds; - int minMediaSequence; - int currentMediaSequence; - Bool isVariantPlaylist; - Bool isPlaylistEnded; - u64 byteRangeStart, byteRangeEnd; -} s_accumulated_attributes; -static Bool safe_start_equals(const char * attribute, const char * line) { +#define GROUP_ID_TO_PROGRAM_ID(type, group_id) (\ + MEDIA_TYPE_##type + \ + string2num(group_id) \ + ) \ + +static Bool safe_start_equals(const char *attribute, const char *line) { size_t len, atlen; if (line == NULL) - return 0; + return GF_FALSE; len = strlen(line); atlen = strlen(attribute); if (len < atlen) - return 0; - return 0 == strncmp(attribute, line, atlen); + return GF_FALSE; + return (0 == strncmp(attribute, line, atlen)); +} + +typedef struct _s_accumulated_attributes { + //TODO: store as a structure with: { attribute, version, mandatory } + char *title; + char *mediaURL; + double duration_in_seconds; + int bandwidth; + int width, height; + int stream_id; + char *codecs; + char *language; + MediaType type; + union { + char *audio; + char *video; + } group; + int target_duration_in_seconds; + int min_media_sequence; + int current_media_seq; + int version; + int compatibility_version; /*compute version required by the M3U8 content*/ + Bool is_master_playlist; + Bool is_playlist_ended; + u64 byte_range_start, byte_range_end; + PlaylistElementDRMMethod key_method; + char *key_url; + bin128 key_iv; +} s_accumulated_attributes; + +static void reset_attributes(s_accumulated_attributes *attributes) +{ + memset(attributes, 0, sizeof(s_accumulated_attributes)); + attributes->type = MEDIA_TYPE_UNKNOWN; + attributes->min_media_sequence = 1; + attributes->version = 1; + attributes->compatibility_version = 0; + attributes->key_method = DRM_NONE; } -static char ** extractAttributes(const char * name, const char * line, const int numberOfAttributes) { - int sz, i, currentAttribute, start; - char ** ret; - u8 quote=0; +static char** extract_attributes(const char *name, const char *line, const int num_attributes) { + int sz, i, curr_attribute, start; + char **ret; + u8 quote = 0; int len = (u32) strlen(line); start = (u32) strlen(name); if (len <= start) return NULL; if (!safe_start_equals(name, line)) return NULL; - ret = gf_calloc((numberOfAttributes + 1 ), sizeof(char*)); - currentAttribute = 0; - for (i = start ; i <= len ; i++) { - if (line[i] == '\0' || (!quote && line[i] == ',') || (line[i] == quote) ) { + ret = gf_calloc((num_attributes + 1), sizeof(char*)); + curr_attribute = 0; + for (i=start; i<=len; i++) { + if (line[i] == '\0' || (!quote && line[i] == ',') || (line[i] == quote)) { u32 spaces = 0; sz = 1 + i - start; - while (line[start+spaces] == ' ') spaces++; - ret[currentAttribute] = gf_calloc( (1+sz-spaces), sizeof(char)); - strncpy(ret[currentAttribute], &(line[start+spaces]), sz-spaces); - currentAttribute++; + while (line[start+spaces] == ' ') + spaces++; + ret[curr_attribute] = gf_calloc( (1+sz-spaces), sizeof(char)); + strncpy(ret[curr_attribute], &(line[start+spaces]), sz-spaces); + curr_attribute++; start = i+1; if (start == len) { return ret; } } if ((line[i] == '\'') || (line[i] == '"')) { - if (quote) quote = 0; - else quote = line[i]; + if (quote) + quote = 0; + else + quote = line[i]; } } - if (currentAttribute == 0) { + if (curr_attribute == 0) { gf_free(ret); return NULL; } return ret; } +#define M3U8_COMPATIBILITY_VERSION(v) \ + if (v > attributes->compatibility_version) \ + attributes->compatibility_version = v; + /** -* Parses the attributes and accumulate into the attributes structure -*/ -static char ** parseAttributes(const char * line, s_accumulated_attributes * attributes) { - int intValue, i; - char ** ret; - char * endPtr; - char * utility; + * Parses the attributes and accumulate into the attributes structure + */ +static char** parse_attributes(const char *line, s_accumulated_attributes *attributes) { + int int_value, i; + double double_value; + char **ret; + char *end_ptr; + char *utility; if (line == NULL) return NULL; if (!safe_start_equals("#EXT", line)) return NULL; if (safe_start_equals("#EXT-X-ENDLIST", line)) { - attributes->isPlaylistEnded = 1; + attributes->is_playlist_ended = GF_TRUE; + M3U8_COMPATIBILITY_VERSION(1); return NULL; } - ret = extractAttributes("#EXT-X-TARGETDURATION:", line, 1); + /* reset not accumated attributes */ + attributes->type = MEDIA_TYPE_UNKNOWN; + + ret = extract_attributes("#EXT-X-TARGETDURATION:", line, 1); if (ret) { /* #EXT-X-TARGETDURATION:<seconds> */ if (ret[0]) { - intValue = strtol(ret[0], &endPtr, 10); - if (endPtr != ret[0]) { - attributes->targetDurationInSeconds = intValue; + int_value = (s32) strtol(ret[0], &end_ptr, 10); + if (end_ptr != ret[0]) { + attributes->target_duration_in_seconds = int_value; } } + M3U8_COMPATIBILITY_VERSION(1); return ret; } - ret = extractAttributes("#EXT-X-MEDIA-SEQUENCE:", line, 1); + ret = extract_attributes("#EXT-X-MEDIA-SEQUENCE:", line, 1); if (ret) { /* #EXT-X-MEDIA-SEQUENCE:<number> */ if (ret[0]) { - intValue = strtol(ret[0], &endPtr, 10); - if (endPtr != ret[0]) { - attributes->minMediaSequence = intValue; - attributes->currentMediaSequence = intValue; + int_value = (s32)strtol(ret[0], &end_ptr, 10); + if (end_ptr != ret[0]) { + attributes->min_media_sequence = int_value; + attributes->current_media_seq = int_value; + } + } + M3U8_COMPATIBILITY_VERSION(1); + return ret; + } + ret = extract_attributes("#EXT-X-VERSION:", line, 1); + if (ret) { + /* #EXT-X-VERSION:<number> */ + if (ret[0]) { + int_value = (s32)strtol(ret[0], &end_ptr, 10); + if (end_ptr != ret[0]) { + attributes->version = int_value; } + M3U8_COMPATIBILITY_VERSION(2); } return ret; } - ret = extractAttributes("#EXTINF:", line, 2); + ret = extract_attributes("#EXTINF:", line, 2); if (ret) { + M3U8_COMPATIBILITY_VERSION(1); /* #EXTINF:<duration>,<title> */ if (ret[0]) { - intValue = strtol(ret[0], &endPtr, 10); - if (endPtr != ret[0]) { - attributes->durationInSeconds = intValue; + double_value = strtod(ret[0], &end_ptr); + if (end_ptr != ret[0]) { + attributes->duration_in_seconds = double_value; + } + if (strstr(ret[0], ".") || (double_value > (int)double_value)) { + M3U8_COMPATIBILITY_VERSION(3); } } if (ret[1]) { @@ -427,31 +400,67 @@ static char ** parseAttributes(const char * line, s_accumulated_attributes * att } return ret; } - ret = extractAttributes("#EXT-X-KEY:", line, 2); + ret = extract_attributes("#EXT-X-KEY:", line, 4); if (ret) { /* #EXT-X-KEY:METHOD=<method>[,URI="<URI>"] */ - /* Not Supported for now */ + const char *method = "METHOD="; + const size_t method_len = strlen(method); + if (safe_start_equals(method, ret[0])) { + if (strncmp(ret[0]+method_len, "NONE", 4)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] EXT-X-KEY not supported.\n", line)); + } + attributes->key_method = DRM_AES_128; + if (ret[1] != NULL && safe_start_equals("URI=\"", ret[1])) { + int_value = (u32) strlen(ret[1]); + if (ret[1][int_value-1] == '"') { + attributes->key_url = gf_strdup(&(ret[1][4])); + } + } + } + M3U8_COMPATIBILITY_VERSION(1); + return ret; + } + ret = extract_attributes("#EXT-X-PROGRAM-DATE-TIME:", line, 1); + if (ret) { + /* #EXT-X-PROGRAM-DATE-TIME:<YYYY-MM-DDThh:mm:ssZ> */ + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[M3U8] EXT-X-PROGRAM-DATE-TIME not supported.\n", line)); + M3U8_COMPATIBILITY_VERSION(1); + return ret; + } + ret = extract_attributes("#EXT-X-ALLOW-CACHE:", line, 1); + if (ret) { + /* #EXT-X-ALLOW-CACHE:<YES|NO> */ + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[M3U8] EXT-X-ALLOW-CACHE not supported.\n", line)); + M3U8_COMPATIBILITY_VERSION(1); return ret; } - ret = extractAttributes("#EXT-X-STREAM-INF:", line, 10); + ret = extract_attributes("#EXT-X-PLAYLIST-TYPE", line, 1); + if (ret) { + /* #EXT-X-PLAYLIST-TYPE:<EVENT|VOD> */ + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[M3U8] EXT-X-PLAYLIST-TYPE not supported.\n", line)); + M3U8_COMPATIBILITY_VERSION(3); + return ret; + } + ret = extract_attributes("#EXT-X-STREAM-INF:", line, 10); if (ret) { /* #EXT-X-STREAM-INF:[attribute=value][,attribute=value]* */ i = 0; - attributes->isVariantPlaylist = 1; + attributes->is_master_playlist = GF_TRUE; + M3U8_COMPATIBILITY_VERSION(1); while (ret[i] != NULL) { if (safe_start_equals("BANDWIDTH=", ret[i])) { utility = &(ret[i][10]); - intValue = strtol(utility, &endPtr, 10); - if (endPtr != utility) - attributes->bandwidth = intValue; + int_value = (s32) strtol(utility, &end_ptr, 10); + if (end_ptr != utility) + attributes->bandwidth = int_value; } else if (safe_start_equals("PROGRAM-ID=", ret[i])) { utility = &(ret[i][11]); - intValue = strtol(utility, &endPtr, 10); - if (endPtr != utility) - attributes->programId = intValue; + int_value = (s32) strtol(utility, &end_ptr, 10); + if (end_ptr != utility) + attributes->stream_id = int_value; } else if (safe_start_equals("CODECS=\"", ret[i])) { - intValue = (u32) strlen(ret[i]); - if (ret[i][intValue-1] == '"') { + int_value = (u32) strlen(ret[i]); + if (ret[i][int_value-1] == '"') { attributes->codecs = gf_strdup(&(ret[i][7])); } } else if (safe_start_equals("RESOLUTION=", ret[i])) { @@ -461,46 +470,457 @@ static char ** parseAttributes(const char * line, s_accumulated_attributes * att attributes->width = w; attributes->height = h; } + M3U8_COMPATIBILITY_VERSION(2); + } else if (safe_start_equals("AUDIO=", ret[i])) { + assert(attributes->type == MEDIA_TYPE_UNKNOWN); + attributes->type = MEDIA_TYPE_AUDIO; + attributes->group.audio = gf_strdup(ret[i] + 6); + M3U8_COMPATIBILITY_VERSION(4); + } else if (safe_start_equals("VIDEO=", ret[i])) { + assert(attributes->type == MEDIA_TYPE_UNKNOWN); + attributes->type = MEDIA_TYPE_VIDEO; + attributes->group.video = gf_strdup(ret[i] + 6); + M3U8_COMPATIBILITY_VERSION(4); } i++; } + if (!attributes->stream_id) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-STREAM-INF: no PROGRAM-ID found. Ignoring the line.\n")); + return NULL; + } + return ret; + } + ret = extract_attributes("#EXT-X-DISCONTINUITY", line, 0); + if (ret) { + /* #EXT-X-DISCONTINUITY */ + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] EXT-X-DISCONTINUITY not supported.\n", line)); + M3U8_COMPATIBILITY_VERSION(1); return ret; } - ret = extractAttributes("#EXT-X-BYTERANGE:", line, 1); + ret = extract_attributes("#EXT-X-BYTERANGE:", line, 1); if (ret) { /* #EXT-X-BYTERANGE:<begin@end> */ if (ret[0]) { u64 begin, size; if (sscanf(ret[0], LLU"@"LLU, &size, &begin) == 2) { if (size) { - attributes->byteRangeStart = begin; - attributes->byteRangeEnd = begin + size - 1; + attributes->byte_range_start = begin; + attributes->byte_range_end = begin + size - 1; } else { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Invalid byte range %s\n", ret[0])); } } } + M3U8_COMPATIBILITY_VERSION(4); return ret; } + ret = extract_attributes("#EXT-X-MEDIA:", line, 14); + if (ret) { + /* #EXT-X-MEDIA:[TYPE={AUDIO,VIDEO}],[URI],[GROUP-ID],[LANGUAGE],[NAME],[DEFAULT={YES,NO}],[AUTOSELECT={YES,NO}] */ + M3U8_COMPATIBILITY_VERSION(4); + attributes->is_master_playlist = GF_TRUE; + i = 0; + while (ret[i] != NULL) { + if (safe_start_equals("TYPE=", ret[i])) { + if (!strncmp(ret[i]+5, "AUDIO", 5)) { + attributes->type = MEDIA_TYPE_AUDIO; + } else if (!strncmp(ret[i]+5, "VIDEO", 5)) { + attributes->type = MEDIA_TYPE_VIDEO; + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA:TYPE=%s\n", ret[i]+5)); + } + } else if (safe_start_equals("URI=\"", ret[i])) { + size_t len; + attributes->mediaURL = gf_strdup(ret[i]+5); + len = strlen(attributes->mediaURL); + if (len && (attributes->mediaURL[len-1] == '"')) { + attributes->mediaURL[len-1] = '\0'; + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Misformed #EXT-X-MEDIA:URI=%s. Quotes are incorrect.\n", ret[i]+5)); + } + } else if (safe_start_equals("GROUP-ID=", ret[i])) { + if (attributes->type == MEDIA_TYPE_AUDIO) { + attributes->group.audio = gf_strdup(ret[i]+9); + attributes->stream_id = GROUP_ID_TO_PROGRAM_ID(AUDIO, attributes->group.audio); + } else if (attributes->type == MEDIA_TYPE_VIDEO) { + attributes->group.video = gf_strdup(ret[i]+9); + attributes->stream_id = GROUP_ID_TO_PROGRAM_ID(VIDEO, attributes->group.video); + } else if (attributes->type == MEDIA_TYPE_UNKNOWN) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA:GROUP-ID=%s. Ignoring the line.\n", ret[i]+9)); + return NULL; + } + } else if (safe_start_equals("LANGUAGE=\"", ret[i])) { + size_t len; + attributes->language = gf_strdup(ret[i]+9); + len = strlen(attributes->language); + if (len && (attributes->language[len-1] == '"')) { + attributes->language[len-1] = '\0'; + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Misformed #EXT-X-MEDIA:LANGUAGE=%s. Quotes are incorrect.\n", ret[i]+5)); + } + } else if (safe_start_equals("NAME=", ret[i])) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[M3U8] EXT-X-MEDIA:NAME not supported\n")); + //attributes->name = gf_strdup(ret[i]+5); + } else if (safe_start_equals("DEFAULT=", ret[i])) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[M3U8] EXT-X-MEDIA:DEFAULT not supported\n")); + if (!strncmp(ret[i]+8, "YES", 3)) { + //TODO + } else if (!strncmp(ret[i]+8, "NO", 2)) { + //TODO + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA:DEFAULT=%s\n", ret[i]+8)); + } + } else if (safe_start_equals("AUTOSELECT=", ret[i])) { + GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[M3U8] EXT-X-MEDIA:AUTOSELECT not supported\n")); + if (!strncmp(ret[i]+11, "YES", 3)) { + //TODO + } else if (!strncmp(ret[i]+11, "NO", 2)) { + //TODO + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA:AUTOSELECT=%s\n", ret[i]+11)); + } + } + + i++; + } + + if (attributes->type == MEDIA_TYPE_UNKNOWN) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA: TYPE is missing. Ignoring the line.\n")); + return NULL; + } + if (attributes->type == MEDIA_TYPE_CLOSED_CAPTIONS && attributes->mediaURL) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA: TYPE is CLOSED-CAPTIONS but URI is present. Ignoring the URI.\n")); + gf_free(attributes->mediaURL); + attributes->mediaURL = NULL; + } + if ((attributes->type == MEDIA_TYPE_AUDIO && !attributes->group.audio) + || (attributes->type == MEDIA_TYPE_VIDEO && !attributes->group.video)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA: missing GROUP-ID attribute. Ignoring the line.\n")); + return NULL; + } + if (!attributes->stream_id) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Invalid #EXT-X-MEDIA: no ID was computed. Check previous errors. Ignoring the line.\n")); + return NULL; + } + + return ret; + } + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH,("[M3U8] Unknown line in M3U8 file %s\n", line)); + return NULL; +} + +/** + * Creates a new MasterPlaylist + * \return NULL if MasterPlaylist element could not be allocated + */ +MasterPlaylist* master_playlist_new() +{ + MasterPlaylist *pl = (MasterPlaylist*)gf_malloc(sizeof(MasterPlaylist)); + if (pl == NULL) + return NULL; + pl->streams = gf_list_new(); + if (!pl->streams) { + gf_free(pl); + return NULL; + } + pl->current_stream = -1; + pl->playlist_needs_refresh = GF_TRUE; + return pl; +} + + +/********** master_playlist **********/ + +GF_Err gf_m3u8_master_playlist_del(MasterPlaylist *playlist) { + if (playlist == NULL) + return GF_OK; + assert(playlist->streams); + while (gf_list_count(playlist->streams)) { + Stream *p = gf_list_get(playlist->streams, 0); + assert(p); + while (gf_list_count(p->variants)) { + PlaylistElement *pl = gf_list_get(p->variants, 0); + assert(pl); + playlist_element_del(pl); + gf_list_rem(p->variants, 0); + } + gf_list_del(p->variants); + p->variants = NULL; + stream_del(p); + gf_list_rem(playlist->streams, 0); + } + gf_list_del(playlist->streams); + playlist->streams = NULL; + gf_free(playlist); + + return GF_OK; +} + +static Stream* master_playlist_find_matching_stream(const MasterPlaylist *pl, const u32 stream_id) { + u32 count, i; + assert(pl); + assert(pl->streams); + assert(stream_id >= 0); + count = gf_list_count(pl->streams); + for (i=0; i<count; i++) { + Stream *cur = gf_list_get(pl->streams, i); + assert(cur); + if (stream_id == cur->stream_id) { + /* We found the program */ + return cur; + } + } return NULL; } + +/********** sub_playlist **********/ + #define M3U8_BUF_SIZE 2048 -GF_Err parse_root_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL) +GF_EXPORT +GF_Err gf_m3u8_parse_master_playlist(const char *file, MasterPlaylist **playlist, const char *baseURL) { - return parse_sub_playlist(file, playlist, baseURL, NULL, NULL); + return gf_m3u8_parse_sub_playlist(file, playlist, baseURL, NULL, NULL); } -GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL, Program * in_program, PlaylistElement *sub_playlist) +GF_Err declare_sub_playlist(char *currentLine, const char *baseURL, s_accumulated_attributes *attribs, PlaylistElement *sub_playlist, MasterPlaylist **playlist, Stream *in_stream) +{ + u32 i, iv, count; + + char *fullURL = currentLine; + + if (gf_url_is_local(fullURL)) { + fullURL = gf_url_concatenate(baseURL, fullURL); + assert(fullURL); + } + + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[M3U8] declaring sub-playlist %s\n", fullURL)); + + memset(attribs->key_iv, 0, sizeof(bin128) ); + iv = gf_htonl(attribs->current_media_seq); + memcpy(attribs->key_iv + 12, (const void *) &iv, sizeof(iv)); + + { + PlaylistElement *curr_playlist = sub_playlist; + /* First, we have to find the matching stream */ + Stream *stream = in_stream; + if (!in_stream) + stream = master_playlist_find_matching_stream(*playlist, attribs->stream_id); + /* We did not found the stream, we create it */ + if (stream == NULL) { + stream = stream_new(attribs->stream_id); + if (stream == NULL) { + /* OUT of memory */ + gf_m3u8_master_playlist_del(*playlist); + playlist = NULL; + return GF_OUT_OF_MEM; + } + gf_list_add((*playlist)->streams, stream); + /* take the first regular variant stream */ + if ((*playlist)->current_stream < 0 && stream->stream_id < MEDIA_TYPE_AUDIO) + (*playlist)->current_stream = stream->stream_id; + } + + /* OK, we have a stream, we have to choose the elements within the same stream variant */ + assert(stream); + assert(stream->variants); + count = gf_list_count(stream->variants); + + if (!curr_playlist) { + for (i=0; i<(s32)count; i++) { + PlaylistElement *i_playlist_element = gf_list_get(stream->variants, i); + assert(i_playlist_element); + if (stream->stream_id < MEDIA_TYPE_AUDIO) { + /* regular stream (EXT-X-STREAM-INF) */ + // Two stream are identical only if they have the same URL + if (!strcmp(i_playlist_element->url, fullURL)) { + curr_playlist = i_playlist_element; + break; + } + } else { + /* group streams (EXT-X-MEDIA) */ + //TODO: add renditions and compare depending on context parameters + } + } + } + + if (attribs->is_master_playlist) { + /* We are the Master Playlist */ + if (curr_playlist != NULL) { + /* should not happen, it means we redefine something previously added */ + assert(0); + } + curr_playlist = playlist_element_new( + TYPE_UNKNOWN, + fullURL, + attribs->title, + attribs->codecs, + attribs->language, + attribs->duration_in_seconds, + attribs->byte_range_start, attribs->byte_range_end, + attribs->key_method, attribs->key_url, attribs->key_iv); + if (curr_playlist == NULL) { + /* OUT of memory */ + gf_m3u8_master_playlist_del(*playlist); + playlist = NULL; + return GF_OUT_OF_MEM; + } + assert(fullURL); + if (curr_playlist->url) + gf_free(curr_playlist->url); + curr_playlist->url = gf_strdup(fullURL); + if (curr_playlist->title) + gf_free(curr_playlist->title); + curr_playlist->title = attribs->title ? gf_strdup(attribs->title) : NULL; + if (curr_playlist->codecs) + gf_free(curr_playlist->codecs); + curr_playlist->codecs = attribs->codecs ? gf_strdup(attribs->codecs) : NULL; + if (curr_playlist->audio_group) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[M3U8] Warning: found an AUDIO group in the master playlist.")); + } + if (curr_playlist->video_group) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[M3U8] Warning: found an VIDEO group in the master playlist.")); + } + gf_list_add(stream->variants, curr_playlist); + curr_playlist->width = attribs->width; + curr_playlist->height = attribs->height; + } else { + /* Normal Playlist */ + assert((*playlist)->streams); + if (curr_playlist == NULL) { + /* This is a "normal" playlist without any element in it */ + PlaylistElement *subElement; + assert(baseURL); + curr_playlist = playlist_element_new( + TYPE_PLAYLIST, + baseURL, + attribs->title, + attribs->codecs, + attribs->language, + attribs->duration_in_seconds, + attribs->byte_range_start, attribs->byte_range_end, + attribs->key_method, attribs->key_url, + attribs->key_iv); + if (curr_playlist == NULL) { + /* OUT of memory */ + gf_m3u8_master_playlist_del(*playlist); + playlist = NULL; + return GF_OUT_OF_MEM; + } + assert(curr_playlist->element.playlist.elements); + assert(fullURL); + assert(curr_playlist->url && !curr_playlist->title && !curr_playlist->codecs); + curr_playlist->title = NULL; + curr_playlist->codecs = NULL; + subElement = playlist_element_new( + TYPE_UNKNOWN, + fullURL, + attribs->title, + attribs->codecs, + attribs->language, + attribs->duration_in_seconds, + attribs->byte_range_start, attribs->byte_range_end, + attribs->key_method, attribs->key_url, + attribs->key_iv); + if (subElement == NULL) { + gf_m3u8_master_playlist_del(*playlist); + playlist_element_del(curr_playlist); + playlist = NULL; + return GF_OUT_OF_MEM; + } + gf_list_add(curr_playlist->element.playlist.elements, subElement); + gf_list_add(stream->variants, curr_playlist); + curr_playlist->element.playlist.computed_duration += subElement->duration_info; + assert(stream); + assert(stream->variants); + assert(curr_playlist); + } else { + PlaylistElement *subElement = playlist_element_new( + TYPE_UNKNOWN, + fullURL, + attribs->title, + attribs->codecs, + attribs->language, + attribs->duration_in_seconds, + attribs->byte_range_start, attribs->byte_range_end, + attribs->key_method, attribs->key_url, + attribs->key_iv); + if (curr_playlist->element_type != TYPE_PLAYLIST) { + curr_playlist->element_type = TYPE_PLAYLIST; + if (!curr_playlist->element.playlist.elements) + curr_playlist->element.playlist.elements = gf_list_new(); + } + if (subElement == NULL) { + gf_m3u8_master_playlist_del(*playlist); + playlist_element_del(curr_playlist); + playlist = NULL; + return GF_OUT_OF_MEM; + } + gf_list_add(curr_playlist->element.playlist.elements, subElement); + curr_playlist->element.playlist.computed_duration += subElement->duration_info; + } + } + + curr_playlist->element.playlist.current_media_seq = attribs->current_media_seq; + /* We first set the default duration for element, aka targetDuration */ + if (attribs->target_duration_in_seconds > 0) { + curr_playlist->element.playlist.target_duration = attribs->target_duration_in_seconds; + curr_playlist->duration_info = attribs->target_duration_in_seconds; + } + if (attribs->duration_in_seconds) { + if (curr_playlist->duration_info == 0) { + /* we set the playlist duration info as the duration of a segment, only if it's not set + There are cases of playlist with the last segment with a duration different from the others + (example: Apple bipbop test)*/ + curr_playlist->duration_info = attribs->duration_in_seconds; + } + } + curr_playlist->element.playlist.media_seq_min = attribs->min_media_sequence; + curr_playlist->element.playlist.media_seq_max = attribs->current_media_seq; + if (attribs->bandwidth > 1) + curr_playlist->bandwidth = attribs->bandwidth; + if (attribs->is_playlist_ended) + curr_playlist->element.playlist.is_ended = GF_TRUE; + } + /* Cleanup all line-specific fields */ + if (attribs->title) { + gf_free(attribs->title); + attribs->title = NULL; + } + attribs->duration_in_seconds = 0; + attribs->bandwidth = 0; + attribs->stream_id = 0; + if (attribs->codecs != NULL) { + gf_free(attribs->codecs); + attribs->codecs = NULL; + } + if (attribs->language != NULL) { + gf_free(attribs->language); + attribs->language = NULL; + } + if (attribs->group.audio != NULL) { + gf_free(attribs->group.audio); + attribs->group.audio = NULL; + } + if (attribs->group.video != NULL) { + gf_free(attribs->group.video); + attribs->group.video = NULL; + } + if (fullURL != currentLine) { + gf_free(fullURL); + } + return GF_OK; +} + +GF_Err gf_m3u8_parse_sub_playlist(const char *file, MasterPlaylist **playlist, const char *baseURL, Stream *in_stream, PlaylistElement *sub_playlist) { int len, i, currentLineNumber; - FILE * f=NULL; + FILE *f = NULL; char *m3u8_payload; u32 m3u8_size, m3u8pos; - VariantPlaylist * pl; char currentLine[M3U8_BUF_SIZE]; - char ** attributes = NULL; + char **attributes = NULL; s_accumulated_attributes attribs; if (!strncmp(file, "gmem://", 7)) { @@ -509,44 +929,38 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const return GF_SERVICE_ERROR; } } else { - f = gf_f64_open(file, "rt"); + f = gf_fopen(file, "rt"); if (!f) { - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot Open m3u8 file %s for reading\n", file)); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot open m3u8 file %s for reading\n", file)); return GF_SERVICE_ERROR; } } if (*playlist == NULL) { - *playlist = variant_playlist_new(); + *playlist = master_playlist_new(); if (!(*playlist)) { - if (f) fclose(f); + if (f) gf_fclose(f); return GF_OUT_OF_MEM; } } - pl = *playlist; currentLineNumber = 0; - bzero(&attribs, sizeof(s_accumulated_attributes)); - attribs.bandwidth = 0; - attribs.durationInSeconds = 0; - attribs.targetDurationInSeconds = 0; - attribs.isVariantPlaylist = 0; - attribs.isPlaylistEnded = 0; - attribs.minMediaSequence = 0; - attribs.currentMediaSequence = 0; - m3u8pos=0; + reset_attributes(&attribs); + m3u8pos = 0; while (1) { - char * eof; + char *eof; if (f) { if (!fgets(currentLine, sizeof(currentLine), f)) break; } else { - u32 __idx=0; - if (m3u8pos>=m3u8_size) + u32 __idx = 0; + if (m3u8pos >= m3u8_size) break; while (1) { + assert(__idx < M3U8_BUF_SIZE); + currentLine[__idx] = m3u8_payload[m3u8pos]; __idx++; m3u8pos++; - if ((currentLine[__idx-1]=='\n') || (currentLine[__idx-1]=='\r')) { + if ((currentLine[__idx-1]=='\n') || (currentLine[__idx-1]=='\r') || (m3u8pos >= m3u8_size)) { currentLine[__idx]=0; break; } @@ -559,252 +973,86 @@ GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const eof = strchr(currentLine, '\n'); if (eof) eof[0] = '\0'; - len = (u32) strlen( currentLine); + len = (u32) strlen(currentLine); if (len < 1) continue; if (currentLineNumber == 1) { /* Playlist MUST start with #EXTM3U */ - /* if (len < 7 || strncmp("#EXTM3U", currentLine, 7)!=0) { - fclose(f); - variant_playlist_del(pl); - GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Failed to parse M3U8 File, it should start with #EXTM3U, but was : %s\n", currentLine)); - return GF_STREAM_NOT_FOUND; - } - continue; - */ + if (len < 7 || (strncmp("#EXTM3U", currentLine, 7) != 0)) { + gf_fclose(f); + gf_m3u8_master_playlist_del(*playlist); + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Failed to parse M3U8 File, it should start with #EXTM3U, but was : %s\n", currentLine)); + return GF_STREAM_NOT_FOUND; + } + continue; } if (currentLine[0] == '#') { /* A comment or a directive */ - if (strncmp("#EXT", currentLine, 4)==0) { - attributes = parseAttributes(currentLine, &attribs); + if (strncmp("#EXT", currentLine, 4) == 0) { + attributes = parse_attributes(currentLine, &attribs); if (attributes == NULL) { - MYLOG(("Comment at line %d : %s\n", currentLineNumber, currentLine)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Comment at line %d : %s\n", currentLineNumber, currentLine)); } else { - MYLOG(("Directive at line %d: \"%s\", attributes=", currentLineNumber, currentLine)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Directive at line %d: \"%s\", attributes=", currentLineNumber, currentLine)); i = 0; while (attributes[i] != NULL) { - MYLOG((" [%d]='%s'", i, attributes[i])); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, (" [%d]='%s'", i, attributes[i])); gf_free(attributes[i]); attributes[i] = NULL; i++; } - MYLOG(("\n")); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("\n")); gf_free(attributes); attributes = NULL; } - if (attribs.isPlaylistEnded) { - pl->playlistNeedsRefresh = 0; - } - } - } else { - char * fullURL = currentLine; - - if (gf_url_is_local(currentLine)) { - /* - if (gf_url_is_local(baseURL)){ - int num_chars = -1; - if (baseURL[strlen(baseURL)-1] == '/'){ - num_chars = asprintf(&fullURL, "%s%s", baseURL, currentLine); - } else { - num_chars = asprintf(&fullURL, "%s/%s", baseURL, currentLine); - } - if (num_chars < 0 || fullURL == NULL){ - variant_playlist_del(*playlist); - playlist = NULL; - return GF_OUT_OF_MEM; + if (attribs.is_playlist_ended) { + (*playlist)->playlist_needs_refresh = GF_FALSE; } - } else */ { - fullURL = gf_url_concatenate(baseURL, currentLine); - } - assert( fullURL ); - } - { - u32 count; - PlaylistElement * currentPlayList = sub_playlist; - /* First, we have to find the matching program */ - Program * program = in_program; - if (!in_program) program = variant_playlist_find_matching_program(pl, attribs.programId); - /* We did not found the program, we create it */ - if (program == NULL) { - program = program_new(attribs.programId); - if (program == NULL) { - /* OUT of memory */ - variant_playlist_del(*playlist); - if (f) fclose(f); - playlist = NULL; - return GF_OUT_OF_MEM; + if (attribs.mediaURL) { + GF_Err e = declare_sub_playlist(attribs.mediaURL, baseURL, &attribs, sub_playlist, playlist, in_stream); + gf_free(attribs.mediaURL); + attribs.mediaURL = NULL; + if (e != GF_OK) { + if (f) gf_fclose(f); + return e; } - gf_list_add(pl->programs, program); - if (pl->currentProgram < 0) - pl->currentProgram = program->programId; } - - /* OK, we have a program, we have to choose the elements with same bandwidth */ - assert( program ); - assert( program->bitrates); - count = gf_list_count( program->bitrates); - - if (!currentPlayList) { - for (i = 0; i < (s32) count; i++) { - PlaylistElement * itPlayListElement = gf_list_get(program->bitrates, i); - assert( itPlayListElement ); - if (itPlayListElement->bandwidth == attribs.bandwidth) { - currentPlayList = itPlayListElement; - break; - } - } - } - - if (attribs.isVariantPlaylist) { - /* We are the Variant Playlist */ - if (currentPlayList != NULL) { - /* should not happen, it means we redefine something previsouly added */ - //assert( 0 ); - } - currentPlayList = playlist_element_new( - TYPE_UNKNOWN, - fullURL, - attribs.title, - attribs.codecs, - attribs.durationInSeconds, - attribs.byteRangeStart, attribs.byteRangeEnd); - if (currentPlayList == NULL) { - /* OUT of memory */ - variant_playlist_del(*playlist); - playlist = NULL; - if (f) fclose(f); - return GF_OUT_OF_MEM; - } - assert( fullURL); - currentPlayList->url = gf_strdup(fullURL); - currentPlayList->title = attribs.title ? gf_strdup(attribs.title):NULL; - currentPlayList->codecs = attribs.codecs ? gf_strdup(attribs.codecs):NULL; - gf_list_add(program->bitrates, currentPlayList); - currentPlayList->width = attribs.width; - currentPlayList->height = attribs.height; - } else { - /* Normal Playlist */ - assert( pl->programs); - if (currentPlayList == NULL) { - /* This is in facts a "normal" playlist without any element in it */ - PlaylistElement * subElement; - assert(baseURL); - currentPlayList = playlist_element_new( - TYPE_PLAYLIST, - baseURL, - attribs.title, - attribs.codecs, - attribs.durationInSeconds, - attribs.byteRangeStart, attribs.byteRangeEnd); - if (currentPlayList == NULL) { - /* OUT of memory */ - variant_playlist_del(*playlist); - playlist = NULL; - if (f) fclose(f); - return GF_OUT_OF_MEM; - } - assert(currentPlayList->element.playlist.elements); - assert( fullURL); - assert( currentPlayList->url); - currentPlayList->title = NULL; - currentPlayList->codecs = NULL; - subElement = playlist_element_new( - TYPE_UNKNOWN, - fullURL, - attribs.title, - attribs.codecs, - attribs.durationInSeconds, - attribs.byteRangeStart, attribs.byteRangeEnd); - if (subElement == NULL) { - variant_playlist_del(*playlist); - playlist_element_del(currentPlayList); - playlist = NULL; - if (f) fclose(f); - return GF_OUT_OF_MEM; - } - gf_list_add(currentPlayList->element.playlist.elements, subElement); - gf_list_add(program->bitrates, currentPlayList); - currentPlayList->element.playlist.computed_duration += subElement->durationInfo; - assert( program ); - assert( program->bitrates); - assert( currentPlayList); - - } else { - PlaylistElement * subElement = playlist_element_new( - TYPE_UNKNOWN, - fullURL, - attribs.title, - attribs.codecs, - attribs.durationInSeconds, - attribs.byteRangeStart, attribs.byteRangeEnd); - if (currentPlayList->elementType != TYPE_PLAYLIST) { - currentPlayList->elementType = TYPE_PLAYLIST; - if (!currentPlayList->element.playlist.elements) - currentPlayList->element.playlist.elements = gf_list_new(); - } - if (subElement == NULL) { - variant_playlist_del(*playlist); - playlist_element_del(currentPlayList); - playlist = NULL; - if (f) fclose(f); - return GF_OUT_OF_MEM; - } - gf_list_add(currentPlayList->element.playlist.elements, subElement); - currentPlayList->element.playlist.computed_duration += subElement->durationInfo; - } - } - - currentPlayList->element.playlist.currentMediaSequence = attribs.currentMediaSequence ; - /* We first set the default duration for element, aka targetDuration */ - if (attribs.targetDurationInSeconds > 0) { - currentPlayList->element.playlist.target_duration = attribs.targetDurationInSeconds; - currentPlayList->durationInfo = attribs.targetDurationInSeconds; - } - if (attribs.durationInSeconds) { - if (currentPlayList->durationInfo == 0) { - /* we set the playlist duration info as the duration of a segment, only if it's not set - There are cases of playlist with the last segment with a duration different from the others - (example: Apple bipbop test)*/ - currentPlayList->durationInfo = attribs.durationInSeconds; - } - } - currentPlayList->element.playlist.mediaSequenceMin = attribs.minMediaSequence; - currentPlayList->element.playlist.mediaSequenceMax = attribs.currentMediaSequence++; - if (attribs.bandwidth > 1) - currentPlayList->bandwidth = attribs.bandwidth; - if (attribs.isPlaylistEnded) - currentPlayList->element.playlist.is_ended = 1; - } - /* Cleanup all line-specific fields */ - if (attribs.title) { - gf_free(attribs.title); - attribs.title = NULL; } - attribs.durationInSeconds = 0; - attribs.bandwidth = 0; - attribs.programId = 0; - if (attribs.codecs != NULL) { - gf_free(attribs.codecs); - attribs.codecs = NULL; - } - if (fullURL != currentLine) { - gf_free(fullURL); + } else { + /*file encountered: sub-playlist or segment*/ + GF_Err e = declare_sub_playlist(currentLine, baseURL, &attribs, sub_playlist, playlist, in_stream); + attribs.current_media_seq += 1; + if (e != GF_OK) { + if (f) gf_fclose(f); + return e; } + + //do not reset all attributes but at least set width/height/codecs to NULL, otherwise we may miss detection + //of audio-only playlists in av sequences + //reset_attributes(&attribs); + attribs.width = attribs.height = 0; + attribs.codecs = NULL; } } - if (f) fclose(f); + if (f) gf_fclose(f); - for (i=0; i < (int) gf_list_count(pl->programs); i++) { + for (i=0; i<(int)gf_list_count((*playlist)->streams); i++) { u32 j; - Program *prog = gf_list_get(pl->programs, i); + Stream *prog = gf_list_get((*playlist)->streams, i); prog->computed_duration = 0; - for (j=0; j<gf_list_count(prog->bitrates); j++) { - PlaylistElement *ple = gf_list_get(prog->bitrates, j); - if (ple->elementType==TYPE_PLAYLIST) { + for (j=0; j<gf_list_count(prog->variants); j++) { + PlaylistElement *ple = gf_list_get(prog->variants, j); + if (ple->element_type == TYPE_PLAYLIST) { if (ple->element.playlist.computed_duration > prog->computed_duration) prog->computed_duration = ple->element.playlist.computed_duration; } } + + } + if (attribs.key_url) + gf_free(attribs.key_url); + if (attribs.version < attribs.compatibility_version) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[M3U8] Version %d specified but tags from version %d detected\n", attribs.version, attribs.compatibility_version)); } return GF_OK; } diff --git a/src/media_tools/media_export.c b/src/media_tools/media_export.c index 07d6ffe..44e8919 100644 --- a/src/media_tools/media_export.c +++ b/src/media_tools/media_export.c @@ -88,7 +88,7 @@ static GF_Err gf_dump_to_ogg(GF_MediaExporter *dumper, char *szName, u32 track) op.b_o_s = 1; op.e_o_s = 0; - out = szName ? gf_f64_open(szName, "wb") : stdout; + out = szName ? gf_fopen(szName, "wb") : stdout; if (!out) return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); theora_kgs = 0; @@ -180,7 +180,7 @@ static GF_Err gf_dump_to_ogg(GF_MediaExporter *dumper, char *szName, u32 track) gf_fwrite(og.body, 1, og.body_len, out); } ogg_stream_clear(&os); - if (szName) fclose(out); + if (szName) gf_fclose(out); return GF_OK; #endif } @@ -218,9 +218,9 @@ GF_Err gf_export_hint(GF_MediaExporter *dumper) } if (e) return gf_export_message(dumper, e, "Error fetching hint packet %d", i); sprintf(szName, "%s_pck_%04d.%s", dumper->out_name, i, gf_4cc_to_str(m_stype)); - out = gf_f64_open(szName, "wb"); + out = gf_fopen(szName, "wb"); gf_fwrite(pck, size, 1, out); - fclose(out); + gf_fclose(out); gf_free(pck); i++; if (count) gf_set_progress("Hint Export", sn, count); @@ -389,6 +389,9 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper) } else if (m_stype==GF_ISOM_SUBTYPE_AC3) { gf_export_message(dumper, GF_OK, "Extracting AC3 sample%s", szNum); strcpy(szEXT, ".ac3"); + } else if (m_stype==GF_ISOM_SUBTYPE_MP3) { + gf_export_message(dumper, GF_OK, "Extracting MP3 sample%s", szNum); + strcpy(szEXT, ".mp3"); } else if (m_stype==GF_4CC('x','d','v','b') ) { gf_export_message(dumper, GF_OK, "Extracting MPEG-2 sample%s", szNum); strcpy(szEXT, ".m2v"); @@ -412,9 +415,21 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper) gf_export_message(dumper, GF_OK, "Extracting WebVTT sample%s", szNum); strcpy(szEXT, ".vtt"); is_wvtt = GF_TRUE; - } else if (m_stype==GF_ISOM_SUBTYPE_STSE) { + } else if (m_stype==GF_ISOM_SUBTYPE_STXT) { gf_export_message(dumper, GF_OK, "Extracting Simple Text sample%s", szNum); strcpy(szEXT, ".txt"); + } else if (m_stype==GF_ISOM_SUBTYPE_METT) { + gf_export_message(dumper, GF_OK, "Extracting Metadata Text sample%s", szNum); + strcpy(szEXT, ".txt"); + } else if (m_stype==GF_ISOM_SUBTYPE_SBTT) { + gf_export_message(dumper, GF_OK, "Extracting Subtitle Text sample%s", szNum); + strcpy(szEXT, ".txt"); + } else if (m_stype==GF_ISOM_SUBTYPE_METX) { + gf_export_message(dumper, GF_OK, "Extracting Metadata XML sample%s", szNum); + strcpy(szEXT, ".xml"); + } else if (m_stype==GF_ISOM_SUBTYPE_STPP) { + gf_export_message(dumper, GF_OK, "Extracting Subtitle XML sample%s", szNum); + strcpy(szEXT, ".xml"); } else if (m_type==GF_ISOM_MEDIA_HINT) { return gf_export_hint(dumper); } else if (m_stype==GF_4CC('m','j','p','2')) { @@ -460,7 +475,7 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper) } else { sprintf(szName, "%s_%d%s", dumper->out_name, dumper->sample_num, szEXT); } - out = is_stdout ? stdout : gf_f64_open(szName, "wb"); + out = is_stdout ? stdout : gf_fopen(szName, "wb"); bs = gf_bs_from_file(out, GF_BITSTREAM_WRITE); if (is_mj2k) write_jp2_file(bs, samp->data, samp->dataLength, dsi, dsi_size); @@ -484,7 +499,7 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper) gf_bs_del(bs); if (!is_stdout) - fclose(out); + gf_fclose(out); if (dsi) gf_free(dsi); return GF_OK; @@ -511,7 +526,7 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper) } } - out = is_stdout ? stdout : gf_f64_open(szName, "wb"); + out = is_stdout ? stdout : gf_fopen(szName, "wb"); bs = gf_bs_from_file(out, GF_BITSTREAM_WRITE); if (dsi) gf_bs_write_data(bs, dsi, dsi_size); if (is_mj2k) @@ -536,7 +551,7 @@ GF_Err gf_media_export_samples(GF_MediaExporter *dumper) gf_set_progress("Media Export", i+1, count); gf_bs_del(bs); if (!is_stdout) - fclose(out); + gf_fclose(out); if (dumper->flags & GF_EXPORT_DO_ABORT) break; } if (dsi) gf_free(dsi); @@ -549,7 +564,7 @@ static GF_Err gf_dump_to_vobsub(GF_MediaExporter *dumper, char *szName, u32 trac FILE *fidx, *fsub; u32 width, height, i, count, di; GF_ISOSample *samp; - char lang[] = "\0\0\0\0"; + char *lang = NULL; /* Check decoder specific information (palette) size - should be 64 */ if (dsiSize != 64) { @@ -557,7 +572,7 @@ static GF_Err gf_dump_to_vobsub(GF_MediaExporter *dumper, char *szName, u32 trac } /* Create an idx file */ - fidx = gf_f64_open(szName, "w"); + fidx = gf_fopen(szName, "w"); if (!fidx) { return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } @@ -565,9 +580,9 @@ static GF_Err gf_dump_to_vobsub(GF_MediaExporter *dumper, char *szName, u32 trac /* Create a sub file */ vobsub_trim_ext(szName); szName = strcat(szName, ".sub"); - fsub = gf_f64_open(szName, "wb"); + fsub = gf_fopen(szName, "wb"); if (!fsub) { - fclose(fidx); + gf_fclose(fidx); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } @@ -608,8 +623,9 @@ static GF_Err gf_dump_to_vobsub(GF_MediaExporter *dumper, char *szName, u32 trac fputs("# Language index in use\nlangidx: 0\n", fidx); /* Write language header */ - gf_isom_get_media_language(dumper->file, track, lang); + gf_isom_get_media_language(dumper->file, track, &lang); fprintf(fidx, "id: %s, index: 0\n", vobsub_lang_id(lang)); + gf_free(lang); /* Retrieve sample count */ count = gf_isom_get_sample_count(dumper->file, track); @@ -633,14 +649,14 @@ static GF_Err gf_dump_to_vobsub(GF_MediaExporter *dumper, char *szName, u32 trac mm = (u32)(dts % 60); hh = (u32)(dts / 60); #if defined(WIN32) && !defined(__GNUC__) - fprintf(fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n", hh, mm, ss, ms, gf_f64_tell(fsub)); + fprintf(fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n", hh, mm, ss, ms, gf_ftell(fsub)); #else - fprintf(fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: " LLXPAD("09") "\n", hh, mm, ss, ms, gf_f64_tell(fsub)); + fprintf(fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: " LLXPAD("09") "\n", hh, mm, ss, ms, gf_ftell(fsub)); #endif if (vobsub_packetize_subpicture(fsub, samp->DTS, samp->data, samp->dataLength) != GF_OK) { gf_isom_sample_del(&samp); - fclose(fsub); - fclose(fidx); + gf_fclose(fsub); + gf_fclose(fidx); return gf_export_message(dumper, GF_IO_ERR, "Unable packetize subpicture into file %s\n", szName); } @@ -657,8 +673,8 @@ static GF_Err gf_dump_to_vobsub(GF_MediaExporter *dumper, char *szName, u32 trac gf_isom_sample_del(&samp); } - fclose(fsub); - fclose(fidx); + gf_fclose(fsub); + gf_fclose(fidx); return GF_OK; #else @@ -671,6 +687,26 @@ static const char *QCP_QCELP_GUID_1 = "\x41\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\ static const char *QCP_EVRC_GUID = "\x8D\xD4\x89\xE6\x76\x90\xB5\x46\x91\xEF\x73\x6A\x51\x00\xCE\xB4"; static const char *QCP_SMV_GUID = "\x75\x2B\x7C\x8D\x97\xA7\x46\xED\x98\x5E\xD5\x3C\x8C\xC7\x5F\x84"; +#define DUMP_AVCPARAM(_params) \ + count = gf_list_count(_params); \ + for (i=0;i<count;i++) { \ + GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(_params, i); \ + gf_bs_write_u32(bs, 1); \ + gf_bs_write_data(bs, sl->data, sl->size); \ + } \ + +#define DUMP_HEVCPARAM(_params) \ + count = gf_list_count(_params->param_array); \ + for (i=0;i<count;i++) { \ + u32 j; \ + GF_HEVCParamArray *ar = (GF_HEVCParamArray *)gf_list_get(_params->param_array, i); \ + for (j=0; j<gf_list_count(ar->nalus); j++) { \ + GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j); \ + gf_bs_write_u32(bs, 1); \ + gf_bs_write_data(bs, sl->data, sl->size); \ + } \ + } \ + GF_Err gf_media_export_native(GF_MediaExporter *dumper) { @@ -687,13 +723,14 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) GF_AVCConfig *avccfg, *svccfg; GF_HEVCConfig *hevccfg, *shvccfg; GF_M4ADecSpecInfo a_cfg; + const char *stxtcfg; GF_BitStream *bs; u32 track, i, di, count, m_type, m_stype, dsi_size, qcp_type; Bool is_ogg, has_qcp_pad, is_vobsub; - u32 aac_type, is_aac; + u32 aac_type, aac_mode; char *dsi; QCPRateTable rtable[8]; - Bool is_stdout=0; + Bool is_stdout = GF_FALSE; Bool is_webvtt = GF_FALSE; dsi_size = 0; @@ -702,6 +739,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) avccfg = NULL; svccfg = NULL; shvccfg = NULL; + stxtcfg = NULL; if (!(track = gf_isom_get_track_by_id(dumper->file, dumper->trackID))) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Wrong track ID %d for file %s \n", dumper->trackID, gf_isom_get_filename(dumper->file))); @@ -710,21 +748,45 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) m_type = gf_isom_get_media_type(dumper->file, track); m_stype = gf_isom_get_media_subtype(dumper->file, track, 1); - has_qcp_pad = 0; - if (dumper->out_name && !strcmp(dumper->out_name, "std")) - is_stdout = 1; + has_qcp_pad = GF_FALSE; + if (dumper->out_name && !strcmp(dumper->out_name, "std")) { + is_stdout = GF_TRUE; + } - is_aac = aac_type = 0; + aac_mode = aac_type = 0; qcp_type = 0; - is_ogg = 0; - is_vobsub = 0; + is_ogg = GF_FALSE; + is_vobsub = GF_FALSE; udesc = NULL; - dcfg = NULL; - if ((m_stype==GF_ISOM_SUBTYPE_MPEG4) || (m_stype==GF_ISOM_SUBTYPE_MPEG4_CRYP)) - dcfg = gf_isom_get_decoder_config(dumper->file, track, 1); - add_ext = (dumper->out_name && strrchr(dumper->out_name , '.')==NULL) ? 1 : 0; + /* check if the output file name needs an extension or already has one */ + if (dumper->out_name) { + char *lastPathPart; + lastPathPart = strrchr(dumper->out_name , GF_PATH_SEPARATOR); + if (!lastPathPart) { + lastPathPart = dumper->out_name; + } else { + lastPathPart++; + } + if (strrchr(lastPathPart , '.')==NULL) { + add_ext = GF_TRUE; + } else { + add_ext = GF_FALSE; + } + } else { + add_ext = GF_FALSE; + } strcpy(szName, dumper->out_name ? dumper->out_name : ""); + + /* Find the decoder configuration: + - Check first if the stream is carried according to MPEG-4 Systems, + i.e. using the Object Descriptor Framework, to get the Decoder Specific Info (dsi) + - Or get it specifically depending on the media type + */ + dcfg = NULL; + if ((m_stype==GF_ISOM_SUBTYPE_MPEG4) || (m_stype==GF_ISOM_SUBTYPE_MPEG4_CRYP)) { + dcfg = gf_isom_get_decoder_config(dumper->file, track, 1); + } if (dcfg) { switch (dcfg->streamType) { case GF_STREAM_VISUAL: @@ -784,7 +846,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) if (add_ext) strcat(szName, ".ogg"); gf_export_message(dumper, GF_OK, "Extracting Ogg video"); - is_ogg = 1; + is_ogg = GF_TRUE; break; default: gf_odf_desc_del((GF_Descriptor *) dcfg); @@ -801,7 +863,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) dsi_size = dcfg->decoderSpecificInfo->dataLength; if (add_ext) strcat(szName, ".aac"); - is_aac = 1; + aac_mode = 1; aac_type = dcfg->objectTypeIndication - GPAC_OTI_AUDIO_AAC_MPEG2_MP; gf_export_message(dumper, GF_OK, "Extracting MPEG-2 AAC"); break; @@ -814,7 +876,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) dsi = dcfg->decoderSpecificInfo->data; dcfg->decoderSpecificInfo->data = NULL; dsi_size = dcfg->decoderSpecificInfo->dataLength; - is_aac = 2; + aac_mode = 2; if (add_ext) strcat(szName, ".aac"); gf_export_message(dumper, GF_OK, "Extracting MPEG-4 AAC"); @@ -828,7 +890,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) case GPAC_OTI_MEDIA_OGG: if (add_ext) strcat(szName, ".ogg"); - is_ogg = 1; + is_ogg = GF_TRUE; gf_export_message(dumper, GF_OK, "Extracting Ogg audio"); break; case GPAC_OTI_AUDIO_13K_VOICE: @@ -848,7 +910,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) memcpy(GUID, QCP_SMV_GUID, sizeof(char)*16); if (dumper->flags & GF_EXPORT_PROBE_ONLY) dumper->flags |= GF_EXPORT_USE_QCP; break; - case 0xD1: + case 0xD1: /* OTI in the user private range already assigned to GPAC's internal GPAC_OTI_SCENE_SVG_GZ */ if (dcfg->decoderSpecificInfo && (dcfg->decoderSpecificInfo->dataLength==8) && !strnicmp(dcfg->decoderSpecificInfo->data, "pvmm", 4)) { qcp_type = 3; @@ -866,7 +928,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) switch (dcfg->objectTypeIndication) { case GPAC_OTI_MEDIA_SUBPIC: - is_vobsub = 1; + is_vobsub = GF_TRUE; dsi = dcfg->decoderSpecificInfo->data; dcfg->decoderSpecificInfo->data = NULL; dsi_size = dcfg->decoderSpecificInfo->dataLength; @@ -885,6 +947,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) } gf_odf_desc_del((GF_Descriptor *) dcfg); } else { + /* Not using the MPEG-4 Descriptor Framework */ if (m_stype==GF_ISOM_SUBTYPE_3GP_AMR) { if (add_ext) strcat(szName, ".amr"); @@ -912,11 +975,11 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) if (add_ext) strcat(szName, ".263"); } else if (m_stype==GF_4CC('x','d','v','b')) { - gf_export_message(dumper, GF_OK, "Extracting MPEG-2 Video"); + gf_export_message(dumper, GF_OK, "Extracting MPEG-2 Video (xdvb)"); if (add_ext) strcat(szName, ".m2v"); } else if (m_stype==GF_ISOM_SUBTYPE_3GP_DIMS) { - return gf_media_export_nhml(dumper, 1); + return gf_media_export_nhml(dumper, GF_TRUE); } else if ((m_stype==GF_ISOM_SUBTYPE_AVC_H264) || (m_stype==GF_ISOM_SUBTYPE_AVC2_H264) || (m_stype==GF_ISOM_SUBTYPE_AVC3_H264) @@ -944,17 +1007,51 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) gf_export_message(dumper, GF_OK, "Extracting Macromedia Flash Movie"); if (add_ext) strcat(szName, ".swf"); + } else if (m_stype==GF_ISOM_SUBTYPE_MP3) { + gf_export_message(dumper, GF_OK, "Extracting MPEG-1/2 Audio"); + if (add_ext) + strcat(szName, ".mp3"); } else if (m_stype==GF_ISOM_SUBTYPE_AC3) { gf_export_message(dumper, GF_OK, "Extracting AC3 Audio"); - if (add_ext) - strcat(szName, ".ac3"); + if (add_ext) { + GF_AC3Config *cfg = gf_isom_ac3_config_get(dumper->file, track, 1); + if (cfg->is_ec3) + strcat(szName, ".ec3"); + else + strcat(szName, ".ac3"); + gf_free(cfg); + } } else if (m_stype==GF_ISOM_SUBTYPE_WVTT) { gf_export_message(dumper, GF_OK, "Extracting WebVTT"); is_webvtt = GF_TRUE; - strcat(szName, ".vtt"); - } else if (m_stype==GF_ISOM_SUBTYPE_STSE) { - gf_export_message(dumper, GF_OK, "Extracting Simple Text"); - strcat(szName, ".txt"); + if (add_ext) + strcat(szName, ".vtt"); + } else if ((m_stype==GF_ISOM_SUBTYPE_STXT) || (m_stype==GF_ISOM_SUBTYPE_METT)) { + const char *mime; + const char *encoding; + gf_export_message(dumper, GF_OK, "Extracting %s Stream", (m_stype==GF_ISOM_SUBTYPE_STXT) ? "Simple Text" : "Text-based Metadata"); + gf_isom_stxt_get_description(dumper->file, track, 1, &mime, &encoding, &stxtcfg); + if (add_ext) { + if (mime && !strcmp(mime, "image/svg+xml")) { + gf_export_message(dumper, GF_OK, "as SVG file"); + strcat(szName, ".svg"); + } else { + strcat(szName, ".txt"); + } + } + } else if (m_stype==GF_ISOM_SUBTYPE_SBTT) { + gf_export_message(dumper, GF_OK, "Extracting Text-based Subtitle Stream"); + if (add_ext) + strcat(szName, ".txt"); + } else if (m_stype==GF_ISOM_SUBTYPE_STPP) { + gf_export_message(dumper, GF_OK, "Extracting XML Subtitle Stream"); + if (add_ext) + strcat(szName, ".xml"); + return gf_export_message(dumper, GF_NOT_SUPPORTED, "XML Subtitles re-assembling is not supported yet.", dumper->trackID); + } else if (m_stype==GF_ISOM_SUBTYPE_METX) { + gf_export_message(dumper, GF_OK, "Extracting XML Metadata Stream"); + if (add_ext) + strcat(szName, ".xml"); } else { if (add_ext) { strcat(szName, "."); @@ -980,7 +1077,34 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) if (udesc) gf_free(udesc); } } + if (qcp_type>1) { + if (dumper->flags & GF_EXPORT_USE_QCP) { + if (add_ext) + strcat(szName, ".qcp"); + gf_export_message(dumper, GF_OK, "Extracting %s audio (QCP file)", (qcp_type==2) ? "SMV" : "EVRC"); + } else if (qcp_type==2) { + if (add_ext) + strcat(szName, ".smv"); + gf_export_message(dumper, GF_OK, "Extracting SMV audio"); + } else { + if (add_ext) + strcat(szName, ".evc"); + gf_export_message(dumper, GF_OK, "Extracting EVRC audio"); + } + } + if (aac_mode) { + gf_m4a_get_config(dsi, dsi_size, &a_cfg); + if (aac_mode==2) aac_type = a_cfg.base_object_type - 1; + gf_free(dsi); + dsi = NULL; + } + if (dumper->flags & GF_EXPORT_SVC_LAYER) { + gf_isom_set_nalu_extract_mode(dumper->file, track, GF_ISOM_NALU_EXTRACT_LAYER_ONLY); + } + /* The stream can be extracted and we found its DSI or config (if any), and the file extension is set up */ + if (dumper->flags & GF_EXPORT_PROBE_ONLY) { + /* We don't need to go further in this mode */ if (dsi) gf_free(dsi); if (avccfg) gf_odf_avc_cfg_del(avccfg); if (svccfg) gf_odf_avc_cfg_del(svccfg); @@ -988,13 +1112,13 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) if (shvccfg) gf_odf_hevc_cfg_del(shvccfg); return GF_OK; } - if (dumper->flags & GF_EXPORT_SVC_LAYER) - gf_isom_set_nalu_extract_mode(dumper->file, track, GF_ISOM_NALU_EXTRACT_LAYER_ONLY); - - if (is_ogg) return gf_dump_to_ogg(dumper, is_stdout ? NULL : szName, track); - - if (is_vobsub) return gf_dump_to_vobsub(dumper, szName, track, dsi, dsi_size); + if (is_ogg) { + return gf_dump_to_ogg(dumper, is_stdout ? NULL : szName, track); + } + if (is_vobsub) { + return gf_dump_to_vobsub(dumper, szName, track, dsi, dsi_size); + } if (is_webvtt) { #ifndef GPAC_DISABLE_TTXT GF_Err gf_webvtt_dump_iso_track(GF_MediaExporter *dumper, char *szName, u32 track, Bool merge); @@ -1004,29 +1128,13 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) #endif } - if (qcp_type>1) { - if (dumper->flags & GF_EXPORT_USE_QCP) { - if (add_ext) - strcat(szName, ".qcp"); - gf_export_message(dumper, GF_OK, "Extracting %s audio (QCP file)", (qcp_type==2) ? "SMV" : "EVRC"); - } else if (qcp_type==2) { - if (add_ext) - strcat(szName, ".smv"); - gf_export_message(dumper, GF_OK, "Extracting SMV audio"); - } else { - if (add_ext) - strcat(szName, ".evc"); - gf_export_message(dumper, GF_OK, "Extracting EVRC audio"); - } - } - if (is_stdout) { out = stdout; } else if (dumper->out_name && (dumper->flags & GF_EXPORT_MERGE)) { - out = gf_f64_open(dumper->out_name, "a+b"); - if (out) gf_f64_seek(out, 0, SEEK_END); + out = gf_fopen(dumper->out_name, "a+b"); + if (out) gf_fseek(out, 0, SEEK_END); } else { - out = gf_f64_open(szName, "wb"); + out = gf_fopen(szName, "wb"); } if (!out) { if (dsi) gf_free(dsi); @@ -1036,38 +1144,14 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) if (shvccfg) gf_odf_hevc_cfg_del(shvccfg); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } + + /* Start writing the stream out */ bs = gf_bs_from_file(out, GF_BITSTREAM_WRITE); - if (is_aac) { - gf_m4a_get_config(dsi, dsi_size, &a_cfg); - if (is_aac==2) aac_type = a_cfg.base_object_type - 1; - gf_free(dsi); - dsi = NULL; - } if (dsi) { gf_bs_write_data(bs, dsi, dsi_size); gf_free(dsi); } -#define DUMP_AVCPARAM(_params) \ - count = gf_list_count(_params); \ - for (i=0;i<count;i++) { \ - GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(_params, i); \ - gf_bs_write_u32(bs, 1); \ - gf_bs_write_data(bs, sl->data, sl->size); \ - } \ - -#define DUMP_HEVCPARAM(_params) \ - count = gf_list_count(_params->param_array); \ - for (i=0;i<count;i++) { \ - u32 j; \ - GF_HEVCParamArray *ar = gf_list_get(_params->param_array, i); \ - for (j=0; j<gf_list_count(ar->nalus); j++) { \ - GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_list_get(ar->nalus, j); \ - gf_bs_write_u32(bs, 1); \ - gf_bs_write_data(bs, sl->data, sl->size); \ - } \ - } \ - if (avccfg) { DUMP_AVCPARAM(avccfg->sequenceParameterSets); @@ -1079,8 +1163,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) } if (svccfg || shvccfg) { - if (!(dumper->flags & GF_EXPORT_SVC_LAYER)) - { + if (!(dumper->flags & GF_EXPORT_SVC_LAYER)) { GF_AVCConfig *cfg; GF_HEVCConfig *hcfg; u32 ref_track = 0, t; @@ -1105,13 +1188,11 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) // copy avcC and svcC from lower layer countRef = gf_isom_get_reference_count(dumper->file, track, GF_ISOM_REF_SCAL); - if (countRef < 0) - { + if (countRef < 0) { e = gf_isom_last_error(dumper->file); goto exit; } - for (t = 2; t <= (u32) countRef; t++) // referenceIndex 1 is the base layer - { + for (t = 2; t <= (u32) countRef; t++) { // referenceIndex 1 is the base layer gf_isom_get_reference(dumper->file, track, GF_ISOM_REF_SCAL, t, &ref_track); cfg = gf_isom_svc_config_get(dumper->file, ref_track, 1); if (cfg) { @@ -1138,19 +1219,25 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) } - qcp_rates = NULL; - count = gf_isom_get_sample_count(dumper->file, track); - rt_cnt = 0; - - if (m_stype==GF_ISOM_SUBTYPE_3GP_AMR) gf_bs_write_data(bs, "#!AMR\n", 6); - else if (m_stype==GF_ISOM_SUBTYPE_3GP_AMR_WB) gf_bs_write_data(bs, "#!AMR-WB\n", 9); - else if ((qcp_type>1) && !(dumper->flags & GF_EXPORT_USE_QCP)) { + if (m_stype==GF_ISOM_SUBTYPE_3GP_AMR) { + gf_bs_write_data(bs, "#!AMR\n", 6); + } else if (m_stype==GF_ISOM_SUBTYPE_3GP_AMR_WB) { + gf_bs_write_data(bs, "#!AMR-WB\n", 9); + } else if ((qcp_type>1) && !(dumper->flags & GF_EXPORT_USE_QCP)) { if (qcp_type==2) gf_bs_write_data(bs, "#!SMV\n", 6); else gf_bs_write_data(bs, "#!EVRC\n", 7); qcp_type = 0; + } else if ((m_stype==GF_ISOM_SUBTYPE_STXT) || (m_stype==GF_ISOM_SUBTYPE_METT)) { + if (stxtcfg) { + gf_bs_write_data(bs, stxtcfg, (u32)strlen(stxtcfg)); + } } + count = gf_isom_get_sample_count(dumper->file, track); + /*QCP formatting*/ + qcp_rates = NULL; + rt_cnt = 0; if (qcp_type) { GF_ISOSample *samp; Bool needs_rate_octet; @@ -1186,17 +1273,17 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) } /*check sample format - packetvideo doesn't include rate octet...*/ - needs_rate_octet = 1; + needs_rate_octet = GF_TRUE; samp = gf_isom_get_sample_info(dumper->file, track, 1, NULL, NULL); for (i=0; i<rt_cnt; i++) { if (qcp_rates[2*i+1]==samp->dataLength) { - needs_rate_octet = 0; + needs_rate_octet = GF_FALSE; break; } } gf_isom_sample_del(&samp); if (needs_rate_octet) data_size += count; - has_qcp_pad = (data_size % 2) ? 1 : 0; + has_qcp_pad = (data_size % 2) ? GF_TRUE : GF_FALSE; avg_rate = 8*data_size*sample_rate/count/block_size; /*QLCM + fmt + vrat + data*/ @@ -1243,7 +1330,7 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) qcp_type = needs_rate_octet ? 1 : 0; } - + /* Start exporting samples */ for (i=0; i<count; i++) { GF_ISOSample *samp = gf_isom_get_sample(dumper->file, track, i+1, &di); if (!samp) { @@ -1283,9 +1370,9 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) } } /*adts frame header*/ - else if (is_aac) { + else if (aac_mode > 0) { gf_bs_write_int(bs, 0xFFF, 12);/*sync*/ - gf_bs_write_int(bs, (is_aac==1) ? 1 : 0, 1);/*mpeg2 aac*/ + gf_bs_write_int(bs, (aac_mode==1) ? 1 : 0, 1);/*mpeg2 aac*/ gf_bs_write_int(bs, 0, 2); /*layer*/ gf_bs_write_int(bs, 1, 1); /* protection_absent*/ gf_bs_write_int(bs, aac_type, 2); @@ -1307,7 +1394,9 @@ GF_Err gf_media_export_native(GF_MediaExporter *dumper) } } } - if (!avccfg && !svccfg && !hevccfg && !shvccfg &!is_webvtt) gf_bs_write_data(bs, samp->data, samp->dataLength); + if (!avccfg && !svccfg && !hevccfg && !shvccfg &!is_webvtt) { + gf_bs_write_data(bs, samp->data, samp->dataLength); + } gf_isom_sample_del(&samp); gf_set_progress("Media Export", i+1, count); if (dumper->flags & GF_EXPORT_DO_ABORT) break; @@ -1320,7 +1409,7 @@ exit: if (shvccfg) gf_odf_hevc_cfg_del(shvccfg); gf_bs_del(bs); if (!is_stdout) - fclose(out); + gf_fclose(out); return e; #endif /*GPAC_DISABLE_AV_PARSERS*/ } @@ -1370,13 +1459,13 @@ static GF_Err gf_media_export_avi_track(GF_MediaExporter *dumper) strcpy(szOutFile, dumper->out_name); } - fout = is_stdout ? stdout : gf_f64_open(szOutFile, "wb"); + fout = is_stdout ? stdout : gf_fopen(szOutFile, "wb"); max_size = 0; frame = NULL; - num_samples = AVI_video_frames(in); + num_samples = (u32) AVI_video_frames(in); for (i=0; i<num_samples; i++) { - size = AVI_frame_size(in, i); + size = (s32) AVI_frame_size(in, i); if (!size) { AVI_read_frame(in, NULL, (int*)&key); continue; @@ -1391,13 +1480,20 @@ static GF_Err gf_media_export_avi_track(GF_MediaExporter *dumper) } gf_free(frame); if(!is_stdout) - fclose(fout); + gf_fclose(fout); fout = NULL; goto exit; } i = 0; tot_size = max_size = 0; - while ((size = AVI_audio_size(in, i) )>0) { + size = (s32) AVI_audio_size(in, i); + if (size < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[AVIExport] Error reading AVI audio sample\n")); + e = GF_NON_COMPLIANT_BITSTREAM; + goto exit; + } + + while (size > 0) { if (max_size<(u32) size) max_size=size; tot_size += size; i++; @@ -1452,6 +1548,9 @@ static GF_Err gf_media_export_avi_track(GF_MediaExporter *dumper) case 0x55: comp = "mp3"; break; + case 0x0000706d: + comp = "aac"; + break; default: comp = "raw"; break; @@ -1465,12 +1564,16 @@ static GF_Err gf_media_export_avi_track(GF_MediaExporter *dumper) strcpy(szOutFile, dumper->out_name); } - fout = is_stdout ? stdout : gf_f64_open(szOutFile, "wb"); + fout = is_stdout ? stdout : gf_fopen(szOutFile, "wb"); num_samples = 0; while (1) { Bool continuous; - size = AVI_read_audio(in, frame, max_size, (int*)&continuous); - if (!size) break; + size = (s32) AVI_read_audio(in, frame, max_size, (int*)&continuous); + if (size < 0) { + GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[AVIExport] Error reading AVI audio sample\n")); + e = GF_NON_COMPLIANT_BITSTREAM; + goto exit; + } num_samples += size; gf_fwrite(frame, 1, size, fout); gf_set_progress("AVI Extract", num_samples, tot_size); @@ -1479,7 +1582,7 @@ static GF_Err gf_media_export_avi_track(GF_MediaExporter *dumper) exit: - if (fout && !is_stdout) fclose(fout); + if (fout && !is_stdout) gf_fclose(fout); AVI_close(in); return e; } @@ -1507,16 +1610,16 @@ GF_Err gf_media_export_nhnt(GF_MediaExporter *dumper) } sprintf(szName, "%s.media", dumper->out_name); - out_med = gf_f64_open(szName, "wb"); + out_med = gf_fopen(szName, "wb"); if (!out_med) { gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } sprintf(szName, "%s.nhnt", dumper->out_name); - out_nhnt = gf_f64_open(szName, "wb"); + out_nhnt = gf_fopen(szName, "wb"); if (!out_nhnt) { - fclose(out_med); + gf_fclose(out_med); gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } @@ -1526,9 +1629,9 @@ GF_Err gf_media_export_nhnt(GF_MediaExporter *dumper) if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { sprintf(szName, "%s.info", dumper->out_name); - out_inf = gf_f64_open(szName, "wb"); + out_inf = gf_fopen(szName, "wb"); if (out_inf) gf_fwrite(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, 1, out_inf); - fclose(out_inf); + gf_fclose(out_inf); } /*write header*/ @@ -1589,9 +1692,9 @@ GF_Err gf_media_export_nhnt(GF_MediaExporter *dumper) gf_set_progress("NHNT Export", i+1, count); if (dumper->flags & GF_EXPORT_DO_ABORT) break; } - fclose(out_med); + gf_fclose(out_med); gf_bs_del(bs); - fclose(out_nhnt); + gf_fclose(out_nhnt); return GF_OK; } @@ -1785,11 +1888,11 @@ GF_Err gf_media_export_isom(GF_MediaExporter *dumper) add_to_iod = 1; mode = GF_ISOM_WRITE_EDIT; if (!is_stdout && (dumper->flags & GF_EXPORT_MERGE)) { - FILE *t = gf_f64_open(szName, "rb"); + FILE *t = gf_fopen(szName, "rb"); if (t) { add_to_iod = 0; mode = GF_ISOM_OPEN_EDIT; - fclose(t); + gf_fclose(t); } } outfile = gf_isom_open(is_stdout ? "std" : szName, mode, NULL); @@ -1866,7 +1969,7 @@ GF_Err gf_media_export_avi(GF_MediaExporter *dumper) return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } - /*compute FPS - note we assume constant frame rate without droped frames...*/ + /*compute FPS - note we assume constant frame rate without dropped frames...*/ count = gf_isom_get_sample_count(dumper->file, track); FPS = gf_isom_get_media_timescale(dumper->file, track); FPS *= (count-1); @@ -1981,7 +2084,7 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) szRootName = "DIMSStream"; } else { sprintf(szMedia, "%s.media", dumper->out_name); - med = gf_f64_open(szMedia, "wb"); + med = gf_fopen(szMedia, "wb"); if (!med) { if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szMedia); @@ -1990,15 +2093,17 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) sprintf(szName, "%s.nhml", dumper->out_name); szRootName = "NHNTStream"; } - nhml = gf_f64_open(szName, "wt"); + nhml = gf_fopen(szName, "wt"); if (!nhml) { - fclose(med); + gf_fclose(med); if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } mstype = gf_isom_get_media_subtype(dumper->file, track, 1); + gf_export_message(dumper, GF_OK, "Exporting NHML for track %s", gf_4cc_to_str(mstype) ); + /*write header*/ fprintf(nhml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); fprintf(nhml, "<%s version=\"1.0\" timeScale=\"%d\" ", szRootName, gf_isom_get_media_timescale(dumper->file, track) ); @@ -2006,9 +2111,9 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) fprintf(nhml, "streamType=\"%d\" objectTypeIndication=\"%d\" ", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication); if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { sprintf(szName, "%s.info", dumper->out_name); - inf = gf_f64_open(szName, "wb"); + inf = gf_fopen(szName, "wb"); if (inf) gf_fwrite(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, 1, inf); - fclose(inf); + gf_fclose(inf); fprintf(nhml, "specificInfoFile=\"%s\" ", szName); } gf_odf_desc_del((GF_Descriptor *) esd); @@ -2039,13 +2144,26 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) } if (sdesc->extension_buf) { sprintf(szName, "%s.info", dumper->out_name); - inf = gf_f64_open(szName, "wb"); + inf = gf_fopen(szName, "wb"); if (inf) gf_fwrite(sdesc->extension_buf, sdesc->extension_buf_size, 1, inf); - fclose(inf); + gf_fclose(inf); fprintf(nhml, "specificInfoFile=\"%s\" ", szName); gf_free(sdesc->extension_buf); } gf_free(sdesc); + } else { + const char *mime, *encoding, *config; + switch (mstype) { + case GF_ISOM_SUBTYPE_METT: + if (gf_isom_stxt_get_description(dumper->file, track, 1, &mime, &encoding, &config) == GF_OK) { + sprintf(szName, "%s.info", dumper->out_name); + inf = gf_fopen(szName, "wb"); + if (inf) gf_fwrite(config, strlen(config), 1, inf); + gf_fclose(inf); + fprintf(nhml, "specificInfoFile=\"%s\" ", szName); + } + break; + } } } @@ -2135,7 +2253,7 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) svg_data[d_stream.total_out - done] = 0; fprintf(nhml, "%s", svg_data); if (err== Z_STREAM_END) break; - done = d_stream.total_out; + done = (u32) d_stream.total_out; d_stream.avail_out = 2048; d_stream.next_out = (Bytef*)svg_data; } @@ -2145,8 +2263,8 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Error: your version of GPAC was compile with no libz support.")); gf_bs_del(bs); gf_isom_sample_del(&samp); - if (med) fclose(med); - fclose(nhml); + if (med) gf_fclose(med); + gf_fclose(nhml); return GF_NOT_SUPPORTED; #endif } else { @@ -2162,8 +2280,8 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) } else { fprintf(nhml, "<NHNTSample DTS=\""LLU"\" dataLength=\"%d\" ", LLU_CAST samp->DTS, samp->dataLength); if (full_dump || samp->CTS_Offset) fprintf(nhml, "CTSOffset=\"%u\" ", samp->CTS_Offset); - if (samp->IsRAP==1) fprintf(nhml, "isRAP=\"yes\" "); - else if (samp->IsRAP==2) fprintf(nhml, "isSyncShadow=\"yes\" "); + if (samp->IsRAP==RAP) fprintf(nhml, "isRAP=\"yes\" "); + else if (samp->IsRAP==RAP_REDUNDANT) fprintf(nhml, "isSyncShadow=\"yes\" "); else if (full_dump) fprintf(nhml, "isRAP=\"no\" "); if (full_dump) fprintf(nhml, "mediaOffset=\"%d\" ", pos); fprintf(nhml, "/>\n"); @@ -2175,8 +2293,8 @@ GF_Err gf_media_export_nhml(GF_MediaExporter *dumper, Bool dims_doc) if (dumper->flags & GF_EXPORT_DO_ABORT) break; } fprintf(nhml, "</%s>\n", szRootName); - if (med) fclose(med); - fclose(nhml); + if (med) gf_fclose(med); + gf_fclose(nhml); return GF_OK; } @@ -2212,7 +2330,7 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) if (dumper->flags & GF_EXPORT_WEBVTT_META_EMBEDDED) { } else { sprintf(szMedia, "%s.media", dumper->out_name); - med = gf_f64_open(szMedia, "wb"); + med = gf_fopen(szMedia, "wb"); if (!med) { if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szMedia); @@ -2220,9 +2338,9 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) } sprintf(szName, "%s.vtt", dumper->out_name); - vtt = gf_f64_open(szName, "wt"); + vtt = gf_fopen(szName, "wt"); if (!vtt) { - fclose(med); + gf_fclose(med); if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } @@ -2239,10 +2357,10 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) fprintf(vtt, "WEBVTT Metadata track generated by GPAC MP4Box %s\n", GPAC_FULL_VERSION); fprintf(vtt, "kind:metadata\n"); { - /* TODO: use BCP 47 strings */ - char lang[4]; - gf_isom_get_media_language(dumper->file, track, lang); + char *lang; + gf_isom_get_media_language(dumper->file, track, &lang); fprintf(vtt, "language:%s\n", lang); + gf_free(lang); } { const char *handler; @@ -2286,7 +2404,7 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) if (mstype == GF_ISOM_SUBTYPE_WVTT) { /* Warning: Just use -raw export */ mime = "text/vtt"; - } else if (mstype == GF_ISOM_SUBTYPE_STSE) { + } else if (mstype == GF_ISOM_SUBTYPE_STXT) { /* TODO: find the mime type from the ESD, assume SVG for now */ mime = "image/svg+xml"; } else if (mstype == GF_ISOM_SUBTYPE_STPP) { @@ -2294,7 +2412,7 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) mime = "application/ttml+xml"; } if (dumper->flags & GF_EXPORT_WEBVTT_META_EMBEDDED) { - if (mstype == GF_ISOM_SUBTYPE_STSE) { + if (mstype == GF_ISOM_SUBTYPE_STXT) { if (esd->decoderConfig->decoderSpecificInfo->dataLength) { fprintf(vtt, "text-header: \n"); gf_webvtt_dump_header_boxed(vtt, esd->decoderConfig->decoderSpecificInfo->data+4, esd->decoderConfig->decoderSpecificInfo->dataLength, &headerLength); @@ -2381,8 +2499,8 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) fprintf(vtt, "dataLength:%d ", samp->dataLength); } if (samp->CTS_Offset) fprintf(vtt, "CTS: "LLD"", samp->DTS+samp->CTS_Offset); - if (samp->IsRAP==1) fprintf(vtt, "isRAP:true "); - else if (samp->IsRAP==2) fprintf(vtt, "isSyncShadow: true "); + if (samp->IsRAP==RAP) fprintf(vtt, "isRAP:true "); + else if (samp->IsRAP==RAP_REDUNDANT) fprintf(vtt, "isSyncShadow: true "); else fprintf(vtt, "isRAP:false "); fprintf(vtt, "\n"); } @@ -2413,8 +2531,8 @@ GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper) gf_set_progress("WebVTT metadata Export", i+1, count); if (dumper->flags & GF_EXPORT_DO_ABORT) break; } - if (med) fclose(med); - fclose(vtt); + if (med) gf_fclose(med); + gf_fclose(vtt); return GF_OK; } @@ -2443,7 +2561,7 @@ GF_Err gf_media_export_six(GF_MediaExporter *dumper) esd = gf_isom_get_esd(dumper->file, track, 1); media = NULL; sprintf(szMedia, "%s.media", dumper->out_name); - media = gf_f64_open(szMedia, "wb"); + media = gf_fopen(szMedia, "wb"); if (!media) { if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szMedia); @@ -2452,9 +2570,9 @@ GF_Err gf_media_export_six(GF_MediaExporter *dumper) sprintf(szName, "%s.six", dumper->out_name); szRootName = "stream"; - six = gf_f64_open(szName, "wt"); + six = gf_fopen(szName, "wt"); if (!six) { - fclose(media); + gf_fclose(media); if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } @@ -2477,7 +2595,7 @@ GF_Err gf_media_export_six(GF_MediaExporter *dumper) if (esd) { if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { #ifndef GPAC_DISABLE_TTXT - if (mstype == GF_ISOM_SUBTYPE_WVTT || mstype == GF_ISOM_SUBTYPE_STSE) { + if (mstype == GF_ISOM_SUBTYPE_WVTT || mstype == GF_ISOM_SUBTYPE_STXT) { gf_webvtt_dump_header_boxed(media, esd->decoderConfig->decoderSpecificInfo->data+4, esd->decoderConfig->decoderSpecificInfo->dataLength, @@ -2510,8 +2628,8 @@ GF_Err gf_media_export_six(GF_MediaExporter *dumper) } fprintf(six, "<unit time=\""LLU"\" ", LLU_CAST samp->DTS); - if (samp->IsRAP==1) fprintf(six, "rap=\"1\" "); - else if (samp->IsRAP==0) fprintf(six, "rap=\"0\" "); + if (samp->IsRAP==RAP) fprintf(six, "rap=\"1\" "); + else if (samp->IsRAP==RAP_NO) fprintf(six, "rap=\"0\" "); fprintf(six, "range-begin=\"%d\" ", pos); fprintf(six, "range-end=\"%d\" ", pos+samp->dataLength-1); fprintf(six, "/>\n"); @@ -2522,8 +2640,8 @@ GF_Err gf_media_export_six(GF_MediaExporter *dumper) if (dumper->flags & GF_EXPORT_DO_ABORT) break; } fprintf(six, "</%s>\n", szRootName); - if (media) fclose(media); - fclose(six); + if (media) gf_fclose(media); + gf_fclose(six); return GF_OK; } @@ -2620,7 +2738,7 @@ GF_Err gf_media_export_saf(GF_MediaExporter *dumper) is_stdout = 1; strcpy(out_file, dumper->out_name); strcat(out_file, ".saf"); - saf_f = is_stdout ? stdout : gf_f64_open(out_file, "wb"); + saf_f = is_stdout ? stdout : gf_fopen(out_file, "wb"); samp_done = 0; while (samp_done<tot_samp) { @@ -2628,7 +2746,7 @@ GF_Err gf_media_export_saf(GF_MediaExporter *dumper) GF_ISOSample *samp; if (safs[i].last_sample==safs[i].nb_samp) continue; samp = gf_isom_get_sample(dumper->file, safs[i].track_num, safs[i].last_sample + 1, &di); - gf_saf_mux_add_au(mux, safs[i].stream_id, (u32) (samp->DTS+samp->CTS_Offset), samp->data, samp->dataLength, samp->IsRAP); + gf_saf_mux_add_au(mux, safs[i].stream_id, (u32) (samp->DTS+samp->CTS_Offset), samp->data, samp->dataLength, (samp->IsRAP==RAP) ? 1 : 0); /*data is kept by muxer!!*/ gf_free(samp); safs[i].last_sample++; @@ -2649,7 +2767,7 @@ GF_Err gf_media_export_saf(GF_MediaExporter *dumper) gf_free(data); } if (!is_stdout) - fclose(saf_f); + gf_fclose(saf_f); gf_saf_mux_del(mux); return GF_OK; @@ -2664,19 +2782,47 @@ void m2ts_export_check(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) { // if (evt_type == GF_M2TS_EVT_PAT_REPEAT) ts->user = NULL; if (evt_type == GF_M2TS_EVT_PMT_REPEAT) ts->user = NULL; - else if (evt_type == GF_M2TS_EVT_PAT_FOUND) ts->segment_switch = 1; + else if (evt_type == GF_M2TS_EVT_PAT_FOUND) gf_m2ts_abort_parsing(ts, GF_FALSE); } + +struct _ts_export +{ + FILE *dst; + Bool is_latm; +}; + void m2ts_export_dump(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) { + struct _ts_export *tsx = (struct _ts_export *) ts->user; + if (evt_type == GF_M2TS_EVT_PES_PCK) { - FILE *dst = (FILE*)ts->user; GF_M2TS_PES_PCK *pck = (GF_M2TS_PES_PCK *)par; - gf_fwrite(pck->data, pck->data_len, 1, dst); + + if (tsx->is_latm) { + GF_BitStream *bs = gf_bs_from_file(tsx->dst, GF_BITSTREAM_WRITE); + + gf_bs_write_int(bs, 0xFFF, 12);/*sync*/ + gf_bs_write_int(bs, 0, 1);/*mpeg2 aac*/ + gf_bs_write_int(bs, 0, 2); /*layer*/ + gf_bs_write_int(bs, 1, 1); /* protection_absent*/ + + gf_bs_write_int(bs, pck->stream->aud_aac_obj_type - 1 , 2); + + gf_bs_write_int(bs, pck->stream->aud_aac_sr_idx, 4); + gf_bs_write_int(bs, 0, 1); + gf_bs_write_int(bs, pck->stream->aud_nb_ch, 3); + gf_bs_write_int(bs, 0, 4); + gf_bs_write_int(bs, 7+pck->data_len, 13); + gf_bs_write_int(bs, 0x7FF, 11); + gf_bs_write_int(bs, 0, 2); + + gf_bs_del(bs); + } + gf_fwrite(pck->data, pck->data_len, 1, tsx->dst); } else if (evt_type == GF_M2TS_EVT_SL_PCK) { - FILE *dst = (FILE*)ts->user; GF_M2TS_SL_PCK *pck = (GF_M2TS_SL_PCK *)par; - gf_fwrite(pck->data + 5, pck->data_len - 5, 1, dst); + gf_fwrite(pck->data + 5, pck->data_len - 5, 1, tsx->dst); } } @@ -2688,16 +2834,17 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper) u64 size, fsize, fdone; Bool is_stdout=0; GF_M2TS_Demuxer *ts; - FILE *src, *dst; + FILE *src; + struct _ts_export tsx; if (dumper->flags & GF_EXPORT_PROBE_ONLY) return GF_OK; - src = gf_f64_open(dumper->in_name, "rb"); + src = gf_fopen(dumper->in_name, "rb"); if (!src) return gf_export_message(dumper, GF_CODEC_NOT_FOUND, "Error opening %s", dumper->in_name); - gf_f64_seek(src, 0, SEEK_END); - fsize = gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_END); + fsize = gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); ts = gf_m2ts_demux_new(); ts->on_event = m2ts_export_check; @@ -2710,12 +2857,12 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper) gf_m2ts_process_data(ts, data, (u32)size); if (!ts->user) break; } - if (!ts->segment_switch && ts->user) { - fclose(src); + if (!ts->abort_parsing && ts->user) { + gf_fclose(src); gf_m2ts_demux_del(ts); return gf_export_message(dumper, GF_URL_ERROR, "Cannot locate program association table"); } - ts->segment_switch = 0; + ts->abort_parsing = GF_FALSE; stream = NULL; for (i=0; i<GF_M2TS_MAX_STREAMS; i++) { @@ -2730,11 +2877,12 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper) } } if (!stream) { - fclose(src); + gf_fclose(src); gf_m2ts_demux_del(ts); return gf_export_message(dumper, GF_URL_ERROR, "Cannot find PID %d in transport stream", dumper->trackID); } + tsx.is_latm = 0; sprintf(szFile, "%s_pid%d", dumper->out_name ? dumper->out_name : "", stream->pid); switch (stream->stream_type) { case GF_M2TS_VIDEO_MPEG1: @@ -2757,6 +2905,11 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper) strcat(szFile, ".aac"); gf_export_message(dumper, GF_OK, "Extracting MPEG-4 Audio stream to aac"); break; + case GF_M2TS_AUDIO_LATM_AAC: + strcat(szFile, ".aac"); + tsx.is_latm = 1; + gf_export_message(dumper, GF_OK, "Extracting MPEG-4 Audio LATM stream to aac"); + break; case GF_M2TS_VIDEO_MPEG4: strcat(szFile, ".cmp"); gf_export_message(dumper, GF_OK, "Extracting MPEG-4 Visual stream to cmp"); @@ -2786,17 +2939,17 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper) if (dumper->out_name && !strcmp(dumper->out_name, "std")) is_stdout=1; - dst = is_stdout ? stdout : gf_f64_open(szFile, "wb"); - if (!dst) { - fclose(src); + tsx.dst = is_stdout ? stdout : gf_fopen(szFile, "wb"); + if (!tsx.dst) { + gf_fclose(src); gf_m2ts_demux_del(ts); return gf_export_message(dumper, GF_IO_ERR, "Cannot open file %s for writing", szFile); } gf_m2ts_reset_parsers(ts); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_SET); fdone = 0; - ts->user = dst; + ts->user = &tsx; ts->on_event = m2ts_export_dump; while (!feof(src)) { size = fread(data, 1, 188, src); @@ -2810,8 +2963,8 @@ GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper) gf_set_progress("MPEG-2 TS Extract", fsize, fsize); if (!is_stdout) - fclose(dst); - fclose(src); + gf_fclose(tsx.dst); + gf_fclose(src); gf_m2ts_demux_del(ts); return GF_OK; } diff --git a/src/media_tools/media_import.c b/src/media_tools/media_import.c index 0181bd2..b83ea0c 100644 --- a/src/media_tools/media_import.c +++ b/src/media_tools/media_import.c @@ -46,13 +46,13 @@ GF_Err gf_import_message(GF_MediaImporter *import, GF_Err e, char *format, ...) { #ifndef GPAC_DISABLE_LOG - if (gf_log_tool_level_on(GF_LOG_AUTHOR, e ? GF_LOG_ERROR : GF_LOG_INFO)) { + if (gf_log_tool_level_on(GF_LOG_AUTHOR, e ? GF_LOG_WARNING : GF_LOG_INFO)) { va_list args; char szMsg[1024]; va_start(args, format); vsprintf(szMsg, format, args); va_end(args); - GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_INFO), GF_LOG_AUTHOR, ("%s\n", szMsg) ); + GF_LOG((u32) (e ? GF_LOG_WARNING : GF_LOG_INFO), GF_LOG_AUTHOR, ("%s\n", szMsg) ); } #endif return e; @@ -104,19 +104,22 @@ static GF_Err gf_media_update_par(GF_ISOFile *file, u32 track) } -static void MP4T_RecomputeBitRate(GF_ISOFile *file, u32 track) +static void gf_media_update_bitrate(GF_ISOFile *file, u32 track) { #ifndef GPAC_DISABLE_ISOM_WRITE - u32 i, count, timescale; - u64 time_wnd, rate, max_rate, avg_rate; + u32 i, count, timescale, db_size; + u64 time_wnd, rate, max_rate, avg_rate, bitrate; Double br; GF_ESD *esd; - esd = gf_isom_get_esd(file, track, 1); - if (!esd) return; + db_size = 0; - esd->decoderConfig->avgBitrate = 0; - esd->decoderConfig->maxBitrate = 0; + esd = gf_isom_get_esd(file, track, 1); + if (esd) { + db_size = esd->decoderConfig->bufferSizeDB; + esd->decoderConfig->avgBitrate = 0; + esd->decoderConfig->maxBitrate = 0; + } rate = max_rate = avg_rate = time_wnd = 0; timescale = gf_isom_get_media_timescale(file, track); @@ -124,9 +127,8 @@ static void MP4T_RecomputeBitRate(GF_ISOFile *file, u32 track) for (i=0; i<count; i++) { GF_ISOSample *samp = gf_isom_get_sample_info(file, track, i+1, NULL, NULL); - if (samp->dataLength>esd->decoderConfig->bufferSizeDB) esd->decoderConfig->bufferSizeDB = samp->dataLength; + if (samp->dataLength > db_size) db_size = samp->dataLength; - if (esd->decoderConfig->bufferSizeDB < samp->dataLength) esd->decoderConfig->bufferSizeDB = samp->dataLength; avg_rate += samp->dataLength; rate += samp->dataLength; if (samp->DTS > time_wnd + timescale) { @@ -140,13 +142,21 @@ static void MP4T_RecomputeBitRate(GF_ISOFile *file, u32 track) br = (Double) (s64) gf_isom_get_media_duration(file, track); br /= timescale; - esd->decoderConfig->avgBitrate = (u32) ((Double) (s64)avg_rate / br); + bitrate = (u32) ((Double) (s64)avg_rate / br); + bitrate *= 8; + max_rate *= 8; + /*move to bps*/ - esd->decoderConfig->avgBitrate *= 8; - esd->decoderConfig->maxBitrate = (u32) (max_rate*8); + if (esd) { + esd->decoderConfig->avgBitrate = (u32) bitrate; + esd->decoderConfig->maxBitrate = (u32) max_rate; + esd->decoderConfig->bufferSizeDB = db_size; + gf_isom_change_mpeg4_description(file, track, 1, esd); + gf_odf_desc_del((GF_Descriptor *)esd); + } else { + gf_isom_update_bitrate(file, track, 1, (u32) bitrate, (u32) max_rate, db_size); + } - gf_isom_change_mpeg4_description(file, track, 1, esd); - gf_odf_desc_del((GF_Descriptor *)esd); #endif } @@ -181,20 +191,22 @@ static GF_Err gf_import_still_image(GF_MediaImporter *import, Bool mult_desc_all u8 OTI; char *dsi, *data; FILE *src; - Bool import_mpeg4 = 0; + Bool import_mpeg4 = GF_FALSE; - if (import->flags & GF_IMPORT_FORCE_MPEG4) import_mpeg4 = 1; - else if (import->esd) import_mpeg4 = 1; + if (import->flags & GF_IMPORT_FORCE_MPEG4) + import_mpeg4 = GF_TRUE; + else if (import->esd) + import_mpeg4 = GF_TRUE; - src = gf_f64_open(import->in_name, "rb"); + src = gf_fopen(import->in_name, "rb"); if (!src) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); - gf_f64_seek(src, 0, SEEK_END); - size = (u32) gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_END); + size = (u32) gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); data = (char*)gf_malloc(sizeof(char)*size); size = (u32) fread(data, sizeof(char), size, src); - fclose(src); + gf_fclose(src); /*get image size*/ bs = gf_bs_new(data, size, GF_BITSTREAM_READ); @@ -301,7 +313,7 @@ static GF_Err gf_import_still_image(GF_MediaImporter *import, Bool mult_desc_all gf_isom_set_visual_info(import->dest, track, di, w, h); samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; samp->dataLength = size; if (import->initial_time_offset) samp->DTS = (u64) (import->initial_time_offset*1000); @@ -356,15 +368,15 @@ static GF_Err gf_import_afx_sc3dmc(GF_MediaImporter *import, Bool mult_desc_allo return GF_OK; } - src = gf_f64_open(import->in_name, "rb"); + src = gf_fopen(import->in_name, "rb"); if (!src) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); - gf_f64_seek(src, 0, SEEK_END); - size = (u32) gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); + gf_fseek(src, 0, SEEK_END); + size = (u32) gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); data = (char*)gf_malloc(sizeof(char)*size); size = (u32) fread(data, sizeof(char), size, src); - fclose(src); + gf_fclose(src); OTI = GPAC_OTI_SCENE_AFX; @@ -413,7 +425,7 @@ static GF_Err gf_import_afx_sc3dmc(GF_MediaImporter *import, Bool mult_desc_allo if (e) goto exit; //gf_isom_set_visual_info(import->dest, track, di, w, h); samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; samp->dataLength = size; if (import->initial_time_offset) samp->DTS = (u64) (import->initial_time_offset*1000); @@ -455,28 +467,51 @@ GF_Err gf_import_mp3(GF_MediaImporter *import) GF_Err e; u16 sr; u32 nb_chan; + Bool force_mpeg4 = GF_FALSE; FILE *in; - u32 hdr, size, max_size, track, di; + u32 hdr, size, max_size, track, di, id3_end = 0; u64 done, tot_size, offset, duration; GF_ISOSample *samp; - in = gf_f64_open(import->in_name, "rb"); + in = gf_fopen(import->in_name, "rb"); if (!in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); + + { + unsigned char id3v2[10]; + u32 pos = (u32) fread(id3v2, sizeof(unsigned char), 10, in); + if (pos == 10) { + /* Did we read an ID3v2 ? */ + if (id3v2[0] == 'I' && id3v2[1] == 'D' && id3v2[2] == '3') { + u32 sz = ((id3v2[9] & 0x7f) + ((id3v2[8] & 0x7f) << 7) + ((id3v2[7] & 0x7f) << 14) + ((id3v2[6] & 0x7f) << 21)); + + while (sz) { + u32 r = (u32) fread(id3v2, sizeof(unsigned char), 1, in); + if (r != 1) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[MP3 import] failed to read ID3\n")); + } + sz--; + } + id3_end = (u32) gf_ftell(in); + } + } + fseek(in, id3_end, SEEK_SET); + } + hdr = gf_mp3_get_next_header(in); if (!hdr) { - fclose(in); + gf_fclose(in); return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Audio isn't MPEG-1/2 audio"); } sr = gf_mp3_sampling_rate(hdr); oti = gf_mp3_object_type_indication(hdr); if (!oti) { - fclose(in); + gf_fclose(in); return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Audio isn't MPEG-1/2 audio"); } if (import->flags & GF_IMPORT_PROBE_ONLY) { - fclose(in); + gf_fclose(in); import->tk_info[0].track_num = 1; import->tk_info[0].type = GF_ISOM_MEDIA_AUDIO; import->tk_info[0].flags = GF_IMPORT_USE_DATAREF; @@ -492,7 +527,12 @@ GF_Err gf_import_mp3(GF_MediaImporter *import) if (!import->esd) { import->esd = gf_odf_desc_esd_new(2); destroy_esd = 1; + } else { + force_mpeg4 = 1; } + if (import->flags & GF_IMPORT_FORCE_MPEG4) + force_mpeg4 = 1; + if (!import->esd->decoderConfig) import->esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); /*update stream type/oti*/ @@ -515,16 +555,28 @@ GF_Err gf_import_mp3(GF_MediaImporter *import) import->final_trackID = import->esd->ESID; if (import->esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) import->esd->decoderConfig->decoderSpecificInfo); import->esd->decoderConfig->decoderSpecificInfo = NULL; - gf_isom_new_mpeg4_description(import->dest, track, import->esd, (import->flags & GF_IMPORT_USE_DATAREF) ? import->in_name : NULL, NULL, &di); + + if (force_mpeg4) { + gf_isom_new_mpeg4_description(import->dest, track, import->esd, (import->flags & GF_IMPORT_USE_DATAREF) ? import->in_name : NULL, NULL, &di); + } else { + GF_GenericSampleDescription udesc; + memset(&udesc, 0, sizeof(GF_GenericSampleDescription)); + udesc.codec_tag = GF_4CC('.', 'm', 'p', '3'); + memcpy(udesc.compressor_name, "\3MP3", 4); + udesc.samplerate = sr; + udesc.nb_channels = nb_chan; + gf_isom_new_generic_sample_description(import->dest, track, (import->flags & GF_IMPORT_USE_DATAREF) ? import->in_name : NULL, NULL, &udesc, &di); + } + gf_isom_set_audio_info(import->dest, track, di, sr, nb_chan, 16); - gf_f64_seek(in, 0, SEEK_END); - tot_size = gf_f64_tell(in); - gf_f64_seek(in, 0, SEEK_SET); + gf_fseek(in, 0, SEEK_END); + tot_size = gf_ftell(in); + gf_fseek(in, id3_end, SEEK_SET); e = GF_OK; samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; duration = import->duration; duration *= sr; @@ -538,7 +590,7 @@ GF_Err gf_import_mp3(GF_MediaImporter *import) /*MP3 stream truncated*/ if (!hdr) break; - offset = gf_f64_tell(in) - 4; + offset = gf_ftell(in) - 4; size = gf_mp3_frame_size(hdr); assert(size); if (size>max_size) { @@ -568,7 +620,7 @@ GF_Err gf_import_mp3(GF_MediaImporter *import) if (duration && (samp->DTS > duration)) break; if (import->flags & GF_IMPORT_DO_ABORT) break; } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_set_progress("Importing MP3", tot_size, tot_size); exit: @@ -577,7 +629,7 @@ exit: import->esd = NULL; } if (samp) gf_isom_sample_del(&samp); - fclose(in); + gf_fclose(in); return e; } @@ -681,7 +733,7 @@ static Bool LOAS_LoadFrame(GF_BitStream *bs, GF_M4ADecSpecInfo *acfg, u32 *nb_by num_lay = gf_bs_read_int(bs, 3); for (j=0; j<=num_lay; j++) { u32 frameLengthType; - Bool same_cfg = 0; + Bool same_cfg = GF_FALSE; if (i || j) same_cfg = gf_bs_read_int(bs, 1); if (!same_cfg) { @@ -752,7 +804,7 @@ GF_Err gf_import_aac_loas(GF_MediaImporter *import) u32 track, di; GF_ISOSample *samp; - in = gf_f64_open(import->in_name, "rb"); + in = gf_fopen(import->in_name, "rb"); if (!in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); bs = gf_bs_from_file(in, GF_BITSTREAM_READ); @@ -771,7 +823,7 @@ GF_Err gf_import_aac_loas(GF_MediaImporter *import) import->tk_info[0].audio_info.sample_rate = sr; import->tk_info[0].audio_info.nb_channels = acfg.nb_chan; gf_bs_del(bs); - fclose(in); + gf_fclose(in); return GF_OK; } @@ -820,7 +872,7 @@ GF_Err gf_import_aac_loas(GF_MediaImporter *import) e = GF_OK; /*add first sample*/ samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; samp->dataLength = nbbytes; samp->data = (char *) aac_buf; @@ -850,7 +902,7 @@ GF_Err gf_import_aac_loas(GF_MediaImporter *import) if (duration && (samp->DTS > duration)) break; if (import->flags & GF_IMPORT_DO_ABORT) break; } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_AUDIO, acfg.audioPL); gf_set_progress("Importing AAC", tot_size, tot_size); @@ -864,7 +916,7 @@ exit: gf_isom_sample_del(&samp); } gf_bs_del(bs); - fclose(in); + gf_fclose(in); return e; } @@ -885,7 +937,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) u32 max_size, track, di, i; GF_ISOSample *samp; - in = gf_f64_open(import->in_name, "rb"); + in = gf_fopen(import->in_name, "rb"); if (!in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); bs = gf_bs_from_file(in, GF_BITSTREAM_READ); @@ -893,7 +945,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) sync_frame = ADTS_SyncFrame(bs, &hdr, &frames_skipped); if (!sync_frame) { gf_bs_del(bs); - fclose(in); + gf_fclose(in); return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Audio isn't MPEG-2/4 AAC with ADTS"); } @@ -902,7 +954,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) sync_frame = LOAS_LoadFrame(bs, &acfg, NULL, NULL); if (sync_frame) { gf_bs_del(bs); - fclose(in); + gf_fclose(in); return gf_import_aac_loas(import); } } @@ -911,7 +963,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) /*keep MPEG-2 AAC OTI even for HE-SBR (that's correct according to latest MPEG-4 audio spec)*/ oti = hdr.is_mp2 ? hdr.profile+GPAC_OTI_AUDIO_AAC_MPEG2_MP-1 : GPAC_OTI_AUDIO_AAC_MPEG4; - timescale = sr = GF_M4ASampleRates[hdr.sr_idx]; + sr = GF_M4ASampleRates[hdr.sr_idx]; if (import->flags & GF_IMPORT_PROBE_ONLY) { import->tk_info[0].track_num = 1; @@ -921,7 +973,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) import->tk_info[0].audio_info.sample_rate = sr; import->tk_info[0].audio_info.nb_channels = hdr.nb_ch; gf_bs_del(bs); - fclose(in); + gf_fclose(in); return GF_OK; } @@ -965,7 +1017,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo)); acfg.base_object_type = hdr.profile; acfg.base_sr = sr; - acfg.nb_chan = hdr.nb_ch; + acfg.nb_chan = gf_m4a_get_channel_cfg(hdr.nb_ch); acfg.sbr_object_type = 0; if (import->flags & GF_IMPORT_SBR_EXPLICIT) { acfg.has_sbr = 1; @@ -1021,9 +1073,10 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) } /*not MPEG4 tool*/ if (0 && hdr.is_mp2) acfg.audioPL = 0xFE; - gf_bs_align(dsi); + timescale = sr; + e = GF_OK; destroy_esd = 0; if (!import->esd) { @@ -1047,7 +1100,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) (import->flags & (GF_IMPORT_PS_IMPLICIT|GF_IMPORT_PS_EXPLICIT)) ? "+PS" : "", ((import->flags & (GF_IMPORT_SBR_EXPLICIT|GF_IMPORT_PS_EXPLICIT)) ? " (explicit) " : " "), sr, - (oti==0x40) ? "MPEG-4" : "MPEG-2", + (oti==GPAC_OTI_AUDIO_AAC_MPEG4) ? "MPEG-4" : "MPEG-2", hdr.nb_ch, (hdr.nb_ch>1) ? "s" : ""); @@ -1065,7 +1118,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) e = GF_OK; /*add first sample*/ samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; max_size = samp->dataLength = hdr.frame_size; samp->data = (char*)gf_malloc(sizeof(char)*hdr.frame_size); offset = gf_bs_get_position(bs); @@ -1109,7 +1162,7 @@ GF_Err gf_import_aac_adts(GF_MediaImporter *import) if (duration && (samp->DTS > duration)) break; if (import->flags & GF_IMPORT_DO_ABORT) break; } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_AUDIO, acfg.audioPL); gf_set_progress("Importing AAC", tot_size, tot_size); @@ -1120,13 +1173,44 @@ exit: } if (samp) gf_isom_sample_del(&samp); gf_bs_del(bs); - fclose(in); + gf_fclose(in); return e; } #endif /*GPAC_DISABLE_AV_PARSERS*/ + +static void update_edit_list_for_bframes(GF_ISOFile *file, u32 track) +{ + u32 i, count, di; + u64 max_cts, min_cts, doff; + + count = gf_isom_get_sample_count(file, track); + max_cts = 0; + min_cts = (u64) -1; + for (i=0; i<count; i++) { + GF_ISOSample *s = gf_isom_get_sample_info(file, track, i+1, &di, &doff); + if (s->DTS + s->CTS_Offset > max_cts) + max_cts = s->DTS + s->CTS_Offset; + + if (min_cts > s->DTS + s->CTS_Offset) + min_cts = s->DTS + s->CTS_Offset; + + gf_isom_sample_del(&s); + } + + if (min_cts) { + max_cts -= min_cts; + max_cts += gf_isom_get_sample_duration(file, track, count); + + max_cts *= gf_isom_get_timescale(file); + max_cts /= gf_isom_get_media_timescale(file, track); + gf_isom_set_edit_segment(file, track, 0, max_cts, min_cts, GF_ISOM_EDIT_NORMAL); + } +} + + #ifndef GPAC_DISABLE_AV_PARSERS static GF_Err gf_import_cmp(GF_MediaImporter *import, Bool mpeg12) @@ -1143,7 +1227,7 @@ static GF_Err gf_import_cmp(GF_MediaImporter *import, Bool mpeg12) GF_BitStream *bs; destroy_esd = forced_packed = 0; - mdia = gf_f64_open(import->in_name, "rb"); + mdia = gf_fopen(import->in_name, "rb"); if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Opening %s failed", import->in_name); bs = gf_bs_from_file(mdia, GF_BITSTREAM_READ); @@ -1297,7 +1381,7 @@ static GF_Err gf_import_cmp(GF_MediaImporter *import, Bool mpeg12) } /*policy is to keep non coded frame (constant frame rate), add*/ } - samp->IsRAP = 0; + samp->IsRAP = RAP_NO; if (ftype==2) { b_frames++; @@ -1312,7 +1396,7 @@ static GF_Err gf_import_cmp(GF_MediaImporter *import, Bool mpeg12) } } else { if (ftype==0) { - samp->IsRAP = 1; + samp->IsRAP = RAP; nbI++; } else { nbP++; @@ -1356,6 +1440,11 @@ static GF_Err gf_import_cmp(GF_MediaImporter *import, Bool mpeg12) if (has_cts_offset) { gf_import_message(import, GF_OK, "Has B-Frames (%d max consecutive B-VOPs)", max_b); gf_isom_set_cts_packing(import->dest, track, 0); + + + if (!(import->flags & GF_IMPORT_NO_EDIT_LIST)) + update_edit_list_for_bframes(import->dest, track); + /*this is plain ugly but since some encoders (divx) don't use the video PL correctly we force the system video_pl to ASP@L5 since we have I, P, B in base layer*/ if (PL<=3) { @@ -1373,7 +1462,7 @@ static GF_Err gf_import_cmp(GF_MediaImporter *import, Bool mpeg12) gf_m4v_rewrite_pl(&import->esd->decoderConfig->decoderSpecificInfo->data, &import->esd->decoderConfig->decoderSpecificInfo->dataLength, (u8) PL); gf_isom_change_mpeg4_description(import->dest, track, 1, import->esd); } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); if (is_vfr) { if (!nbB) { @@ -1397,7 +1486,7 @@ exit: /*this destroys the bitstream as well*/ gf_m4v_parser_del(vparse); - fclose(mdia); + gf_fclose(mdia); return e; } @@ -1424,9 +1513,9 @@ static GF_Err gf_import_avi_video(GF_MediaImporter *import) char *comp, *frame; avi_t *in; - test = gf_f64_open(import->in_name, "rb"); + test = gf_fopen(import->in_name, "rb"); if (!test) return gf_import_message(import, GF_URL_ERROR, "Opening %s failed", import->in_name); - fclose(test); + gf_fclose(test); in = AVI_open_input_file(import->in_name, 1); if (!in) return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Unsupported avi file"); @@ -1446,8 +1535,8 @@ static GF_Err gf_import_avi_video(GF_MediaImporter *import) import->tk_info[i+1].track_num = i+2; import->tk_info[i+1].type = GF_ISOM_MEDIA_AUDIO; import->tk_info[i+1].flags = GF_IMPORT_USE_DATAREF; - import->tk_info[i+1].audio_info.sample_rate = AVI_audio_rate(in); - import->tk_info[i+1].audio_info.nb_channels = AVI_audio_channels(in); + import->tk_info[i+1].audio_info.sample_rate = (u32) AVI_audio_rate(in); + import->tk_info[i+1].audio_info.nb_channels = (u32) AVI_audio_channels(in); import->nb_tracks ++; } AVI_close(in); @@ -1510,7 +1599,7 @@ static GF_Err gf_import_avi_video(GF_MediaImporter *import) max_size = 0; samp_offset = 0; frame = NULL; - num_samples = AVI_video_frames(in); + num_samples = (u32) AVI_video_frames(in); samp = gf_isom_sample_new(); PL = 0; track = 0; @@ -1648,7 +1737,7 @@ proceed: else is_packed = 1; nb_f++; - samp->IsRAP = 0; + samp->IsRAP = RAP_NO; if (ftype==2) { b_frames ++; @@ -1663,7 +1752,7 @@ proceed: } } else { if (!ftype) { - samp->IsRAP = 1; + samp->IsRAP = RAP; nbI++; } else { nbP++; @@ -1718,6 +1807,10 @@ proceed: gf_import_message(import, GF_OK, "Has B-Frames (%d max consecutive B-VOPs%s)", max_b, is_packed ? " - packed bitstream" : ""); /*repack CTS tables and adjust offsets for B-frames*/ gf_isom_set_cts_packing(import->dest, track, 0); + + if (!(import->flags & GF_IMPORT_NO_EDIT_LIST)) + update_edit_list_for_bframes(import->dest, track); + /*this is plain ugly but since some encoders (divx) don't use the video PL correctly we force the system video_pl to ASP@L5 since we have I, P, B in base layer*/ if (PL<=3) { @@ -1739,7 +1832,7 @@ proceed: gf_m4v_rewrite_pl(&import->esd->decoderConfig->decoderSpecificInfo->data, &import->esd->decoderConfig->decoderSpecificInfo->dataLength, (u8) PL); gf_isom_change_mpeg4_description(import->dest, track, 1, import->esd); } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); if (is_vfr) { if (nbB) { @@ -1790,9 +1883,9 @@ GF_Err gf_import_avi_audio(GF_MediaImporter *import) if (import->trackID==1) return GF_OK; - test = gf_f64_open(import->in_name, "rb"); + test = gf_fopen(import->in_name, "rb"); if (!test) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); - fclose(test); + gf_fclose(test); in = AVI_open_input_file(import->in_name, 1); if (!in) return gf_import_message(import, GF_NOT_SUPPORTED, "Unsupported avi file"); @@ -1848,7 +1941,7 @@ GF_Err gf_import_avi_audio(GF_MediaImporter *import) i = 0; tot_size = max_size = 0; - while ((size = AVI_audio_size(in, i) )>0) { + while ((size = (s32) AVI_audio_size(in, i) )>0) { if (max_size<size) max_size=size; tot_size += size; i++; @@ -1868,7 +1961,7 @@ GF_Err gf_import_avi_audio(GF_MediaImporter *import) is_cbr = 1; while (1) { if (AVI_read_audio(in, frame, 4, (int*)&continuous) != 4) break; - offset = gf_f64_tell(in->fdes) - 4; + offset = gf_ftell(in->fdes) - 4; hdr = GF_4CC((u8) frame[0], (u8) frame[1], (u8) frame[2], (u8) frame[3]); size = gf_mp3_frame_size(hdr); @@ -1877,14 +1970,14 @@ GF_Err gf_import_avi_audio(GF_MediaImporter *import) if (max_size) is_cbr = 0; max_size = size; } - size = 4 + AVI_read_audio(in, &frame[4], size - 4, &continuous); + size = 4 + (s32) AVI_read_audio(in, &frame[4], size - 4, &continuous); if ((import->flags & GF_IMPORT_USE_DATAREF) && !continuous) { - gf_import_message(import, GF_IO_ERR, "Cannot use media references, splited input audio frame found"); + gf_import_message(import, GF_IO_ERR, "Cannot use media references, splitted input audio frame found"); e = GF_IO_ERR; goto exit; } - samp->IsRAP = 1; + samp->IsRAP = RAP; samp->data = frame; samp->dataLength = size; if (import->flags & GF_IMPORT_USE_DATAREF) { @@ -1908,7 +2001,7 @@ GF_Err gf_import_avi_audio(GF_MediaImporter *import) samp->data = NULL; gf_isom_sample_del(&samp); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_AUDIO, 0xFE); @@ -1933,7 +2026,7 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) s32 trans_x, trans_y; s16 layer; u8 bps; - char lang[4]; + char *lang; const char *orig_name = gf_url_get_resource_name(gf_isom_get_filename(import->orig)); Bool sbr, ps; GF_ISOSample *samp; @@ -1951,9 +2044,11 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) } else if (import->tk_info[i].type == GF_ISOM_MEDIA_AUDIO) { gf_isom_get_audio_info(import->orig, i+1, 1, &import->tk_info[i].audio_info.sample_rate, &import->tk_info[i].audio_info.nb_channels, NULL); } - lang[3] = 0; - gf_isom_get_media_language(import->orig, i+1, lang); - import->tk_info[i].lang = GF_4CC(' ', lang[0], lang[1], lang[2]); + lang = NULL; + gf_isom_get_media_language(import->orig, i+1, &lang); + if (lang) { + import->tk_info[i].lang = GF_4CC(' ', lang[0], lang[1], lang[2]); + } import->nb_tracks ++; } return GF_OK; @@ -2031,6 +2126,10 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) } gf_odf_desc_del((GF_Descriptor *) iod); + if ( ! gf_isom_get_track_count(import->dest)) { + u32 timescale = gf_isom_get_timescale(import->orig); + gf_isom_set_timescale(import->dest, timescale); + } e = gf_isom_clone_track(import->orig, track_in, import->dest, (import->flags & GF_IMPORT_USE_DATAREF), &track); if (e) goto exit; @@ -2047,6 +2146,8 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_DECODE, import->esd->dependsOnESID); } + mstype = gf_isom_get_media_subtype(import->orig, track_in, di); + switch (mtype) { case GF_ISOM_MEDIA_VISUAL: gf_import_message(import, GF_OK, "IsoMedia import %s - track ID %d - Video (size %d x %d)", orig_name, trackID, w, h); @@ -2084,10 +2185,32 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) gf_isom_sample_del(&samp); } + is_cenc = gf_isom_is_cenc_media(import->orig, track_in, 1); + duration = (u64) (((Double)import->duration * gf_isom_get_media_timescale(import->orig, track_in)) / 1000); gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT); + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + if (is_cenc ) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ISOM import] CENC media detected - cannot switch parameter set storage mode\n")); + } else if (import->flags & GF_IMPORT_USE_DATAREF) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ISOM import] Cannot switch parameter set storage mode when using data reference\n")); + } else { + switch (mstype) { + case GF_4CC('a', 'v', 'c', '1'): + gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG); + gf_isom_avc_set_inband_config(import->dest, track, 1); + break; + case GF_4CC('h', 'v', 'c', '1'): + gf_isom_set_nalu_extract_mode(import->orig, track_in, GF_ISOM_NALU_EXTRACT_INSPECT | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG); + gf_isom_hevc_set_inband_config(import->dest, track, 1); + break; + } + } + } + num_samples = gf_isom_get_sample_count(import->orig, track_in); - is_cenc = gf_isom_is_cenc_media(import->orig, track_in, 1); + if (is_cenc) { u32 container_type; e = gf_isom_cenc_get_sample_aux_info(import->orig, track_in, 0, NULL, &container_type); @@ -2125,7 +2248,12 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) } sampDTS = samp->DTS; gf_isom_sample_del(&samp); + + gf_isom_copy_sample_info(import->dest, track, import->orig, track_in, i+1); + gf_set_progress("Importing ISO File", i+1, num_samples); + + if (duration && (sampDTS > duration) ) break; if (import->flags & GF_IMPORT_DO_ABORT) break; if (e) @@ -2169,12 +2297,26 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) } } + //adjust last sample duration + if (i==num_samples) { + u32 dur = gf_isom_get_sample_duration(import->orig, track_in, num_samples); + gf_isom_set_last_sample_duration(import->dest, track, dur); + } else { + s64 mediaOffset; + if (gf_isom_get_edit_list_type(import->orig, track_in, &mediaOffset)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ISOBMF Import] Multiple edits found in source media, import may be broken\n")); + } + gf_isom_update_edit_list_duration(import->dest, track); + gf_isom_update_duration(import->dest); + } + if (gf_isom_has_time_offset(import->orig, track_in)==2) { e = gf_isom_set_composition_offset_mode(import->dest, track, 1); if (e) goto exit; } + if (import->esd) { if (!import->esd->slConfig) { import->esd->slConfig = origin_esd ? origin_esd->slConfig : NULL; @@ -2186,7 +2328,7 @@ GF_Err gf_import_isomedia(GF_MediaImporter *import) } } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); exit: if (origin_esd) gf_odf_desc_del((GF_Descriptor *) origin_esd); @@ -2332,7 +2474,7 @@ GF_Err gf_import_mpeg_ps_video(GF_MediaImporter *import) samp->data = buf; samp->dataLength = buf_len; samp->DTS = (u64)dts_inc*(frames-1); - samp->IsRAP = (ftype==1) ? 1 : 0; + samp->IsRAP = (ftype==1) ? RAP : RAP_NO; samp->CTS_Offset = 0; e = gf_isom_add_sample(import->dest, track, di, samp); samp->data = NULL; @@ -2352,9 +2494,12 @@ GF_Err gf_import_mpeg_ps_video(GF_MediaImporter *import) if (import->flags & GF_IMPORT_DO_ABORT) break; } gf_isom_set_cts_packing(import->dest, track, 0); + if (!(import->flags & GF_IMPORT_NO_EDIT_LIST)) + update_edit_list_for_bframes(import->dest, track); + if (last_pos!=file_size) gf_set_progress("Importing MPEG-PS Video", frames, frames); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); if (ar) gf_media_change_par(import->dest, track, ar>>16, ar&0xffff); exit: @@ -2452,7 +2597,7 @@ GF_Err gf_import_mpeg_ps_audio(GF_MediaImporter *import) duration = (u64) ((Double)import->duration/1000.0 * sr); samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; samp->DTS = 0; file_size = mpeg2ps_get_ps_size(ps); @@ -2474,7 +2619,7 @@ GF_Err gf_import_mpeg_ps_audio(GF_MediaImporter *import) samp->data = NULL; gf_isom_sample_del(&samp); if (last_pos!=file_size) gf_set_progress("Importing MPEG-PS Audio", frames, frames); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); exit: if (import->esd && destroy_esd) { @@ -2513,14 +2658,14 @@ GF_Err gf_import_nhnt(GF_MediaImporter *import) strcpy(szMedia, szName); strcat(szMedia, ".nhnt"); - nhnt = gf_f64_open(szMedia, "rb"); + nhnt = gf_fopen(szMedia, "rb"); if (!nhnt) return gf_import_message(import, GF_URL_ERROR, "Cannot find NHNT file %s", szMedia); strcpy(szMedia, szName); strcat(szMedia, ".media"); - mdia = gf_f64_open(szMedia, "rb"); + mdia = gf_fopen(szMedia, "rb"); if (!mdia) { - fclose(nhnt); + gf_fclose(nhnt); return gf_import_message(import, GF_URL_ERROR, "Cannot find MEDIA file %s", szMedia); } @@ -2538,20 +2683,20 @@ GF_Err gf_import_nhnt(GF_MediaImporter *import) strcpy(szNhnt, szName); strcat(szNhnt, ".info"); - info = gf_f64_open(szNhnt, "rb"); + info = gf_fopen(szNhnt, "rb"); if (info) { if (import->esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) import->esd->decoderConfig->decoderSpecificInfo); import->esd->decoderConfig->decoderSpecificInfo = NULL; import->esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); - gf_f64_seek(info, 0, SEEK_END); - import->esd->decoderConfig->decoderSpecificInfo->dataLength = (u32) gf_f64_tell(info); + gf_fseek(info, 0, SEEK_END); + import->esd->decoderConfig->decoderSpecificInfo->dataLength = (u32) gf_ftell(info); import->esd->decoderConfig->decoderSpecificInfo->data = (char*)gf_malloc(sizeof(char) * import->esd->decoderConfig->decoderSpecificInfo->dataLength); - gf_f64_seek(info, 0, SEEK_SET); + gf_fseek(info, 0, SEEK_SET); if (0==fread(import->esd->decoderConfig->decoderSpecificInfo->data, 1, import->esd->decoderConfig->decoderSpecificInfo->dataLength, info)) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHML import] Failed to read dataLength\n")); } - fclose(info); + gf_fclose(info); } /*keep parsed dsi (if any) if no .info file exists*/ @@ -2648,9 +2793,9 @@ GF_Err gf_import_nhnt(GF_MediaImporter *import) samp->data = (char*)gf_malloc(sizeof(char) * 1024); max_size = 1024; count = 0; - gf_f64_seek(mdia, 0, SEEK_END); - media_size = gf_f64_tell(mdia); - gf_f64_seek(mdia, 0, SEEK_SET); + gf_fseek(mdia, 0, SEEK_END); + media_size = gf_ftell(mdia); + gf_fseek(mdia, 0, SEEK_SET); media_done = 0; next_is_start = 1; @@ -2693,7 +2838,7 @@ GF_Err gf_import_nhnt(GF_MediaImporter *import) samp->data = (char*)gf_realloc(samp->data, sizeof(char) * samp->dataLength); max_size = samp->dataLength; } - gf_f64_seek(mdia, offset, SEEK_SET); + gf_fseek(mdia, offset, SEEK_SET); if (0==fread( samp->data, 1, samp->dataLength, mdia)) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Failed to read samp->dataLength\n")); } @@ -2712,12 +2857,12 @@ GF_Err gf_import_nhnt(GF_MediaImporter *import) } if (media_done!=media_size) gf_set_progress("Importing NHNT", (u32) (media_size/1024), (u32) (media_size/1024)); gf_isom_sample_del(&samp); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); exit: gf_bs_del(bs); - fclose(nhnt); - fclose(mdia); + gf_fclose(nhnt); + gf_fclose(mdia); if (import->esd && destroy_esd) { gf_odf_desc_del((GF_Descriptor *) import->esd); import->esd = NULL; @@ -2793,19 +2938,31 @@ static void nhml_node_end(void *sax_cbck, const char *node_name, const char *nam GF_Err gf_import_sample_from_xml(GF_MediaImporter *import, GF_ISOSample *samp, char *xml_file, char *xmlFrom, char *xmlTo, u32 *max_size) { GF_Err e; + u32 read; XMLBreaker breaker; char *tmp; FILE *xml; - + u8 szBOM[3]; if (!xml_file || !xmlFrom || !xmlTo) return GF_BAD_PARAM; memset(&breaker, 0, sizeof(XMLBreaker)); - xml = gf_f64_open(xml_file, "rb"); + xml = gf_fopen(xml_file, "rb"); if (!xml) { e = gf_import_message(import, GF_BAD_PARAM, "NHML import failure: file %s not found", xml_file); goto exit; } + //we cannot use files with BOM since the XML position we get from the parser are offsets in the UTF-8 version of the XML. + //TODO: to support files with BOM we would need to serialize on the fly the callback from the sax parser + read = (u32) fread(szBOM, 1, 3, xml); + if (read==3) { + fseek(xml, 0, SEEK_SET); + if ((szBOM[0]==0xFF) || (szBOM[0]==0xFE) || (szBOM[0]==0xEF)) { + e = gf_import_message(import, GF_NOT_SUPPORTED, "NHML import failure: XML file %s uses BOM, please convert to plin UTF-8 or ANSI first", xml_file); + goto exit; + } + } + memset(&breaker, 0, sizeof(XMLBreaker)); breaker.id_stack = gf_list_new(); @@ -2835,9 +2992,9 @@ GF_Err gf_import_sample_from_xml(GF_MediaImporter *import, GF_ISOSample *samp, c e = GF_OK; if (!breaker.to_id) { - gf_f64_seek(xml, 0, SEEK_END); - breaker.to_pos = gf_f64_tell(xml); - gf_f64_seek(xml, 0, SEEK_SET); + gf_fseek(xml, 0, SEEK_END); + breaker.to_pos = gf_ftell(xml); + gf_fseek(xml, 0, SEEK_SET); } if(breaker.to_pos < breaker.from_pos) { e = gf_import_message(import, GF_BAD_PARAM, "NHML import failure: xmlFrom %s is located after xmlTo %s", xmlFrom, xmlTo); @@ -2851,13 +3008,13 @@ GF_Err gf_import_sample_from_xml(GF_MediaImporter *import, GF_ISOSample *samp, c *max_size = samp->dataLength; samp->data = (char*)gf_realloc(samp->data, sizeof(char)*samp->dataLength); } - gf_f64_seek(xml, breaker.from_pos, SEEK_SET); + gf_fseek(xml, breaker.from_pos, SEEK_SET); if (0==fread(samp->data, 1, samp->dataLength, xml)) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Failed to read samp->dataLength\n")); } exit: - if (xml) fclose(xml); + if (xml) gf_fclose(xml); while (gf_list_count(breaker.id_stack)) { char *id = (char *)gf_list_last(breaker.id_stack); gf_list_rem_last(breaker.id_stack); @@ -2924,7 +3081,7 @@ static GF_Err compress_sample_data(GF_ISOSample *samp, u32 *max_size, char **dic } memcpy(samp->data + offset, dest, sizeof(char)*stream.total_out); - samp->dataLength = offset + stream.total_out; + samp->dataLength = (u32) (offset + stream.total_out); gf_free(dest); deflateEnd(&stream); @@ -2952,14 +3109,15 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) GF_Err e; GF_DIMSDescription dims; Bool destroy_esd, inRootOD, do_compress, use_dict, is_dims; - u32 i, track, tkID, di, mtype, max_size, count, streamType, oti, timescale, specInfoSize, dts_inc, par_den, par_num; + u32 i, track, tkID, di, mtype, max_size, count, streamType, oti, timescale, specInfoSize, header_end, dts_inc, par_den, par_num; GF_ISOSample *samp; GF_XMLAttribute *att; s64 media_size, media_done, offset; u64 duration, sample_duration; FILE *nhml, *mdia, *info; char *dictionary = NULL; - char *ext, szName[1000], szMedia[1000], szMediaTemp[1000], szInfo[1000], szXmlFrom[1000], szXmlTo[1000], *specInfo; + char *ext, szName[1000], szMedia[1000], szMediaTemp[1000], szInfo[1000], szXmlFrom[1000], szXmlTo[1000], szXmlHeaderEnd[1000]; + char *specInfo; GF_GenericSampleDescription sdesc; GF_DOMParser *parser; GF_XMLNode *root, *node, *childnode; @@ -2976,8 +3134,8 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) import->tk_info[0].flags = GF_IMPORT_USE_DATAREF; return GF_OK; } - nhml = gf_f64_open(import->in_name, "rt"); - if (!nhml) return gf_import_message(import, GF_URL_ERROR, "Cannot find %s file %s", szImpName, szMedia); + nhml = gf_fopen(import->in_name, "rt"); + if (!nhml) return gf_import_message(import, GF_URL_ERROR, "Cannot find %s file %s", szImpName, import->in_name); strcpy(szName, import->in_name); ext = strrchr(szName, '.'); @@ -2991,7 +3149,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) parser = gf_xml_dom_new(); e = gf_xml_dom_parse(parser, import->in_name, nhml_on_progress, import); if (e) { - fclose(nhml); + gf_fclose(nhml); gf_import_message(import, e, "Error parsing %s file: Line %d - %s", szImpName, gf_xml_dom_get_line(parser), gf_xml_dom_get_error(parser)); gf_xml_dom_del(parser); return e; @@ -3025,87 +3183,133 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) tkID = mtype = streamType = oti = par_den = par_num = 0; timescale = 1000; i=0; + strcpy(szXmlHeaderEnd, ""); + header_end = 0; + while ((att = (GF_XMLAttribute *)gf_list_enum(root->attributes, &i))) { - if (!stricmp(att->name, "streamType")) NHML_SCAN_INT("%u", streamType) - else if (!stricmp(att->name, "mediaType") && (strlen(att->value)==4)) { - mtype = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]); - } - else if (!stricmp(att->name, "mediaSubType") && (strlen(att->value)==4)) { - sdesc.codec_tag = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]); - } - else if (!stricmp(att->name, "objectTypeIndication")) NHML_SCAN_INT("%u", oti) - else if (!stricmp(att->name, "timeScale")) NHML_SCAN_INT("%u", timescale) - else if (!stricmp(att->name, "width")) NHML_SCAN_INT("%hu", sdesc.width) - else if (!stricmp(att->name, "height")) NHML_SCAN_INT("%hu", sdesc.height) - else if (!stricmp(att->name, "parNum")) NHML_SCAN_INT("%u", par_num) - else if (!stricmp(att->name, "parDen")) NHML_SCAN_INT("%u", par_den) - else if (!stricmp(att->name, "sampleRate")) NHML_SCAN_INT("%u", sdesc.samplerate) - else if (!stricmp(att->name, "numChannels")) NHML_SCAN_INT("%hu", sdesc.nb_channels) - else if (!stricmp(att->name, "baseMediaFile")) strcpy(szMedia, att->value); - else if (!stricmp(att->name, "specificInfoFile")) strcpy(szInfo, att->value); - else if (!stricmp(att->name, "trackID")) NHML_SCAN_INT("%u", tkID) - else if (!stricmp(att->name, "inRootOD")) inRootOD = (!stricmp(att->value, "yes") ); - else if (!stricmp(att->name, "DTS_increment")) NHML_SCAN_INT("%u", dts_inc) - else if (!stricmp(att->name, "gzipSamples")) do_compress = (!stricmp(att->value, "yes")) ? 1 : 0; - else if (!stricmp(att->name, "gzipDictionary")) { - u64 d_size; - if (stricmp(att->value, "self")) { - FILE *d = gf_f64_open(att->value, "rb"); - if (!d) { - gf_import_message(import, GF_IO_ERR, "Cannot open dictionary file %s", att->value); - continue; - } - gf_f64_seek(d, 0, SEEK_END); - d_size = gf_f64_tell(d); - dictionary = (char*)gf_malloc(sizeof(char)*(size_t)(d_size+1)); - gf_f64_seek(d, 0, SEEK_SET); - d_size = fread(dictionary, sizeof(char), (size_t)d_size, d); - dictionary[d_size]=0; - } - use_dict = 1; - } + if (!stricmp(att->name, "streamType")) { + NHML_SCAN_INT("%u", streamType) + } else if (!stricmp(att->name, "mediaType") && (strlen(att->value)==4)) { + mtype = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]); + } else if (!stricmp(att->name, "mediaSubType") && (strlen(att->value)==4)) { + sdesc.codec_tag = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]); + } else if (!stricmp(att->name, "objectTypeIndication")) { + NHML_SCAN_INT("%u", oti) + } else if (!stricmp(att->name, "timeScale")) { + NHML_SCAN_INT("%u", timescale) + } else if (!stricmp(att->name, "width")) { + NHML_SCAN_INT("%hu", sdesc.width) + } else if (!stricmp(att->name, "height")) { + NHML_SCAN_INT("%hu", sdesc.height) + } else if (!stricmp(att->name, "parNum")) { + NHML_SCAN_INT("%u", par_num) + } else if (!stricmp(att->name, "parDen")) { + NHML_SCAN_INT("%u", par_den) + } else if (!stricmp(att->name, "sampleRate")) { + NHML_SCAN_INT("%u", sdesc.samplerate) + } else if (!stricmp(att->name, "numChannels")) { + NHML_SCAN_INT("%hu", sdesc.nb_channels) + } else if (!stricmp(att->name, "baseMediaFile")) { + strcpy(szMedia, att->value); + } else if (!stricmp(att->name, "specificInfoFile")) { + strcpy(szInfo, att->value); + } else if (!stricmp(att->name, "headerEnd")) { + NHML_SCAN_INT("%u", header_end) + } else if (!stricmp(att->name, "trackID")) { + NHML_SCAN_INT("%u", tkID) + } else if (!stricmp(att->name, "inRootOD")) { + inRootOD = (!stricmp(att->value, "yes") ); + } else if (!stricmp(att->name, "DTS_increment")) { + NHML_SCAN_INT("%u", dts_inc) + } else if (!stricmp(att->name, "gzipSamples")) { + do_compress = (!stricmp(att->value, "yes")) ? 1 : 0; + } else if (!stricmp(att->name, "gzipDictionary")) { + u64 d_size; + if (stricmp(att->value, "self")) { + FILE *d = gf_fopen(att->value, "rb"); + if (!d) { + gf_import_message(import, GF_IO_ERR, "Cannot open dictionary file %s", att->value); + continue; + } + gf_fseek(d, 0, SEEK_END); + d_size = gf_ftell(d); + dictionary = (char*)gf_malloc(sizeof(char)*(size_t)(d_size+1)); + gf_fseek(d, 0, SEEK_SET); + d_size = fread(dictionary, sizeof(char), (size_t)d_size, d); + dictionary[d_size]=0; + } + use_dict = 1; + } /*unknow desc related*/ - else if (!stricmp(att->name, "compressorName")) strcpy(sdesc.compressor_name, att->value); - else if (!stricmp(att->name, "codecVersion")) NHML_SCAN_INT("%hu", sdesc.version) - else if (!stricmp(att->name, "codecRevision")) NHML_SCAN_INT("%hu", sdesc.revision) - else if (!stricmp(att->name, "codecVendor") && (strlen(att->value)==4)) { - sdesc.vendor_code = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]); - } - else if (!stricmp(att->name, "temporalQuality")) NHML_SCAN_INT("%u", sdesc.temporal_quality) - else if (!stricmp(att->name, "spatialQuality")) NHML_SCAN_INT("%u", sdesc.spatial_quality) - else if (!stricmp(att->name, "horizontalResolution")) NHML_SCAN_INT("%u", sdesc.h_res) - else if (!stricmp(att->name, "verticalResolution")) NHML_SCAN_INT("%u", sdesc.v_res) - else if (!stricmp(att->name, "bitDepth")) NHML_SCAN_INT("%hu", sdesc.depth) - else if (!stricmp(att->name, "bitsPerSample")) NHML_SCAN_INT("%hu", sdesc.bits_per_sample) - - /*DIMS stuff*/ - else if (!stricmp(att->name, "profile")) NHML_SCAN_INT("%c", dims.profile) - else if (!stricmp(att->name, "level")) NHML_SCAN_INT("%c", dims.level) - else if (!stricmp(att->name, "pathComponents")) NHML_SCAN_INT("%c", dims.pathComponents) - else if (!stricmp(att->name, "useFullRequestHost") && !stricmp(att->value, "yes")) dims.fullRequestHost = 1; - else if (!stricmp(att->name, "stream_type") && !stricmp(att->value, "secondary")) dims.streamType = 0; - else if (!stricmp(att->name, "contains_redundant")) { - if (!stricmp(att->value, "main")) dims.containsRedundant = 1; - else if (!stricmp(att->value, "redundant")) dims.containsRedundant = 2; - else if (!stricmp(att->value, "main+redundant")) dims.containsRedundant = 3; - } - else if (!stricmp(att->name, "text_encoding")) dims.textEncoding = att->value; - else if (!stricmp(att->name, "content_encoding")) { - if (!strcmp(att->value, "deflate")) { - dims.contentEncoding = att->value; - do_compress = 1; - } - } - else if (!stricmp(att->name, "content_script_types")) dims.content_script_types = att->value; - else if (!stricmp(att->name, "mime_type")) dims.mime_type = att->value; - else if (!stricmp(att->name, "media_namespace")) dims.mime_type = att->value; - else if (!stricmp(att->name, "media_schema_location")) dims.xml_schema_loc = att->value; - else if (!stricmp(att->name, "xml_namespace")) dims.contentEncoding = att->value; - else if (!stricmp(att->name, "xml_schema_location")) dims.xml_schema_loc = att->value; - - } - if (sdesc.samplerate && !timescale) timescale = sdesc.samplerate; - if (!sdesc.bits_per_sample) sdesc.bits_per_sample = 16; + else if (!stricmp(att->name, "compressorName")) { + strcpy(sdesc.compressor_name, att->value); + } else if (!stricmp(att->name, "codecVersion")) { + NHML_SCAN_INT("%hu", sdesc.version) + } else if (!stricmp(att->name, "codecRevision")) { + NHML_SCAN_INT("%hu", sdesc.revision) + } else if (!stricmp(att->name, "codecVendor") && (strlen(att->value)==4)) { + sdesc.vendor_code = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]); + } else if (!stricmp(att->name, "temporalQuality")) { + NHML_SCAN_INT("%u", sdesc.temporal_quality) + } else if (!stricmp(att->name, "spatialQuality")) { + NHML_SCAN_INT("%u", sdesc.spatial_quality) + } else if (!stricmp(att->name, "horizontalResolution")) { + NHML_SCAN_INT("%u", sdesc.h_res) + } else if (!stricmp(att->name, "verticalResolution")) { + NHML_SCAN_INT("%u", sdesc.v_res) + } else if (!stricmp(att->name, "bitDepth")) { + NHML_SCAN_INT("%hu", sdesc.depth) + } else if (!stricmp(att->name, "bitsPerSample")) { + NHML_SCAN_INT("%hu", sdesc.bits_per_sample) + } + /*DIMS stuff*/ + else if (!stricmp(att->name, "profile")) { + NHML_SCAN_INT("%c", dims.profile) + } else if (!stricmp(att->name, "level")) { + NHML_SCAN_INT("%c", dims.level) + } else if (!stricmp(att->name, "pathComponents")) { + NHML_SCAN_INT("%c", dims.pathComponents) + } else if (!stricmp(att->name, "useFullRequestHost") && !stricmp(att->value, "yes")) { + dims.fullRequestHost = 1; + } else if (!stricmp(att->name, "stream_type") && !stricmp(att->value, "secondary")) { + dims.streamType = 0; + } else if (!stricmp(att->name, "contains_redundant")) { + if (!stricmp(att->value, "main")) { + dims.containsRedundant = 1; + } else if (!stricmp(att->value, "redundant")) { + dims.containsRedundant = 2; + } else if (!stricmp(att->value, "main+redundant")) { + dims.containsRedundant = 3; + } + } else if (!stricmp(att->name, "text_encoding")) { + dims.textEncoding = att->value; + } else if (!stricmp(att->name, "content_encoding")) { + if (!strcmp(att->value, "deflate")) { + dims.contentEncoding = att->value; + do_compress = 1; + } + } else if (!stricmp(att->name, "content_script_types")) { + dims.content_script_types = att->value; + } else if (!stricmp(att->name, "mime_type")) { + dims.mime_type = att->value; + } else if (!stricmp(att->name, "media_namespace")) { + dims.mime_type = att->value; + } else if (!stricmp(att->name, "media_schema_location")) { + dims.xml_schema_loc = att->value; + } else if (!stricmp(att->name, "xml_namespace")) { + dims.mime_type = att->value; + } else if (!stricmp(att->name, "xml_schema_location")) { + dims.xml_schema_loc = att->value; + } else if (!stricmp(att->name, "xmlHeaderEnd")) { + strcpy(szXmlHeaderEnd, att->value); + } + } + if (sdesc.samplerate && !timescale) { + timescale = sdesc.samplerate; + } + if (!sdesc.bits_per_sample) { + sdesc.bits_per_sample = 16; + } if (dims_doc || (sdesc.codec_tag==GF_ISOM_SUBTYPE_3GP_DIMS)) { mtype = GF_ISOM_MEDIA_DIMS; @@ -3115,7 +3319,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) import->flags &= ~GF_IMPORT_USE_DATAREF; } - mdia = gf_f64_open(szMedia, "rb"); + mdia = gf_fopen(szMedia, "rb"); specInfoSize = 0; if (!streamType && !mtype && !sdesc.codec_tag) { @@ -3123,14 +3327,36 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) goto exit; } - info = gf_f64_open(szInfo, "rb"); + info = gf_fopen(szInfo, "rb"); if (info) { - gf_f64_seek(info, 0, SEEK_END); - specInfoSize = (u32) gf_f64_tell(info); + gf_fseek(info, 0, SEEK_END); + specInfoSize = (u32) gf_ftell(info); specInfo = (char*)gf_malloc(sizeof(char) * specInfoSize); - gf_f64_seek(info, 0, SEEK_SET); + gf_fseek(info, 0, SEEK_SET); specInfoSize = (u32) fread(specInfo, sizeof(char), specInfoSize, info); - fclose(info); + gf_fclose(info); + } else if (header_end) { + /* for text based streams, the decoder specific info can be at the beginning of the file */ + specInfoSize = header_end; + specInfo = (char*)gf_malloc(sizeof(char) * (specInfoSize+1)); + specInfoSize = (u32) fread(specInfo, sizeof(char), specInfoSize, mdia); + specInfo[specInfoSize] = 0; + header_end = specInfoSize; + } else if (strlen(szXmlHeaderEnd)) { + /* for XML based streams, the decoder specific info can be up to some element in the file */ + samp = gf_isom_sample_new(); + max_size = 0; + strcpy(szXmlFrom, "doc.start"); + e = gf_import_sample_from_xml(import, samp, szMedia, szXmlFrom, szXmlHeaderEnd, &max_size); + if (e) { + gf_isom_sample_del(&samp); + goto exit; + } + specInfo = (char*)gf_malloc(sizeof(char) * (samp->dataLength+1)); + memcpy(specInfo, samp->data, samp->dataLength); + specInfoSize = samp->dataLength; + specInfo[specInfoSize] = 0; + gf_isom_sample_del(&samp); } i=0; @@ -3238,17 +3464,46 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) if (e) goto exit; gf_import_message(import, GF_OK, "3GPP DIMS import"); - } else if (mtype == GF_ISOM_MEDIA_MPEG_SUBT) { + } else if (mtype == GF_ISOM_MEDIA_MPEG_SUBT || mtype == GF_ISOM_MEDIA_SUBT || mtype == GF_ISOM_MEDIA_TEXT) { + track = gf_isom_new_track(import->dest, tkID, mtype, timescale); + if (!track) { + e = gf_isom_last_error(import->dest); + goto exit; + } + if(sdesc.codec_tag == GF_ISOM_SUBTYPE_STPP) { + e = gf_isom_new_xml_subtitle_description(import->dest, track, + dims.mime_type, dims.xml_schema_loc, NULL, + &di); + } else if (sdesc.codec_tag == GF_ISOM_SUBTYPE_SBTT) { + e = gf_isom_new_stxt_description(import->dest, track, GF_ISOM_SUBTYPE_SBTT, + dims.mime_type, dims.textEncoding, specInfo, + &di); + } else if (sdesc.codec_tag == GF_ISOM_SUBTYPE_STXT) { + e = gf_isom_new_stxt_description(import->dest, track, GF_ISOM_SUBTYPE_STXT, + dims.mime_type, dims.textEncoding, specInfo, + &di); + } else { + e = GF_NOT_SUPPORTED; + } + if (e) goto exit; + } else if (mtype == GF_ISOM_MEDIA_META) { track = gf_isom_new_track(import->dest, tkID, mtype, timescale); if (!track) { e = gf_isom_last_error(import->dest); goto exit; } - e = gf_isom_new_xml_subtitle_description(import->dest, track, - (char *)dims.contentEncoding, (char *)dims.xml_schema_loc, (char *)dims.mime_type, - &di); + if(sdesc.codec_tag == GF_ISOM_SUBTYPE_METX) { + e = gf_isom_new_xml_metadata_description(import->dest, track, + dims.mime_type, dims.xml_schema_loc, dims.textEncoding, + &di); + } else if (sdesc.codec_tag == GF_ISOM_SUBTYPE_METT) { + e = gf_isom_new_stxt_description(import->dest, track, GF_ISOM_SUBTYPE_METT, + dims.mime_type, dims.textEncoding, specInfo, + &di); + } else { + e = GF_NOT_SUPPORTED; + } if (e) goto exit; - } else { char szT[5]; sdesc.extension_buf = specInfo; @@ -3292,13 +3547,14 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) count = 0; media_size = 0; if (mdia) { - gf_f64_seek(mdia, 0, SEEK_END); - media_size = gf_f64_tell(mdia); - gf_f64_seek(mdia, 0, SEEK_SET); + gf_fseek(mdia, 0, SEEK_END); + media_size = gf_ftell(mdia); + gf_fseek(mdia, 0, SEEK_SET); } - media_done = 0; + /* if we've read the header from the same file, mark the header data as used */ + media_done = header_end; - samp->IsRAP = 1; + samp->IsRAP = RAP; i=0; while ((node = (GF_XMLNode *) gf_list_enum(root->content, &i))) { u32 j, dims_flags; @@ -3331,9 +3587,9 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) } else if (!stricmp(att->name, "CTSOffset")) samp->CTS_Offset = atoi(att->value); else if (!stricmp(att->name, "isRAP") && !samp->IsRAP) { - samp->IsRAP = (!stricmp(att->value, "yes")) ? 1 : 0; + samp->IsRAP = (!stricmp(att->value, "yes")) ? RAP : RAP_NO; } - else if (!stricmp(att->name, "isSyncShadow")) samp->IsRAP = !stricmp(att->value, "yes") ? 2 : 0; + else if (!stricmp(att->name, "isSyncShadow")) samp->IsRAP = !stricmp(att->value, "yes") ? RAP_REDUNDANT : RAP_NO; else if (!stricmp(att->name, "mediaOffset")) offset = (s64) atof(att->value) ; else if (!stricmp(att->name, "dataLength")) samp->dataLength = atoi(att->value); else if (!stricmp(att->name, "mediaFile")) strcpy(szMediaTemp, att->value); @@ -3344,7 +3600,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) dims_flags |= GF_DIMS_UNIT_S; else if (!stricmp(att->name, "is-RAP") && !stricmp(att->value, "yes")) { dims_flags |= GF_DIMS_UNIT_M; - samp->IsRAP = 1; + samp->IsRAP = RAP; } else if (!stricmp(att->name, "is-redundant") && !stricmp(att->value, "yes")) dims_flags |= GF_DIMS_UNIT_I; @@ -3357,7 +3613,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) else if (!stricmp(att->name, "duration") ) sscanf(att->value, ""LLU, &sample_duration); } - if (samp->IsRAP==1) + if (samp->IsRAP==RAP) dims_flags |= GF_DIMS_UNIT_M; if (!count && samp->DTS) samp->DTS = 0; @@ -3411,12 +3667,12 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) e = gf_xml_parse_bit_sequence(node, &samp->data, &samp->dataLength); max_size = samp->dataLength; } else { - Bool close = 0; + Bool close = GF_FALSE; FILE *f = mdia; if (strlen(szMediaTemp)) { - f = gf_f64_open(szMediaTemp, "rb"); - close = 1; - if (offset) gf_f64_seek(f, offset, SEEK_SET); + f = gf_fopen(szMediaTemp, "rb"); + close = GF_TRUE; + if (offset) gf_fseek(f, offset, SEEK_SET); } else { if (!offset) offset = media_done; } @@ -3426,14 +3682,14 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) } if (!samp->dataLength) { - u64 cur_pos = gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_END); - assert(gf_f64_tell(f) < 1<<31); - samp->dataLength = (u32) gf_f64_tell(f); - gf_f64_seek(f, cur_pos, SEEK_SET); + u64 cur_pos = gf_ftell(f); + gf_fseek(f, 0, SEEK_END); + assert(gf_ftell(f) < 1<<31); + samp->dataLength = (u32) gf_ftell(f); + gf_fseek(f, cur_pos, SEEK_SET); } - gf_f64_seek(f, offset, SEEK_SET); + gf_fseek(f, offset, SEEK_SET); if (is_dims) { GF_BitStream *bs; if (samp->dataLength+3>max_size) { @@ -3458,10 +3714,10 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) max_size = samp->dataLength; } if (samp->dataLength != fread( samp->data, sizeof(char), samp->dataLength, f)) { - GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHML import dims] Failed to fully read samp->dataLength\n")); + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[NHML import] Failed to fully read samp->dataLength\n")); } } - if (close) fclose(f); + if (close) gf_fclose(f); } if (e) goto exit; @@ -3492,7 +3748,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) } - if ((samp->IsRAP==2) && !is_dims) { + if ((samp->IsRAP==RAP_REDUNDANT) && !is_dims) { e = gf_isom_add_sample_shadow(import->dest, track, samp); } else if (append) { e = gf_isom_append_sample_data(import->dest, track, samp->data, samp->dataLength); @@ -3500,7 +3756,7 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) e = gf_isom_add_sample(import->dest, track, di, samp); } if (e) goto exit; - samp->IsRAP = 0; + samp->IsRAP = RAP_NO; samp->CTS_Offset = 0; if (sample_duration) samp->DTS += sample_duration; @@ -3517,17 +3773,17 @@ GF_Err gf_import_nhml_dims(GF_MediaImporter *import, Bool dims_doc) } if (media_done!=media_size) gf_set_progress(is_dims ? "Importing DIMS" : "Importing NHML", (u32) media_size, (u32) media_size); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); if (inRootOD) gf_isom_add_track_to_root_od(import->dest, track); exit: - fclose(nhml); + gf_fclose(nhml); if (samp) { samp->dataLength = 1; gf_isom_sample_del(&samp); } - if (mdia) fclose(mdia); + if (mdia) gf_fclose(mdia); if (import->esd && destroy_esd) { gf_odf_desc_del((GF_Descriptor *) import->esd); import->esd = NULL; @@ -3560,7 +3816,7 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) return GF_OK; } - mdia = gf_f64_open(import->in_name, "rb"); + mdia = gf_fopen(import->in_name, "rb"); if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Cannot find file %s", import->in_name); update_gpp_cfg = 0; @@ -3568,38 +3824,38 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) sample_rate = 8000; block_size = 160; if (6 > fread(magic, sizeof(char), 20, mdia)) { - fclose(mdia); + gf_fclose(mdia); return gf_import_message(import, GF_URL_ERROR, "Cannot guess type for file %s, size lower than 6", import->in_name); } if (!strnicmp(magic, "#!AMR\n", 6)) { gf_import_message(import, GF_OK, "Importing AMR Audio"); - gf_f64_seek(mdia, 6, SEEK_SET); + gf_fseek(mdia, 6, SEEK_SET); mtype = GF_ISOM_SUBTYPE_3GP_AMR; update_gpp_cfg = 1; msg = "Importing AMR"; } else if (!strnicmp(magic, "#!EVRC\n", 7)) { gf_import_message(import, GF_OK, "Importing EVRC Audio"); - gf_f64_seek(mdia, 7, SEEK_SET); + gf_fseek(mdia, 7, SEEK_SET); mtype = GF_ISOM_SUBTYPE_3GP_EVRC; oti = GPAC_OTI_AUDIO_EVRC_VOICE; msg = "Importing EVRC"; } else if (!strnicmp(magic, "#!SMV\n", 6)) { gf_import_message(import, GF_OK, "Importing SMV Audio"); - gf_f64_seek(mdia, 6, SEEK_SET); + gf_fseek(mdia, 6, SEEK_SET); mtype = GF_ISOM_SUBTYPE_3GP_SMV; oti = GPAC_OTI_AUDIO_SMV_VOICE; msg = "Importing SMV"; } else if (!strnicmp(magic, "#!AMR_MC1.0\n", 12)) { - fclose(mdia); + gf_fclose(mdia); return gf_import_message(import, GF_NOT_SUPPORTED, "Multichannel AMR Audio Not Supported"); } else if (!strnicmp(magic, "#!AMR-WB\n", 9)) { gf_import_message(import, GF_OK, "Importing AMR WideBand Audio"); - gf_f64_seek(mdia, 9, SEEK_SET); + gf_fseek(mdia, 9, SEEK_SET); mtype = GF_ISOM_SUBTYPE_3GP_AMR_WB; sample_rate = 16000; block_size = 320; @@ -3607,7 +3863,7 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) msg = "Importing AMR-WB"; } else if (!strnicmp(magic, "#!AMR-WB_MC1.0\n", 15)) { - fclose(mdia); + gf_fclose(mdia); return gf_import_message(import, GF_NOT_SUPPORTED, "Multichannel AMR WideBand Audio Not Supported"); } else { @@ -3631,11 +3887,11 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) msg = "Importing SMV"; } else { - fclose(mdia); + gf_fclose(mdia); return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Corrupted AMR/SMV/EVRC file header"); } - gf_f64_seek(mdia, 0, SEEK_SET); + gf_fseek(mdia, 0, SEEK_SET); gf_import_message(import, GF_OK, "Importing %s Audio (File header corrupted, missing \"#!%s\\n\")", ext, ext); } @@ -3685,11 +3941,11 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) samp = gf_isom_sample_new(); samp->data = (char*)gf_malloc(sizeof(char) * 200); - samp->IsRAP = 1; - offset = gf_f64_tell(mdia); - gf_f64_seek(mdia, 0, SEEK_END); - media_size = gf_f64_tell(mdia) - offset; - gf_f64_seek(mdia, offset, SEEK_SET); + samp->IsRAP = RAP; + offset = gf_ftell(mdia); + gf_fseek(mdia, 0, SEEK_END); + media_size = gf_ftell(mdia) - offset; + gf_fseek(mdia, offset, SEEK_SET); media_done = 0; nb_frames = 0; @@ -3697,7 +3953,7 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) while (!feof(mdia)) { u8 ft, toc; - offset = gf_f64_tell(mdia); + offset = gf_ftell(mdia); toc = fgetc(mdia); switch (gpp_cfg.type) { case GF_ISOM_SUBTYPE_3GP_AMR: @@ -3760,7 +4016,7 @@ GF_Err gf_import_amr_evrc_smv(GF_MediaImporter *import) gf_isom_sample_del(&samp); gf_isom_refresh_size_info(import->dest, track); - if (import->flags & GF_IMPORT_FORCE_MPEG4) MP4T_RecomputeBitRate(import->dest, track); + if (import->flags & GF_IMPORT_FORCE_MPEG4) gf_media_update_bitrate(import->dest, track); if (update_gpp_cfg) gf_isom_3gp_config_update(import->dest, track, &gpp_cfg, 1); @@ -3769,7 +4025,7 @@ exit: gf_odf_desc_del((GF_Descriptor *) import->esd); import->esd = NULL; } - fclose(mdia); + gf_fclose(mdia); return e; } @@ -3806,7 +4062,7 @@ GF_Err gf_import_qcp(GF_MediaImporter *import) memset(&gpp_cfg, 0, sizeof(GF_3GPConfig)); delete_esd = 0; - mdia = gf_f64_open(import->in_name, "rb"); + mdia = gf_fopen(import->in_name, "rb"); if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Cannot find file %s", import->in_name); bs = gf_bs_from_file(mdia, GF_BITSTREAM_READ); @@ -3951,12 +4207,12 @@ GF_Err gf_import_qcp(GF_MediaImporter *import) samp = gf_isom_sample_new(); samp->data = (char*)gf_malloc(sizeof(char) * 200); - samp->IsRAP = 1; + samp->IsRAP = RAP; max_size = 200; - offset = gf_f64_tell(mdia); - gf_f64_seek(mdia, 0, SEEK_END); - media_size = gf_f64_tell(mdia) - offset; - gf_f64_seek(mdia, offset, SEEK_SET); + offset = gf_ftell(mdia); + gf_fseek(mdia, 0, SEEK_END); + media_size = gf_ftell(mdia) - offset; + gf_fseek(mdia, offset, SEEK_SET); nb_pck = 0; media_done = 0; @@ -4033,7 +4289,7 @@ GF_Err gf_import_qcp(GF_MediaImporter *import) } gf_isom_sample_del(&samp); gf_isom_set_brand_info(import->dest, GF_ISOM_BRAND_3G2A, 65536); - if (import->flags & GF_IMPORT_FORCE_MPEG4) MP4T_RecomputeBitRate(import->dest, track); + if (import->flags & GF_IMPORT_FORCE_MPEG4) gf_media_update_bitrate(import->dest, track); gf_set_progress("Importing QCP", size_in_packets, size_in_packets); exit: @@ -4042,7 +4298,7 @@ exit: import->esd = NULL; } gf_bs_del(bs); - fclose(mdia); + gf_fclose(mdia); return e; } @@ -4129,7 +4385,7 @@ GF_Err gf_import_h263(GF_MediaImporter *import) FILE *mdia; GF_BitStream *bs; - mdia = gf_f64_open(import->in_name, "rb"); + mdia = gf_fopen(import->in_name, "rb"); if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Cannot find file %s", import->in_name); e = GF_OK; @@ -4214,7 +4470,7 @@ GF_Err gf_import_h263(GF_MediaImporter *import) } gf_bs_read_data(bs, samp_data, samp->dataLength); /*we ignore pict number and import at const FPS*/ - samp->IsRAP = (samp_data[4]&0x02) ? 0 : 1; + samp->IsRAP = (samp_data[4]&0x02) ? RAP_NO : RAP; samp->data = samp_data; if (import->flags & GF_IMPORT_USE_DATAREF) { e = gf_isom_add_sample_reference(import->dest, track, di, samp, offset); @@ -4241,7 +4497,7 @@ GF_Err gf_import_h263(GF_MediaImporter *import) exit: gf_bs_del(bs); - fclose(mdia); + gf_fclose(mdia); return e; } @@ -4300,7 +4556,7 @@ static GF_Err gf_import_avc_h264(GF_MediaImporter *import) GF_AVCConfig *avccfg, *svccfg, *dstcfg; GF_BitStream *bs; GF_BitStream *sample_data; - Bool flush_sample, sample_is_rap, sample_has_islice, first_nal, slice_is_ref, has_cts_offset, detect_fps, is_paff, set_subsamples, slice_force_ref; + Bool flush_sample, sample_is_rap, sample_has_islice, is_islice, first_nal, slice_is_ref, has_cts_offset, detect_fps, is_paff, set_subsamples, slice_force_ref; u32 ref_frame, timescale, copy_size, size_length, dts_inc; s32 last_poc, max_last_poc, max_last_b_poc, poc_diff, prev_last_poc, min_poc, poc_shift; Bool first_avc; @@ -4322,7 +4578,7 @@ static GF_Err gf_import_avc_h264(GF_MediaImporter *import) set_subsamples = (import->flags & GF_IMPORT_SET_SUBSAMPLES) ? 1 : 0; - mdia = gf_f64_open(import->in_name, "rb"); + mdia = gf_fopen(import->in_name, "rb"); if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Cannot find file %s", import->in_name); detect_fps = 1; @@ -4413,7 +4669,12 @@ restart_import: while (gf_bs_available(bs)) { u8 nal_hdr, skip_nal, is_subseq, add_sps; - nal_size = gf_media_nalu_next_start_code_bs(bs); + u32 nal_and_trailing_size; + + nal_and_trailing_size = nal_size = gf_media_nalu_next_start_code_bs(bs); + if (!(import->flags & GF_IMPORT_KEEP_TRAILING)) { + nal_size = gf_media_nalu_payload_end_bs(bs); + } if (nal_size>max_size) { buffer = (char*)gf_realloc(buffer, sizeof(char)*nal_size); @@ -4430,6 +4691,7 @@ restart_import: is_subseq = 0; skip_nal = 0; copy_size = flush_sample = 0; + is_islice = 0; if (nal_type == GF_AVC_NALU_SVC_SUBSEQ_PARAM || nal_type == GF_AVC_NALU_SVC_PREFIX_NALU || nal_type == GF_AVC_NALU_SVC_SLICE) { avc.is_svc = 1; @@ -4491,6 +4753,12 @@ restart_import: } } + //always keep NAL + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + copy_size = nal_size; + } + + //first declaration of SPS, if (add_sps) { dstcfg->configurationVersion = 1; dstcfg->profile_compatibility = avc.sps[idx].prof_compat; @@ -4500,14 +4768,20 @@ restart_import: dstcfg->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8; dstcfg->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8; - 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(dstcfg->sequenceParameterSets, slc); + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + copy_size = nal_size; + } else { + 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(dstcfg->sequenceParameterSets, slc); + } + /*disable frame rate scan, most bitstreams have wrong values there*/ - if (detect_fps && avc.sps[idx].vui.timing_info_present_flag && avc.sps[idx].vui.fixed_frame_rate_flag + if (detect_fps && avc.sps[idx].vui.timing_info_present_flag /*if detected FPS is greater than 1000, assume wrong timing info*/ && (avc.sps[idx].vui.time_scale <= 1000*avc.sps[idx].vui.num_units_in_tick) ) { @@ -4527,7 +4801,11 @@ restart_import: timescale = 2 * avc.sps[idx].vui.time_scale; dts_inc = 2 * avc.sps[idx].vui.num_units_in_tick * DeltaTfiDivisorIdx; FPS = (Double)timescale / dts_inc; - detect_fps = 0; + detect_fps = GF_FALSE; + + if (avc.sps[idx].vui.fixed_frame_rate_flag) + GF_LOG(GF_LOG_INFO, GF_LOG_CODING, ("[avc-h264] Possible Variable Frame Rate: VUI \"fixed_frame_rate_flag\" absent.\n")); + gf_isom_remove_track(import->dest, track); if (sample_data) gf_bs_del(sample_data); gf_odf_avc_cfg_del(avccfg); @@ -4538,7 +4816,7 @@ restart_import: buffer = NULL; gf_bs_del(bs); bs = NULL; - gf_f64_seek(mdia, 0, SEEK_SET); + gf_fseek(mdia, 0, SEEK_SET); goto restart_import; } @@ -4582,23 +4860,28 @@ restart_import: copy_size = nal_size; } - if (avc.pps[idx].status==1) { - avc.pps[idx].status = 2; - 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); - dstcfg = (import->flags & GF_IMPORT_SVC_EXPLICIT) ? svccfg : avccfg; + //always keep NAL + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + copy_size = nal_size; + } else { + if (avc.pps[idx].status==1) { + avc.pps[idx].status = 2; + 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); + dstcfg = (import->flags & GF_IMPORT_SVC_EXPLICIT) ? svccfg : avccfg; - /* by default, we put all PPS in the base AVC layer, - they will be moved to the SVC layer upon analysis of SVC slice. */ - dstcfg = avccfg; + /* by default, we put all PPS in the base AVC layer, + they will be moved to the SVC layer upon analysis of SVC slice. */ + dstcfg = avccfg; - if (import->flags & GF_IMPORT_SVC_EXPLICIT) - dstcfg = svccfg; + if (import->flags & GF_IMPORT_SVC_EXPLICIT) + dstcfg = svccfg; - gf_list_add(dstcfg->pictureParameterSets, slc); + gf_list_add(dstcfg->pictureParameterSets, slc); + } } break; case GF_AVC_NALU_SEI: @@ -4624,7 +4907,7 @@ restart_import: case GF_AVC_TYPE_I: case GF_AVC_TYPE2_I: nb_i++; - sample_has_islice = 1; + is_islice = 1; break; case GF_AVC_TYPE_B: case GF_AVC_TYPE2_B: @@ -4730,10 +5013,10 @@ restart_import: if (flush_sample && sample_data) { GF_ISOSample *samp = gf_isom_sample_new(); samp->DTS = (u64)dts_inc*cur_samp; - samp->IsRAP = sample_is_rap; + samp->IsRAP = sample_is_rap ? RAP : RAP_NO; if (!sample_is_rap) { if (sample_has_islice && (import->flags & GF_IMPORT_FORCE_SYNC) && (sei_recovery_frame_count==0)) { - samp->IsRAP = 1; + samp->IsRAP = RAP; if (!use_opengop_gdr) { use_opengop_gdr = 1; GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[AVC Import] Forcing non-IDR samples with I slices to be marked as sync points - resulting file will not be ISO conformant\n")); @@ -4784,9 +5067,9 @@ restart_import: cur_samp++; /*write sampleGroups info*/ - if (!samp->IsRAP && (sei_recovery_frame_count>=0)) { + if (!samp->IsRAP && ( (sei_recovery_frame_count>=0) || sample_has_islice) ) { /*generic GDR*/ - if (sei_recovery_frame_count) { + if (sei_recovery_frame_count>=0) { if (!use_opengop_gdr) use_opengop_gdr = 1; e = gf_isom_set_sample_roll_group(import->dest, track, cur_samp, (s16) sei_recovery_frame_count); } @@ -4810,6 +5093,9 @@ restart_import: } if (copy_size) { + if (is_islice) + sample_has_islice = 1; + if ((size_length<32) && ( (u32) (1<<size_length)-1 < copy_size)) { u32 diff_size = 8; while ((size_length<32) && ( (u32) (1<<(size_length+diff_size))-1 < copy_size)) diff_size+=8; @@ -5000,9 +5286,9 @@ restart_import: gf_bs_align(bs); nal_end = gf_bs_get_position(bs); assert(nal_start <= nal_end); - assert(nal_end <= nal_start + nal_size); - if (nal_end != nal_start + nal_size) - gf_bs_seek(bs, nal_start + nal_size); + assert(nal_end <= nal_start + nal_and_trailing_size); + if (nal_end != nal_start + nal_and_trailing_size) + gf_bs_seek(bs, nal_start + nal_and_trailing_size); if (!gf_bs_available(bs)) break; if (duration && (dts_inc*cur_samp > duration)) break; @@ -5026,9 +5312,9 @@ restart_import: if (sample_data) { GF_ISOSample *samp = gf_isom_sample_new(); samp->DTS = (u64)dts_inc*cur_samp; - samp->IsRAP = sample_is_rap; + samp->IsRAP = sample_is_rap ? RAP : RAP_NO; if (!sample_is_rap && sample_has_islice && (import->flags & GF_IMPORT_FORCE_SYNC)) { - samp->IsRAP = 1; + samp->IsRAP = RAP; } /*we store the frame order (based on the POC) as the CTS offset and update the whole table at the end*/ samp->CTS_Offset = last_poc - poc_shift; @@ -5046,7 +5332,7 @@ restart_import: /*recompute all CTS offsets*/ if (has_cts_offset) { u32 i, last_cts_samp; - u64 last_dts, max_cts; + u64 last_dts, max_cts, min_cts; if (!poc_diff) poc_diff = 1; /*no b-frame references, no need to cope with negative poc*/ if (!max_total_delay) { @@ -5057,6 +5343,7 @@ restart_import: min_poc *= -1; last_dts = 0; max_cts = 0; + min_cts = (u64) -1; last_cts_samp = 0; for (i=0; i<cur_samp; i++) { @@ -5088,6 +5375,10 @@ restart_import: max_cts = samp->DTS + samp->CTS_Offset; last_cts_samp = i; } + if (min_cts >= samp->DTS + samp->CTS_Offset) + min_cts = samp->DTS + samp->CTS_Offset; + + /*this should never happen, however some streams seem to do weird POC increases (cf sorenson streams, last 2 frames), this should hopefully take care of some bugs and ensure proper CTS...*/ if ((s32)samp->CTS_Offset<0) { @@ -5115,6 +5406,14 @@ restart_import: } /*and repack table*/ gf_isom_set_cts_packing(import->dest, track, 0); + + if (!(import->flags & GF_IMPORT_NO_EDIT_LIST) && min_cts) { + last_dts = max_cts - min_cts + gf_isom_get_sample_duration(import->dest, track, gf_isom_get_sample_count(import->dest, track) ); + + last_dts *= gf_isom_get_timescale(import->dest); + last_dts /= gf_isom_get_media_timescale(import->dest, track); + gf_isom_set_edit_segment(import->dest, track, 0, last_dts, min_cts, GF_ISOM_EDIT_NORMAL); + } } else { gf_isom_remove_cts_info(import->dest, track); } @@ -5125,7 +5424,11 @@ restart_import: avccfg->nal_unit_size = size_length/8; svccfg->nal_unit_size = size_length/8; - if (gf_list_count(avccfg->sequenceParameterSets) || !gf_list_count(svccfg->sequenceParameterSets) ) { + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + gf_isom_avc_config_update(import->dest, track, 1, avccfg); + gf_isom_avc_set_inband_config(import->dest, track, 1); + } else if (gf_list_count(avccfg->sequenceParameterSets) || !gf_list_count(svccfg->sequenceParameterSets) ) { gf_isom_avc_config_update(import->dest, track, 1, avccfg); if (gf_list_count(svccfg->sequenceParameterSets)) { gf_isom_svc_config_update(import->dest, track, 1, svccfg, 1); @@ -5133,13 +5436,15 @@ restart_import: } else { gf_isom_svc_config_update(import->dest, track, 1, svccfg, 0); } + + gf_media_update_par(import->dest, track); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); - gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_VISUAL, 0x15); + gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_VISUAL, 0x7F); gf_isom_modify_alternate_brand(import->dest, GF_ISOM_BRAND_AVC1, 1); - if (!gf_list_count(avccfg->sequenceParameterSets) && !gf_list_count(svccfg->sequenceParameterSets)) { + if (!gf_list_count(avccfg->sequenceParameterSets) && !gf_list_count(svccfg->sequenceParameterSets) && !(import->flags & GF_IMPORT_FORCE_XPS_INBAND)) { e = gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Import results: No SPS or PPS found in the bitstream ! Nothing imported\n"); } else { u32 i; @@ -5186,7 +5491,7 @@ exit: gf_odf_avc_cfg_del(svccfg); gf_free(buffer); gf_bs_del(bs); - fclose(mdia); + gf_fclose(mdia); return e; } @@ -5204,10 +5509,13 @@ static GF_HEVCParamArray *get_hevc_param_array(GF_HEVCConfig *hevc_cfg, u8 type) static void hevc_set_parall_type(GF_HEVCConfig *hevc_cfg) { - u32 use_tiles, use_wpp, nb_pps; + u32 use_tiles, use_wpp, nb_pps, i, count; HEVCState hevc; GF_HEVCParamArray *ar = get_hevc_param_array(hevc_cfg, GF_HEVC_NALU_PIC_PARAM); - u32 i, count = gf_list_count(ar->nalus); + if (!ar) + return; + + count = gf_list_count(ar->nalus); memset(&hevc, 0, sizeof(HEVCState)); hevc.sps_active_idx = -1; @@ -5216,7 +5524,6 @@ static void hevc_set_parall_type(GF_HEVCConfig *hevc_cfg) use_wpp = 0; nb_pps = 0; - for (i=0; i<count; i++) { HEVC_PPS *pps; GF_AVCConfigSlot *slc = gf_list_get(ar->nalus, i); @@ -5257,7 +5564,7 @@ static GF_Err gf_import_hevc(GF_MediaImporter *import) GF_HEVCParamArray *spss, *ppss, *vpss; GF_BitStream *bs; GF_BitStream *sample_data; - Bool flush_sample, flush_next_sample, is_empty_sample, sample_is_rap, sample_has_islice, first_nal, slice_is_ref, has_cts_offset, is_paff, set_subsamples, slice_force_ref; + Bool flush_sample, flush_next_sample, is_empty_sample, sample_is_rap, sample_has_islice, is_islice, first_nal, slice_is_ref, has_cts_offset, is_paff, set_subsamples, slice_force_ref; u32 ref_frame, timescale, copy_size, size_length, dts_inc; s32 last_poc, max_last_poc, max_last_b_poc, poc_diff, prev_last_poc, min_poc, poc_shift; Bool first_hevc; @@ -5278,7 +5585,7 @@ static GF_Err gf_import_hevc(GF_MediaImporter *import) set_subsamples = (import->flags & GF_IMPORT_SET_SUBSAMPLES) ? 1 : 0; - mdia = gf_f64_open(import->in_name, "rb"); + mdia = gf_fopen(import->in_name, "rb"); if (!mdia) return gf_import_message(import, GF_URL_ERROR, "Cannot find file %s", import->in_name); detect_fps = GF_TRUE; @@ -5361,22 +5668,27 @@ restart_import: last_poc = max_last_poc = max_last_b_poc = prev_last_poc = 0; max_total_delay = 0; - gf_isom_set_cts_packing(import->dest, track, 1); - has_cts_offset = 0; + gf_isom_set_cts_packing(import->dest, track, GF_TRUE); + has_cts_offset = GF_FALSE; min_poc = 0; poc_shift = 0; - flush_next_sample = 0; - is_empty_sample = 1; + flush_next_sample = GF_FALSE; + is_empty_sample = GF_TRUE; while (gf_bs_available(bs)) { s32 res; - Bool force_shvc = 0; + Bool force_shvc = GF_FALSE; GF_HEVCConfig *prev_cfg; u8 nal_unit_type, temporal_id, layer_id; Bool skip_nal, add_sps, is_slice, has_vcl_nal; + u32 nal_and_trailing_size; has_vcl_nal = 0; - nal_size = gf_media_nalu_next_start_code_bs(bs); + nal_and_trailing_size = nal_size = gf_media_nalu_next_start_code_bs(bs); + if (!(import->flags & GF_IMPORT_KEEP_TRAILING)) { + nal_size = gf_media_nalu_payload_end_bs(bs); + } + if (nal_size>max_size) { buffer = (char*)gf_realloc(buffer, sizeof(char)*nal_size); @@ -5394,6 +5706,8 @@ restart_import: goto next_nal; } + is_islice = 0; + prev_cfg = dst_cfg; //todo check layer type, for now only scalable (not 3D etc) ... if (import->flags & GF_IMPORT_SVC_EXPLICIT) { @@ -5467,14 +5781,24 @@ restart_import: 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); + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + vpss->array_completeness = 0; + copy_size = nal_size; + } else { + 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); + gf_list_add(vpss->nalus, slc); + } } + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + copy_size = nal_size; + } + break; case GF_HEVC_NALU_SEQ_PARAM: idx = gf_media_hevc_read_sps(buffer, nal_size, &hevc); @@ -5525,13 +5849,6 @@ restart_import: 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); - /*disable frame rate scan, most bitstreams have wrong values there*/ if (detect_fps && hevc.sps[idx].has_timing_info /*if detected FPS is greater than 1000, assume wrong timing info*/ @@ -5551,10 +5868,22 @@ restart_import: buffer = NULL; gf_bs_del(bs); bs = NULL; - gf_f64_seek(mdia, 0, SEEK_SET); + gf_fseek(mdia, 0, SEEK_SET); goto restart_import; } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + spss->array_completeness = 0; + copy_size = nal_size; + } else { + 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 (first_hevc) { first_hevc = 0; gf_import_message(import, GF_OK, "HEVC import - frame size %d x %d at %02.3f FPS", hevc.sps[idx].width, hevc.sps[idx].height, FPS); @@ -5568,6 +5897,9 @@ restart_import: max_h = hevc.sps[idx].height; } } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + copy_size = nal_size; + } break; case GF_HEVC_NALU_PIC_PARAM: @@ -5598,25 +5930,40 @@ restart_import: ppss->type = GF_HEVC_NALU_PIC_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); + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + ppss->array_completeness = 0; + copy_size = nal_size; + } else { + 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(ppss->nalus, slc); + gf_list_add(ppss->nalus, slc); + } } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + copy_size = nal_size; + } + break; case GF_HEVC_NALU_SEI_SUFFIX: if (!layer_id) flush_next_sample = 1; - case GF_HEVC_NALU_SEI_PREFIX: if (hevc.sps_active_idx != -1) { - /*TODO*/ - //copy_size = gf_media_avc_reformat_sei(buffer, nal_size, &hevc); copy_size = nal_size; if (copy_size) nb_sei++; } + break; + case GF_HEVC_NALU_SEI_PREFIX: + if (hevc.sps_active_idx != -1) { + copy_size = nal_size; + if (copy_size) { + nb_sei++; + flush_sample=1; + } + } break; /*slice_segment_layer_rbsp*/ @@ -5651,7 +5998,7 @@ restart_import: break; case GF_HEVC_TYPE_I: nb_i++; - sample_has_islice = 1; + is_islice = 1; break; case GF_HEVC_TYPE_B: nb_b++; @@ -5681,10 +6028,10 @@ restart_import: if (flush_sample && sample_data) { GF_ISOSample *samp = gf_isom_sample_new(); samp->DTS = (u64)dts_inc*cur_samp; - samp->IsRAP = sample_is_rap; + samp->IsRAP = sample_is_rap ? RAP : RAP_NO; if (!sample_is_rap) { if (sample_has_islice && (import->flags & GF_IMPORT_FORCE_SYNC) && (sei_recovery_frame_count==0)) { - samp->IsRAP = 1; + samp->IsRAP = RAP; if (!use_opengop_gdr) { use_opengop_gdr = 1; GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[HEVC Import] Forcing non-IDR samples with I slices to be marked as sync points - resulting file will not be ISO conformant\n")); @@ -5705,9 +6052,9 @@ restart_import: cur_samp++; /*write sampleGroups info*/ - if (!samp->IsRAP && (sei_recovery_frame_count>=0)) { + if (!samp->IsRAP && ((sei_recovery_frame_count>=0) || sample_has_islice) ) { /*generic GDR*/ - if (sei_recovery_frame_count) { + if (sei_recovery_frame_count >= 0) { if (!use_opengop_gdr) use_opengop_gdr = 1; e = gf_isom_set_sample_roll_group(import->dest, track, cur_samp, (s16) sei_recovery_frame_count); } @@ -5732,6 +6079,9 @@ restart_import: } if (copy_size) { + if (is_islice) + sample_has_islice = 1; + if ((size_length<32) && ( (u32) (1<<size_length)-1 < copy_size)) { u32 diff_size = 8; while ((size_length<32) && ( (u32) (1<<(size_length+diff_size))-1 < copy_size)) diff_size+=8; @@ -5884,9 +6234,9 @@ next_nal: gf_bs_align(bs); nal_end = gf_bs_get_position(bs); assert(nal_start <= nal_end); - assert(nal_end <= nal_start + nal_size); - if (nal_end != nal_start + nal_size) - gf_bs_seek(bs, nal_start + nal_size); + assert(nal_end <= nal_start + nal_and_trailing_size); + if (nal_end != nal_start + nal_and_trailing_size) + gf_bs_seek(bs, nal_start + nal_and_trailing_size); if (!gf_bs_available(bs)) break; if (duration && (dts_inc*cur_samp > duration)) break; @@ -5910,9 +6260,9 @@ next_nal: if (sample_data) { GF_ISOSample *samp = gf_isom_sample_new(); samp->DTS = (u64)dts_inc*cur_samp; - samp->IsRAP = sample_is_rap; + samp->IsRAP = sample_is_rap ? RAP : RAP_NO; if (!sample_is_rap && sample_has_islice && (import->flags & GF_IMPORT_FORCE_SYNC)) { - samp->IsRAP = 1; + samp->IsRAP = RAP; } /*we store the frame order (based on the POC) as the CTS offset and update the whole table at the end*/ samp->CTS_Offset = last_poc - poc_shift; @@ -5930,7 +6280,7 @@ next_nal: /*recompute all CTS offsets*/ if (has_cts_offset) { u32 last_cts_samp; - u64 last_dts, max_cts; + u64 last_dts, max_cts, min_cts; if (!poc_diff) poc_diff = 1; /*no b-frame references, no need to cope with negative poc*/ if (!max_total_delay) { @@ -5941,6 +6291,7 @@ next_nal: min_poc *= -1; last_dts = 0; max_cts = 0; + min_cts = (u64) -1; last_cts_samp = 0; for (i=0; i<cur_samp; i++) { @@ -5972,6 +6323,10 @@ next_nal: max_cts = samp->DTS + samp->CTS_Offset; last_cts_samp = i; } + if (min_cts > samp->DTS + samp->CTS_Offset) { + min_cts = samp->DTS + samp->CTS_Offset; + } + /*this should never happen, however some streams seem to do weird POC increases (cf sorenson streams, last 2 frames), this should hopefully take care of some bugs and ensure proper CTS...*/ if ((s32)samp->CTS_Offset<0) { @@ -5999,6 +6354,13 @@ next_nal: } /*and repack table*/ gf_isom_set_cts_packing(import->dest, track, 0); + + if (!(import->flags & GF_IMPORT_NO_EDIT_LIST) && min_cts) { + last_dts = max_cts - min_cts + gf_isom_get_sample_duration(import->dest, track, gf_isom_get_sample_count(import->dest, track) ); + last_dts *= gf_isom_get_timescale(import->dest); + last_dts /= gf_isom_get_media_timescale(import->dest, track); + gf_isom_set_edit_segment(import->dest, track, 0, last_dts, min_cts, GF_ISOM_EDIT_NORMAL); + } } else { gf_isom_remove_cts_info(import->dest, track); } @@ -6014,7 +6376,12 @@ next_nal: shvc_cfg->num_layers ++; } - if (gf_list_count(hevc_cfg->param_array) || !gf_list_count(shvc_cfg->param_array) ) { + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + hevc_set_parall_type(hevc_cfg); + gf_isom_hevc_config_update(import->dest, track, 1, hevc_cfg); + gf_isom_hevc_set_inband_config(import->dest, track, 1); + } else if (gf_list_count(hevc_cfg->param_array) || !gf_list_count(shvc_cfg->param_array) ) { hevc_set_parall_type(hevc_cfg); gf_isom_hevc_config_update(import->dest, track, 1, hevc_cfg); if (gf_list_count(shvc_cfg->param_array)) { @@ -6033,7 +6400,7 @@ next_nal: } gf_media_update_par(import->dest, track); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); // gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_VISUAL, 0x15); gf_isom_set_brand_info(import->dest, GF_ISOM_BRAND_ISO4, 1); @@ -6077,7 +6444,7 @@ exit: gf_odf_hevc_cfg_del(shvc_cfg); gf_free(buffer); gf_bs_del(bs); - fclose(mdia); + gf_fclose(mdia); return e; #endif //GPAC_DISABLE_HEVC } @@ -6112,7 +6479,7 @@ static u32 get_ogg_serial_no_for_stream(char *fileName, u32 stream_num, Bool is_ /*means first one*/ if (!stream_num) return 0; - f_in = gf_f64_open(fileName, "rb"); + f_in = gf_fopen(fileName, "rb"); if (!f_in) return 0; track = 0; @@ -6141,7 +6508,7 @@ static u32 get_ogg_serial_no_for_stream(char *fileName, u32 stream_num, Bool is_ serial_no = 0; } ogg_sync_clear(&oy); - fclose(f_in); + gf_fclose(f_in); return serial_no; } @@ -6167,7 +6534,7 @@ GF_Err gf_import_ogg_video(GF_MediaImporter *import) dts_inc = 0; /*assume audio or simple AV file*/ if (import->flags & GF_IMPORT_PROBE_ONLY) { - f_in = gf_f64_open(import->in_name, "rb"); + f_in = gf_fopen(import->in_name, "rb"); if (!f_in) return GF_URL_ERROR; import->nb_tracks = 0; @@ -6209,7 +6576,7 @@ GF_Err gf_import_ogg_video(GF_MediaImporter *import) import->nb_tracks++; } ogg_sync_clear(&oy); - fclose(f_in); + gf_fclose(f_in); return GF_OK; } @@ -6219,14 +6586,14 @@ GF_Err gf_import_ogg_video(GF_MediaImporter *import) /*not our stream*/ if (!sno && import->trackID) return GF_OK; - f_in = gf_f64_open(import->in_name, "rb"); + f_in = gf_fopen(import->in_name, "rb"); if (!f_in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); e = GF_OK; done = 0; - gf_f64_seek(f_in, 0, SEEK_END); - tot_size = gf_f64_tell(f_in); - gf_f64_seek(f_in, 0, SEEK_SET); + gf_fseek(f_in, 0, SEEK_END); + tot_size = gf_ftell(f_in); + gf_fseek(f_in, 0, SEEK_SET); destroy_esd = 0; @@ -6353,7 +6720,7 @@ GF_Err gf_import_ogg_video(GF_MediaImporter *import) flag = oggpackB_read(&opb, 1); if (flag==0) { /*add packet*/ - samp->IsRAP = oggpackB_read(&opb, 1) ? 0 : 1; + samp->IsRAP = oggpackB_read(&opb, 1) ? RAP_NO : RAP; samp->data = (char *)oggpacket.packet; samp->dataLength = oggpacket.bytes; e = gf_isom_add_sample(import->dest, track, di, samp); @@ -6374,7 +6741,7 @@ GF_Err gf_import_ogg_video(GF_MediaImporter *import) if (!serial_no) { gf_import_message(import, GF_OK, "OGG: No supported video found"); } else { - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_VISUAL, 0xFE); } @@ -6389,7 +6756,7 @@ exit: gf_odf_desc_del((GF_Descriptor *) import->esd); import->esd = NULL; } - fclose(f_in); + gf_fclose(f_in); return e; } @@ -6422,17 +6789,17 @@ GF_Err gf_import_ogg_audio(GF_MediaImporter *import) /*not our stream*/ if (!sno && import->trackID) return GF_OK; - f_in = gf_f64_open(import->in_name, "rb"); + f_in = gf_fopen(import->in_name, "rb"); if (!f_in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); e = GF_OK; done = 0; - gf_f64_seek(f_in, 0, SEEK_END); - tot_size = gf_f64_tell(f_in); - gf_f64_seek(f_in, 0, SEEK_SET); + gf_fseek(f_in, 0, SEEK_END); + tot_size = gf_ftell(f_in); + gf_fseek(f_in, 0, SEEK_SET); - destroy_esd = 0; + destroy_esd = GF_FALSE; samp = gf_isom_sample_new(); /*avoids gcc warnings*/ track = num_headers = 0; @@ -6535,7 +6902,7 @@ GF_Err gf_import_ogg_audio(GF_MediaImporter *import) if (!block_size) continue; /*add packet*/ - samp->IsRAP = 1; + samp->IsRAP = RAP; samp->data = (char *)oggpacket.packet; samp->dataLength = oggpacket.bytes; e = gf_isom_add_sample(import->dest, track, di, samp); @@ -6559,7 +6926,7 @@ GF_Err gf_import_ogg_audio(GF_MediaImporter *import) gf_isom_set_pl_indication(import->dest, GF_ISOM_PL_AUDIO, 0xFE); gf_set_progress("Importing OGG Audio", (u32) tot_size, (u32) tot_size); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); } exit: @@ -6571,7 +6938,7 @@ exit: gf_odf_desc_del((GF_Descriptor *) import->esd); import->esd = NULL; } - fclose(f_in); + gf_fclose(f_in); return e; #endif /*defined(GPAC_DISABLE_AV_PARSERS) */ } @@ -6595,7 +6962,7 @@ GF_Err gf_import_raw_unit(GF_MediaImporter *import) return gf_import_message(import, GF_BAD_PARAM, "Raw stream needs ESD and DecoderConfig for import"); } - src = gf_f64_open(import->in_name, "rb"); + src = gf_fopen(import->in_name, "rb"); if (!src) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); switch (import->esd->decoderConfig->streamType) { @@ -6652,19 +7019,19 @@ GF_Err gf_import_raw_unit(GF_MediaImporter *import) gf_import_message(import, GF_OK, "Raw Access Unit import (StreamType %s)", gf_odf_stream_type_name(import->esd->decoderConfig->streamType)); samp = gf_isom_sample_new(); - gf_f64_seek(src, 0, SEEK_END); - assert(gf_f64_tell(src) < 1<<31); - samp->dataLength = (u32) gf_f64_tell(src); - gf_f64_seek(src, 0, SEEK_SET); - samp->IsRAP = 1; + gf_fseek(src, 0, SEEK_END); + assert(gf_ftell(src) < 1<<31); + samp->dataLength = (u32) gf_ftell(src); + gf_fseek(src, 0, SEEK_SET); + samp->IsRAP = RAP; samp->data = (char *)gf_malloc(sizeof(char)*samp->dataLength); readen = (u32) fread(samp->data, sizeof(char), samp->dataLength, src); assert( readen == samp->dataLength ); e = gf_isom_add_sample(import->dest, track, di, samp); gf_isom_sample_del(&samp); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); exit: - fclose(src); + gf_fclose(src); return e; } @@ -6681,7 +7048,7 @@ GF_Err gf_import_saf(GF_MediaImporter *import) import->flags |= GF_IMPORT_USE_DATAREF; } - saf = gf_f64_open(import->in_name, "rb"); + saf = gf_fopen(import->in_name, "rb"); if (!saf) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); track = 0; @@ -6699,7 +7066,7 @@ GF_Err gf_import_saf(GF_MediaImporter *import) au_size = gf_bs_read_u16(bs); if (au_size<2) { gf_bs_del(bs); - fclose(saf); + gf_fclose(saf); return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Invalid SAF Packet Header"); } type = gf_bs_read_int(bs, 4); @@ -6708,7 +7075,7 @@ GF_Err gf_import_saf(GF_MediaImporter *import) if (!stream_id) stream_id = 1000; if ((type==1) || (type==2) || (type==7)) { - Bool in_root_od = 0; + Bool in_root_od = GF_FALSE; u32 mtype, stype; char *name = "Unknown"; @@ -6806,10 +7173,10 @@ GF_Err gf_import_saf(GF_MediaImporter *import) import->nb_tracks++; } } else if ((stream_id==import->trackID) && !track) { - Bool delete_esd = 0; + Bool delete_esd = GF_FALSE; if (!import->esd) { import->esd = gf_odf_desc_esd_new(0); - delete_esd = 1; + delete_esd = GF_TRUE; if (import->esd->URLString) gf_free(import->esd->URLString); import->esd->URLString = NULL; } @@ -6851,7 +7218,7 @@ GF_Err gf_import_saf(GF_MediaImporter *import) GF_ISOSample *samp = gf_isom_sample_new(); samp->dataLength = au_size; samp->DTS = cts; - samp->IsRAP = is_rap; + samp->IsRAP = is_rap ? RAP : RAP_NO; if (import->flags & GF_IMPORT_USE_DATAREF) { e = gf_isom_add_sample_reference(import->dest, track, 1, samp, gf_bs_get_position(bs) ); } else { @@ -6863,7 +7230,7 @@ GF_Err gf_import_saf(GF_MediaImporter *import) gf_isom_sample_del(&samp); if (e) { gf_bs_del(bs); - fclose(saf); + gf_fclose(saf); return e; } gf_set_progress("Importing SAF", gf_bs_get_position(bs), tot); @@ -6871,11 +7238,11 @@ GF_Err gf_import_saf(GF_MediaImporter *import) gf_bs_skip_bytes(bs, au_size); } gf_bs_del(bs); - fclose(saf); + gf_fclose(saf); if (import->flags & GF_IMPORT_PROBE_ONLY) return GF_OK; gf_set_progress("Importing SAF", tot, tot); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); return GF_OK; #else return GF_NOT_SUPPORTED; @@ -7027,7 +7394,7 @@ static void m2ts_create_track(GF_TSImport *tsimp, u32 mtype, u32 stype, u32 oti, GF_MediaImporter *import= (GF_MediaImporter *)tsimp->import; if (mtype != GF_ISOM_MEDIA_ESM) { u32 di; - Bool destroy_esd = 0; + Bool destroy_esd = GF_FALSE; if (import->esd) mpeg4_es_id = import->esd->ESID; else if (!mpeg4_es_id) mpeg4_es_id = import->trackID; @@ -7102,11 +7469,12 @@ void m2ts_rewrite_nalu_sample(GF_MediaImporter *import, GF_TSImport *tsimp) } #ifndef GPAC_DISABLE_HEVC -static void hevc_cfg_add_nalu(GF_HEVCConfig *hevccfg, u8 nal_type, char *data, u32 data_len) +static void hevc_cfg_add_nalu(GF_MediaImporter *import, GF_HEVCConfig *hevccfg, u8 nal_type, char *data, u32 data_len) { u32 i, count; GF_AVCConfigSlot *sl; GF_HEVCParamArray *ar = NULL; + count = gf_list_count(hevccfg->param_array); for (i=0; i<count; i++) { ar = gf_list_get(hevccfg->param_array, i); @@ -7120,6 +7488,12 @@ static void hevc_cfg_add_nalu(GF_HEVCConfig *hevccfg, u8 nal_type, char *data, u ar->nalus = gf_list_new(); gf_list_add(hevccfg->param_array, ar); } + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + ar->array_completeness = 0; + return; + } + if (data) { GF_SAFEALLOC(sl, GF_AVCConfigSlot); sl->data = gf_malloc(sizeof(char)*data_len); @@ -7165,7 +7539,6 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) if (import->flags & GF_IMPORT_PROBE_ONLY) { import->probe_duration = ((GF_M2TS_PES_PCK *) par)->PTS; - //import->flags |= GF_IMPORT_DO_ABORT; } break; @@ -7412,6 +7785,11 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) stype = GF_STREAM_AUDIO; oti = GPAC_OTI_AUDIO_AAC_MPEG4; break; + case GF_M2TS_AUDIO_AC3: + mtype = GF_ISOM_MEDIA_AUDIO; + stype = GF_STREAM_AUDIO; + oti = GPAC_OTI_AUDIO_AC3; + break; case GF_M2TS_SYSTEMS_MPEG4_PES: case GF_M2TS_SYSTEMS_MPEG4_SECTIONS: if (prog->pmt_iod && !import->esd) { @@ -7452,7 +7830,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) import->tk_info[i].audio_info.sample_rate = pck->stream->aud_sr; import->tk_info[i].audio_info.nb_channels = pck->stream->aud_nb_ch; if ((pck->stream->stream_type==GF_M2TS_AUDIO_AAC) || (pck->stream->stream_type==GF_M2TS_AUDIO_LATM_AAC)) { - sprintf(import->tk_info[i].szCodecProfile, "mp4a.40.%02x", (u8) pck->stream->aud_obj_type); + sprintf(import->tk_info[i].szCodecProfile, "mp4a.40.%02x", (u8) pck->stream->aud_aac_obj_type); } import->tk_info[i].audio_info.sample_rate = pck->stream->aud_sr; import->tk_info[i].audio_info.nb_channels = pck->stream->aud_nb_ch; @@ -7522,26 +7900,26 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) if (tsimp->avccfg && !pck->data[0] && !pck->data[1]) { GF_AVCConfigSlot *slc; s32 idx; - Bool add_sps, is_subseq = 0; + Bool add_sps, is_subseq = GF_FALSE; u32 nal_type = pck->data[4] & 0x1F; switch (nal_type) { case GF_AVC_NALU_SVC_SUBSEQ_PARAM: - is_subseq = 1; + is_subseq = GF_TRUE; case GF_AVC_NALU_SEQ_PARAM: idx = gf_media_avc_read_sps(pck->data+4, pck->data_len-4, &tsimp->avc, is_subseq, NULL); - add_sps = 0; + add_sps = GF_FALSE; if (idx>=0) { if (is_subseq) { if ((tsimp->avc.sps[idx].state & AVC_SUBSPS_PARSED) && !(tsimp->avc.sps[idx].state & AVC_SUBSPS_DECLARED)) { tsimp->avc.sps[idx].state |= AVC_SUBSPS_DECLARED; - add_sps = 1; + add_sps = GF_TRUE; } } else { if ((tsimp->avc.sps[idx].state & AVC_SPS_PARSED) && !(tsimp->avc.sps[idx].state & AVC_SPS_DECLARED)) { tsimp->avc.sps[idx].state |= AVC_SPS_DECLARED; - add_sps = 1; + add_sps = GF_TRUE; } } if (add_sps) { @@ -7551,34 +7929,45 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) tsimp->avccfg->profile_compatibility = tsimp->avc.sps[idx].prof_compat; tsimp->avccfg->AVCProfileIndication = tsimp->avc.sps[idx].profile_idc; tsimp->avccfg->AVCLevelIndication = tsimp->avc.sps[idx].level_idc; - slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); - slc->size = pck->data_len-4; - slc->data = (char*)gf_malloc(sizeof(char)*slc->size); - memcpy(slc->data, pck->data+4, sizeof(char)*slc->size); - gf_list_add(tsimp->avccfg->sequenceParameterSets, slc); if (pck->stream->vid_w < tsimp->avc.sps[idx].width) pck->stream->vid_w = tsimp->avc.sps[idx].width; if (pck->stream->vid_h < tsimp->avc.sps[idx].height) pck->stream->vid_h = tsimp->avc.sps[idx].height; + + if (!(import->flags & GF_IMPORT_FORCE_XPS_INBAND)) { + slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = pck->data_len-4; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + memcpy(slc->data, pck->data+4, sizeof(char)*slc->size); + gf_list_add(tsimp->avccfg->sequenceParameterSets, slc); + } } } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + break; + } return; case GF_AVC_NALU_PIC_PARAM: idx = gf_media_avc_read_pps(pck->data+4, pck->data_len-4, &tsimp->avc); if ((idx>=0) && (tsimp->avc.pps[idx].status==1)) { tsimp->avc.pps[idx].status = 2; - slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); - slc->size = pck->data_len-4; - slc->data = (char*)gf_malloc(sizeof(char)*slc->size); - memcpy(slc->data, pck->data+4, sizeof(char)*slc->size); - gf_list_add(tsimp->avccfg->pictureParameterSets, slc); + if (!(import->flags & GF_IMPORT_FORCE_XPS_INBAND)) { + slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot)); + slc->size = pck->data_len-4; + slc->data = (char*)gf_malloc(sizeof(char)*slc->size); + memcpy(slc->data, pck->data+4, sizeof(char)*slc->size); + gf_list_add(tsimp->avccfg->pictureParameterSets, slc); + } + } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + break; } /*else discard because of invalid PPS*/ return; /*remove*/ case GF_AVC_NALU_ACCESS_UNIT: - tsimp->force_next_au_start = 1; + tsimp->force_next_au_start = GF_TRUE; return; case GF_AVC_NALU_FILLER_DATA: case GF_AVC_NALU_END_OF_SEQ: @@ -7586,16 +7975,12 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) return; case GF_AVC_NALU_SEI: break; - if (tsimp->avc.sps_active_idx != -1) { - idx = gf_media_avc_reformat_sei(pck->data+4, pck->data_len-4, &tsimp->avc); - if (idx>0) pck->data_len = idx+4; - } - break; + } if (tsimp->force_next_au_start) { - is_au_start = 1; - tsimp->force_next_au_start = 0; + is_au_start = GF_TRUE; + tsimp->force_next_au_start = GF_FALSE; } } @@ -7604,7 +7989,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) #ifndef GPAC_DISABLE_HEVC else if (tsimp->hevccfg && !pck->data[0] && !pck->data[1]) { s32 idx; - Bool add_sps, is_subseq = 0; + Bool add_sps, is_subseq = GF_FALSE; u32 nal_type = (pck->data[4] & 0x7E) >> 1; switch (nal_type) { @@ -7638,7 +8023,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) tsimp->hevccfg->luma_bit_depth = tsimp->hevc.sps[idx].bit_depth_luma; tsimp->hevccfg->chroma_bit_depth = tsimp->hevc.sps[idx].bit_depth_chroma; - hevc_cfg_add_nalu(tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4); + hevc_cfg_add_nalu(import, tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4); if (pck->stream->vid_w < tsimp->avc.sps[idx].width) pck->stream->vid_w = tsimp->avc.sps[idx].width; @@ -7646,12 +8031,20 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) pck->stream->vid_h = tsimp->avc.sps[idx].height; } } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + is_au_start = 1; + break; + } return; case GF_HEVC_NALU_PIC_PARAM: idx = gf_media_hevc_read_pps(pck->data+4, pck->data_len-4, &tsimp->hevc); if ((idx>=0) && (tsimp->hevc.pps[idx].state==1)) { tsimp->hevc.pps[idx].state = 2; - hevc_cfg_add_nalu(tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4); + hevc_cfg_add_nalu(import, tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4); + } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + is_au_start = 1; + break; } return; case GF_HEVC_NALU_VID_PARAM: @@ -7661,7 +8054,11 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) tsimp->hevccfg->avgFrameRate = tsimp->hevc.vps[idx].rates[0].avg_pic_rate; tsimp->hevccfg->constantFrameRate = tsimp->hevc.vps[idx].rates[0].constand_pic_rate_idc; tsimp->hevccfg->numTemporalLayers = tsimp->hevc.vps[idx].max_sub_layers; - hevc_cfg_add_nalu(tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4); + hevc_cfg_add_nalu(import, tsimp->hevccfg, nal_type, pck->data+4, pck->data_len-4); + } + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + is_au_start = 1; + break; } return; /*remove*/ @@ -7673,11 +8070,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) case GF_HEVC_NALU_END_OF_STREAM: return; case GF_HEVC_NALU_SEI_PREFIX: - /*TODO if (tsimp->avc.sps_active_idx != -1) { - idx = gf_media_avc_reformat_sei(pck->data+4, pck->data_len-4, &tsimp->avc); - if (idx>0) pck->data_len = idx+4; - } - */ + is_au_start = 1; break; } @@ -7692,7 +8085,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) e = gf_isom_append_sample_data(import->dest, tsimp->track, (char*)pck->data, pck->data_len); if (e) { if (!gf_isom_get_sample_count(import->dest, tsimp->track)) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] missed begining of sample data\n")); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] missed beginning of sample data\n")); e = GF_OK; } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS Import] Error appending sample data\n")); @@ -7741,6 +8134,12 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) case GF_M2TS_AUDIO_AAC: gf_import_message(import, GF_OK, "MPEG-4 AAC Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid); break; + case GF_M2TS_AUDIO_AC3: + gf_import_message(import, GF_OK, "Dolby AC3 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid); + break; + case GF_M2TS_AUDIO_EC3: + gf_import_message(import, GF_OK, "Dolby E-AC3 Audio import - SampleRate %d Channels %d Language %s (TS PID %d)", pck->stream->aud_sr, pck->stream->aud_nb_ch, gf_4cc_to_str(pck->stream->lang), pck->stream->pid); + break; } if (pck->stream->lang) gf_isom_set_media_language(import->dest, tsimp->track, (char *) gf_4cc_to_str(pck->stream->lang)+1); @@ -7764,7 +8163,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) if (samp->DTS >= pck->stream->first_dts) { samp->DTS -= pck->stream->first_dts; - samp->IsRAP = (pck->flags & GF_M2TS_PES_PCK_RAP) ? 1 : 0; + samp->IsRAP = (pck->flags & GF_M2TS_PES_PCK_RAP) ? RAP : RAP_NO; samp->data = pck->data; samp->dataLength = pck->data_len; @@ -7909,7 +8308,7 @@ void on_m2ts_import_data(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) samp->CTS_Offset = (u32) (hdr.compositionTimeStamp - samp->DTS); if (samp->DTS >= sl_pck->stream->first_dts) { samp->DTS -= sl_pck->stream->first_dts; - samp->IsRAP = import->esd->slConfig->useRandomAccessPointFlag ? hdr.randomAccessPointFlag: 1; + samp->IsRAP = import->esd->slConfig->useRandomAccessPointFlag ? hdr.randomAccessPointFlag : RAP; /*fix for some DMB streams where TSs are not coded*/ if ((tsimp->last_dts == samp->DTS) && gf_isom_get_sample_count(import->dest, tsimp->track)) @@ -7956,19 +8355,19 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) GF_TSImport tsimp; u64 fsize, done; u32 size, i; - Bool do_import = 1; + Bool do_import = GF_TRUE; FILE *mts; char progress[1000]; if (import->trackID > GF_M2TS_MAX_STREAMS) return gf_import_message(import, GF_BAD_PARAM, "Invalid PID %d", import->trackID ); - mts = gf_f64_open(import->in_name, "rb"); + mts = gf_fopen(import->in_name, "rb"); if (!mts) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); - gf_f64_seek(mts, 0, SEEK_END); - fsize = gf_f64_tell(mts); - gf_f64_seek(mts, 0, SEEK_SET); + gf_fseek(mts, 0, SEEK_END); + fsize = gf_ftell(mts); + gf_fseek(mts, 0, SEEK_SET); done = 0; memset(&tsimp, 0, sizeof(GF_TSImport)); @@ -8005,7 +8404,7 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) if (tsimp.avccfg) gf_odf_avc_cfg_del(tsimp.avccfg); if (tsimp.hevccfg) gf_odf_hevc_cfg_del(tsimp.hevccfg); gf_m2ts_demux_del(ts); - fclose(mts); + gf_fclose(mts); return e; } @@ -8029,7 +8428,7 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) es = (GF_M2TS_ES *)ts->ess[import->trackID]; if (!es) { gf_m2ts_demux_del(ts); - fclose(mts); + gf_fclose(mts); return gf_import_message(import, GF_BAD_PARAM, "Unknown PID %d", import->trackID); } @@ -8037,6 +8436,11 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) u32 w = ((GF_M2TS_PES*)es)->vid_w; u32 h = ((GF_M2TS_PES*)es)->vid_h; gf_isom_avc_config_update(import->dest, tsimp.track, 1, tsimp.avccfg); + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + gf_isom_avc_set_inband_config(import->dest, tsimp.track, 1); + } + gf_isom_set_visual_info(import->dest, tsimp.track, 1, w, h); gf_isom_set_track_layout_info(import->dest, tsimp.track, w<<16, h<<16, 0, 0, 0); @@ -8051,6 +8455,11 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) u32 h = ((GF_M2TS_PES*)es)->vid_h; hevc_set_parall_type(tsimp.hevccfg); gf_isom_hevc_config_update(import->dest, tsimp.track, 1, tsimp.hevccfg); + + if (import->flags & GF_IMPORT_FORCE_XPS_INBAND) { + gf_isom_hevc_set_inband_config(import->dest, tsimp.track, 1); + } + gf_isom_set_visual_info(import->dest, tsimp.track, 1, w, h); gf_isom_set_track_layout_info(import->dest, tsimp.track, w<<16, h<<16, 0, 0, 0); @@ -8061,7 +8470,7 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) if (tsimp.track) { - MP4T_RecomputeBitRate(import->dest, tsimp.track); + gf_media_update_bitrate(import->dest, tsimp.track); /* creation of the edit lists */ if ((es->first_dts != es->program->first_dts) && gf_isom_get_sample_count(import->dest, tsimp.track) ) { u32 media_ts, moov_ts, offset; @@ -8092,7 +8501,7 @@ GF_Err gf_import_mpeg_ts(GF_MediaImporter *import) } gf_m2ts_demux_del(ts); - fclose(mts); + gf_fclose(mts); return GF_OK; } @@ -8107,7 +8516,7 @@ GF_Err gf_import_vobsub(GF_MediaImporter *import) int version; vobsub_file *vobsub = NULL; u32 c, trackID, track, di; - Bool destroy_esd = 0; + Bool destroy_esd = GF_FALSE; GF_Err err = GF_OK; GF_ISOSample *samp = NULL; GF_List *subpic; @@ -8119,7 +8528,7 @@ GF_Err gf_import_vobsub(GF_MediaImporter *import) vobsub_trim_ext(filename); strcat(filename, ".idx"); - file = gf_f64_open(filename, "r"); + file = gf_fopen(filename, "r"); if (!file) { err = gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", filename); goto error; @@ -8132,7 +8541,7 @@ GF_Err gf_import_vobsub(GF_MediaImporter *import) } err = vobsub_read_idx(file, vobsub, &version); - fclose(file); + gf_fclose(file); if (err != GF_OK) { err = gf_import_message(import, err, "Reading VobSub file %s failed", filename); @@ -8160,7 +8569,7 @@ GF_Err gf_import_vobsub(GF_MediaImporter *import) vobsub_trim_ext(filename); strcat(filename, ".sub"); - file = gf_f64_open(filename, "rb"); + file = gf_fopen(filename, "rb"); if (!file) { err = gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", filename); goto error; @@ -8245,8 +8654,8 @@ GF_Err gf_import_vobsub(GF_MediaImporter *import) break; } - gf_f64_seek(file, pos->filepos, SEEK_SET); - if (gf_f64_tell(file) != pos->filepos) { + gf_fseek(file, pos->filepos, SEEK_SET); + if (gf_ftell(file) != pos->filepos) { err = gf_import_message(import, GF_IO_ERR, "Could not seek in file"); goto error; } @@ -8329,7 +8738,7 @@ GF_Err gf_import_vobsub(GF_MediaImporter *import) gf_isom_set_last_sample_duration(import->dest, track, last_samp_dur); - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_set_progress("Importing VobSub", total, total); err = GF_OK; @@ -8348,7 +8757,7 @@ error: vobsub_free(vobsub); } if (file) { - fclose(file); + gf_fclose(file); } return err; @@ -8359,7 +8768,7 @@ error: #ifndef GPAC_DISABLE_AV_PARSERS -GF_Err gf_import_ac3(GF_MediaImporter *import) +GF_Err gf_import_ac3(GF_MediaImporter *import, Bool is_EAC3) { GF_AC3Header hdr; GF_AC3Config cfg; @@ -8372,21 +8781,28 @@ GF_Err gf_import_ac3(GF_MediaImporter *import) u32 max_size, track, di; u64 tot_size, done, duration; GF_ISOSample *samp; + Bool (*ac3_parser_bs)(GF_BitStream*, GF_AC3Header*, Bool) = gf_ac3_parser_bs; - in = gf_f64_open(import->in_name, "rb"); + in = gf_fopen(import->in_name, "rb"); if (!in) return gf_import_message(import, GF_URL_ERROR, "Opening file %s failed", import->in_name); bs = gf_bs_from_file(in, GF_BITSTREAM_READ); - if (!gf_ac3_parser_bs(bs, &hdr, GF_TRUE)) { - gf_bs_del(bs); - fclose(in); - return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Audio isn't AC3 audio"); + memset(&hdr, 0, sizeof(GF_AC3Header)); + memset(&cfg, 0, sizeof(GF_AC3Config)); + if (is_EAC3 || !gf_ac3_parser_bs(bs, &hdr, GF_TRUE)) { + if (!gf_eac3_parser_bs(bs, &hdr, GF_TRUE)) { + gf_bs_del(bs); + gf_fclose(in); + return gf_import_message(import, GF_NON_COMPLIANT_BITSTREAM, "Audio is neither AC3 or E-AC3 audio"); + } + is_EAC3 = GF_TRUE; + ac3_parser_bs = gf_eac3_parser_bs; } sr = hdr.sample_rate; if (import->flags & GF_IMPORT_PROBE_ONLY) { gf_bs_del(bs); - fclose(in); + gf_fclose(in); import->tk_info[0].track_num = 1; import->tk_info[0].type = GF_ISOM_MEDIA_AUDIO; import->tk_info[0].media_type = GF_4CC('A', 'C', '3', ' '); @@ -8407,13 +8823,13 @@ GF_Err gf_import_ac3(GF_MediaImporter *import) if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); /*update stream type/oti*/ import->esd->decoderConfig->streamType = GF_STREAM_AUDIO; - import->esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AC3; + import->esd->decoderConfig->objectTypeIndication = is_EAC3 ? GPAC_OTI_AUDIO_EAC3 : GPAC_OTI_AUDIO_AC3; import->esd->decoderConfig->bufferSizeDB = 20; import->esd->slConfig->timestampResolution = sr; samp = NULL; nb_chan = hdr.channels; - gf_import_message(import, GF_OK, "AC3 import - sample rate %d - %d%s channel%s", sr, hdr.lfon ? (nb_chan-1) : nb_chan, hdr.lfon?".1":"", (nb_chan>1) ? "s" : ""); + gf_import_message(import, GF_OK, "%sAC3 import - sample rate %d - %d%s channel%s", is_EAC3 ? "Enhanced " : "", sr, hdr.lfon ? (nb_chan-1) : nb_chan, hdr.lfon?".1":"", (nb_chan>1) ? "s" : ""); track = gf_isom_new_track(import->dest, import->esd->ESID, GF_ISOM_MEDIA_AUDIO, sr); if (!track) { @@ -8426,7 +8842,7 @@ GF_Err gf_import_ac3(GF_MediaImporter *import) if (import->esd->decoderConfig->decoderSpecificInfo) gf_odf_desc_del((GF_Descriptor *) import->esd->decoderConfig->decoderSpecificInfo); import->esd->decoderConfig->decoderSpecificInfo = NULL; - cfg.is_ec3 = 0; + cfg.is_ec3 = is_EAC3; cfg.nb_streams = 1; cfg.brcode = hdr.brcode; cfg.streams[0].acmod = hdr.acmod; @@ -8443,7 +8859,7 @@ GF_Err gf_import_ac3(GF_MediaImporter *import) e = GF_OK; samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; duration = import->duration; duration *= sr; @@ -8451,9 +8867,11 @@ GF_Err gf_import_ac3(GF_MediaImporter *import) max_size = 0; done = 0; - while (gf_ac3_parser_bs(bs, &hdr, 0)) { - samp->dataLength = hdr.framesize; - + while (ac3_parser_bs(bs, &hdr, GF_FALSE)) { + if (is_EAC3) + samp->dataLength = 2*(1+hdr.framesize); + else + samp->dataLength = hdr.framesize; if (import->flags & GF_IMPORT_USE_DATAREF) { e = gf_isom_add_sample_reference(import->dest, track, di, samp, gf_bs_get_position(bs) ); @@ -8466,16 +8884,19 @@ GF_Err gf_import_ac3(GF_MediaImporter *import) gf_bs_read_data(bs, samp->data, samp->dataLength); e = gf_isom_add_sample(import->dest, track, di, samp); } - if (e) goto exit; + if (e) + goto exit; gf_set_progress("Importing AC3", done, tot_size); samp->DTS += 1536; - done += samp->dataLength; - if (duration && (samp->DTS > duration)) break; - if (import->flags & GF_IMPORT_DO_ABORT) break; + done = gf_bs_get_position(bs); + if (duration && (samp->DTS > duration)) + break; + if (import->flags & GF_IMPORT_DO_ABORT) + break; } - MP4T_RecomputeBitRate(import->dest, track); + gf_media_update_bitrate(import->dest, track); gf_set_progress("Importing AC3", tot_size, tot_size); exit: @@ -8484,7 +8905,8 @@ exit: import->esd = NULL; } if (samp) gf_isom_sample_del(&samp); - fclose(in); + gf_bs_del(bs); + gf_fclose(in); return e; } #endif @@ -8500,7 +8922,7 @@ GF_Err gf_media_import_chapters_file(GF_MediaImporter *import) u32 i, h, m, s, ms, fr, fps; char line[1024]; char szTitle[1024]; - FILE *f = gf_f64_open(import->in_name, "rt"); + FILE *f = gf_fopen(import->in_name, "rt"); if (!f) return GF_URL_ERROR; readen = (u32) fread(line, 1, 4, f); @@ -8527,10 +8949,10 @@ GF_Err gf_media_import_chapters_file(GF_MediaImporter *import) } else { offset = 0; } - gf_f64_seek(f, offset, SEEK_SET); + gf_fseek(f, offset, SEEK_SET); if (import->flags & GF_IMPORT_PROBE_ONLY) { - Bool is_chap_or_sub = 0; + Bool is_chap_or_sub = GF_FALSE; import->nb_tracks = 0; while (!is_chap_or_sub && (fgets(line, 1024, f) != NULL)) { char *sep; @@ -8546,7 +8968,7 @@ GF_Err gf_media_import_chapters_file(GF_MediaImporter *import) else if (strstr(line, "Zoom") || strstr(line, "zoom")) is_chap_or_sub = 1; } } - fclose(f); + gf_fclose(f); if (is_chap_or_sub) { import->nb_tracks = 1; import->tk_info[0].media_type = GF_4CC('C','H','A','P'); @@ -8731,7 +9153,7 @@ GF_Err gf_media_import_chapters_file(GF_MediaImporter *import) err_exit: - fclose(f); + gf_fclose(f); return e; } @@ -8813,7 +9235,7 @@ GF_Err gf_media_import(GF_MediaImporter *importer) #ifndef GPAC_DISABLE_MPEG2TS /*MPEG-2 TS*/ - if (!strnicmp(ext, ".ts", 3) || !strnicmp(ext, ".m2t", 4) + if (!strnicmp(ext, ".ts", 3) || !strnicmp(ext, ".m2t", 4) || !strnicmp(ext, ".trp", 4) || !strnicmp(ext, ".mts", 4) || !stricmp(fmt, "MPEGTS") || !stricmp(fmt, "MPEG-TS") || !stricmp(fmt, "MPGTS") || !stricmp(fmt, "MPG-TS") || !stricmp(fmt, "MPEG2TS") || !stricmp(fmt, "MPEG2-TS") @@ -8845,12 +9267,14 @@ GF_Err gf_media_import(GF_MediaImporter *importer) || !stricmp(fmt, "AVC") || !stricmp(fmt, "H264") ) return gf_import_avc_h264(importer); /*HEVC video*/ - if (!strnicmp(ext, ".hevc", 5) || !strnicmp(ext, ".hvc", 4) || !strnicmp(ext, ".265", 4) || !strnicmp(ext, ".shvc", 5) + if (!strnicmp(ext, ".hevc", 5) || !strnicmp(ext, ".hvc", 4) || !strnicmp(ext, ".265", 4) || !strnicmp(ext, ".h265", 5) || !strnicmp(ext, ".shvc", 5) || !stricmp(fmt, "HEVC") || !stricmp(fmt, "SHVC") || !stricmp(fmt, "H265") ) return gf_import_hevc(importer); - /*AC3*/ + /*AC3 and E-AC3*/ if (!strnicmp(ext, ".ac3", 4) || !stricmp(fmt, "AC3") ) - return gf_import_ac3(importer); + return gf_import_ac3(importer, GF_FALSE); + if (!strnicmp(ext, ".ec3", 4) || !stricmp(fmt, "EC3") || !stricmp(fmt, "E-AC3") || !stricmp(fmt, "EAC3") ) + return gf_import_ac3(importer, GF_TRUE); #endif /*NHNT*/ @@ -8927,7 +9351,10 @@ GF_Err gf_media_import(GF_MediaImporter *importer) gf_free(xml_type); } - return gf_import_message(importer, e, "Unknown input file type"); + if (gf_m2ts_probe_file(importer->in_name)) + return gf_import_mpeg_ts(importer); + + return gf_import_message(importer, e, "[Importer] Unknown input file type for \"%s\"", importer->in_name); } diff --git a/src/media_tools/mpd.c b/src/media_tools/mpd.c index 842bd86..b63a2fc 100644 --- a/src/media_tools/mpd.c +++ b/src/media_tools/mpd.c @@ -1,27 +1,27 @@ -/* -* GPAC - Multimedia Framework C SDK -* +/** + * GPAC - Multimedia Framework C SDK + * * Authors: Jean Le Feuvre, Cyril COncolato * Copyright (c) Telecom ParisTech 2000-2012 -* All rights reserved -* -* This file is part of GPAC / 3GPP/MPEG Media Presentation Description input module -* -* 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. -* -*/ + * All rights reserved + * + * This file is part of GPAC / 3GPP/MPEG Media Presentation Description input module + * + * 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 <gpac/internal/mpd.h> #include <gpac/download.h> @@ -47,11 +47,12 @@ static char *gf_mpd_parse_string(char *attr) return gf_strdup(attr); } + static Bool gf_mpd_valid_child(GF_MPD *mpd, GF_XMLNode *child) { if (child->type != GF_XML_NODE_TYPE) return 0; if (!mpd->xml_namespace && !child->ns) return 1; - if (mpd->xml_namespace && child->ns && !strcmp(mpd->xml_namespace, child->ns) ) return 1; + if (mpd->xml_namespace && child->ns && !strcmp(mpd->xml_namespace, child->ns)) return 1; return 0; } @@ -368,6 +369,10 @@ static void gf_mpd_parse_segment_url(GF_List *container, GF_XMLNode *root) else if (!strcmp(att->name, "index")) seg->index = gf_mpd_parse_string(att->value); else if (!strcmp(att->name, "mediaRange")) seg->media_range = gf_mpd_parse_byte_range(att->value); else if (!strcmp(att->name, "indexRange")) seg->index_range = gf_mpd_parse_byte_range(att->value); + //else if (!strcmp(att->name, "hls:keyMethod")) seg->key_url = gf_mpd_parse_string(att->value); + else if (!strcmp(att->name, "hls:keyURL")) seg->key_url = gf_mpd_parse_string(att->value); + else if (!strcmp(att->name, "hls:keyIV")) gf_bin128_parse(att->value, seg->key_iv); + } } @@ -430,9 +435,22 @@ static GF_Err gf_mpd_parse_content_component(GF_List *container, GF_XMLNode *roo return GF_OK; } +#define MPD_STORE_EXTENSION_ATTR(_elem) \ + if (!_elem->attributes) _elem->attributes = gf_list_new(); \ + i--; \ + gf_list_rem(root->attributes, i); \ + gf_list_add(_elem->attributes, att); \ + +#define MPD_STORE_EXTENSION_NODE(_elem) \ + if (!_elem->children) _elem->children = gf_list_new(); \ + i--; \ + gf_list_rem(root->content, i); \ + gf_list_add(_elem->children, child); \ + static GF_Err gf_mpd_parse_descriptor(GF_List *container, GF_XMLNode *root) { GF_XMLAttribute *att; + GF_XMLNode *child; GF_MPD_Descriptor *mpd_desc; u32 i = 0; @@ -441,8 +459,20 @@ static GF_Err gf_mpd_parse_descriptor(GF_List *container, GF_XMLNode *root) if (!strcmp(att->name, "schemeIdUri")) mpd_desc->scheme_id_uri = gf_mpd_parse_string(att->value); else if (!strcmp(att->name, "value")) mpd_desc->value = gf_mpd_parse_string(att->value); else if (!strcmp(att->name, "id")) mpd_desc->id = gf_mpd_parse_string(att->value); + else { + MPD_STORE_EXTENSION_ATTR(mpd_desc) + } } gf_list_add(container, mpd_desc); + + i = 0; + while ( (child = gf_list_enum(root->content, &i))) { + if (child->type != GF_XML_NODE_TYPE) continue; + + MPD_STORE_EXTENSION_NODE(mpd_desc) + + } + return GF_OK; } @@ -482,10 +512,10 @@ static void gf_mpd_parse_common_representation(GF_MPD *mpd, GF_MPD_CommonAttribu while ( (child = gf_list_enum(root->content, &i))) { if (!gf_mpd_valid_child(mpd, child)) continue; if (!strcmp(child->name, "FramePacking")) { - gf_mpd_parse_content_component(com->frame_packing, child); + gf_mpd_parse_descriptor(com->frame_packing, child); } else if (!strcmp(child->name, "AudioChannelConfiguration")) { - gf_mpd_parse_content_component(com->audio_channels, child); + gf_mpd_parse_descriptor(com->audio_channels, child); } else if (!strcmp(child->name, "ContentProtection")) { gf_mpd_parse_descriptor(com->content_protection, child); @@ -739,9 +769,8 @@ void gf_mpd_url_free(void *_item) if (ptr->sourceURL) gf_free(ptr->sourceURL); gf_free(ptr); } -void gf_mpd_string_free(void *_item) -{ - gf_free( (char *) _item ); +void gf_mpd_string_free(void *_item) { + gf_free(_item); } void gf_mpd_prog_info_free(void *_item) @@ -761,6 +790,7 @@ void gf_mpd_segment_url_free(void *_ptr) if (ptr->index_range) gf_free(ptr->index_range); if (ptr->media) gf_free(ptr->media); if (ptr->media_range) gf_free(ptr->media_range); + if (ptr->key_url) gf_free(ptr->key_url); gf_free(ptr); } void gf_mpd_segment_base_free(void *_item) @@ -807,12 +837,37 @@ void gf_mpd_segment_template_free(void *_item) if (ptr->bitstream_switching) gf_free(ptr->bitstream_switching); gf_free(ptr); } + +void gf_mpd_extensible_free(GF_MPD_ExtensibleVirtual *item) +{ + if (item->attributes) { + while (gf_list_count(item->attributes)) { + GF_XMLAttribute *att = gf_list_last(item->attributes); + gf_list_rem_last(item->attributes); + if (att->name) gf_free(att->name); + if (att->value) gf_free(att->value); + gf_free(att); + } + gf_list_del(item->attributes); + } + if (item->children) { + while (gf_list_count(item->children)) { + GF_XMLNode *child = gf_list_last(item->children); + gf_list_rem_last(item->children); + gf_xml_dom_node_del(child); + } + gf_list_del(item->children); + } +} + void gf_mpd_descriptor_free(void *item) { GF_MPD_Descriptor *mpd_desc = (GF_MPD_Descriptor*) item; if (mpd_desc->id) gf_free(mpd_desc->id); if (mpd_desc->scheme_id_uri) gf_free(mpd_desc->scheme_id_uri); if (mpd_desc->value) gf_free(mpd_desc->value); + gf_mpd_extensible_free((GF_MPD_ExtensibleVirtual *)mpd_desc); + gf_free(mpd_desc); } @@ -846,6 +901,8 @@ void gf_mpd_representation_free(void *_item) if (ptr->media_stream_structure_id) gf_free(ptr->media_stream_structure_id); if (ptr->playback.cached_init_segment_url) gf_free(ptr->playback.cached_init_segment_url); + if (ptr->playback.init_segment_data) gf_free(ptr->playback.init_segment_data); + if (ptr->playback.key_url) gf_free(ptr->playback.key_url); gf_mpd_del_list(ptr->base_URLs, gf_mpd_base_url_free, 0); gf_mpd_del_list(ptr->sub_representations, NULL/*TODO*/, 0); @@ -875,6 +932,7 @@ void gf_mpd_adaptation_set_free(void *_item) gf_mpd_del_list(ptr->representations, gf_mpd_representation_free, 0); gf_free(ptr); } + void gf_mpd_period_free(void *_item) { GF_MPD_Period *ptr = (GF_MPD_Period *)_item; @@ -900,37 +958,23 @@ void gf_mpd_del(GF_MPD *mpd) gf_mpd_del_list(mpd->periods, gf_mpd_period_free, 0); if (mpd->profiles) gf_free(mpd->profiles); if (mpd->ID) gf_free(mpd->ID); + gf_mpd_extensible_free((GF_MPD_ExtensibleVirtual*) mpd); gf_free(mpd); } + GF_EXPORT -GF_Err gf_mpd_init_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *default_base_url) +GF_Err gf_mpd_complete_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *default_base_url) { GF_Err e; - Bool ns_ok = 0; - u32 att_index, child_index; + u32 i; + Bool ns_ok = GF_FALSE; GF_XMLAttribute *att; GF_XMLNode *child; if (!root || !mpd) return GF_BAD_PARAM; - - assert( !mpd->periods ); - mpd->periods = gf_list_new(); - mpd->program_infos = gf_list_new(); - mpd->base_URLs = gf_list_new(); - mpd->locations = gf_list_new(); - mpd->metrics = gf_list_new(); - /*setup some defaults*/ - mpd->type = GF_MPD_TYPE_STATIC; - /*infinite by default*/ - mpd->time_shift_buffer_depth = (u32) -1; - - mpd->xml_namespace = NULL; - att_index = 0; - child_index = gf_list_count(root->attributes); - for (att_index = 0 ; att_index < child_index; att_index++) { - att = gf_list_get(root->attributes, att_index); - if (!att) continue; + i=0; + while ((att = gf_list_enum(root->attributes, &i))) { if (!strcmp(att->name, "xmlns")) { if (!root->ns && (!strcmp(att->value, "urn:mpeg:dash:schema:mpd:2011") || !strcmp(att->value, "urn:mpeg:DASH:schema:MPD:2011")) ) { ns_ok = 1; @@ -940,7 +984,7 @@ GF_Err gf_mpd_init_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *default_b else if (!strncmp(att->name, "xmlns:", 6)) { if (root->ns && !strcmp(att->name+6, root->ns) && (!strcmp(att->value, "urn:mpeg:dash:schema:mpd:2011") || !strcmp(att->value, "urn:mpeg:DASH:schema:MPD:2011")) ) { ns_ok = 1; - mpd->xml_namespace = root->ns; + if (!mpd->xml_namespace) mpd->xml_namespace = root->ns; break; } } @@ -950,13 +994,12 @@ GF_Err gf_mpd_init_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *default_b GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD] Wrong namespace found for DASH MPD - cannot parse\n")); } - att_index = 0; - for (att_index = 0 ; att_index < child_index; att_index++) { - att = gf_list_get(root->attributes, att_index); - if (!att) { - continue; - } + if (!strcmp(root->name, "Period")) { + return gf_mpd_parse_period(mpd, root); + } + i = 0; + while ((att = gf_list_enum(root->attributes, &i))) { if (!strcmp(att->name, "id")) { mpd->ID = gf_mpd_parse_string(att->value); } else if (!strcmp(att->name, "profiles")) { @@ -984,39 +1027,61 @@ GF_Err gf_mpd_init_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *default_b mpd->max_segment_duration = gf_mpd_parse_duration(att->value); } else if (!strcmp(att->name, "maxSubsegmentDuration")) { mpd->max_subsegment_duration = gf_mpd_parse_duration(att->value); + } else { + MPD_STORE_EXTENSION_ATTR(mpd) } } if (mpd->type == GF_MPD_TYPE_STATIC) mpd->minimum_update_period = mpd->time_shift_buffer_depth = 0; - child_index = 0; - while (1) { - child = gf_list_get(root->content, child_index); - if (!child) { - break; - } else if (gf_mpd_valid_child(mpd, child) ) { - if (!strcmp(child->name, "ProgramInformation")) { - e = gf_mpd_parse_program_info(mpd, child); - if (e) return e; - } else if (!strcmp(child->name, "Location")) { - e = gf_mpd_parse_location(mpd, child); - if (e) return e; - } else if (!strcmp(child->name, "Period")) { - e = gf_mpd_parse_period(mpd, child); - if (e) return e; - } else if (!strcmp(child->name, "Metrics")) { - e = gf_mpd_parse_metrics(mpd, child); - if (e) return e; - } else if (!strcmp(child->name, "BaseURL")) { - e = gf_mpd_parse_base_url(mpd->base_URLs, child); - if (e) return e; - } + i = 0; + while ( ( child = gf_list_enum(root->content, &i )) ) { + if (! gf_mpd_valid_child(mpd, child)) + continue; + + if (!strcmp(child->name, "ProgramInformation")) { + e = gf_mpd_parse_program_info(mpd, child); + if (e) return e; + } else if (!strcmp(child->name, "Location")) { + e = gf_mpd_parse_location(mpd, child); + if (e) return e; + } else if (!strcmp(child->name, "Period")) { + e = gf_mpd_parse_period(mpd, child); + if (e) return e; + } else if (!strcmp(child->name, "Metrics")) { + e = gf_mpd_parse_metrics(mpd, child); + if (e) return e; + } else if (!strcmp(child->name, "BaseURL")) { + e = gf_mpd_parse_base_url(mpd->base_URLs, child); + if (e) return e; + } else { + MPD_STORE_EXTENSION_NODE(mpd) } - child_index++; } return GF_OK; } + +GF_EXPORT +GF_Err gf_mpd_init_from_dom(GF_XMLNode *root, GF_MPD *mpd, const char *default_base_url) +{ + if (!root || !mpd) return GF_BAD_PARAM; + + assert(!mpd->periods); + mpd->periods = gf_list_new(); + mpd->program_infos = gf_list_new(); + mpd->base_URLs = gf_list_new(); + mpd->locations = gf_list_new(); + mpd->metrics = gf_list_new(); + + /*setup some defaults*/ + mpd->type = GF_MPD_TYPE_STATIC; + mpd->time_shift_buffer_depth = (u32) -1; /*infinite by default*/ + mpd->xml_namespace = NULL; + + return gf_mpd_complete_from_dom(root, mpd, default_base_url); +} + GF_EXPORT GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, const char *mpd_file, @@ -1024,20 +1089,21 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, { GF_Err e; char *sep, *template_base, *template_ext; - u32 i, count, j, count2, k, count3, template_width, template_idx_start; + u32 i, nb_streams, j, k, template_width, template_idx_start; Double update_interval; - VariantPlaylist * pl = NULL; + MasterPlaylist *pl = NULL; Bool use_template; - Program *prog; + Stream *stream; PlaylistElement *pe, *the_pe, *elt; FILE *fmpd; Bool is_end; u32 max_dur = 0; - e = parse_root_playlist(m3u8_file, &pl, base_url); + e = gf_m3u8_parse_master_playlist(m3u8_file, &pl, base_url); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[M3U8] Failed to parse root playlist '%s', error = %s\n", m3u8_file, gf_error_to_string(e))); - if (pl) variant_playlist_del(pl); + if (pl) + gf_m3u8_master_playlist_del(pl); pl = NULL; return e; } @@ -1045,138 +1111,138 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, gf_delete_file(m3u8_file); mpd_file = m3u8_file; } + the_pe = NULL; pe = NULL; - i=0; - assert( pl ); - assert( pl->programs ); - while ((prog = gf_list_enum(pl->programs, &i))) { - u32 j=0; - - while (NULL != (pe = gf_list_enum(prog->bitrates, &j))) { - Bool found = 0; - u32 k; + i = 0; + assert(pl); + assert(pl->streams); + while ((stream = gf_list_enum(pl->streams, &i))) { + j = 0; + while (NULL != (pe = gf_list_enum(stream->variants, &j))) { + Bool found = GF_FALSE; char *suburl; - - if (!pe->url ) + if (!pe->url) continue; - /*filter out duplicated entries (seen on M6 m3u8)*/ - for (k=0; k<j-1; k++) { - PlaylistElement *a_pe = gf_list_get(prog->bitrates, k); + /* filter out duplicated entries (seen on M6 m3u8) */ + for (k=0; k<j-1; ++k) { + PlaylistElement *a_pe = gf_list_get(stream->variants, k); if (a_pe->url && pe->url && !strcmp(a_pe->url, pe->url)) { - found = 1; + found = GF_TRUE; break; } } - if (found) continue; + if (found) + continue; the_pe = pe; suburl = NULL; - - /*not HLS*/ - if ( !strstr(pe->url, ".m3u8")) - continue; + if (!strstr(pe->url, ".m3u8")) + continue; /*not HLS*/ if (strcmp(base_url, pe->url)) suburl = gf_url_concatenate(base_url, pe->url); if (!suburl || !strcmp(base_url, suburl)) { - if (suburl) gf_free(suburl); + if (suburl) + gf_free(suburl); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD Generator] Not downloading, programs are identical for %s...\n", pe->url)); continue; } + if (getter && getter->new_session && getter->del_session && getter->get_cache_name) { e = getter->new_session(getter, suburl); if (e) { gf_free(suburl); - break; + pe->load_error = e; + continue; } - if (e==GF_OK) { - e = parse_sub_playlist(getter->get_cache_name(getter), &pl, suburl, prog, pe); + if (e == GF_OK) { + pe->load_error = gf_m3u8_parse_sub_playlist(getter->get_cache_name(getter), &pl, suburl, stream, pe); } getter->del_session(getter); - -#if 0 - GF_DownloadSession *sess = gf_service_download_new(service, suburl, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL); - if (!sess) { - gf_free(suburl); - break; - } - e = gf_dm_sess_process(sess); - if (e==GF_OK) { - e = parse_sub_playlist(gf_dm_sess_get_cache_name(sess), &pl, suburl, prog, pe); - } - gf_service_download_del(sess); -#endif - gf_free(suburl); } else { /* for use in MP4Box */ - if (strstr(suburl, "://") ) { - e = gf_dm_wget(suburl, "tmp.m3u8", 0, 0); - if (e==GF_OK) { - e = parse_sub_playlist("tmp.m3u8", &pl, suburl, prog, pe); + if (strstr(suburl, "://")) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD Generator] Downloading %s...\n", suburl)); + e = gf_dm_wget(suburl, "tmp.m3u8", 0, 0, NULL); + if (e == GF_OK) { + e = gf_m3u8_parse_sub_playlist("tmp.m3u8", &pl, suburl, stream, pe); + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD Generator] Download faile for %s\n", suburl)); } gf_delete_file("tmp.m3u8"); } else { - e = parse_sub_playlist(suburl, &pl, suburl, prog, pe); + e = gf_m3u8_parse_sub_playlist(suburl, &pl, suburl, stream, pe); } } + gf_free(suburl); + } + if (max_dur < (u32) stream->computed_duration) { + max_dur = (u32) stream->computed_duration; } - if (max_dur < (u32) prog->computed_duration) - max_dur = (u32) prog->computed_duration; } - is_end = !pl->playlistNeedsRefresh; - assert(the_pe); + is_end = !pl->playlist_needs_refresh; + if (!the_pe) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD Generator] The M3U8 playlist is not correct.\n")); + return GF_BAD_PARAM; + } update_interval = 0; /*update interval is set to the duration of the last media file with rules defined in http live streaming RFC section 6.3.4*/ switch (reload_count) { case 0: - update_interval = the_pe->durationInfo; + update_interval = the_pe->duration_info; break; case 1: - update_interval = (Double)the_pe->durationInfo/2; + update_interval = (Double)the_pe->duration_info / 2; break; case 2: - update_interval = 3*((Double)the_pe->durationInfo/2); + update_interval = 3 * ((Double)the_pe->duration_info / 2); break; default: - update_interval = 3*(the_pe->durationInfo); + update_interval = 3 * the_pe->duration_info; break; } - if (is_end || ((the_pe->elementType == TYPE_PLAYLIST) && the_pe->element.playlist.is_ended)) { + if (is_end || ((the_pe->element_type == TYPE_PLAYLIST) && the_pe->element.playlist.is_ended)) { update_interval = 0; - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD Generator] NO NEED to refresh playlist !\n")); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD Generator] No need to refresh playlist!\n")); } else { - GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD Generator] Playlist will be refreshed every %g seconds, len=%d\n", update_interval, the_pe->durationInfo)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD Generator] Playlist will be refreshed every %g seconds, len=%d\n", update_interval, the_pe->duration_info)); } - assert( mpd_file ); - fmpd = gf_f64_open(mpd_file, "wt"); + assert(mpd_file); + fmpd = gf_fopen(mpd_file, "wt"); if (!fmpd) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[MPD Generator] Cannot write to temp file %s!\n", mpd_file)); - variant_playlist_del(pl); + gf_m3u8_master_playlist_del(pl); return GF_IO_ERR; } - fprintf(fmpd, "<MPD type=\"%s\" xmlns=\"urn:mpeg:DASH:schema:MPD:2011\" profiles=\"urn:mpeg:dash:profile:full:2011\"", is_end ? "static" : "dynamic" ); + + fprintf(fmpd, "<MPD type=\"%s\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xmlns:hls=\"urn:gpac:hls:aes:mpd:2015\" profiles=\"urn:mpeg:dash:profile:full:2011\"", is_end ? "static" : "dynamic" ); sep = strrchr(m3u8_file, '/'); - if (!sep) sep = strrchr(m3u8_file, '\\'); - if (sep) sep = sep + 1; - else sep = (char *)m3u8_file; + if (!sep) + sep = strrchr(m3u8_file, '\\'); + if (sep) + sep = sep + 1; + else + sep = (char *)m3u8_file; fprintf(fmpd, " id=\"%s\"", sep); - if (update_interval) fprintf(fmpd, " minimumUpdatePeriod=\"PT%02.2gS\"", update_interval); - if (is_end) fprintf(fmpd, " mediaPresentationDuration=\"PT%dS\"", max_dur); + if (update_interval) + fprintf(fmpd, " minimumUpdatePeriod=\"PT%02.2gS\"", update_interval); + if (is_end) + fprintf(fmpd, " mediaPresentationDuration=\"PT%dS\"", max_dur); fprintf(fmpd, " minBufferTime=\"PT1.5S\""); fprintf(fmpd, ">\n"); fprintf(fmpd, " <ProgramInformation moreInformationURL=\"http://gpac.sourceforge.net\">\n"); { - char * title = the_pe->title; + char *title = the_pe->title; if (!title || strlen(title) < 2) title = the_pe->url; - fprintf(fmpd, " <Title>%s\n", title ); + fprintf(fmpd, " %s\n", title); } fprintf(fmpd, " Generated from URL %s\n", base_url ); fprintf(fmpd, " Generated by GPAC %s from %s\n", GPAC_FULL_VERSION, base_url); @@ -1185,25 +1251,28 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, fprintf(fmpd, " \n"); - - - count = gf_list_count(pl->programs); + + nb_streams = gf_list_count(pl->streams); /*check if we use templates*/ template_base = NULL; template_ext = NULL; use_template = use_mpd_templates; template_width = 0; template_idx_start = 0; - for (i=0; iprograms, i); - count2 = gf_list_count(prog->bitrates); - for (j = 0; jbitrates, j); - if (pe->elementType != TYPE_PLAYLIST) + elt = NULL; + for (i=0; istreams, i); + count_variants = gf_list_count(stream->variants); + for (j=0; jvariants, j); + if (pe->element_type != TYPE_PLAYLIST) continue; - count3 = gf_list_count(pe->element.playlist.elements); - if (!count3) continue; + count_elements = gf_list_count(pe->element.playlist.elements); + if (!count_elements) + continue; if (!template_base && use_template) { char *sub_url; @@ -1230,7 +1299,7 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, } k++; if (!template_base[k]) { - use_template = 0; + use_template = GF_FALSE; break; } } @@ -1238,22 +1307,28 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, if (!template_ext) template_ext=""; if (use_template) { - for (k=0; kelement.playlist.elements, k); - if (template_width==2) sprintf(szURL, "%s%02d%s", template_base, template_idx_start + k, template_ext); - else if (template_width==3) sprintf(szURL, "%s%03d%s", template_base, template_idx_start + k, template_ext); - else if (template_width==4) sprintf(szURL, "%s%04d%s", template_base, template_idx_start + k, template_ext); - else if (template_width==5) sprintf(szURL, "%s%05d%s", template_base, template_idx_start + k, template_ext); - else if (template_width==6) sprintf(szURL, "%s%06d%s", template_base, template_idx_start + k, template_ext); - else sprintf(szURL, "%s%d%s", template_base, template_idx_start + k, template_ext); + if (template_width == 2) + sprintf(szURL, "%s%02d%s", template_base, template_idx_start + k, template_ext); + else if (template_width == 3) + sprintf(szURL, "%s%03d%s", template_base, template_idx_start + k, template_ext); + else if (template_width == 4) + sprintf(szURL, "%s%04d%s", template_base, template_idx_start + k, template_ext); + else if (template_width == 5) + sprintf(szURL, "%s%05d%s", template_base, template_idx_start + k, template_ext); + else if (template_width == 6) + sprintf(szURL, "%s%06d%s", template_base, template_idx_start + k, template_ext); + else + sprintf(szURL, "%s%d%s", template_base, template_idx_start + k, template_ext); sub_url = strrchr(elt->url, '/'); if (!sub_url) sub_url = elt->url; else sub_url ++; if (strcmp(szURL, sub_url)) { - use_template = 0; + use_template = GF_FALSE; break; } } @@ -1261,95 +1336,100 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, } } + + nb_streams = gf_list_count(pl->streams); + for (i=0; i\n"); - fprintf(fmpd, " \n"); - - /*if we use templates, put the SegmentTemplate element at the adaptationSet level*/ - if (use_template) { - fprintf(fmpd, " durationInfo); - if (template_width>1) { - fprintf(fmpd, " media=\"%s$%%0%ddNumber$%s\"", template_base, template_width, template_ext); - } else { - fprintf(fmpd, " media=\"%s$Number$%s\"", template_base, template_ext); + fprintf(fmpd, " duration=\"%d\"", (u32) pe->duration_info); + if (template_width > 1) { + fprintf(fmpd, " media=\"%s$%%0%ddNumber$%s\"", template_base, template_width, template_ext); + } else { + fprintf(fmpd, " media=\"%s$Number$%s\"", template_base, template_ext); + } + fprintf(fmpd, " startNumber=\"%d\"", template_idx_start); + fprintf(fmpd, "/>\n"); } - fprintf(fmpd, " startNumber=\"%d\"", template_idx_start); - fprintf(fmpd, "/>\n"); - } - if (do_import) { -#ifndef GPAC_DISABLE_MEDIA_IMPORT - GF_Err e; - GF_MediaImporter import; - char *tmp_file = NULL; - elt = gf_list_get(pe->element.playlist.elements, 0); - memset(&import, 0, sizeof(GF_MediaImporter)); - import.trackID = 0; - import.flags = GF_IMPORT_PROBE_ONLY; - - if (strstr(elt->url, "://") && !strstr(elt->url, "file://")) { - tmp_file = strrchr(elt->url, '/'); - if (!tmp_file) tmp_file = strrchr(elt->url, '\\'); - if (tmp_file) { - e = gf_dm_wget(elt->url, tmp_file, 0, 0); - if (e==GF_OK) { - import.in_name = tmp_file; - e = gf_media_import(&import); + if (elt && do_import) { + #ifndef GPAC_DISABLE_MEDIA_IMPORT + GF_Err e; + GF_MediaImporter import; + char *tmp_file = NULL; + elt = gf_list_get(pe->element.playlist.elements, 0); + memset(&import, 0, sizeof(GF_MediaImporter)); + import.trackID = 0; + import.flags = GF_IMPORT_PROBE_ONLY; + + if (strstr(elt->url, "://") && !strstr(elt->url, "file://")) { + tmp_file = strrchr(elt->url, '/'); + if (!tmp_file) tmp_file = strrchr(elt->url, '\\'); + if (tmp_file) { + e = gf_dm_wget(elt->url, tmp_file, 0, 0, NULL); + if (e==GF_OK) { + import.in_name = tmp_file; + e = gf_media_import(&import); + } } + } else { + import.in_name = elt->url; + e = gf_media_import(&import); } - } else { - import.in_name = elt->url; - e = gf_media_import(&import); - } - - if (import.nb_tracks>1) { - for (k=0; k 1) { + for (k=0; k\n"); } - fprintf(fmpd, "/>\n"); } + if (tmp_file) + gf_delete_file(tmp_file); + #endif } - if (tmp_file) - gf_delete_file(tmp_file); -#endif - } - /*check if we use templates*/ - count = gf_list_count(pl->programs); - for (i=0; iprograms, i); - count2 = gf_list_count(prog->bitrates); - for (j = 0; jstreams, i); + count_variants = gf_list_count(stream->variants); + for (j=0; jbitrates, j); - - if (pe->elementType == TYPE_STREAM) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD] NOT SUPPORTED: M3U8 Stream\n")); - } else if (pe->elementType != TYPE_PLAYLIST) { - GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD] NOT SUPPORTED: M3U8 unknown type\n")); + pe = gf_list_get(stream->variants, j); + + if (pe->element_type == TYPE_MEDIA) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD] NOT SUPPORTED: M3U8 Media\n")); + } else if (pe->load_error) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD] Error loading playlist element %s: %s\n", pe->url, gf_error_to_string(e) )); + } else if (pe->element_type != TYPE_PLAYLIST) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD] NOT SUPPORTED: M3U8 unknown type for %s\n", pe->url)); } - count3 = gf_list_count(pe->element.playlist.elements); - if (!count3) continue; + count_elements = gf_list_count(pe->element.playlist.elements); + if (!count_elements) + continue; base_url = gf_strdup(pe->url); sep = strrchr(base_url, '/'); @@ -1361,14 +1441,21 @@ GF_Err gf_m3u8_to_mpd(const char *m3u8_file, const char *base_url, } #ifndef GPAC_DISABLE_MEDIA_IMPORT if (pe->bandwidth && pe->codecs && pe->width && pe->height) { - import_file = 0; + import_file = GF_FALSE; } #endif + k = 0; +#ifndef GPAC_DISABLE_MEDIA_IMPORT +try_next_segment: +#endif + k++; + elt = gf_list_get(pe->element.playlist.elements, k); + if (!elt) + break; /*get rid of level 0 aac*/ - elt = gf_list_get(pe->element.playlist.elements, 0); if (elt && strstr(elt->url, ".aac")) - is_aac = 1; + is_aac = GF_TRUE; if (is_aac) fprintf(fmpd, "\n"); } - } - if (template_base) { - gf_free(template_base); - template_base = NULL; - } + if (template_base) { + gf_free(template_base); + template_base = NULL; + } - fprintf(fmpd, " \n"); + fprintf(fmpd, " \n"); + } fprintf(fmpd, " \n"); fprintf(fmpd, ""); - fclose(fmpd); - variant_playlist_del(pl); + + gf_fclose(fmpd); + gf_m3u8_master_playlist_del(pl); + return GF_OK; } + +void gf_mpd_print_date(FILE *out, char *name, u64 time) +{ + time_t gtime; + struct tm *t; + gtime = time / 1000; + t = gmtime(>ime); + fprintf(out, " %s=\"%d-%02d-%02dT%02d:%02d:%02dZ\"", name, 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); +} + +void gf_mpd_print_duration(FILE *out, char *name, u32 duration) +{ + u32 h, m; + Double s; + h = (u32) (duration / 3600000); + m = (u32) (duration/ 60000) - h*60; + s = ((Double) duration/1000.0) - h*3600 - m*60; + + fprintf(out, " %s=\"PT%02dH%02dM%02.2fS\"", name, h, m, s); +} + +static void gf_mpd_print_base_url(FILE *out, GF_List *base_URLs, char *indent) +{ + GF_MPD_BaseURL *url; + u32 i; + i=0; + while ((url = (GF_MPD_BaseURL *)gf_list_enum(base_URLs, &i))) { + fprintf(out, "%sservice_location) + fprintf(out, " serviceLocation=\"%s\"", url->service_location); + if (url->byte_range) + fprintf(out, " byteRange=\""LLD"-"LLD"\"", url->byte_range->start_range, url->byte_range->end_range); + fprintf(out, ">%s\n", url->URL); + } +} + +static void gf_mpd_print_url(FILE *out, GF_MPD_URL *url, char *name, char *indent) +{ + fprintf(out, "%s<%s", indent, name); + if (url->byte_range) fprintf(out, " range=\""LLD"-"LLD"\"", url->byte_range->start_range, url->byte_range->end_range); + if (url->sourceURL) fprintf(out, " range=\"%s\"", url->sourceURL); + fprintf(out, "/>\n"); +} + +static void gf_mpd_print_segment_base_attr(FILE *out, GF_MPD_SegmentBase *s) +{ + if (s->timescale) fprintf(out, " timescale=\"%d\"", s->timescale); + if (s->presentation_time_offset) fprintf(out, " timescale=\""LLU"\"", s->presentation_time_offset); + if (s->index_range) fprintf(out, " indexRange=\""LLD"-"LLD"\"", s->index_range->start_range, s->index_range->end_range); + if (s->index_range_exact) fprintf(out, " indexRangeExact=\"true\""); + if (s->availability_time_offset) fprintf(out, " availabilityTimeOffset=\"%g\"", s->availability_time_offset); + if (s->time_shift_buffer_depth) + gf_mpd_print_duration(out, "timeShiftBufferDepth", s->time_shift_buffer_depth); +} + +static void gf_mpd_print_segment_base(FILE *out, GF_MPD_SegmentBase *s, char *indent) +{ + fprintf(out, "%s\n"); + + if (s->initialization_segment) gf_mpd_print_url(out, s->initialization_segment, "Initialization", indent); + if (s->representation_index) gf_mpd_print_url(out, s->representation_index, "RepresentationIndex", indent); + + fprintf(out, "%s\n", indent); +} + +static void gf_mpd_print_segment_timeline(FILE *out, GF_MPD_SegmentTimeline *tl, char *indent) +{ + u32 i; + GF_MPD_SegmentTimelineEntry *se; + fprintf(out, "%s \n", indent); + + i = 0; + while ( (se = gf_list_enum(tl->entries, &i))) { + fprintf(out, "%s start_time) fprintf(out, " t=\""LLD"\"", se->start_time); + if (se->duration) fprintf(out, " d=\"%d\"", se->duration); + if (se->repeat_count) fprintf(out, " r=\"%d\"", se->repeat_count); + fprintf(out, ">\n"); + } + fprintf(out, "%s \n", indent); +} + +static u32 gf_mpd_print_multiple_segment_base(FILE *out, GF_MPD_MultipleSegmentBase *ms, char *indent) +{ + gf_mpd_print_segment_base_attr(out, (GF_MPD_SegmentBase *)ms); + + if (ms->duration) fprintf(out, " duration=\""LLD"\"", ms->duration); + if (ms->start_number != (u32) -1) fprintf(out, " startNumber=\"%d\"", ms->start_number); + + + if (!ms->bitstream_switching_url && !ms->segment_timeline && !ms->initialization_segment && !ms->representation_index) { + fprintf(out, "/>\n"); + return 1; + } + fprintf(out, ">\n"); + + if (ms->initialization_segment) gf_mpd_print_url(out, ms->initialization_segment, "Initialization", indent); + if (ms->representation_index) gf_mpd_print_url(out, ms->representation_index, "RepresentationIndex", indent); + + if (ms->segment_timeline) gf_mpd_print_segment_timeline(out, ms->segment_timeline, indent); + if (ms->bitstream_switching_url) gf_mpd_print_url(out, ms->bitstream_switching_url, "BitstreamSwitching", indent); + return 0; +} + +static void gf_mpd_print_segment_list(FILE *out, GF_MPD_SegmentList *s, char *indent) +{ + fprintf(out, "%sxlink_href) { + fprintf(out, " xlink:href=\"%s\"", s->xlink_href); + if (s->xlink_actuate_on_load) + fprintf(out, " actuate=\"onLoad\""); + } + gf_mpd_print_multiple_segment_base(out, (GF_MPD_MultipleSegmentBase *)s, indent); + + if (s->segment_URLs) { + u32 i; + GF_MPD_SegmentURL *url; + i = 0; + while ( (url = gf_list_enum(s->segment_URLs, &i))) { + fprintf(out, "%smedia) fprintf(out, " media=\"%s\"", url->media); + if (url->index) fprintf(out, " index=\"%s\"", url->index); + if (url->media_range) fprintf(out, " mediaRange=\""LLD"-"LLD"\"", url->media_range->start_range, url->media_range->end_range); + if (url->index_range) fprintf(out, " indexRange=\""LLD"-"LLD"\"", url->index_range->start_range, url->index_range->end_range); + if (url->key_url) { + u32 idx; + fprintf(out, " hls:keyMethod=\"aes-128\" hls:KeyURL=%s hls:KeyIV=\"", url->key_url); + for (idx=0; idx<16; i++) { + fprintf(out, "%02x", url->key_iv[i]); + } + fprintf(out, "\""); + } + fprintf(out, "/>\n"); + fprintf(out, "/>\n"); + } + } + fprintf(out, "%s\n", indent); +} + +static void gf_mpd_print_segment_template(FILE *out, GF_MPD_SegmentTemplate *s, char *indent) +{ + fprintf(out, "%smedia) fprintf(out, " media=\"%s\"", s->media); + if (s->index) fprintf(out, " index=\"%s\"", s->index); + if (s->initialization) fprintf(out, " initialization=\"%s\"", s->initialization); + if (s->bitstream_switching) fprintf(out, " bitstreamSwitching=\"%s\"", s->bitstream_switching); + + if (gf_mpd_print_multiple_segment_base(out, (GF_MPD_MultipleSegmentBase *)s, indent)) + return; + + fprintf(out, "%s\n", indent); +} + +static void gf_mpd_extensible_print_attr(FILE *out, GF_MPD_ExtensibleVirtual *item) +{ + if (item->attributes) { + u32 j=0; + GF_XMLAttribute *att; + while ((att = (GF_XMLAttribute *)gf_list_enum(item->attributes, &j))) { + fprintf(out, " %s=\"%s\"", att->name, att->value); + } + } +} + +static void gf_mpd_extensible_print_nodes(FILE *out, GF_MPD_ExtensibleVirtual *item) +{ + if (item->children) { + u32 j=0; + GF_XMLNode *child; + fprintf(out, ">\n"); + while ((child = (GF_XMLNode *)gf_list_enum(item->children, &j))) { + char *txt = gf_xml_dom_serialize(child, 0); + fprintf(out, "%s", txt); + gf_free(txt); + } + } +} + +static void gf_mpd_print_descriptors(FILE *out, GF_List *desc_list, char *desc_name, char *indent) +{ + u32 i=0; + GF_MPD_Descriptor *desc; + while ((desc = (GF_MPD_Descriptor *)gf_list_enum(desc_list, &i))) { + fprintf(out, "%s<%s", indent, desc_name); + if (desc->id) fprintf(out, " id=\"%s\"", desc->id); + if (desc->scheme_id_uri) fprintf(out, " schemeIdUri=\"%s\"", desc->scheme_id_uri); + if (desc->value) fprintf(out, " value=\"%s\"", desc->value); + + if (desc->attributes) gf_mpd_extensible_print_attr(out, (GF_MPD_ExtensibleVirtual*)desc); + + if (desc->children) { + gf_mpd_extensible_print_nodes(out, (GF_MPD_ExtensibleVirtual*)desc); + fprintf(out, "%s\n", indent, desc_name); + } else { + fprintf(out, "/>\n"); + } + } +} + +static u32 gf_mpd_print_common_representation(FILE *out, GF_MPD_CommonAttributes *ca, char *indent, Bool can_close) +{ + if (ca->profiles) fprintf(out, " profiles=\"%s\"", ca->profiles); + if (ca->width) fprintf(out, " width=\"%d\"", ca->width); + if (ca->height) fprintf(out, " height=\"%d\"", ca->height); + if (ca->sar) fprintf(out, " sar=\"%d:%d\"", ca->sar->num, ca->sar->den); + if (ca->framerate) fprintf(out, " frameRate=\"%d:%d\"", ca->framerate->num, ca->framerate->den); + if (ca->samplerate) fprintf(out, " audioSamplingRate=\"%d\"", ca->samplerate); + if (ca->mime_type) fprintf(out, " mimeType=\"%s\"", ca->mime_type); + if (ca->segmentProfiles) fprintf(out, " segmentProfiles=\"%s\"", ca->segmentProfiles); + if (ca->codecs) fprintf(out, " codecs=\"%s\"", ca->codecs); + if (ca->maximum_sap_period) fprintf(out, " maximumSAPPeriod=\"%d\"", ca->maximum_sap_period); + if (ca->starts_with_sap) fprintf(out, " startWithSAP=\"%d\"", ca->starts_with_sap); + if (ca->max_playout_rate) fprintf(out, " maxPlayoutRate=\"%g\"", ca->max_playout_rate); + if (ca->coding_dependency) fprintf(out, " codingDependency=\"true\""); + if (ca->scan_type!=GF_MPD_SCANTYPE_UNKNWON) fprintf(out, " scanType=\"%s\"", ca->scan_type==GF_MPD_SCANTYPE_PROGRESSIVE ? "progressive" : "interlaced"); + + if (can_close && !gf_list_count(ca->frame_packing) && !gf_list_count(ca->audio_channels) && !gf_list_count(ca->content_protection) && !gf_list_count(ca->essential_properties) && !gf_list_count(ca->supplemental_properties) && !ca->isobmf_tracks) { + fprintf(out, "/>\n"); + return 1; + } + + fprintf(out, ">\n"); + + if (ca->isobmf_tracks) { + u32 k=0; + GF_MPD_ISOBMFInfo *info; + fprintf(out, "%s\n", indent); + while ((info = (GF_MPD_ISOBMFInfo *) gf_list_enum(ca->isobmf_tracks, &k))) { + fprintf(out, "%s trackID) fprintf(out, " ID=\"%d\"", info->trackID); + if (info->stsd) fprintf(out, " stsd=\"%s\"", info->stsd); + if (info->mediaOffset) fprintf(out, " offset=\""LLD"\"", info->mediaOffset); + fprintf(out, "/>\n"); + } + fprintf(out, "%s\n", indent); + } + + gf_mpd_print_descriptors(out, ca->frame_packing, "Framepacking", indent); + gf_mpd_print_descriptors(out, ca->audio_channels, "AudioChannelConfiguration", indent); + gf_mpd_print_descriptors(out, ca->content_protection, "ContentProtection", indent); + gf_mpd_print_descriptors(out, ca->essential_properties, "EssentialProperty", indent); + gf_mpd_print_descriptors(out, ca->supplemental_properties, "SupplementalProperty", indent); + return 0; +} + +static void gf_mpd_print_representation(FILE *out, GF_MPD_Representation *rep) +{ + Bool can_close = GF_FALSE; + fprintf(out, " id) fprintf(out, " id=\"%s\"", rep->id); + if (rep->bandwidth) fprintf(out, " bandwidth=\"%d\"", rep->bandwidth); + if (rep->quality_ranking) fprintf(out, " qualityRanking=\"%d\"", rep->quality_ranking); + if (rep->dependency_id) fprintf(out, " dependencyId=\"%s\"", rep->dependency_id); + if (rep->media_stream_structure_id) fprintf(out, " mediaStreamStructureId=\"%s\"", rep->media_stream_structure_id); + + + if (!gf_list_count(rep->base_URLs) && !rep->segment_base && !rep->segment_template && !rep->segment_list && !gf_list_count(rep->sub_representations)) { + can_close = 1; + } + + if (gf_mpd_print_common_representation(out, (GF_MPD_CommonAttributes*)rep, " ", can_close)) + return; + + gf_mpd_print_base_url(out, rep->base_URLs, " "); + if (rep->segment_base) { + gf_mpd_print_segment_base(out, rep->segment_base, " "); + } + if (rep->segment_list) { + gf_mpd_print_segment_list(out, rep->segment_list, " "); + } + if (rep->segment_template) { + gf_mpd_print_segment_template(out, rep->segment_template, " "); + } + /*TODO + e = gf_mpd_parse_subrepresentation(rep->sub_representations, child); + if (e) return e; + */ + + fprintf(out, " \n"); +} + +static void gf_mpd_print_adaptation_set(FILE *out, GF_MPD_AdaptationSet *as) +{ + u32 i; + GF_MPD_Representation *rep; + fprintf(out, " xlink_href) { + fprintf(out, " xlink:href=\"%s\"", as->xlink_href); + if (as->xlink_actuate_on_load) + fprintf(out, " actuate=\"onLoad\""); + } + if (as->id) fprintf(out, " id=\"%d\"", as->id); + if (as->group != (u32) -1) fprintf(out, " group=\"%d\"", as->group); + if (as->lang) fprintf(out, " lang=\"%s\"", as->lang); + if (as->par) fprintf(out, " par=\"%d:%d\"", as->par->num, as->par->den); + if (as->min_bandwidth) fprintf(out, " minBandwidth=\"%d\"", as->min_bandwidth); + if (as->max_bandwidth) fprintf(out, " maxBandwidth=\"%d\"", as->max_bandwidth); + if (as->min_width) fprintf(out, " minWidth=\"%d\"", as->min_width); + if (as->max_width) fprintf(out, " maxWidth=\"%d\"", as->max_width); + if (as->min_height) fprintf(out, " minHeight=\"%d\"", as->min_height); + if (as->max_height) fprintf(out, " maxHeight=\"%d\"", as->max_height); + if (as->min_framerate) fprintf(out, " minFrameRate=\"%d\"", as->min_framerate); + if (as->max_framerate) fprintf(out, " maxFrameRate=\"%d\"", as->max_framerate); + if (as->segment_alignment) fprintf(out, " segmentAlignment=\"true\""); + if (as->bitstream_switching) fprintf(out, " bitstreamSwitching=\"true\""); + if (as->subsegment_alignment) fprintf(out, " subsegmentAlignment=\"true\""); + if (as->subsegment_starts_with_sap) fprintf(out, " subsegmentStartsWithSAP=\"%d\"", as->subsegment_starts_with_sap); + + + gf_mpd_print_common_representation(out, (GF_MPD_CommonAttributes*)as, " ", 0); + + gf_mpd_print_base_url(out, as->base_URLs, " "); + + gf_mpd_print_descriptors(out, as->accessibility, "Accessibility", " "); + gf_mpd_print_descriptors(out, as->role, "Role", " "); + gf_mpd_print_descriptors(out, as->rating, "Rating", " "); + gf_mpd_print_descriptors(out, as->viewpoint, "Viewpoint", " "); + +// e = gf_mpd_parse_content_component(set->content_component, child); + + if (as->segment_base) { + gf_mpd_print_segment_base(out, as->segment_base, " "); + } + if (as->segment_list) { + gf_mpd_print_segment_list(out, as->segment_list, " "); + } + if (as->segment_template) { + gf_mpd_print_segment_template(out, as->segment_template, " "); + } + + i=0; + while ((rep = (GF_MPD_Representation *)gf_list_enum(as->representations, &i))) { + gf_mpd_print_representation(out, rep); + } + fprintf(out, " \n"); + + +} + +static void gf_mpd_print_period(GF_MPD_Period *period, FILE *out) +{ + GF_MPD_AdaptationSet *as; + u32 i; + fprintf(out, " xlink_href) { + fprintf(out, " xlink:href=\"%s\"", period->xlink_href); + if (period->xlink_actuate_on_load) + fprintf(out, " actuate=\"onLoad\""); + } + if (period->ID) + fprintf(out, " id=\"%s\"", period->ID); + if (period->start) + gf_mpd_print_duration(out, "start", period->start); + if (period->duration) + gf_mpd_print_duration(out, "duration", period->start); + if (period->bitstream_switching) + fprintf(out, " bitstreamSwitching=\"true\""); + + fprintf(out, ">\n"); + + gf_mpd_print_base_url(out, period->base_URLs, " "); + + if (period->segment_base) { + gf_mpd_print_segment_base(out, period->segment_base, " "); + } + if (period->segment_list) { + gf_mpd_print_segment_list(out, period->segment_list, " "); + } + if (period->segment_template) { + gf_mpd_print_segment_template(out, period->segment_template, " "); + } + + i=0; + while ( (as = (GF_MPD_AdaptationSet *) gf_list_enum(period->adaptation_sets, &i))) { + gf_mpd_print_adaptation_set(out, as); + } + fprintf(out, "
\n"); + +} + +static GF_Err gf_mpd_write(GF_MPD *mpd, FILE *out) +{ + u32 i; + GF_MPD_ProgramInfo *info; + char *text; + GF_MPD_Period *period; + + fprintf(out, "\nxml_namespace, (mpd->type == GF_MPD_TYPE_STATIC) ? "static" : "dynamic"); + + if (mpd->ID) + fprintf(out, " ID=\"%s\"", mpd->ID); + + if (mpd->profiles) + fprintf(out, " profiles=\"%s\"", mpd->profiles); + if (mpd->availabilityStartTime) + gf_mpd_print_date(out, "availabilityStartTime", mpd->availabilityStartTime); + if (mpd->availabilityEndTime) + gf_mpd_print_date(out, "availabilityStartTime", mpd->availabilityEndTime); + if (mpd->publishTime) + gf_mpd_print_date(out, "availabilityStartTime", mpd->publishTime); + if (mpd->media_presentation_duration) + gf_mpd_print_duration(out, "mediaPresentationDuration", mpd->media_presentation_duration); + if (mpd->minimum_update_period) + gf_mpd_print_duration(out, "minimumUpdatePeriod", mpd->minimum_update_period); + if (mpd->min_buffer_time) + gf_mpd_print_duration(out, "minBufferTime", mpd->min_buffer_time); + if (mpd->time_shift_buffer_depth) + gf_mpd_print_duration(out, "timeShiftBufferDepth", mpd->time_shift_buffer_depth); + if (mpd->suggested_presentaton_delay) + gf_mpd_print_duration(out, "suggestedPresentationDelay", mpd->suggested_presentaton_delay); + if (mpd->max_segment_duration) + gf_mpd_print_duration(out, "maxSegmentDuration", mpd->max_segment_duration); + if (mpd->max_subsegment_duration) + gf_mpd_print_duration(out, "maxSubsegmentDuration", mpd->max_subsegment_duration); + + if (mpd->attributes) gf_mpd_extensible_print_attr(out, (GF_MPD_ExtensibleVirtual*)mpd); + + fprintf(out, ">\n"); + + if (mpd->children) { + gf_mpd_extensible_print_nodes(out, (GF_MPD_ExtensibleVirtual*)mpd); + } + + i=0; + while ((info = (GF_MPD_ProgramInfo *)gf_list_enum(mpd->program_infos, &i))) { + fprintf(out, " lang) { + fprintf(out, " lang=\"%s\"", info->lang); + } + if (info->more_info_url) { + fprintf(out, " moreInformationURL=\"%s\"", info->more_info_url); + } + fprintf(out, ">\n"); + if (info->title) { + fprintf(out, " %s\n", info->title); + } + if (info->source) { + fprintf(out, " %s\n", info->source); + } + if (info->copyright) { + fprintf(out, " %s\n", info->copyright); + } + fprintf(out, " \n"); + } + + gf_mpd_print_base_url(out, mpd->base_URLs, " "); + + i=0; + while ((text = (char *)gf_list_enum(mpd->locations, &i))) { + fprintf(out, " %s\n", text); + } + +/* + i=0; + while ((text = (char *)gf_list_enum(mpd->metrics, &i))) { + + } +*/ + + i=0; + while ((period = (GF_MPD_Period *)gf_list_enum(mpd->periods, &i))) { + gf_mpd_print_period(period, out); + } + + + fprintf(out, "\n"); + + return GF_OK; +} + +GF_EXPORT +GF_Err gf_mpd_write_file(GF_MPD *mpd, char *file_name) +{ + GF_Err e; + FILE *out; + if (!strcmp(file_name, "std")) out = stdout; + else { + out = gf_fopen(file_name, "wb"); + if (!out) return GF_IO_ERR; + } + + e = gf_mpd_write(mpd, out); + gf_fclose(out); + return e; +} + + +GF_EXPORT +GF_Err gf_mpd_resolve_url(GF_MPD *mpd, GF_MPD_Representation *rep, GF_MPD_AdaptationSet *set, GF_MPD_Period *period, const char *mpd_url, GF_MPD_URLResolveType resolve_type, u32 item_index, u32 nb_segments_removed, char **out_url, u64 *out_range_start, u64 *out_range_end, u64 *segment_duration, Bool *is_in_base_url, char **out_key_url, bin128 *out_key_iv) +{ + GF_MPD_BaseURL *url_child; + GF_MPD_SegmentTimeline *timeline = NULL; + u32 start_number = 1; + u32 timescale=0; + char *url; + char *url_to_solve, *solved_template, *first_sep, *media_url; + char *init_template, *index_template; + + *out_range_start = *out_range_end = 0; + *out_url = NULL; + if (out_key_url) *out_key_url = NULL; + /*resolve base URLs from document base (download location) to representation (media)*/ + url = gf_strdup(mpd_url); + + url_child = gf_list_get(mpd->base_URLs, 0); + if (url_child) { + char *t_url = gf_url_concatenate(url, url_child->URL); + gf_free(url); + url = t_url; + } + + url_child = gf_list_get(period->base_URLs, 0); + if (url_child) { + char *t_url = gf_url_concatenate(url, url_child->URL); + gf_free(url); + url = t_url; + } + + url_child = gf_list_get(set->base_URLs, 0); + if (url_child) { + char *t_url = gf_url_concatenate(url, url_child->URL); + gf_free(url); + url = t_url; + } + + url_child = gf_list_get(rep->base_URLs, 0); + if (url_child) { + char *t_url = gf_url_concatenate(url, url_child->URL); + gf_free(url); + url = t_url; + } + + /*single URL*/ + if (!rep->segment_list && !set->segment_list && !period->segment_list && !rep->segment_template && !set->segment_template && !period->segment_template) { + GF_MPD_URL *res_url; + GF_MPD_SegmentBase *base_seg = NULL; + if (item_index > 0) + return GF_EOS; + switch (resolve_type) { + case GF_MPD_RESOLVE_URL_MEDIA: + case GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE: + if (!url) return GF_NON_COMPLIANT_BITSTREAM; + *out_url = url; + return GF_OK; + case GF_MPD_RESOLVE_URL_INIT: + case GF_MPD_RESOLVE_URL_INDEX: + res_url = NULL; + base_seg = rep->segment_base; + if (!base_seg) base_seg = set->segment_base; + if (!base_seg) base_seg = period->segment_base; + + if (base_seg) { + if (resolve_type == GF_MPD_RESOLVE_URL_INDEX) { + res_url = base_seg->representation_index; + } else { + res_url = base_seg->initialization_segment; + } + } + if (is_in_base_url) *is_in_base_url = 0; + /*no initialization segment / index, use base URL*/ + if (res_url && res_url->sourceURL) { + if (res_url->is_resolved) { + *out_url = gf_strdup(res_url->sourceURL); + } else { + *out_url = gf_url_concatenate(url, res_url->sourceURL); + } + gf_free(url); + } else { + *out_url = url; + if (is_in_base_url) *is_in_base_url = 1; + } + if (res_url && res_url->byte_range) { + *out_range_start = res_url->byte_range->start_range; + *out_range_end = res_url->byte_range->end_range; + } else if (base_seg && base_seg->index_range && (resolve_type == GF_MPD_RESOLVE_URL_INDEX)) { + *out_range_start = base_seg->index_range->start_range; + *out_range_end = base_seg->index_range->end_range; + } + return GF_OK; + default: + break; + } + gf_free(url); + return GF_BAD_PARAM; + } + + /*segmentList*/ + if (rep->segment_list || set->segment_list || period->segment_list) { + GF_MPD_URL *init_url, *index_url; + GF_MPD_SegmentURL *segment; + GF_List *segments = NULL; + u32 segment_count; + + init_url = index_url = NULL; + + /*apply inheritance of attributes, lowest level having preceedence*/ + if (period->segment_list) { + if (period->segment_list->initialization_segment) init_url = period->segment_list->initialization_segment; + if (period->segment_list->representation_index) index_url = period->segment_list->representation_index; + if (period->segment_list->segment_URLs) segments = period->segment_list->segment_URLs; + if (period->segment_list->start_number != (u32) -1) start_number = period->segment_list->start_number; + if (period->segment_list->segment_timeline) timeline = period->segment_list->segment_timeline; + if (!timescale && period->segment_list->timescale) timescale = period->segment_list->timescale; + } + if (set->segment_list) { + if (set->segment_list->initialization_segment) init_url = set->segment_list->initialization_segment; + if (set->segment_list->representation_index) index_url = set->segment_list->representation_index; + if (set->segment_list->segment_URLs) segments = set->segment_list->segment_URLs; + if (set->segment_list->start_number != (u32) -1) start_number = set->segment_list->start_number; + if (set->segment_list->segment_timeline) timeline = set->segment_list->segment_timeline; + if (!timescale && set->segment_list->timescale) timescale = set->segment_list->timescale; + } + if (rep->segment_list) { + if (rep->segment_list->initialization_segment) init_url = rep->segment_list->initialization_segment; + if (rep->segment_list->representation_index) index_url = rep->segment_list->representation_index; + if (rep->segment_list->segment_URLs) segments = rep->segment_list->segment_URLs; + if (rep->segment_list->start_number != (u32) -1) start_number = rep->segment_list->start_number; + if (rep->segment_list->segment_timeline) timeline = rep->segment_list->segment_timeline; + if (!timescale && rep->segment_list->timescale) timescale = rep->segment_list->timescale; + } + + + segment_count = gf_list_count(segments); + + switch (resolve_type) { + case GF_MPD_RESOLVE_URL_INIT: + if (init_url) { + if (init_url->sourceURL) { + if (init_url->is_resolved) { + *out_url = gf_strdup(init_url->sourceURL); + } else { + *out_url = gf_url_concatenate(url, init_url->sourceURL); + } + gf_free(url); + } else { + *out_url = url; + } + if (init_url->byte_range) { + *out_range_start = init_url->byte_range->start_range; + *out_range_end = init_url->byte_range->end_range; + } + } else { + gf_free(url); + } + return GF_OK; + case GF_MPD_RESOLVE_URL_MEDIA: + case GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE: + if (!url) { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Media URL is not set in segment list\n")); + return GF_SERVICE_ERROR; + } + if ((item_index >= segment_count) || ((s32) item_index < 0)) { + gf_free(url); + return GF_EOS; + } + *out_url = url; + segment = gf_list_get(segments, item_index); + if (segment->media) { + *out_url = gf_url_concatenate(url, segment->media); + gf_free(url); + } + if (segment->media_range) { + *out_range_start = segment->media_range->start_range; + *out_range_end = segment->media_range->end_range; + } + if (segment->duration) { + *segment_duration = (u32) ((Double) (segment->duration) * 1000.0 / timescale); + } + if (segment->key_url && out_key_url) { + *out_key_url = gf_strdup((const char *) segment->key_url); + if (out_key_iv) + memcpy((*out_key_iv), segment->key_iv, sizeof(bin128) ); + } + return GF_OK; + case GF_MPD_RESOLVE_URL_INDEX: + if (item_index >= segment_count) { + gf_free(url); + return GF_EOS; + } + *out_url = url; + segment = gf_list_get(segments, item_index); + if (segment->index) { + *out_url = gf_url_concatenate(url, segment->index); + gf_free(url); + } + if (segment->index_range) { + *out_range_start = segment->index_range->start_range; + *out_range_end = segment->index_range->end_range; + } + return GF_OK; + default: + break; + } + gf_free(url); + return GF_BAD_PARAM; + } + + /*segmentTemplate*/ + media_url = init_template = index_template = NULL; + + /*apply inheritance of attributes, lowest level having preceedence*/ + if (period->segment_template) { + if (period->segment_template->initialization) init_template = period->segment_template->initialization; + if (period->segment_template->index) index_template = period->segment_template->index; + if (period->segment_template->media) media_url = period->segment_template->media; + if (period->segment_template->start_number != (u32) -1) start_number = period->segment_template->start_number; + if (period->segment_template->segment_timeline) timeline = period->segment_template->segment_timeline; + if (!timescale && period->segment_template->timescale) timescale = period->segment_template->timescale; + } + if (set->segment_template) { + if (set->segment_template->initialization) init_template = set->segment_template->initialization; + if (set->segment_template->index) index_template = set->segment_template->index; + if (set->segment_template->media) media_url = set->segment_template->media; + if (set->segment_template->start_number != (u32) -1) start_number = set->segment_template->start_number; + if (set->segment_template->segment_timeline) timeline = set->segment_template->segment_timeline; + if (!timescale && set->segment_template->timescale) timescale = set->segment_template->timescale; + } + if (rep->segment_template) { + if (rep->segment_template->initialization) init_template = rep->segment_template->initialization; + if (rep->segment_template->index) index_template = rep->segment_template->index; + if (rep->segment_template->media) media_url = rep->segment_template->media; + if (rep->segment_template->start_number != (u32) -1) start_number = rep->segment_template->start_number; + if (rep->segment_template->segment_timeline) timeline = rep->segment_template->segment_timeline; + if (!timescale && rep->segment_template->timescale) timescale = rep->segment_template->timescale; + } + + /*offset the start_number with the number of discarded segments (no longer in our lists)*/ + start_number += nb_segments_removed; + + if (!media_url) { + GF_MPD_BaseURL *base = gf_list_get(rep->base_URLs, 0); + if (!base) return GF_BAD_PARAM; + media_url = base->URL; + } + url_to_solve = NULL; + switch (resolve_type) { + case GF_MPD_RESOLVE_URL_INIT: + url_to_solve = init_template; + break; + case GF_MPD_RESOLVE_URL_MEDIA: + case GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE: + url_to_solve = media_url; + break; + case GF_MPD_RESOLVE_URL_INDEX: + url_to_solve = index_template; + break; + default: + gf_free(url); + return GF_BAD_PARAM; + } + if (!url_to_solve) { + gf_free(url); + return GF_OK; + } + /*let's solve the template*/ + solved_template = gf_malloc(sizeof(char)*(strlen(url_to_solve) + (rep->id ? strlen(rep->id) : 0)) * 2); + solved_template[0] = 0; + strcpy(solved_template, url_to_solve); + first_sep = strchr(solved_template, '$'); + if (first_sep) first_sep[0] = 0; + + first_sep = strchr(url_to_solve, '$'); + while (first_sep) { + char szPrintFormat[50]; + char szFormat[100]; + char *format_tag; + char *second_sep = strchr(first_sep+1, '$'); + if (!second_sep) { + gf_free(url); + gf_free(solved_template); + return GF_NON_COMPLIANT_BITSTREAM; + } + second_sep[0] = 0; + format_tag = strchr(first_sep+1, '%'); + + if (format_tag) { + strcpy(szPrintFormat, format_tag); + format_tag[0] = 0; + if (!strchr(szPrintFormat, 'd') && !strchr(szPrintFormat, 'i') && !strchr(szPrintFormat, 'u')) + strcat(szPrintFormat, "d"); + } else { + strcpy(szPrintFormat, "%d"); + } + /* identifier is $$ -> replace by $*/ + if (!strlen(first_sep+1)) { + strcat(solved_template, "$"); + } + else if (!strcmp(first_sep+1, "RepresentationID")) { + strcat(solved_template, rep->id); + } + else if (!strcmp(first_sep+1, "Number")) { + if (resolve_type==GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE) { + strcat(solved_template, "$Number$"); + } else { + sprintf(szFormat, szPrintFormat, start_number + item_index); + strcat(solved_template, szFormat); + } + } + else if (!strcmp(first_sep+1, "Index")) { + GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] Wrong template identifier Index detected - using Number instead\n\n")); + sprintf(szFormat, szPrintFormat, start_number + item_index); + strcat(solved_template, szFormat); + } + else if (!strcmp(first_sep+1, "Bandwidth")) { + sprintf(szFormat, szPrintFormat, rep->bandwidth); + strcat(solved_template, szFormat); + } + else if (!strcmp(first_sep+1, "Time")) { + if (resolve_type==GF_MPD_RESOLVE_URL_MEDIA_TEMPLATE) { + strcat(solved_template, "$Time$"); + } else if (timeline) { + /*uses segment timeline*/ + u32 k, nb_seg, cur_idx, nb_repeat; + u64 time, start_time; + nb_seg = gf_list_count(timeline->entries); + cur_idx = 0; + start_time=0; + for (k=0; kentries, k); + if (item_index>cur_idx+ent->repeat_count) { + cur_idx += 1 + ent->repeat_count; + if (ent->start_time) start_time = ent->start_time; + + start_time += ent->duration * (1 + ent->repeat_count); + continue; + } + *segment_duration = ent->duration; + *segment_duration = (u32) ((Double) (*segment_duration) * 1000.0 / timescale); + nb_repeat = item_index - cur_idx; + time = ent->start_time ? ent->start_time : start_time; + time += nb_repeat * ent->duration; + + /*replace final 'd' with LLD (%lld or I64d)*/ + szPrintFormat[strlen(szPrintFormat)-1] = 0; + strcat(szPrintFormat, &LLD[1]); + sprintf(szFormat, szPrintFormat, time); + strcat(solved_template, szFormat); + break; + } + } + } + else { + GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[DASH] Unknown template identifier %s - disabling rep\n\n", first_sep+1)); + *out_url = NULL; + gf_free(url); + gf_free(solved_template); + return GF_NON_COMPLIANT_BITSTREAM; + } + if (format_tag) format_tag[0] = '%'; + second_sep[0] = '$'; + /*look for next keyword - copy over remaining text if any*/ + first_sep = strchr(second_sep+1, '$'); + if (first_sep) first_sep[0] = 0; + if (strlen(second_sep+1)) + strcat(solved_template, second_sep+1); + if (first_sep) first_sep[0] = '$'; + } + *out_url = gf_url_concatenate(url, solved_template); + gf_free(url); + gf_free(solved_template); + return GF_OK; +} + diff --git a/src/media_tools/mpeg2_ps.c b/src/media_tools/mpeg2_ps.c index 1fd83ab..b764538 100644 --- a/src/media_tools/mpeg2_ps.c +++ b/src/media_tools/mpeg2_ps.c @@ -143,7 +143,7 @@ struct mpeg2ps_ { *************************************************************************/ static FILE *file_open (const char *name) { - return gf_f64_open(name, "rb"); + return gf_fopen(name, "rb"); } static Bool file_okay (FILE *fd) @@ -153,7 +153,7 @@ static Bool file_okay (FILE *fd) static void file_close (FILE *fd) { - fclose(fd); + gf_fclose(fd); } static Bool file_read_bytes(FILE *fd, @@ -167,18 +167,18 @@ static Bool file_read_bytes(FILE *fd, // note: len could be negative. static void file_skip_bytes (FILE *fd, s32 len) { - gf_f64_seek(fd, len, SEEK_CUR); + gf_fseek(fd, len, SEEK_CUR); } -#define file_location(__f) gf_f64_tell(__f) -#define file_seek_to(__f, __off) gf_f64_seek(__f, __off, SEEK_SET) +#define file_location(__f) gf_ftell(__f) +#define file_seek_to(__f, __off) gf_fseek(__f, __off, SEEK_SET) static u64 file_size(FILE *fd) { u64 ret; - gf_f64_seek(fd, 0, SEEK_END); - ret = gf_f64_tell(fd); - gf_f64_seek(fd, 0, SEEK_SET); + gf_fseek(fd, 0, SEEK_END); + ret = gf_ftell(fd); + gf_fseek(fd, 0, SEEK_SET); return ret; } @@ -866,8 +866,9 @@ mpeg2ps_stream_find_mpeg_video_frame (mpeg2ps_stream_t *sptr) static Bool mpeg2ps_stream_find_ac3_frame (mpeg2ps_stream_t *sptr) { u32 diff; - GF_AC3Header hdr; Bool started_new_pes = 0; + GF_AC3Header hdr; + memset(&hdr, 0, sizeof(GF_AC3Header)); sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 6) { if (sptr->pes_buffer_size != sptr->pes_buffer_on) @@ -1044,6 +1045,7 @@ static void get_info_from_frame (mpeg2ps_stream_t *sptr, } else if (sptr->m_substream_id >= 0x80) { u32 pos; GF_AC3Header hdr; + memset(&hdr, 0, sizeof(GF_AC3Header)); gf_ac3_parser(buffer, buflen, &pos, &hdr, 0); sptr->bitrate = hdr.bitrate; sptr->freq = hdr.sample_rate; @@ -1782,12 +1784,12 @@ u64 mpeg2ps_get_ps_size(mpeg2ps_t *ps) s64 mpeg2ps_get_video_pos(mpeg2ps_t *ps, u32 streamno) { if (invalid_video_streamno(ps, streamno)) return 0; - return gf_f64_tell(ps->video_streams[streamno]->m_fd); + return gf_ftell(ps->video_streams[streamno]->m_fd); } s64 mpeg2ps_get_audio_pos(mpeg2ps_t *ps, u32 streamno) { if (invalid_audio_streamno(ps, streamno)) return 0; - return gf_f64_tell(ps->audio_streams[streamno]->m_fd); + return gf_ftell(ps->audio_streams[streamno]->m_fd); } #endif /*GPAC_DISABLE_MPEG2PS*/ diff --git a/src/media_tools/mpegts.c b/src/media_tools/mpegts.c index 15002de..75e2874 100644 --- a/src/media_tools/mpegts.c +++ b/src/media_tools/mpegts.c @@ -130,7 +130,7 @@ static void gf_m2ts_estimate_duration(GF_M2TS_Demuxer *ts, u64 PCR, u16 pcr_pid) ts->first_pcr_found = PCR; ts->pcr_pid = pcr_pid; ts->nb_pck_at_pcr = ts->nb_pck; - } else if (PCR-ts->first_pcr_found > 2*27000000) { + } else if (PCR - ts->first_pcr_found > 2*27000000) { Bool changed = GF_FALSE; Double pck_dur = (Double) (PCR-ts->first_pcr_found); pck_dur /= (ts->nb_pck - ts->nb_pck_at_pcr); @@ -265,7 +265,7 @@ static u32 gf_m2ts_reframe_nalu_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Boo sc_pos=1; } else { - if (start_code_found==2) { + if (!full_au_pes_mode && (start_code_found==2)) { pck.data = (char *)data-1; pck.data[0]=0; pck.data_len = sc_pos+1; @@ -304,6 +304,14 @@ static u32 gf_m2ts_reframe_nalu_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Boo ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck); au_start = NULL; full_au_pes_mode = 0; + if (start_code_found==2) { + pck.data = (char *)data-1; + pck.data[0]=0; + pck.data_len = sc_pos+1; + } else { + pck.data = (char *)data; + pck.data_len = sc_pos; + } } if (au_start_in_pes) { @@ -371,6 +379,14 @@ static u32 gf_m2ts_reframe_nalu_video(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Boo ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck); au_start = NULL; full_au_pes_mode = 0; + if (start_code_found==2) { + pck.data = (char *)data-1; + pck.data[0]=0; + pck.data_len = sc_pos+1; + } else { + pck.data = (char *)data; + pck.data_len = sc_pos; + } } if (au_start_in_pes) { @@ -610,10 +626,10 @@ static u32 gf_m2ts_reframe_aac_adts(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool ADTSHeader hdr; u32 sc_pos = 0; u32 start = 0; - u32 hdr_size = 0; u64 PTS; Bool first = 1; + Bool garbage_bytes = 0; GF_M2TS_PES_PCK pck; /*dispatch frame*/ @@ -623,7 +639,7 @@ static u32 gf_m2ts_reframe_aac_adts(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool pck.PTS = PTS; pck.flags = 0; - if (pes->frame_state && ((pes->frame_state==data_len) || ((data[pes->frame_state]==0xFF) && ((data[pes->frame_state+1] & 0xF0) == 0xF0)))) { + if (pes->frame_state && ((pes->frame_state==data_len) || (((pes->frame_state+1frame_state]==0xFF) && ((data[pes->frame_state+1] & 0xF0) == 0xF0)))) { assert(pes->frame_state<=data_len); /*dispatch frame*/ pck.stream = pes; @@ -648,8 +664,11 @@ static u32 gf_m2ts_reframe_aac_adts(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool continue; } + if (garbage_bytes) { + garbage_bytes = 0; + } /*flush any pending data*/ - if (start < sc_pos) { + else if (start < sc_pos) { /*dispatch frame*/ pck.stream = pes; pck.DTS = PTS; @@ -708,15 +727,25 @@ static u32 gf_m2ts_reframe_aac_adts(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool pck.stream = pes; memset(&cfg, 0, sizeof(GF_M4ADecSpecInfo)); cfg.base_object_type = hdr.profile; - pes->aud_sr = cfg.base_sr = GF_M4ASampleRates[hdr.sr_idx]; + cfg.base_sr = GF_M4ASampleRates[hdr.sr_idx]; + + + if (!cfg.base_sr) { + sc_pos++; + garbage_bytes = 1; + continue; + } + + pes->aud_sr = cfg.base_sr; pes->aud_nb_ch = cfg.nb_chan = hdr.nb_ch; cfg.sbr_object_type = 0; gf_m4a_write_config(&cfg, &pck.data, &pck.data_len); ts->on_event(ts, GF_M2TS_EVT_AAC_CFG, &pck); gf_free(pck.data); + pes->aud_aac_sr_idx = cfg.base_sr_index; pes->aud_sr = cfg.base_sr; pes->aud_nb_ch = cfg.nb_chan; - pes->aud_obj_type = hdr.profile; + pes->aud_aac_obj_type = hdr.profile; } /*dispatch frame*/ @@ -770,6 +799,17 @@ static u32 gf_m2ts_reframe_aac_latm(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool pck.PTS = pes->PTS; pck.flags = 0; + + if (data_len + pes->reassemble_len > pes->reassemble_alloc) { + pes->reassemble_alloc = data_len + pes->reassemble_len; + pes->reassemble_buf = gf_realloc(pes->reassemble_buf, sizeof(char)*pes->reassemble_alloc); + } + memcpy(pes->reassemble_buf + pes->reassemble_len, data, data_len); + pes->reassemble_len += data_len; + data_len = pes->reassemble_len; + data = pes->reassemble_buf; + + /*fixme - we need to test this with more LATM sources were PES framing is on any boundaries*/ while (sc_pos+2= sc_pos); + memmove(pes->reassemble_buf, pes->reassemble_buf + sc_pos, data_len - sc_pos); + pes->reassemble_len -= sc_pos; + sc_pos = 0; + data_len = pes->reassemble_len; + data = pes->reassemble_buf; } /*found a start code*/ amux_len = data[sc_pos+1] & 0x1F; amux_len <<= 8; amux_len |= data[sc_pos+2]; + if (!amux_len) { + sc_pos+=3; + assert(data_len >= sc_pos); + memmove(pes->reassemble_buf, pes->reassemble_buf + sc_pos, data_len - sc_pos); + pes->reassemble_len -= sc_pos; + sc_pos = 0; + data_len = pes->reassemble_len; + data = pes->reassemble_buf; + continue; + } + + + //we cannot check sync wait for next frame + if (data_len < sc_pos+4+amux_len) { + if (pes->aud_sr) { + u32 tsinc = 1024*90000/pes->aud_sr; + pes->PTS += tsinc; + } + return 0; + } + + //we are not sync, trash what is before the start code and continue + if ((data[sc_pos+3+amux_len] != 0x56) || ((data[sc_pos+3+amux_len + 1] & 0xE0) != 0xE0)) { + sc_pos+=2; + assert(data_len >= sc_pos); + memmove(pes->reassemble_buf , pes->reassemble_buf+ sc_pos, data_len - sc_pos); + pes->reassemble_len -= sc_pos; + sc_pos = 0; + data_len = pes->reassemble_len; + data = pes->reassemble_buf; + continue; + } + bs = gf_bs_new((char *)data+sc_pos+3, amux_len, GF_BITSTREAM_READ); @@ -823,9 +900,10 @@ static u32 gf_m2ts_reframe_aac_latm(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool if (!pes->aud_sr) { pck.stream = pes; + pes->aud_aac_sr_idx = cfg.base_sr_index; pes->aud_sr = cfg.base_sr; pes->aud_nb_ch = cfg.nb_chan; - pes->aud_obj_type = cfg.base_object_type; + pes->aud_aac_obj_type = cfg.base_object_type; gf_m4a_write_config(&cfg, &pck.data, &pck.data_len); ts->on_event(ts, GF_M2TS_EVT_AAC_CFG, &pck); @@ -878,17 +956,23 @@ static u32 gf_m2ts_reframe_aac_latm(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool pck.data_len = size; ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck); + } + gf_bs_del(bs); + //trash dispatched AU, including 3 bytes header + sc_pos += amux_len+3; + assert(data_len >= sc_pos); + memmove(pes->reassemble_buf, pes->reassemble_buf + sc_pos, data_len - sc_pos); + pes->reassemble_len -= sc_pos; + sc_pos = 0; + data_len = pes->reassemble_len; + data = pes->reassemble_buf; + + if ((data_len>3) && pes->aud_sr) { /*update PTS in case we don't get any update*/ size = 1024*90000/pes->aud_sr; pes->PTS += size; } - gf_bs_del(bs); - - /*parse amux*/ - sc_pos += amux_len+3; - start = sc_pos; - } /*we consumed all data*/ return 0; @@ -914,8 +998,8 @@ static u32 gf_m2ts_reframe_mpeg_audio(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Boo if (next_hdr && remain && (posaud_sr == gf_mp3_sampling_rate(pes->frame_state) ) - && (pes->aud_nb_ch == gf_mp3_num_channels(pes->frame_state)) - ) { + && (pes->aud_nb_ch == gf_mp3_num_channels(pes->frame_state)) + ) { remain = pos; } } @@ -991,6 +1075,65 @@ static u32 gf_m2ts_reframe_mpeg_audio(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Boo } #endif /*GPAC_DISABLE_AV_PARSERS*/ + + +#ifndef GPAC_DISABLE_AV_PARSERS +static u32 gf_m2ts_reframe_ac3(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr) +{ + GF_M2TS_PES_PCK pck; + pck.flags = 0; + if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP; + if (!same_pts) pck.flags |= GF_M2TS_PES_PCK_AU_START; + pck.DTS = pes->DTS; + pck.PTS = pes->PTS; + + if (!pes->aud_sr) { + GF_AC3Header hdr; + u32 pos; + if (gf_ac3_parser(data, data_len, &pos, &hdr, GF_TRUE)) { + pes->aud_sr = hdr.sample_rate; + pes->aud_nb_ch = hdr.channels; + } + } + + pck.data = (char *)data; + pck.data_len = data_len; + pck.stream = pes; + ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck); + /*we consumed all data*/ + return 0; +} + +static u32 gf_m2ts_reframe_ec3(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, Bool same_pts, unsigned char *data, u32 data_len, GF_M2TS_PESHeader *pes_hdr) +{ + GF_M2TS_PES_PCK pck; + pck.flags = 0; + if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP; + if (!same_pts) pck.flags |= GF_M2TS_PES_PCK_AU_START; + pck.DTS = pes->DTS; + pck.PTS = pes->PTS; + + if (!pes->aud_sr) { + GF_AC3Header hdr; + GF_BitStream *bs = gf_bs_new((const char *) data, data_len, GF_BITSTREAM_READ); + if (gf_eac3_parser_bs(bs, &hdr, GF_TRUE)) { + pes->aud_sr = hdr.sample_rate; + pes->aud_nb_ch = hdr.channels; + } + gf_bs_del(bs); + } + + pck.data = (char *)data; + pck.data_len = data_len; + pck.stream = pes; + ts->on_event(ts, GF_M2TS_EVT_PES_PCK, &pck); + /*we consumed all data*/ + return 0; +} + +#endif /*GPAC_DISABLE_AV_PARSERS*/ + + typedef enum { ID3V2_FRAME_AENC = GF_4CC('A','E','N','C'), ID3V2_FRAME_APIC = GF_4CC('A','P','I','C'), @@ -1178,7 +1321,12 @@ static u32 gf_m2ts_sync(GF_M2TS_Demuxer *ts, Bool simple_check) while (ibuffer_size) { if (i+188>ts->buffer_size) return ts->buffer_size; - if ((ts->buffer[i]==0x47) && (ts->buffer[i+188]==0x47)) break; + if ((ts->buffer[i]==0x47) && (ts->buffer[i+188]==0x47)) + break; + if ((ts->buffer[i]==0x47) && (ts->buffer[i+192]==0x47)) { + ts->prefix_present = 1; + break; + } i++; } if (i) { @@ -1240,6 +1388,8 @@ static void gf_m2ts_section_filter_reset(GF_M2TS_SectionFilter *sf) } sf->cc = -1; sf->length = sf->received = 0; + sf->demux_restarted = 1; + } static void gf_m2ts_section_filter_del(GF_M2TS_SectionFilter *sf) { @@ -1270,6 +1420,7 @@ void gf_m2ts_es_del(GF_M2TS_ES *es, GF_M2TS_Demuxer *ts) if (pes->pck_data) gf_free(pes->pck_data); if (pes->prev_data) gf_free(pes->prev_data); if (pes->buf) gf_free(pes->buf); + if (pes->reassemble_buf) gf_free(pes->reassemble_buf); if (pes->temi_tc_desc) gf_free(pes->temi_tc_desc); } if (es->slcfg) gf_free(es->slcfg); @@ -1351,7 +1502,7 @@ static void gf_m2ts_section_complete(GF_M2TS_Demuxer *ts, GF_M2TS_SectionFilter Bool has_syntax_indicator; u8 table_id; u16 extended_table_id; - u32 status, section_start; + u32 status, section_start, i; GF_M2TS_Table *t, *prev_t; unsigned char *data; Bool section_valid = 0; @@ -1442,7 +1593,7 @@ static void gf_m2ts_section_complete(GF_M2TS_Demuxer *ts, GF_M2TS_SectionFilter } } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted section (CRC32 failed)\n")); - } + } } } else { section_valid = 1; @@ -1481,11 +1632,32 @@ static void gf_m2ts_section_complete(GF_M2TS_Demuxer *ts, GF_M2TS_SectionFilter } if (t->last_section_number == t->section_number) { + u32 table_size; + status |= GF_M2TS_TABLE_END; + + table_size = 0; + for (i=0; isections); i++) { + GF_M2TS_Section *section = gf_list_get(t->sections, i); + table_size += section->data_size; + } + if (t->is_repeat) { + if (t->table_size != table_size) { + status |= GF_M2TS_TABLE_UPDATE; + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Repeated section found with different sizes (old table %d bytes, new table %d bytes)\n", t->table_size, table_size) ); + + t->table_size = table_size; + } + } else { + t->table_size = table_size; + } + t->is_init = 1; /*reset section number*/ t->section_number = 0; + t->is_repeat = 0; + } if (sec->process_individual) { @@ -1655,7 +1827,6 @@ static void gf_m2ts_process_sdt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF } if (table_id != GF_M2TS_TABLE_ID_SDT_ACTUAL) { - gf_m2ts_reset_sdt(ts); return; } @@ -1717,7 +1888,7 @@ static void gf_m2ts_process_sdt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF break; default: - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Skipping descriptor (0x%x) not supported\n", d_tag)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Skipping descriptor (0x%x) not supported\n", d_tag)); d_pos += d_len; if (d_len == 0) d_pos = descs_size; break; @@ -2010,12 +2181,16 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF nb_es = 0; - /*skip if already received*/ - if (status&GF_M2TS_TABLE_REPEAT) { + /*skip if already received but no update detected (eg same data) */ + if ((status&GF_M2TS_TABLE_REPEAT) && !(status&GF_M2TS_TABLE_UPDATE)) { if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PMT_REPEAT, pmt->program); return; } + if (pmt->sec->demux_restarted) { + pmt->sec->demux_restarted = 0; + return; + } GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PMT Found or updated\n")); nb_sections = gf_list_count(sections); @@ -2176,15 +2351,17 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF break; case GF_M2TS_MPE_SECTIONS: - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("stream type MPE found : pid = %d \n", pid)); + if (! ts->prefix_present) { + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("stream type MPE found : pid = %d \n", pid)); #ifdef GPAC_ENABLE_MPE - es = gf_dvb_mpe_section_new(); - if (es->flags & GF_M2TS_ES_IS_SECTION) { - /* NULL means: trigger the call to on_event with DVB_GENERAL type and the raw section as payload */ - ((GF_M2TS_SECTION_ES*)es)->sec = gf_m2ts_section_filter_new(NULL, 1); - } + es = gf_dvb_mpe_section_new(); + if (es->flags & GF_M2TS_ES_IS_SECTION) { + /* NULL means: trigger the call to on_event with DVB_GENERAL type and the raw section as payload */ + ((GF_M2TS_SECTION_ES*)es)->sec = gf_m2ts_section_filter_new(NULL, 1); + } #endif - break; + break; + } default: GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Stream type (0x%x) for PID %d not supported\n", stream_type, pid ) ); @@ -2228,6 +2405,9 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF case GF_4CC('V', 'C', '-', '1'): es->stream_type = GF_M2TS_VIDEO_VC1; break; + default: + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Unknown registration descriptor %s\n", gf_4cc_to_str(reg_desc_format) )); + break; } break; case GF_M2TS_DVB_EAC3_DESCRIPTOR: @@ -2254,7 +2434,7 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF case GF_M2TS_DVB_STREAM_IDENTIFIER_DESCRIPTOR: { es->component_tag = data[2]; - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Component Tag: %d on Program %d\n", es->component_tag, es->program->number)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("Component Tag: %d on Program %d\n", es->component_tag, es->program->number)); } break; case GF_M2TS_DVB_TELETEXT_DESCRIPTOR: @@ -2264,8 +2444,10 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF es->stream_type = GF_M2TS_DVB_VBI; break; case GF_M2TS_HIERARCHY_DESCRIPTOR: - if (pes) - pes->depends_on_pid = (data[4] & 0x3F) + es->program->pmt_pid; + if (pes) { + //u8 hierarchy_layer_idx = (data[3] & 0x3F); + pes->depends_on_pid = (data[4] & 0x3F); + } break; case GF_M2TS_METADATA_DESCRIPTOR: { @@ -2309,27 +2491,41 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF if (!es) continue; - /*watchout for pmt update - FIXME this likely won't work in most cases*/ if (ts->ess[pid]) { - GF_M2TS_ES *o_es = ts->ess[es->pid]; - - if ((o_es->stream_type == es->stream_type) - && ((o_es->flags & GF_M2TS_ES_STATIC_FLAGS_MASK) == (es->flags & GF_M2TS_ES_STATIC_FLAGS_MASK)) - && (o_es->mpeg4_es_id == es->mpeg4_es_id) - && ((o_es->flags & GF_M2TS_ES_IS_SECTION) || ((GF_M2TS_PES *)o_es)->lang == ((GF_M2TS_PES *)es)->lang) - ) { - gf_free(es); + //this is component reuse across programs, overwrite the previously declared stream ... + if (status & GF_M2TS_TABLE_FOUND) { + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d reused across programs %d and %d, not completely supported\n", pid, ts->ess[pid]->program->number, es->program->number ) ); + + //add stream to program but don't reassign the pid table until the stream is playing (>GF_M2TS_PES_FRAMING_SKIP) + gf_list_add(pmt->program->streams, es); + if (!(es->flags & GF_M2TS_ES_IS_SECTION) ) gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP); + + nb_es++; + //skip assignment below es = NULL; - } else { - gf_m2ts_es_del(o_es, ts); - ts->ess[es->pid] = NULL; + } + /*watchout for pmt update - FIXME this likely won't work in most cases*/ + else { + + GF_M2TS_ES *o_es = ts->ess[es->pid]; + + if ((o_es->stream_type == es->stream_type) + && ((o_es->flags & GF_M2TS_ES_STATIC_FLAGS_MASK) == (es->flags & GF_M2TS_ES_STATIC_FLAGS_MASK)) + && (o_es->mpeg4_es_id == es->mpeg4_es_id) + && ((o_es->flags & GF_M2TS_ES_IS_SECTION) || ((GF_M2TS_PES *)o_es)->lang == ((GF_M2TS_PES *)es)->lang) + ) { + gf_free(es); + es = NULL; + } else { + gf_m2ts_es_del(o_es, ts); + ts->ess[es->pid] = NULL; + } } } if (es) { ts->ess[es->pid] = es; gf_list_add(pmt->program->streams, es); - if (!(es->flags & GF_M2TS_ES_IS_SECTION) ) gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP); nb_es++; @@ -2338,6 +2534,18 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF if (nb_es) { + u32 i; + //translate hierarchy descriptors indexes into PIDs - check whether the PMT-index rules are the same for HEVC + for (i=0; iprogram->streams); i++) { + GF_M2TS_PES *an_es = NULL; + GF_M2TS_PES *es = (GF_M2TS_PES *)gf_list_get(pmt->program->streams, i); + if ( !(es->flags & GF_M2TS_ES_IS_PES)) continue; + if (!es->depends_on_pid) continue; + + an_es = (GF_M2TS_PES *)gf_list_get(pmt->program->streams, es->depends_on_pid); + if (an_es) es->depends_on_pid = an_es->pid; + } + evt_type = (status&GF_M2TS_TABLE_FOUND) ? GF_M2TS_EVT_PMT_FOUND : GF_M2TS_EVT_PMT_UPDATE; if (ts->on_event) ts->on_event(ts, evt_type, pmt->program); } else { @@ -2346,7 +2554,6 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF } } -static u32 nb_pat=0; static void gf_m2ts_process_pat(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF_List *sections, u8 table_id, u16 ex_table_id, u8 version_number, u8 last_section_number, u32 status) { GF_M2TS_Program *prog; @@ -2357,8 +2564,6 @@ static void gf_m2ts_process_pat(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF unsigned char *data; GF_M2TS_Section *section; - nb_pat++; - /*wait for the last section */ if (!(status&GF_M2TS_TABLE_END)) return; @@ -2378,10 +2583,13 @@ static void gf_m2ts_process_pat(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, GF data_size = section->data_size; if (!(status&GF_M2TS_TABLE_UPDATE) && gf_list_count(ts->programs)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Multiple different PAT on single TS found, ignoring new PAT declaration (table id %d - extended table id %d)\n", table_id, ex_table_id)); + if (ts->pat->demux_restarted) { + ts->pat->demux_restarted = 0; + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Multiple different PAT on single TS found, ignoring new PAT declaration (table id %d - extended table id %d)\n", table_id, ex_table_id)); + } return; } - nb_progs = data_size / 4; for (i=0; istreams = gf_list_new(); prog->pmt_pid = pid; prog->number = number; + prog->ts = ts; gf_list_add(ts->programs, prog); GF_SAFEALLOC(pmt, GF_M2TS_SECTION_ES); pmt->flags = GF_M2TS_ES_IS_SECTION; @@ -2541,32 +2750,30 @@ void gf_m2ts_pes_header(GF_M2TS_PES *pes, unsigned char *data, u32 data_size, GF } } -static void gf_m2ts_flush_temi(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes) +static void gf_m2ts_store_temi(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes) { - GF_M2TS_TemiTimecodeDescriptor temi_tc; GF_BitStream *bs = gf_bs_new(pes->temi_tc_desc, pes->temi_tc_desc_len, GF_BITSTREAM_READ); u32 has_timestamp = gf_bs_read_int(bs, 2); /*u32 has_ntp = */gf_bs_read_int(bs, 1); /*u32 has_ptp = */gf_bs_read_int(bs, 1); /*u32 has_timecode = */gf_bs_read_int(bs, 2); - memset(&temi_tc, 0, sizeof(GF_M2TS_TemiTimecodeDescriptor)); - temi_tc.force_reload = gf_bs_read_int(bs, 1); - temi_tc.is_paused = gf_bs_read_int(bs, 1); - temi_tc.is_discontinuity = gf_bs_read_int(bs, 1); + memset(&pes->temi_tc, 0, sizeof(GF_M2TS_TemiTimecodeDescriptor)); + pes->temi_tc.force_reload = gf_bs_read_int(bs, 1); + pes->temi_tc.is_paused = gf_bs_read_int(bs, 1); + pes->temi_tc.is_discontinuity = gf_bs_read_int(bs, 1); gf_bs_read_int(bs, 7); - temi_tc.timeline_id = gf_bs_read_int(bs, 8); + pes->temi_tc.timeline_id = gf_bs_read_int(bs, 8); if (has_timestamp) { - temi_tc.media_timescale = gf_bs_read_u32(bs); + pes->temi_tc.media_timescale = gf_bs_read_u32(bs); if (has_timestamp==2) - temi_tc.media_timestamp = gf_bs_read_u64(bs); + pes->temi_tc.media_timestamp = gf_bs_read_u64(bs); else - temi_tc.media_timestamp = gf_bs_read_u32(bs); + pes->temi_tc.media_timestamp = gf_bs_read_u32(bs); } - temi_tc.pes_pts = pes->PTS; gf_bs_del(bs); pes->temi_tc_desc_len = 0; - ts->on_event(ts, GF_M2TS_EVT_TEMI_TIMECODE, &temi_tc); + pes->temi_pending = 1; } void gf_m2ts_flush_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes) @@ -2577,6 +2784,8 @@ void gf_m2ts_flush_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes) if ((pes->pck_data_len >= 4) && !pes->pck_data[0] && !pes->pck_data[1] && (pes->pck_data[2]==0x1)) { u32 len; u32 stream_id = pes->pck_data[3] | 0x100; + Bool same_pts = 0; + if ((stream_id >= 0x1c0 && stream_id <= 0x1df) || (stream_id >= 0x1e0 && stream_id <= 0x1ef) || (stream_id == 0x1bd) || @@ -2584,107 +2793,114 @@ void gf_m2ts_flush_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes) /*SL-packetized*/ ((u8) pes->pck_data[3]==0xfa) ) { - Bool same_pts = 0; + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: unknown stream ID %08X\n", pes->pid, stream_id)); + } - /*OK read header*/ - gf_m2ts_pes_header(pes, pes->pck_data+3, pes->pck_data_len-3, &pesh); - /*send PES timing*/ - if (ts->notify_pes_timing) { - GF_M2TS_PES_PCK pck; - memset(&pck, 0, sizeof(GF_M2TS_PES_PCK)); - pck.PTS = pesh.PTS; - pck.DTS = pesh.DTS; - pck.stream = pes; - if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP; - pes->pes_end_packet_number = ts->pck_number; - if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PES_TIMING, &pck); - } - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d Got PES header PTS %d\n", pes->pid, pesh.PTS)); + /*OK read header*/ + gf_m2ts_pes_header(pes, pes->pck_data+3, pes->pck_data_len-3, &pesh); - if (pesh.PTS) { + /*send PES timing*/ + if (ts->notify_pes_timing) { + GF_M2TS_PES_PCK pck; + memset(&pck, 0, sizeof(GF_M2TS_PES_PCK)); + pck.PTS = pesh.PTS; + pck.DTS = pesh.DTS; + pck.stream = pes; + if (pes->rap) pck.flags |= GF_M2TS_PES_PCK_RAP; + pes->pes_end_packet_number = ts->pck_number; + if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PES_TIMING, &pck); + } + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d Got PES header PTS %d\n", pes->pid, pesh.PTS)); - if (pesh.PTS==pes->PTS) { - same_pts = 1; - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - same PTS "LLU" for two consecutive PES packets \n", pes->pid, pes->PTS) ); - } + if (pesh.PTS) { + + if (pesh.PTS==pes->PTS) { + same_pts = 1; + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - same PTS "LLU" for two consecutive PES packets \n", pes->pid, pes->PTS) ); + } #ifndef GPAC_DISABLE_LOG - /*FIXME - this test should only be done for non bi-directionnally coded media - else if (pesh.PTS < pes->PTS) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - PTS "LLU" less than previous packet PTS "LLU"\n", pes->pid, pesh.PTS, pes->PTS) ); - } - */ + /*FIXME - this test should only be done for non bi-directionnally coded media + else if (pesh.PTS < pes->PTS) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - PTS "LLU" less than previous packet PTS "LLU"\n", pes->pid, pesh.PTS, pes->PTS) ); + } + */ #endif - pes->PTS = pesh.PTS; + pes->PTS = pesh.PTS; #ifndef GPAC_DISABLE_LOG - { - if (pes->DTS && (pesh.DTS==pes->DTS)) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - same DTS "LLU" for two consecutive PES packets \n", pes->pid, pes->DTS) ); - } - if (pesh.DTSDTS) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - DTS "LLU" less than previous DTS "LLU"\n", pes->pid, pesh.DTS, pes->DTS) ); - } + { + if (pes->DTS && (pesh.DTS==pes->DTS)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - same DTS "LLU" for two consecutive PES packets \n", pes->pid, pes->DTS) ); + } + if (pesh.DTSDTS) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d - DTS "LLU" less than previous DTS "LLU"\n", pes->pid, pesh.DTS, pes->DTS) ); } -#endif - pes->DTS = pesh.DTS; } - /*no PTSs were coded, same time*/ - else if (!pesh.hdr_data_len) - same_pts = 1; +#endif + pes->DTS = pesh.DTS; + } + /*no PTSs were coded, same time*/ + else if (!pesh.hdr_data_len) + same_pts = 1; - /*3-byte start-code + 6 bytes header + hdr extensions*/ - len = 9 + pesh.hdr_data_len; + /*3-byte start-code + 6 bytes header + hdr extensions*/ + len = 9 + pesh.hdr_data_len; - if ((u8) pes->pck_data[3]==0xfa) { - GF_M2TS_SL_PCK sl_pck; + if ((u8) pes->pck_data[3]==0xfa) { + GF_M2TS_SL_PCK sl_pck; - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] SL Packet in PES for %d - ES ID %d\n", pes->pid, pes->mpeg4_es_id)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] SL Packet in PES for %d - ES ID %d\n", pes->pid, pes->mpeg4_es_id)); - if (pes->pck_data_len > len) { - sl_pck.data = (char *)pes->pck_data + len; - sl_pck.data_len = pes->pck_data_len - len; - sl_pck.stream = (GF_M2TS_ES *)pes; - if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SL_PCK, &sl_pck); + if (pes->pck_data_len > len) { + sl_pck.data = (char *)pes->pck_data + len; + sl_pck.data_len = pes->pck_data_len - len; + sl_pck.stream = (GF_M2TS_ES *)pes; + if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SL_PCK, &sl_pck); + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Bad SL Packet size: (%d indicated < %d header)\n", pes->pid, pes->pck_data_len, len)); + } + } else if (pes->reframe) { + u32 remain = 0; + u32 offset = len; + + if (pesh.pck_len && (pesh.pck_len-3-pesh.hdr_data_len != pes->pck_data_len-len)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PES payload size %d but received %d bytes\n", pes->pid, (u32) ( pesh.pck_len-3-pesh.hdr_data_len), pes->pck_data_len-len)); + } + //copy over the remaining of previous PES payload before start of this PES payload + if (pes->prev_data_len) { + if (pes->prev_data_len < len) { + offset = len - pes->prev_data_len; + memcpy(pes->pck_data + offset, pes->prev_data, pes->prev_data_len); } else { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Bad SL Packet size: (%d indicated < %d header)\n", pes->pid, pes->pck_data_len, len)); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PES reassembly buffer overflow (%d bytes not processed from previous PES) - discarding prev data\n", pes->pid, pes->prev_data_len )); } - } else if (pes->reframe) { - u32 remain = 0; - u32 offset = len; + } - if (pesh.pck_len && (pesh.pck_len-3-pesh.hdr_data_len != pes->pck_data_len-len)) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PES payload size %d but received %d bytes\n", pes->pid, (u32) ( pesh.pck_len-3-pesh.hdr_data_len), pes->pck_data_len-len)); - } - //copy over the remaining of previous PES payload before start of this PES payload - if (pes->prev_data_len) { - if (pes->prev_data_len < len) { - offset = len - pes->prev_data_len; - memcpy(pes->pck_data + offset, pes->prev_data, pes->prev_data_len); - } else { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PES reassembly buffer overflow (%d bytes not processed from previous PES) - discarding prev data\n", pes->pid, pes->prev_data_len )); - } - } + if (!pes->temi_pending && pes->temi_tc_desc_len) { + gf_m2ts_store_temi(ts, pes); + } - if (pes->temi_tc_desc_len) - gf_m2ts_flush_temi(ts, pes); + if (pes->temi_pending) { + pes->temi_pending = 0; + pes->temi_tc.pes_pts = pes->PTS; + ts->on_event(ts, GF_M2TS_EVT_TEMI_TIMECODE, &pes->temi_tc); + } - if (! ts->start_range) - remain = pes->reframe(ts, pes, same_pts, pes->pck_data+offset, pes->pck_data_len-offset, &pesh); + if (! ts->start_range) + remain = pes->reframe(ts, pes, same_pts, pes->pck_data+offset, pes->pck_data_len-offset, &pesh); - //CLEANUP alloc stuff - if (pes->prev_data) gf_free(pes->prev_data); - pes->prev_data = NULL; - pes->prev_data_len = 0; - if (remain) { - pes->prev_data = gf_malloc(sizeof(char)*remain); - memcpy(pes->prev_data, pes->pck_data + pes->pck_data_len - remain, remain); - pes->prev_data_len = remain; - } + //CLEANUP alloc stuff + if (pes->prev_data) gf_free(pes->prev_data); + pes->prev_data = NULL; + pes->prev_data_len = 0; + if (remain) { + pes->prev_data = gf_malloc(sizeof(char)*remain); + memcpy(pes->prev_data, pes->pck_data + pes->pck_data_len - remain, remain); + pes->prev_data_len = remain; } - } else { - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: unknown stream ID %08X\n", pes->pid, stream_id)); } } else if (pes->pck_data_len) { GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: Bad PES Header, discarding packet (maybe stream is encrypted ?)\n", pes->pid)); @@ -2703,10 +2919,14 @@ static void gf_m2ts_process_pes(GF_M2TS_Demuxer *ts, GF_M2TS_PES *pes, GF_M2TS_H /*duplicated packet, NOT A DISCONTINUITY, we should discard the packet - however we may encounter this configuration in DASH at segment boundaries. If payload start is set, ignore duplication*/ if (hdr->continuity_counter==pes->cc) { - if (!hdr->payload_start || (hdr->adaptation_field!=3) ) return; + if (!hdr->payload_start || (hdr->adaptation_field!=3) ) { + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PES %d: Duplicated Packet found (CC %d) - skipping\n", pes->pid, pes->cc)); + return; + } } else { expect_cc = (pes->cc<0) ? hdr->continuity_counter : (pes->cc + 1) & 0xf; - if (expect_cc != hdr->continuity_counter) disc = 1; + if (expect_cc != hdr->continuity_counter) + disc = 1; } pes->cc = hdr->continuity_counter; @@ -2827,17 +3047,33 @@ static void gf_m2ts_get_adaptation_field(GF_M2TS_Demuxer *ts, GF_M2TS_Adaptation seamless_flag = af_extension[1] & 0x20 ? 1 : 0; af_desc_not_present = af_extension[1] & 0x10 ? 1 : 0; af_extension += 2; + if (!afext_bytes) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid)); + return; + } afext_bytes-=1; if (ltw_flag) { af_extension += 2; + if (afext_bytes<2) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid)); + return; + } afext_bytes-=2; } if (pwr_flag) { af_extension += 3; + if (afext_bytes<3) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid)); + return; + } afext_bytes-=3; } if (seamless_flag) { af_extension += 3; + if (afext_bytes<3) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Bad Adaptation Extension found\n", pid)); + return; + } afext_bytes-=3; } @@ -2857,37 +3093,35 @@ static void gf_m2ts_get_adaptation_field(GF_M2TS_Demuxer *ts, GF_M2TS_Adaptation switch (desc_tag) { case GF_M2TS_AFDESC_LOCATION_DESCRIPTOR: { - Bool external_url , use_base_temi_url; + Bool use_base_temi_url; char URL[255]; GF_M2TS_TemiLocationDescriptor temi_loc; memset(&temi_loc, 0, sizeof(GF_M2TS_TemiLocationDescriptor) ); temi_loc.reload_external = gf_bs_read_int(bs, 1); temi_loc.is_announce = gf_bs_read_int(bs, 1); temi_loc.is_splicing = gf_bs_read_int(bs, 1); - external_url = gf_bs_read_int(bs, 1); use_base_temi_url = gf_bs_read_int(bs, 1); - gf_bs_read_int(bs, 3); //reserved - temi_loc.timeline_id = gf_bs_read_int(bs, 8); - if (!external_url) { - if (!use_base_temi_url) { - char *_url = URL; - u8 scheme = gf_bs_read_int(bs, 8); - u8 url_len = gf_bs_read_int(bs, 8); - switch (scheme) { - case 1: - strcpy(URL, "http://"); - _url = URL+7; - break; - case 2: - strcpy(URL, "https://"); - _url = URL+8; - break; - } - gf_bs_read_data(bs, _url, url_len); - _url[url_len] = 0; + gf_bs_read_int(bs, 5); //reserved + temi_loc.timeline_id = gf_bs_read_int(bs, 7); + if (!use_base_temi_url) { + char *_url = URL; + u8 scheme = gf_bs_read_int(bs, 8); + u8 url_len = gf_bs_read_int(bs, 8); + switch (scheme) { + case 1: + strcpy(URL, "http://"); + _url = URL+7; + break; + case 2: + strcpy(URL, "https://"); + _url = URL+8; + break; } - temi_loc.external_URL = URL; + gf_bs_read_data(bs, _url, url_len); + _url[url_len] = 0; } + temi_loc.external_URL = URL; + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d AF Location descriptor found - URL %s\n", pid, URL)); if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_TEMI_LOCATION, &temi_loc); } @@ -2895,6 +3129,10 @@ static void gf_m2ts_get_adaptation_field(GF_M2TS_Demuxer *ts, GF_M2TS_Adaptation case GF_M2TS_AFDESC_TIMELINE_DESCRIPTOR: if (ts->ess[pid] && (ts->ess[pid]->flags & GF_M2TS_ES_IS_PES)) { GF_M2TS_PES *pes = (GF_M2TS_PES *) ts->ess[pid]; + + if (pes->temi_tc_desc_len) + gf_m2ts_store_temi(ts, pes); + if (pes->temi_tc_desc_alloc_size < desc_len) { pes->temi_tc_desc = gf_realloc(pes->temi_tc_desc, desc_len); pes->temi_tc_desc_alloc_size = desc_len; @@ -2902,7 +3140,7 @@ static void gf_m2ts_get_adaptation_field(GF_M2TS_Demuxer *ts, GF_M2TS_Adaptation memcpy(pes->temi_tc_desc, desc, desc_len); pes->temi_tc_desc_len = desc_len; - GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d AF Timeline descriptor found\n", pid)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d AF Timeline descriptor found\n", pid)); } break; } @@ -2918,7 +3156,7 @@ static void gf_m2ts_get_adaptation_field(GF_M2TS_Demuxer *ts, GF_M2TS_Adaptation GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d: Adaptation Field found: Discontinuity %d - RAP %d - PCR: "LLD"\n", pid, paf->discontinuity_indicator, paf->random_access_indicator, paf->PCR_flag ? paf->PCR_base * 300 + paf->PCR_ext : 0)); } -static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) +static GF_Err gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) { GF_M2TS_ES *es; GF_M2TS_Header hdr; @@ -2930,6 +3168,10 @@ static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) /* read TS packet header*/ hdr.sync = data[0]; + if (hdr.sync != 0x47) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d does not start with sync marker\n", ts->pck_number)); + return GF_CORRUPTED_DATA; + } hdr.error = (data[1] & 0x80) ? 1 : 0; hdr.payload_start = (data[1] & 0x40) ? 1 : 0; hdr.priority = (data[1] & 0x20) ? 1 : 0; @@ -2939,13 +3181,19 @@ static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) hdr.continuity_counter = data[3] & 0xf; if (hdr.error) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet has error (PID could be %d)\n", hdr.pid)); - return; + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d has error (PID could be %d)\n", ts->pck_number, hdr.pid)); + return GF_CORRUPTED_DATA; } //#if DEBUG_TS_PACKET - GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Packet PID %d\n", hdr.pid)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d PID %d CC %d Encrypted %d\n", ts->pck_number, hdr.pid, hdr.continuity_counter, hdr.scrambling_ctrl)); //#endif + if (hdr.scrambling_ctrl) { + //TODO add decyphering + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d is scrambled - not supported\n", ts->pck_number, hdr.pid)); + return GF_NOT_SUPPORTED; + } + paf = NULL; payload_size = 184; pos = 4; @@ -2954,15 +3202,16 @@ static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) case 3: af_size = data[4]; if (af_size>183) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d AF field larger than 183 !\n", ts->pck_number)); //error - return; + return GF_CORRUPTED_DATA; } paf = ⁡ memset(paf, 0, sizeof(GF_M2TS_AdaptationField)); //this will stop you when processing invalid (yet existing) mpeg2ts streams in debug assert( af_size<=182); if (af_size>182) - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Detected wrong adaption field size %u when control value is 3\n", af_size)); + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d Detected wrong adaption field size %u when control value is 3\n", ts->pck_number, af_size)); if (af_size) gf_m2ts_get_adaptation_field(ts, paf, data+5, af_size, hdr.pid); pos += 1+af_size; payload_size = 183 - af_size; @@ -2971,8 +3220,8 @@ static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) case 2: af_size = data[4]; if (af_size != 183) { - GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Non conformant bitstream: AF size is %d when it must be 183 for AF type 2\n", af_size)); - return; + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] TS Packet %d AF size is %d when it must be 183 for AF type 2\n", ts->pck_number, af_size)); + return GF_CORRUPTED_DATA; } paf = ⁡ memset(paf, 0, sizeof(GF_M2TS_AdaptationField)); @@ -2980,11 +3229,11 @@ static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) payload_size = 0; /*no payload and no PCR, return*/ if (! paf->PCR_flag) - return; + return GF_OK; break; /*reserved*/ case 0: - return; + return GF_OK; default: break; } @@ -2993,82 +3242,120 @@ static void gf_m2ts_process_packet(GF_M2TS_Demuxer *ts, unsigned char *data) /*PAT*/ if (hdr.pid == GF_M2TS_PID_PAT) { gf_m2ts_gather_section(ts, ts->pat, NULL, &hdr, data, payload_size); - return; + return GF_OK; } else if (hdr.pid == GF_M2TS_PID_CAT) { gf_m2ts_gather_section(ts, ts->cat, NULL, &hdr, data, payload_size); - return; - } else { - es = ts->ess[hdr.pid]; - if (paf && paf->PCR_flag) { - if (!es) { - u32 i, j; - for(i=0; iprograms); i++) { - GF_M2TS_Program *program = (GF_M2TS_Program *)gf_list_get(ts->programs,i); - if(program->pcr_pid != hdr.pid) continue; - for (j=0; jstreams); j++) { - GF_M2TS_PES *pes = (GF_M2TS_PES *) gf_list_get(program->streams, j); - if (pes->flags & GF_M2TS_INHERIT_PCR) { - ts->ess[hdr.pid] = (GF_M2TS_ES *) pes; - break; - } + return GF_OK; + } + + es = ts->ess[hdr.pid]; + if (paf && paf->PCR_flag) { + if (!es) { + u32 i, j; + for(i=0; iprograms); i++) { + GF_M2TS_PES *first_pes = NULL; + GF_M2TS_Program *program = (GF_M2TS_Program *)gf_list_get(ts->programs,i); + if(program->pcr_pid != hdr.pid) continue; + for (j=0; jstreams); j++) { + GF_M2TS_PES *pes = (GF_M2TS_PES *) gf_list_get(program->streams, j); + if (pes->flags & GF_M2TS_INHERIT_PCR) { + ts->ess[hdr.pid] = (GF_M2TS_ES *) pes; + break; } - break; + if (pes->flags & GF_M2TS_ES_IS_PES) + first_pes = pes; + } + //non found, use the first media stream as a PCR destination - Q: is it legal to have PCR only streams not declared in PMT ? + if (!es) { + es = (GF_M2TS_ES *) first_pes; } + break; + } + if (!es) es = ts->ess[hdr.pid]; + } + if (es) { + GF_M2TS_PES_PCK pck; + s32 prev_diff_in_us; + memset(&pck, 0, sizeof(GF_M2TS_PES_PCK)); + prev_diff_in_us = (s32) (es->program->last_pcr_value /27) - (s32) (es->program->before_last_pcr_value/27); + es->program->before_last_pcr_value = es->program->last_pcr_value; + es->program->before_last_pcr_value_pck_number = es->program->last_pcr_value_pck_number; + es->program->last_pcr_value_pck_number = ts->pck_number; + es->program->last_pcr_value = paf->PCR_base * 300 + paf->PCR_ext; + if (!es->program->last_pcr_value) es->program->last_pcr_value = 1; + + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR found "LLU" ("LLU" at 90kHz) - PCR diff is %d us\n", hdr.pid, es->program->last_pcr_value, es->program->last_pcr_value/300, (u32) (es->program->last_pcr_value - es->program->before_last_pcr_value)/27 )); + + pck.PTS = es->program->last_pcr_value; + pck.stream = (GF_M2TS_PES *)es; + if (paf->discontinuity_indicator) { + s32 diff_in_us = (s32) (es->program->last_pcr_value /27) - (s32) (es->program->before_last_pcr_value/27); + u32 diff = ABS(diff_in_us - prev_diff_in_us); + //ignore PCR discontinuity indicator if PCR found is larger than previously received PCR and diffence between PCR before and after discontinuity indicator is smaller than 50ms + if ((diff_in_us > 0) && (diff < 50000)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR discontinuity signaled but diff is small (diff %d us - PCR diff %d vs prev PCR diff %d) - ignore it\n", hdr.pid, diff, diff_in_us, prev_diff_in_us)); + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR discontinuity signaled (diff %d us - PCR diff %d vs prev PCR diff %d)\n", hdr.pid, diff, diff_in_us, prev_diff_in_us)); + pck.flags = GF_M2TS_PES_PCK_DISCONTINUITY; + } } - if (es) { - GF_M2TS_PES_PCK pck; - memset(&pck, 0, sizeof(GF_M2TS_PES_PCK)); - es->program->before_last_pcr_value = es->program->last_pcr_value; - es->program->before_last_pcr_value_pck_number = es->program->last_pcr_value_pck_number; - es->program->last_pcr_value_pck_number = ts->pck_number; - es->program->last_pcr_value = paf->PCR_base * 300 + paf->PCR_ext; - if (!es->program->last_pcr_value) es->program->last_pcr_value = 1; - pck.PTS = es->program->last_pcr_value; - pck.stream = (GF_M2TS_PES *)es; - if (paf->discontinuity_indicator) pck.flags = GF_M2TS_PES_PCK_DISCONTINUITY; - if (ts->on_event) { - gf_m2ts_estimate_duration(ts, es->program->last_pcr_value, hdr.pid); - ts->on_event(ts, GF_M2TS_EVT_PES_PCR, &pck); + else if ( (es->program->last_pcr_value < es->program->before_last_pcr_value) ) { + //if less than 100 ms before PCR loop at the last PCR, this is a PCR loop + if (2576980377300 - es->program->before_last_pcr_value < 270000) { + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR loop found from "LLU" to "LLU" \n", hdr.pid, es->program->before_last_pcr_value, es->program->last_pcr_value)); + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] PID %d PCR found "LLU" is less than previously received PCR "LLU" but no discontinuity signaled\n", hdr.pid, es->program->last_pcr_value, es->program->before_last_pcr_value)); + pck.flags = GF_M2TS_PES_PCK_DISCONTINUITY; } } - } - /*check for DVB reserved PIDs*/ - if (!es) { - if (hdr.pid == GF_M2TS_PID_SDT_BAT_ST) { - gf_m2ts_gather_section(ts, ts->sdt, NULL, &hdr, data, payload_size); - return; - } else if (hdr.pid == GF_M2TS_PID_NIT_ST) { - /*ignore them, unused at application level*/ - gf_m2ts_gather_section(ts, ts->nit, NULL, &hdr, data, payload_size); - return; - } else if (hdr.pid == GF_M2TS_PID_EIT_ST_CIT) { - /* ignore EIT messages for the moment */ - gf_m2ts_gather_section(ts, ts->eit, NULL, &hdr, data, payload_size); - return; - } else if (hdr.pid == GF_M2TS_PID_TDT_TOT_ST) { - gf_m2ts_gather_section(ts, ts->tdt_tot, NULL, &hdr, data, payload_size); - } else { - /* ignore packet */ + if (pck.flags & GF_M2TS_PES_PCK_DISCONTINUITY) { + gf_m2ts_reset_parsers_for_program(ts, es->program); } - } else if (es->flags & GF_M2TS_ES_IS_SECTION) { /* The stream uses sections to carry its payload */ - GF_M2TS_SECTION_ES *ses = (GF_M2TS_SECTION_ES *)es; - if (ses->sec) gf_m2ts_gather_section(ts, ses->sec, ses, &hdr, data, payload_size); + + if (ts->on_event) { + gf_m2ts_estimate_duration(ts, es->program->last_pcr_value, hdr.pid); + ts->on_event(ts, GF_M2TS_EVT_PES_PCR, &pck); + } + } + } + + /*check for DVB reserved PIDs*/ + if (!es) { + if (hdr.pid == GF_M2TS_PID_SDT_BAT_ST) { + gf_m2ts_gather_section(ts, ts->sdt, NULL, &hdr, data, payload_size); + return GF_OK; + } else if (hdr.pid == GF_M2TS_PID_NIT_ST) { + /*ignore them, unused at application level*/ + gf_m2ts_gather_section(ts, ts->nit, NULL, &hdr, data, payload_size); + return GF_OK; + } else if (hdr.pid == GF_M2TS_PID_EIT_ST_CIT) { + /* ignore EIT messages for the moment */ + gf_m2ts_gather_section(ts, ts->eit, NULL, &hdr, data, payload_size); + return GF_OK; + } else if (hdr.pid == GF_M2TS_PID_TDT_TOT_ST) { + gf_m2ts_gather_section(ts, ts->tdt_tot, NULL, &hdr, data, payload_size); } else { - GF_M2TS_PES *pes = (GF_M2TS_PES *)es; - /* regular stream using PES packets */ - if (pes->reframe && payload_size) gf_m2ts_process_pes(ts, pes, &hdr, data, payload_size, paf); + /* ignore packet */ } + } else if (es->flags & GF_M2TS_ES_IS_SECTION) { /* The stream uses sections to carry its payload */ + GF_M2TS_SECTION_ES *ses = (GF_M2TS_SECTION_ES *)es; + if (ses->sec) gf_m2ts_gather_section(ts, ses->sec, ses, &hdr, data, payload_size); + } else { + GF_M2TS_PES *pes = (GF_M2TS_PES *)es; + /* regular stream using PES packets */ + if (pes->reframe && payload_size) gf_m2ts_process_pes(ts, pes, &hdr, data, payload_size, paf); } - return; + return GF_OK; } GF_EXPORT GF_Err gf_m2ts_process_data(GF_M2TS_Demuxer *ts, char *data, u32 data_size) { - u32 pos; + GF_Err e; + u32 pos, pck_size; Bool is_align = 1; if (ts->buffer) { if (ts->alloc_size < ts->buffer_size+data_size) { @@ -3093,14 +3380,16 @@ GF_Err gf_m2ts_process_data(GF_M2TS_Demuxer *ts, char *data, u32 data_size) } return GF_OK; } + pck_size = ts->prefix_present ? 192 : 188; + e=GF_OK; for (;;) { /*wait for a complete packet*/ - if (ts->buffer_size - pos < 188) { + if (ts->buffer_size < pos + pck_size) { ts->buffer_size -= pos; if (!ts->buffer_size) { if (!is_align) gf_free(ts->buffer); ts->buffer = NULL; - return GF_OK; + return e; } if (is_align) { data = ts->buffer+pos; @@ -3110,13 +3399,19 @@ GF_Err gf_m2ts_process_data(GF_M2TS_Demuxer *ts, char *data, u32 data_size) } else { memmove(ts->buffer, ts->buffer + pos, sizeof(char)*ts->buffer_size); } - return GF_OK; + return e; } /*process*/ - gf_m2ts_process_packet(ts, (unsigned char *)ts->buffer+pos); - pos += 188; + e |= gf_m2ts_process_packet(ts, (unsigned char *)ts->buffer+pos); + pos += pck_size; + + if (ts->abort_parsing) { + if (!is_align) gf_free(ts->buffer); + ts->buffer = NULL; + return e; + } } - return GF_OK; + return e; } GF_ESD *gf_m2ts_get_esd(GF_M2TS_ES *es) @@ -3164,13 +3459,14 @@ void gf_m2ts_set_segment_switch(GF_M2TS_Demuxer *ts) } GF_EXPORT -void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *ts) +void gf_m2ts_reset_parsers_for_program(GF_M2TS_Demuxer *ts, GF_M2TS_Program *prog) { u32 i; - ts->pck_number = 0; + for (i=0; iess[i]; if (!es) continue; + if (prog && (es->program != prog) ) continue; if (es->flags & GF_M2TS_ES_IS_SECTION) { GF_M2TS_SECTION_ES *ses = (GF_M2TS_SECTION_ES *)es; @@ -3185,6 +3481,8 @@ void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *ts) pes->prev_data = NULL; pes->prev_data_len = 0; pes->PTS = pes->DTS = 0; +// pes->prev_PTS = 0; +// pes->first_dts = 0; pes->pes_len = pes->pes_end_packet_number = pes->pes_start_packet_number = 0; if (pes->buf) gf_free(pes->buf); pes->buf = NULL; @@ -3199,9 +3497,15 @@ void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *ts) pes->program->before_last_pcr_value = pes->program->before_last_pcr_value_pck_number = 0; } } -// gf_free(es); -// ts->ess[i] = NULL; } +} + +GF_EXPORT +void gf_m2ts_reset_parsers(GF_M2TS_Demuxer *ts) +{ + gf_m2ts_reset_parsers_for_program(ts, NULL); + + ts->pck_number = 0; gf_m2ts_section_filter_reset(ts->cat); gf_m2ts_section_filter_reset(ts->pat); @@ -3253,6 +3557,16 @@ GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, u32 mode) if (pes->pid==pes->program->pmt_pid) return GF_BAD_PARAM; + //if component reuse, disable previous pes + if ((mode > GF_M2TS_PES_FRAMING_SKIP) && (pes->program->ts->ess[pes->pid] != (GF_M2TS_ES *) pes)) { + GF_M2TS_PES *o_pes = (GF_M2TS_PES *) pes->program->ts->ess[pes->pid]; + if (o_pes->flags & GF_M2TS_ES_IS_PES) + gf_m2ts_set_pes_framing(o_pes, GF_M2TS_PES_FRAMING_SKIP); + + GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MPEG-2 TS] Reassinging PID %d from program %d to program %d\n", pes->pid, o_pes->program->number, pes->program->number) ); + pes->program->ts->ess[pes->pid] = (GF_M2TS_ES *) pes; + } + switch (mode) { case GF_M2TS_PES_FRAMING_RAW: pes->reframe = gf_m2ts_reframe_default; @@ -3292,6 +3606,12 @@ GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, u32 mode) case GF_M2TS_AUDIO_LATM_AAC: pes->reframe = gf_m2ts_reframe_aac_latm; break; + case GF_M2TS_AUDIO_AC3: + pes->reframe = gf_m2ts_reframe_ac3; + break; + case GF_M2TS_AUDIO_EC3: + pes->reframe = gf_m2ts_reframe_ec3; + break; #endif case GF_M2TS_PRIVATE_DATA: @@ -3338,6 +3658,26 @@ GF_M2TS_Demuxer *gf_m2ts_demux_new() return ts; } +GF_EXPORT +void gf_m2ts_abort_parsing(GF_M2TS_Demuxer *ts, Bool force_reset_pes) +{ + u32 i, j, count, count2; + + if (force_reset_pes) { + count = gf_list_count(ts->programs); + for (i=0; iprograms, i); + count2 = gf_list_count(prog->streams); + for (j=0; jstreams, j); + if (pes) + pes->pck_data_len = 0; + } + } + } + ts->abort_parsing = GF_TRUE; +} + GF_EXPORT void gf_m2ts_demux_dmscc_init(GF_M2TS_Demuxer *ts) { @@ -3375,7 +3715,8 @@ void gf_m2ts_demux_del(GF_M2TS_Demuxer *ts) if (ts->tdt_tot) gf_m2ts_section_filter_del(ts->tdt_tot); for (i=0; iess[i]) gf_m2ts_es_del(ts->ess[i], ts); + //bacause of pure PCR streams, en ES might be reassigned on 2 PIDs, one for the ES and one for the PCR + if (ts->ess[i] && (ts->ess[i]->pid==i)) gf_m2ts_es_del(ts->ess[i], ts); } if (ts->buffer) gf_free(ts->buffer); while (gf_list_count(ts->programs)) { @@ -3434,6 +3775,8 @@ void gf_m2ts_demux_del(GF_M2TS_Demuxer *ts) if (ts->th) gf_th_del(ts->th); + + if (ts->socket_url) gf_free(ts->socket_url); gf_free(ts); } @@ -3444,6 +3787,11 @@ void gf_m2ts_print_info(GF_M2TS_Demuxer *ts) #endif } +GF_EXPORT +void gf_m2ts_pause_demux(GF_M2TS_Demuxer *ts, Bool do_pause) +{ + if (ts) ts->paused = do_pause; +} GF_EXPORT GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_byterange, u64 end_byterange, u32 refresh_type, Bool signal_end_of_stream) @@ -3455,7 +3803,12 @@ GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_b GF_BitStream *bs = NULL; FILE *f = NULL; - if (fileName && !strnicmp(fileName, "gmem://", 7)) { + //force EOS signaing + if (!fileName) { + if (!signal_end_of_stream) return GF_BAD_PARAM; + ts->pos_in_stream = 0; + } + else if (fileName && !strnicmp(fileName, "gmem://", 7)) { void *mem_address; u32 remain; if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) { @@ -3473,6 +3826,7 @@ GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_b size -= remain; /*process chunk*/ + ts->abort_parsing = GF_FALSE; e = gf_m2ts_process_data(ts, mem_address, size); if (refresh_type==2) @@ -3483,7 +3837,7 @@ GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_b } else if (fileName) { char data[188000]; - f = gf_f64_open(fileName, "rb"); + f = gf_fopen(fileName, "rb"); if (!f) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDemux] Cannot open next file %s\n", fileName)); @@ -3501,6 +3855,7 @@ GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_b } } read = 0; + ts->abort_parsing = GF_FALSE; while (1) { u32 to_read = 188000; Bool done = 0; @@ -3527,6 +3882,8 @@ GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_b } read += size; if (done) break; + if (ts->abort_parsing) + break; } if ((refresh_type==2) || !gf_bs_available(bs)) { @@ -3536,8 +3893,8 @@ GF_Err gf_m2ts_demux_file(GF_M2TS_Demuxer *ts, const char *fileName, u64 start_b } gf_bs_del(bs); - fclose(f); - + gf_fclose(f); + ts->abort_parsing = GF_FALSE; } if (signal_end_of_stream && !ts->pos_in_stream) { @@ -3559,21 +3916,29 @@ static u32 gf_m2ts_demuxer_run(void *_p) u32 i; GF_Err e; char data[UDP_BUFFER_SIZE]; -#ifdef GPAC_HAS_LINUX_DVB - char dvbts[DVB_BUFFER_SIZE]; -#endif u32 size; - //u32 i; GF_M2TS_Demuxer *ts = _p; gf_m2ts_reset_parsers(ts); + ts->abort_parsing = GF_FALSE; + + //recreate the socket if needed + if (ts->socket_url && !ts->sock) { + gf_m2ts_get_socket(ts->socket_url, ts->network_type, UDP_BUFFER_SIZE, &ts->sock); + } #ifdef GPAC_HAS_LINUX_DVB if (ts->tuner) { + s32 ts_size; // in case of DVB while (ts->run_state) { - s32 ts_size = read(ts->tuner->ts_fd, dvbts, DVB_BUFFER_SIZE); - if (ts_size>0) gf_m2ts_process_data(ts, dvbts, (u32) ts_size); + if (ts->paused) { + gf_sleep(1); + continue; + } + + ts_size = read(ts->tuner->ts_fd, data, UDP_BUFFER_SIZE); + if (ts_size>0) gf_m2ts_process_data(ts, data, (u32) ts_size); } } else #endif @@ -3586,11 +3951,15 @@ static u32 gf_m2ts_demuxer_run(void *_p) Bool first_run, is_rtp; FILE *record_to = NULL; if (ts->record_to) - record_to = gf_f64_open(ts->record_to, "wb"); + record_to = gf_fopen(ts->record_to, "wb"); first_run = 1; is_rtp = 0; while (ts->run_state) { + if (ts->paused) { + gf_sleep(1); + continue; + } size = 0; /*m2ts chunks by chunks*/ e = gf_sk_receive(ts->sock, data, UDP_BUFFER_SIZE, 0, &size); @@ -3639,13 +4008,15 @@ static u32 gf_m2ts_demuxer_run(void *_p) } } if (record_to) - fclose(record_to); + gf_fclose(record_to); #ifndef GPAC_DISABLE_STREAMING if (ch) gf_rtp_reorderer_del(ch); #endif + if (ts->sock) gf_sk_del(ts->sock); + ts->sock = NULL; } else if (ts->dnload) { while (ts->run_state) { gf_dm_sess_process(ts->dnload); @@ -3660,8 +4031,15 @@ static u32 gf_m2ts_demuxer_run(void *_p) else ts_bs = gf_bs_new(ts->ts_data_chunk, ts->ts_data_chunk_size, GF_BITSTREAM_READ); + gf_bs_seek(ts_bs, 0); + while (ts->run_state && gf_bs_available(ts_bs) && !ts->force_file_refresh) { + if (ts->paused) { + gf_sleep(1); + continue; + } + if (ts->start_range && ts->duration) { Double perc = ts->start_range / (1000 * ts->duration); pos = (u32) (s64) (perc * ts->file_size); @@ -3692,13 +4070,6 @@ static u32 gf_m2ts_demuxer_run(void *_p) ts->nb_pck++; - //gf_sleep(0); - /*if asked to regulate, wait until we get a play request*/ - while (ts->run_state && !ts->nb_playing && (ts->file_regulate==1)) { - gf_sleep(50); - continue; - } - if (!gf_bs_available(ts_bs) && ts->loop_demux == 1) { gf_bs_seek(ts_bs, pos); GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TSDemux] Loop \n")); @@ -3728,6 +4099,7 @@ static u32 gf_m2ts_demuxer_run(void *_p) return 0; } + GF_EXPORT GF_Err gf_m2ts_get_socket(const char *url, const char *mcast_ifce_or_mobileip, u32 buf_size, GF_Socket **out_socket) { @@ -3790,6 +4162,9 @@ static GF_Err gf_m2ts_demuxer_setup_live(GF_M2TS_Demuxer *ts, char *url) e = gf_m2ts_get_socket(url, ts->network_type, UDP_BUFFER_SIZE, &ts->sock); if (e) return e; + if (ts->socket_url) gf_free(ts->socket_url); + ts->socket_url = gf_strdup(url); + //gf_th_set_priority(ts->th, GF_THREAD_PRIORITY_HIGHEST); return gf_m2ts_demuxer_play(ts); @@ -3811,7 +4186,7 @@ static GF_Err gf_dvb_tune(GF_Tuner *tuner, const char *url, const char *chan_pat char frontend_name[100], demux_name[100], dvr_name[100]; u32 adapter_num; - chanfile = gf_f64_open(chan_path, "r"); + chanfile = gf_fopen(chan_path, "r"); if (!chanfile) return GF_BAD_PARAM; chan_name = (char *) url+6; // 6 = strlen("dvb://") @@ -3893,7 +4268,7 @@ static GF_Err gf_dvb_tune(GF_Tuner *tuner, const char *url, const char *chan_pat } } } - fclose(chanfile); + gf_fclose(chanfile); sprintf(frontend_name, "/dev/dvb/adapter%d/frontend0", adapter_num); sprintf(demux_name, "/dev/dvb/adapter%d/demux0", adapter_num); @@ -3957,7 +4332,7 @@ u32 gf_dvb_get_freq_from_url(const char *channels_config_path, const char *url) channel_name = (char *)url+6; - channels_config_file = gf_f64_open(channels_config_path, "r"); + channels_config_file = gf_fopen(channels_config_path, "r"); if (!channels_config_file) return GF_BAD_PARAM; freq = 0; @@ -4026,22 +4401,21 @@ static GF_Err gf_m2ts_demuxer_setup_file(GF_M2TS_Demuxer *ts, char *url) ts->ts_data_chunk = mem_address; } else { - ts->file = gf_f64_open(url, "rb"); + ts->file = gf_fopen(url, "rb"); if (!ts->file) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[TSDemux] Could not open TS file: %s\n", url)); return GF_IO_ERR; } strcpy(ts->filename, url); - gf_f64_seek(ts->file, 0, SEEK_END); - ts->file_size = gf_f64_tell(ts->file); - gf_f64_seek(ts->file, 0, SEEK_SET); + gf_fseek(ts->file, 0, SEEK_END); + ts->file_size = gf_ftell(ts->file); + gf_fseek(ts->file, 0, SEEK_SET); } } /* reinitialization for seek */ ts->end_range = ts->start_range = 0; - ts->nb_playing = 0; return gf_m2ts_demuxer_play(ts); } @@ -4051,8 +4425,6 @@ GF_Err gf_m2ts_demuxer_setup(GF_M2TS_Demuxer *ts, const char *url, Bool loop) { char szURL[2048]; char *frag; - - ts->file_regulate = 0; ts->duration = 0; if(loop == 1) { @@ -4099,7 +4471,7 @@ GF_Err gf_m2ts_demuxer_close(GF_M2TS_Demuxer *ts) ts->th = NULL; } - if (ts->file) fclose(ts->file); + if (ts->file) gf_fclose(ts->file); ts->file = NULL; ts->ts_data_chunk = NULL; @@ -4107,7 +4479,8 @@ GF_Err gf_m2ts_demuxer_close(GF_M2TS_Demuxer *ts) } GF_EXPORT -GF_Err gf_m2ts_demuxer_play(GF_M2TS_Demuxer *ts) { +GF_Err gf_m2ts_demuxer_play(GF_M2TS_Demuxer *ts) +{ /*set the state variable outside the TS thread. If inside, we may get called for shutdown before the TS thread has started and we would overwrite the run_state when entering the TS thread, which would make the thread run forever and the stop() wait forever*/ @@ -4121,44 +4494,36 @@ GF_Err gf_m2ts_demuxer_play(GF_M2TS_Demuxer *ts) { } +#define M2TS_PROBE_SIZE 188000 GF_EXPORT Bool gf_m2ts_probe_file(const char *fileName) { - char buf[188]; - u32 count = 10; + char buf[M2TS_PROBE_SIZE]; + GF_Err e; + u32 size; FILE *t; + GF_M2TS_Demuxer *ts; if (!strncmp(fileName, "gmem://", 7)) { - u32 size; u8 *mem_address; if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) { return GF_FALSE; } - while (size>188 && count) { - if (mem_address[0] != 0x47) - return 0; - mem_address+=188; - size-=188; - count--; - } - return GF_TRUE; - } - - t = gf_f64_open(fileName, "rb"); - while (t && count) { - u32 read = (u32) fread(buf, 1, 188, t); - if (!read) { - count = 0; - break; - } - if (buf[0] != 0x47) - break; - if (read<188) - count = 0; - else count--; - } - if (t) fclose(t); - return count ? GF_FALSE : GF_TRUE; + if (size>M2TS_PROBE_SIZE) size = M2TS_PROBE_SIZE; + memcpy(buf, mem_address, size); + } else { + t = gf_fopen(fileName, "rb"); + if (!t) return 0; + size = (u32) fread(buf, 1, M2TS_PROBE_SIZE, t); + gf_fclose(t); + if (!size) return 0; + } + ts = gf_m2ts_demux_new(); + e = gf_m2ts_process_data(ts, buf, size); + if (!ts->pck_number) e = GF_BAD_PARAM; + gf_m2ts_demux_del(ts); + if (e) return 0; + return 1; } static void rewrite_pts_dts(unsigned char *ptr, u64 TS) @@ -4179,7 +4544,7 @@ static void rewrite_pts_dts(unsigned char *ptr, u64 TS) if (_TS < (u64) -ts_shift) _TS = pcr_mod + _TS + ts_shift; \ else _TS = _TS + ts_shift; \ while (_TS > pcr_mod) _TS -= pcr_mod; \ - + GF_Err gf_m2ts_restamp(char *buffer, u32 size, s64 ts_shift, u8 *is_pes) { @@ -4270,4 +4635,3 @@ GF_Err gf_m2ts_restamp(char *buffer, u32 size, s64 ts_shift, u8 *is_pes) } #endif /*GPAC_DISABLE_MPEG2TS*/ - diff --git a/src/media_tools/text_import.c b/src/media_tools/text_import.c index 493562b..baa0d08 100644 --- a/src/media_tools/text_import.c +++ b/src/media_tools/text_import.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -66,20 +67,20 @@ s32 gf_text_get_utf_type(FILE *in_src) if ((BOM[0]==0xFF) && (BOM[1]==0xFE)) { /*UTF32 not supported*/ if (!BOM[2] && !BOM[3]) return -1; - gf_f64_seek(in_src, 2, SEEK_SET); + gf_fseek(in_src, 2, SEEK_SET); return 3; } if ((BOM[0]==0xFE) && (BOM[1]==0xFF)) { /*UTF32 not supported*/ if (!BOM[2] && !BOM[3]) return -1; - gf_f64_seek(in_src, 2, SEEK_SET); + gf_fseek(in_src, 2, SEEK_SET); return 2; } else if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) { - gf_f64_seek(in_src, 3, SEEK_SET); + gf_fseek(in_src, 3, SEEK_SET); return 1; } if (BOM[0]<0x80) { - gf_f64_seek(in_src, 0, SEEK_SET); + gf_fseek(in_src, 0, SEEK_SET); return 0; } return -1; @@ -90,7 +91,7 @@ static GF_Err gf_text_guess_format(char *filename, u32 *fmt) char szLine[2048]; u32 val; s32 uni_type; - FILE *test = gf_f64_open(filename, "rb"); + FILE *test = gf_fopen(filename, "rb"); if (!test) return GF_URL_ERROR; uni_type = gf_text_get_utf_type(test); @@ -109,13 +110,13 @@ static GF_Err gf_text_guess_format(char *filename, u32 *fmt) *fmt = GF_TEXT_IMPORT_NONE; if ((szLine[0]=='{') && strstr(szLine, "}{")) *fmt = GF_TEXT_IMPORT_SUB; - else if (!strnicmp(szLine, ""); if (ext) ext += 2; - if (!ext[0]) { + if (ext && !ext[0]) { if (!fgets(szLine, 2048, test)) szLine[0] = '\0'; } @@ -128,7 +129,7 @@ static GF_Err gf_text_guess_format(char *filename, u32 *fmt) else if (strstr(szLine, " --> ") ) *fmt = GF_TEXT_IMPORT_SRT; /* might want to change the default to WebVTT */ - fclose(test); + gf_fclose(test); return GF_OK; } @@ -278,21 +279,21 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) GF_TextSample * samp; GF_ISOSample *s; u32 sh, sm, ss, sms, eh, em, es, ems, txt_line, char_len, char_line, nb_samp, j, duration, rem_styles; - Bool set_start_char, set_end_char, first_samp; + Bool set_start_char, set_end_char, first_samp, rem_color; u64 start, end, prev_end, file_size; - u32 state, curLine, line, len, ID, OCR_ES_ID; + u32 state, curLine, line, len, ID, OCR_ES_ID, default_color; s32 unicode_type; char szLine[2048], szText[2048], *ptr; unsigned short uniLine[5000], uniText[5000], *sptr; - srt_in = gf_f64_open(import->in_name, "rt"); - gf_f64_seek(srt_in, 0, SEEK_END); - file_size = gf_f64_tell(srt_in); - gf_f64_seek(srt_in, 0, SEEK_SET); + srt_in = gf_fopen(import->in_name, "rt"); + gf_fseek(srt_in, 0, SEEK_END); + file_size = gf_ftell(srt_in); + gf_fseek(srt_in, 0, SEEK_SET); unicode_type = gf_text_get_utf_type(srt_in); if (unicode_type<0) { - fclose(srt_in); + gf_fclose(srt_in); return gf_import_message(import, GF_NOT_SUPPORTED, "Unsupported SRT UTF encoding"); } @@ -321,7 +322,7 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) if (cfg && cfg->timescale) timescale = cfg->timescale; track = gf_isom_new_track(import->dest, ID, GF_ISOM_MEDIA_TEXT, timescale); if (!track) { - fclose(srt_in); + gf_fclose(srt_in); return gf_import_message(import, gf_isom_last_error(import->dest), "Error creating text track"); } gf_isom_set_track_enabled(import->dest, track, 1); @@ -400,6 +401,8 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) gf_text_import_set_language(import, track); duration = (u32) (((Double) import->duration)*timescale/1000.0); + default_color = rec.text_color; + e = GF_OK; state = 0; end = prev_end = 0; @@ -426,7 +429,7 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) gf_isom_delete_text_sample(empty_samp); if (state<=2) { s->DTS = (u64) ((timescale*prev_end)/1000); - s->IsRAP = 1; + s->IsRAP = RAP; gf_isom_add_sample(import->dest, track, 1, s); nb_samp++; } @@ -436,7 +439,7 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) s = gf_isom_text_to_sample(samp); if (state<=2) { s->DTS = (u64) ((timescale*start)/1000); - s->IsRAP = 1; + s->IsRAP = RAP; gf_isom_add_sample(import->dest, track, 1, s); gf_isom_sample_del(&s); nb_samp++; @@ -449,7 +452,7 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) gf_isom_text_reset(samp); //gf_import_progress(import, nb_samp, nb_samp+1); - gf_set_progress("Importing SRT", gf_f64_tell(srt_in), file_size); + gf_set_progress("Importing SRT", gf_ftell(srt_in), file_size); if (duration && (end >= duration)) break; } state = 0; @@ -521,9 +524,62 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) char_line = 0; i=j=0; rem_styles = 0; + rem_color = 0; while (i')) { + style_nb_chars = 3; + style_def_type = 1; + } + else if ( (uniLine[i]=='<') && (uniLine[i+1]=='/') && (uniLine[i+3]=='>')) { + style_def_type = 2; + style_nb_chars = 4; + } + else if (uniLine[i]=='<') { + const unsigned short* src = uniLine + i; + size_t alen = gf_utf8_wcstombs(szLine, 2048, (const unsigned short**) & src); + szLine[alen] = 0; + strlwr(szLine); + if (!strncmp(szLine, "'); + if (e_sep) { + style_nb_chars = (u32) (1 + e_sep - szLine); + style_def_type = 1; + } + } + + } + } + else if (!strncmp(szLine, "", 7) ) { + style_nb_chars = 7; + style_def_type = 2; + font_style = 0xFFFFFFFF; + } + //skip unknown + else { + char *a_sep = strstr(szLine, ">"); + if (a_sep) { + style_nb_chars = (u32) (a_sep - szLine); + i += style_nb_chars; + continue; + } + } + + } + + /*start of new style*/ + if (style_def_type==1) { /*store prev style*/ if (set_end_char) { assert(set_start_char); @@ -531,6 +587,10 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) set_end_char = set_start_char = GF_FALSE; rec.style_flags &= ~rem_styles; rem_styles = 0; + if (rem_color) { + rec.text_color = default_color; + rem_color = 0; + } } if (set_start_char && (rec.startCharOffset != j)) { rec.endCharOffset = char_len + j; @@ -555,13 +615,21 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) set_start_char = GF_TRUE; rec.startCharOffset = char_len + j; break; + case 'f': + case 'F': + if (font_style) { + rec.text_color = font_style; + set_start_char = GF_TRUE; + rec.startCharOffset = char_len + j; + } + break; } - i+=3; + i += style_nb_chars; continue; } /*end of prev style*/ - if ( (uniLine[i]=='<') && (uniLine[i+1]=='/') && (uniLine[i+3]=='>')) { + if (style_def_type==2) { switch (uniLine[i+2]) { case 'b': case 'B': @@ -581,8 +649,15 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) set_end_char = GF_TRUE; rec.endCharOffset = char_len + j; break; + case 'f': + case 'F': + if (font_style) { + rem_color = 1; + set_end_char = GF_TRUE; + rec.endCharOffset = char_len + j; + } } - i+=4; + i+=style_nb_chars; continue; } /*store style*/ @@ -593,6 +668,8 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) rec.startCharOffset = char_len + j; rec.style_flags &= ~rem_styles; rem_styles = 0; + rec.text_color = default_color; + rem_color = 0; } uniText[j] = uniLine[i]; @@ -632,7 +709,7 @@ static GF_Err gf_text_import_srt(GF_MediaImporter *import) exit: if (e) gf_isom_remove_track(import->dest, track); - fclose(srt_in); + gf_fclose(srt_in); return e; } @@ -665,7 +742,7 @@ static void gf_webvtt_flush_sample_to_iso(void *user, GF_WebVTTSample *samp) s = gf_isom_webvtt_to_sample(samp); if (s) { s->DTS = (u64) (flusher->timescale*gf_webvtt_sample_get_start(samp)/1000); - s->IsRAP = 1; + s->IsRAP = RAP; gf_isom_add_sample(flusher->import->dest, flusher->track, flusher->descriptionIndex, s); gf_isom_sample_del(&s); } @@ -768,119 +845,464 @@ static GF_Err gf_text_import_webvtt(GF_MediaImporter *import) return e; } -static GF_Err gf_text_import_ttml(GF_MediaImporter *import) +static char *ttxt_parse_string(GF_MediaImporter *import, char *str, Bool strip_lines) { - GF_Err e; - e = GF_OK; + u32 i=0; + u32 k=0; + u32 len = (u32) strlen(str); + u32 state = 0; - return e; + if (!strip_lines) { + for (i=0; icontent, &idx))) { + if (!strcmp(node->name, "body")) { + *sample_list_node = node; + body_num = gf_list_count(node->content); + while (body_num--) { + body_node = (GF_XMLNode*)gf_list_get(node->content, 0); + assert(gf_list_find(node->content, body_node) == 0); + gf_list_rem(node->content, 0); + gf_xml_dom_node_del(body_node); + } + return; + } + } +} + +static GF_Err gf_text_import_ebu_ttd(GF_MediaImporter *import, GF_DOMParser *parser, GF_XMLNode *root) { - GF_SimpleTextSampleEntryBox *stse; - GF_TrackBox *trak; GF_Err e; + u32 i, track, ID, desc_idx, nb_samples, nb_children; + u64 last_sample_duration, last_sample_end; + GF_XMLAttribute *att; + GF_XMLNode *node, *root_working_copy, *sample_list_node; + GF_DOMParser *parser_working_copy; + char *samp_text, *xmlns; + Bool has_body; + + samp_text = NULL; + xmlns = NULL; + root_working_copy = NULL; + parser_working_copy = NULL; + e = GF_OK; - if (!descriptionIndex) return NULL; + /*setup track in 3GP format directly (no ES desc)*/ + ID = (import->esd) ? import->esd->ESID : 0; + track = gf_isom_new_track(import->dest, ID, GF_ISOM_MEDIA_MPEG_SUBT, 1000); + if (!track) { + e = gf_isom_last_error(import->dest); + goto exit; + } + gf_isom_set_track_enabled(import->dest, track, 1); + /*some MPEG-4 setup*/ + if (import->esd) { + if (!import->esd->ESID) import->esd->ESID = gf_isom_get_track_id(import->dest, track); + if (!import->esd->decoderConfig) import->esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); + if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); + import->esd->slConfig->timestampResolution = 1000; + import->esd->decoderConfig->streamType = GF_STREAM_TEXT; + import->esd->decoderConfig->objectTypeIndication = GPAC_OTI_TEXT_MPEG4; + if (import->esd->OCRESID) gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_OCR, import->esd->OCRESID); + } - e = CanAccessMovie(movie, GF_ISOM_OPEN_READ); - if (e) return NULL; + gf_import_message(import, GF_OK, "TTML Import"); - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return NULL; + /*** root (including language) ***/ + i=0; + while ( (att = (GF_XMLAttribute *)gf_list_enum(root->attributes, &i))) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("Found root attribute name %s, value %s\n", att->name, att->value)); - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_TEXT: - break; - default: - return NULL; + if (!strcmp(att->name, "xmlns")) { + if (strcmp(att->value, "http://www.w3.org/ns/ttml")) { + e = gf_import_message(import, GF_BAD_PARAM, "Found invalid EBU-TTD root attribute name %s, value %s (shall be \"%s\")\n", att->name, att->value, "http://www.w3.org/ns/ttml"); + goto exit; + } + xmlns = att->value; + } else if (!strcmp(att->name, "xml:lang")) { + if (import->esd && !import->esd->langDesc) { + char *lang; + lang = gf_strdup(att->value); + import->esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG); + gf_isom_set_media_language(import->dest, track, lang); + } + } else if (!strcmp(att->name, "ttp:timeBase") && strcmp(att->value, "media")) { + e = gf_import_message(import, GF_BAD_PARAM, "Found invalid EBU-TTD root attribute name %s, value %s (shall be \"%s\")\n", att->name, att->value, "media"); + goto exit; + } else if (!strcmp(att->name, "xmlns:ttp") && strcmp(att->value, "http://www.w3.org/ns/ttml#parameter")) { + e = gf_import_message(import, GF_BAD_PARAM, "Found invalid EBU-TTD root attribute name %s, value %s (shall be \"%s\")\n", att->name, att->value, "http://www.w3.org/ns/ttml#parameter"); + goto exit; + } else if (!strcmp(att->name, "xmlns:tts") && strcmp(att->value, "http://www.w3.org/ns/ttml#styling")) { + e = gf_import_message(import, GF_BAD_PARAM, "Found invalid EBU-TTD root attribute name %s, value %s (shall be \"%s\")\n", att->name, att->value, "http://www.w3.org/ns/ttml#styling"); + goto exit; + } } - stse = (GF_SimpleTextSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, descriptionIndex - 1); - if (!stse) return NULL; - return stse; -} + /*** style ***/ +#if 0 + Bool has_styling, has_style; + GF_TextSampleDescriptor *sd; + has_styling = GF_FALSE; + has_style = GF_FALSE; + sd = (GF_TextSampleDescriptor*)gf_odf_desc_new(GF_ODF_TX3G_TAG); + i=0; + while ( (node = (GF_XMLNode*)gf_list_enum(root->content, &i))) { + if (node->type) { + continue; + } else if (!strcmp(node->name, "head")) { + GF_XMLNode *head_node; + u32 head_idx = 0; + while ( (head_node = (GF_XMLNode*)gf_list_enum(node->content, &head_idx))) { + if (!strcmp(head_node->name, "styling")) { + GF_XMLNode *styling_node; + u32 styling_idx; + if (has_styling) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated \"styling\" element. Abort.\n"); + goto exit; + } + has_styling = GF_TRUE; + + styling_idx = 0; + while ( (styling_node = (GF_XMLNode*)gf_list_enum(head_node->content, &styling_idx))) { + if (!strcmp(styling_node->name, "style")) { + GF_XMLAttribute *p_att; + u32 style_idx = 0; + while ( (p_att = (GF_XMLAttribute*)gf_list_enum(styling_node->attributes, &style_idx))) { + if (!strcmp(p_att->name, "tts:direction")) { + } else if (!strcmp(p_att->name, "tts:fontFamily")) { + sd->fonts = (GF_FontRecord*)gf_malloc(sizeof(GF_FontRecord)); + sd->font_count = 1; + sd->fonts[0].fontID = 1; + sd->fonts[0].fontName = gf_strdup(p_att->value); + } else if (!strcmp(p_att->name, "tts:backgroundColor")) { + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("EBU-TTD style attribute \"%s\" ignored.\n", p_att->name)); + //sd->back_color = ; + } else { + if ( !strcmp(p_att->name, "tts:fontSize") + || !strcmp(p_att->name, "tts:lineHeight") + || !strcmp(p_att->name, "tts:textAlign") + || !strcmp(p_att->name, "tts:color") + || !strcmp(p_att->name, "tts:fontStyle") + || !strcmp(p_att->name, "tts:fontWeight") + || !strcmp(p_att->name, "tts:textDecoration") + || !strcmp(p_att->name, "tts:unicodeBidi") + || !strcmp(p_att->name, "tts:wrapOption") + || !strcmp(p_att->name, "tts:multiRowAlign") + || !strcmp(p_att->name, "tts:linePadding")) { + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("EBU-TTD style attribute \"%s\" ignored.\n", p_att->name)); + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("EBU-TTD unknown style attribute: \"%s\". Ignoring.\n", p_att->name)); + } + } + } + break; //TODO: we only take care of the first style + } + } + } + } + } + } + if (!has_styling) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: missing \"styling\" element. Abort.\n"); + goto exit; + } + if (!has_style) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: missing \"style\" element. Abort.\n"); + goto exit; + } + e = gf_isom_new_text_description(import->dest, track, sd, NULL, NULL, &desc_idx); + gf_odf_desc_del((GF_Descriptor*)sd); +#else + e = gf_isom_new_xml_subtitle_description(import->dest, track, xmlns, NULL, NULL, &desc_idx); +#endif + if (e != GF_OK) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("TTML: incorrect sample description. Abort.\n")); + e = gf_isom_last_error(import->dest); + goto exit; + } -GF_Box *boxstring_new_with_data(u32 type, const char *string); + /*** body ***/ + parser_working_copy = gf_xml_dom_new(); + e = gf_xml_dom_parse(parser_working_copy, import->in_name, NULL, NULL); + assert (e == GF_OK); + root_working_copy = gf_xml_dom_get_root(parser_working_copy); + assert(root_working_copy); + last_sample_duration = 0; + last_sample_end = 0; + nb_samples = 0; + nb_children = gf_list_count(root->content); + has_body = GF_FALSE; + i=0; + while ( (node = (GF_XMLNode*)gf_list_enum(root->content, &i))) { + if (node->type) { + nb_children--; + continue; + } -GF_Err gf_isom_update_simpletext_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, const char *config) -{ - GF_Err e; - GF_SimpleTextSampleEntryBox *stse; - GF_TrackBox *trak; + if (!strcmp(node->name, "body")) { + GF_XMLNode *body_node; + u32 body_idx = 0; - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return GF_BAD_PARAM; + if (has_body) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated \"body\" element. Abort.\n"); + goto exit; + } + has_body = GF_TRUE; + + /*remove all the entries from the working copy, we'll add samples one to one to create full XML samples*/ + gf_text_import_ebu_ttd_remove_samples(root_working_copy, &sample_list_node); + + while ( (body_node = (GF_XMLNode*)gf_list_enum(node->content, &body_idx))) { + if (!strcmp(body_node->name, "div")) { + GF_XMLNode *div_node; + u32 div_idx = 0; + while ( (div_node = (GF_XMLNode*)gf_list_enum(body_node->content, &div_idx))) { + if (!strcmp(div_node->name, "p")) { + GF_XMLNode *p_node; + GF_XMLAttribute *p_att; + u32 p_idx = 0, h, m, s, ms; + s64 ts_begin = -1, ts_end = -1; + + //sample is either in the

... + while ( (p_att = (GF_XMLAttribute*)gf_list_enum(div_node->attributes, &p_idx))) { + if (!strcmp(p_att->name, "begin")) { + if (ts_begin != -1) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated \"begin\" attribute. Abort.\n"); + goto exit; + } + if (sscanf(p_att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) { + ts_begin = (h*3600 + m*60+s)*1000+ms; + } else if (sscanf(p_att->value, "%u:%u:%u", &h, &m, &s) == 3) { + ts_begin = (h*3600 + m*60+s)*1000; + } + } else if (!strcmp(p_att->name, "end")) { + if (ts_end != -1) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated \"end\" attribute. Abort.\n"); + goto exit; + } + if (sscanf(p_att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) { + ts_end = (h*3600 + m*60+s)*1000+ms; + } else if (sscanf(p_att->value, "%u:%u:%u", &h, &m, &s) == 3) { + ts_end = (h*3600 + m*60+s)*1000; + } + } + if ((ts_begin != -1) && (ts_end != -1) && !samp_text && sample_list_node) { + e = gf_xml_dom_append_child(sample_list_node, div_node); + assert(e == GF_OK); + assert(!samp_text); + samp_text = gf_xml_dom_serialize((GF_XMLNode*)root_working_copy, GF_FALSE); + e = gf_xml_dom_rem_child(sample_list_node, div_node); + assert(e == GF_OK); + } + } - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return GF_BAD_PARAM; + //or under a + p_idx = 0; + while ( (p_node = (GF_XMLNode*)gf_list_enum(div_node->content, &p_idx))) { + if (!strcmp(p_node->name, "span")) { + u32 span_idx = 0; + GF_XMLAttribute *span_att; + while ( (span_att = (GF_XMLAttribute*)gf_list_enum(p_node->attributes, &span_idx))) { + if (!strcmp(span_att->name, "begin")) { + if (ts_begin != -1) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated \"begin\" attribute under . Abort.\n"); + goto exit; + } + if (sscanf(span_att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) { + ts_begin = (h*3600 + m*60+s)*1000+ms; + } else if (sscanf(p_att->value, "%u:%u:%u", &h, &m, &s) == 3) { + ts_begin = (h*3600 + m*60+s)*1000; + } + } else if (!strcmp(span_att->name, "end")) { + if (ts_end != -1) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated \"end\" attribute under . Abort.\n"); + goto exit; + } + if (sscanf(span_att->value, "%u:%u:%u.%u", &h, &m, &s, &ms) == 4) { + ts_end = (h*3600 + m*60+s)*1000+ms; + } else if (sscanf(p_att->value, "%u:%u:%u", &h, &m, &s) == 3) { + ts_end = (h*3600 + m*60+s)*1000; + } + } + if ((ts_begin != -1) && (ts_end != -1) && !samp_text && sample_list_node) { + if (samp_text) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: duplicated sample text under . Abort.\n"); + goto exit; + } + + /*append the sample*/ + e = gf_xml_dom_append_child(sample_list_node, div_node); + assert(e == GF_OK); + assert(!samp_text); + samp_text = gf_xml_dom_serialize((GF_XMLNode*)root_working_copy, GF_FALSE); + e = gf_xml_dom_rem_child(sample_list_node, div_node); + assert(e == GF_OK); + } + } + } + } - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_TEXT: - break; - default: - return GF_BAD_PARAM; - } + if ((ts_begin != -1) && (ts_end != -1) && samp_text) { + GF_ISOSample *s; + GF_GenericSubtitleSample *samp; + u32 len; + char *str; - stse = (GF_SimpleTextSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, descriptionIndex - 1); - if (!stse) { - return GF_BAD_PARAM; - } else { - switch (stse->type) { - case GF_ISOM_BOX_TYPE_STSE: - break; - default: - return GF_BAD_PARAM; - } - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); + if (ts_end < ts_begin) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: invalid timings: \"begin\"="LLD" , \"end\"="LLD". Abort.\n", ts_begin, ts_end); + goto exit; + } - stse->config = (GF_StringBox *)boxstring_new_with_data(GF_ISOM_BOX_TYPE_STTC, config); - return GF_OK; + if (ts_begin < (s64)last_sample_end) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: timing overlapping not supported: \"begin\" is "LLD" , last \"end\" was "LLD". Abort.\n", ts_begin, last_sample_end); + goto exit; + } + + str = ttxt_parse_string(import, samp_text, GF_TRUE); + len = (u32) strlen(str); + samp = gf_isom_new_xml_subtitle_sample(); + /*each sample consists of a full valid XML file*/ + e = gf_isom_xml_subtitle_sample_add_text(samp, str, len); + if (e) goto exit; + gf_free(samp_text); + samp_text = NULL; + + s = gf_isom_xml_subtitle_to_sample(samp); + gf_isom_delete_xml_subtitle_sample(samp); + if (!nb_samples) { + s->DTS = 0; /*in MP4 we must start at T=0*/ + } else { + s->DTS = ts_begin; + } + last_sample_duration = ts_end - ts_begin; + last_sample_end = ts_end; + GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("ts_begin="LLD", ts_end="LLD", last_sample_duration="LLU" (real duration: "LLU"), last_sample_end="LLU"\n", ts_begin, ts_end, ts_end - last_sample_end, last_sample_duration, last_sample_end)); + + e = gf_isom_add_sample(import->dest, track, desc_idx, s); + if (e) goto exit; + gf_isom_sample_del(&s); + nb_samples++; + + gf_set_progress("Importing TTML", nb_samples, nb_children); + if (import->duration && (ts_end > import->duration)) + break; + } else { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("TTML: incomplete sample (begin="LLD", end="LLD", text=\"%s\"). Skip.\n", ts_begin, ts_end, samp_text ? samp_text : "NULL")); + } + } + } + } + } + } + } + if (!has_body) { + e = gf_import_message(import, GF_BAD_PARAM, "TTML: missing \"body\" element. Abort.\n"); + goto exit; } + GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("last_sample_duration="LLU", last_sample_end="LLU"\n", last_sample_duration, last_sample_end)); + gf_isom_set_last_sample_duration(import->dest, track, (u32) last_sample_duration); + gf_set_progress("Importing TTML", nb_samples, nb_samples); + +exit: + gf_free(samp_text); + gf_xml_dom_del(parser_working_copy); + if (!gf_isom_get_sample_count(import->dest, track)) + e = GF_BAD_PARAM; + return e; } -GF_Err gf_isom_new_simpletext_description(GF_ISOFile *movie, u32 trackNumber, GF_TextSampleDescriptor *desc, char *URLname, char *URNname, - const char *content_encoding, const char *mime, u32 *outDescriptionIndex) +static GF_Err gf_text_import_ttml(GF_MediaImporter *import) { - GF_TrackBox *trak; GF_Err e; - u32 dataRefIndex; - GF_SimpleTextSampleEntryBox *stse; + GF_DOMParser *parser; + GF_XMLNode *root; - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return e; + if (import->flags == GF_IMPORT_PROBE_ONLY) + return GF_OK; - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return GF_BAD_PARAM; + parser = gf_xml_dom_new(); + e = gf_xml_dom_parse(parser, import->in_name, ttml_import_progress, import); + if (e) { + gf_import_message(import, e, "Error parsing TTML file: Line %d - %s. Abort.", gf_xml_dom_get_line(parser), gf_xml_dom_get_error(parser)); + gf_xml_dom_del(parser); + return e; + } + root = gf_xml_dom_get_root(parser); + if (!root) { + gf_import_message(import, e, "Error parsing TTML file: no \"root\" found. Abort."); + gf_xml_dom_del(parser); + return e; + } - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_TEXT: - break; - default: - return GF_BAD_PARAM; + /*look for EBU-TTD*/ + if (!strcmp(root->name, "tt")) { + e = gf_text_import_ebu_ttd(import, parser, root); + if (e == GF_OK) { + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Note: TTML import - EBU-TTD detected\n")); + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("Unsupported TTML file - only EBU-TTD is supported (root shall be \"tt\", got %s)\n", root->name)); + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("Importing as generic TTML\n")); + e = GF_OK; + } + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("TTML file not recognized: found \"%s\" as root, \"%s\" expected\n", root->name, "tt")); + e = GF_BAD_PARAM; } - //get or create the data ref - e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - if (!dataRefIndex) { - e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - } - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - - stse = (GF_SimpleTextSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSE); - stse->dataReferenceIndex = dataRefIndex; - stse->mime_type = gf_strdup(mime); - gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, stse); - if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); + gf_xml_dom_del(parser); return e; } +/* SimpleText Text tracks -related functions */ +GF_Box *boxstring_new_with_data(u32 type, const char *string); #ifndef GPAC_DISABLE_SWF_IMPORT @@ -901,7 +1323,7 @@ static GF_Err swf_svg_add_iso_sample(void *user, const char *data, u32 length, u if (s) { gf_bs_get_content(bs, &s->data, &s->dataLength); s->DTS = (u64) (flusher->timescale*timestamp/1000); - s->IsRAP = isRap; + s->IsRAP = isRap ? RAP : RAP_NO; gf_isom_add_sample(flusher->import->dest, flusher->track, flusher->descriptionIndex, s); gf_isom_sample_del(&s); } else { @@ -911,11 +1333,15 @@ static GF_Err swf_svg_add_iso_sample(void *user, const char *data, u32 length, u return e; } -static GF_Err swf_svg_add_iso_header(void *user, const char *data, u32 length) +static GF_Err swf_svg_add_iso_header(void *user, const char *data, u32 length, Bool isHeader) { GF_ISOFlusher *flusher = (GF_ISOFlusher *)user; if (!flusher) return GF_BAD_PARAM; - return gf_isom_update_simpletext_description(flusher->import->dest, flusher->track, flusher->descriptionIndex , data); + if (isHeader) { + return gf_isom_update_stxt_description(flusher->import->dest, flusher->track, NULL, data, flusher->descriptionIndex); + } else { + return gf_isom_append_sample_data(flusher->import->dest, flusher->track, (char *)data, length); + } } GF_EXPORT @@ -985,7 +1411,7 @@ GF_Err gf_text_import_swf(GF_MediaImporter *import) /*and set sample descriptions*/ count = gf_list_count(cfg->sample_descriptions); for (i=0; idest, track, NULL, NULL, NULL, NULL, mime, &descIndex); + gf_isom_new_stxt_description(import->dest, track, GF_ISOM_SUBTYPE_STXT, mime, NULL, NULL, &descIndex); } gf_import_message(import, GF_OK, "SWF import - text track %d x %d", cfg->text_width, cfg->text_height); gf_odf_desc_del((GF_Descriptor *)cfg); @@ -996,7 +1422,7 @@ GF_Err gf_text_import_swf(GF_MediaImporter *import) gf_text_get_video_size(import, &w, &h); gf_isom_set_track_layout_info(import->dest, track, w<<16, h<<16, 0, 0, 0); - gf_isom_new_simpletext_description(import->dest, track, NULL, NULL, NULL, NULL, mime, &descIndex); + gf_isom_new_stxt_description(import->dest, track, GF_ISOM_SUBTYPE_STXT, mime, NULL, NULL, &descIndex); gf_import_message(import, GF_OK, "SWF import (as text - type: %s)", import->streamFormat); } @@ -1010,10 +1436,16 @@ GF_Err gf_text_import_swf(GF_MediaImporter *import) flusher.timescale = timescale; flusher.descriptionIndex = descIndex; gf_swf_reader_set_user_mode(read, &flusher, swf_svg_add_iso_sample, swf_svg_add_iso_header); + + e = GF_NOT_SUPPORTED; if (!import->streamFormat || (import->streamFormat && !stricmp(import->streamFormat, "SVG"))) { +#ifndef GPAC_DISABLE_SVG e = swf_to_svg_init(read, import->swf_flags, import->swf_flatten_angle); +#endif } else { /*if (import->streamFormat && !strcmp(import->streamFormat, "BIFS"))*/ +#ifndef GPAC_DISABLE_VRML e = swf_to_bifs_init(read); +#endif } if (e) { goto exit; @@ -1034,7 +1466,7 @@ exit: GF_EXPORT GF_Err gf_text_import_swf(GF_MediaImporter *import) { - GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Warning: GPAC was compiled without SWF import support, can't import track.")); + GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("Warning: GPAC was compiled without SWF import support, can't import track.\n")); return GF_NOT_SUPPORTED; } @@ -1054,14 +1486,14 @@ static GF_Err gf_text_import_sub(GF_MediaImporter *import) char szLine[2048], szTime[20], szText[2048]; GF_ISOSample *s; - sub_in = gf_f64_open(import->in_name, "rt"); - gf_f64_seek(sub_in, 0, SEEK_END); - file_size = gf_f64_tell(sub_in); - gf_f64_seek(sub_in, 0, SEEK_SET); + sub_in = gf_fopen(import->in_name, "rt"); + gf_fseek(sub_in, 0, SEEK_END); + file_size = gf_ftell(sub_in); + gf_fseek(sub_in, 0, SEEK_SET); unicode_type = gf_text_get_utf_type(sub_in); if (unicode_type<0) { - fclose(sub_in); + gf_fclose(sub_in); return gf_import_message(import, GF_NOT_SUPPORTED, "Unsupported SUB UTF encoding"); } @@ -1092,7 +1524,7 @@ static GF_Err gf_text_import_sub(GF_MediaImporter *import) if (cfg && cfg->timescale) timescale = cfg->timescale; track = gf_isom_new_track(import->dest, ID, GF_ISOM_MEDIA_TEXT, timescale); if (!track) { - fclose(sub_in); + gf_fclose(sub_in); return gf_import_message(import, gf_isom_last_error(import->dest), "Error creating text track"); } gf_isom_set_track_enabled(import->dest, track, 1); @@ -1225,7 +1657,7 @@ static GF_Err gf_text_import_sub(GF_MediaImporter *import) if (start && first_samp) { s = gf_isom_text_to_sample(samp); s->DTS = 0; - s->IsRAP = 1; + s->IsRAP = RAP; gf_isom_add_sample(import->dest, track, 1, s); gf_isom_sample_del(&s); first_samp = GF_FALSE; @@ -1259,7 +1691,7 @@ static GF_Err gf_text_import_sub(GF_MediaImporter *import) nb_samp++; gf_isom_text_reset(samp); prev_end = end; - gf_set_progress("Importing SUB", gf_f64_tell(sub_in), file_size); + gf_set_progress("Importing SUB", gf_ftell(sub_in), file_size); if (duration && (end >= duration)) break; } gf_isom_delete_text_sample(samp); @@ -1272,7 +1704,7 @@ static GF_Err gf_text_import_sub(GF_MediaImporter *import) exit: if (e) gf_isom_remove_track(import->dest, track); - fclose(sub_in); + gf_fclose(sub_in); return e; } @@ -1337,54 +1769,6 @@ void ttxt_parse_text_style(GF_MediaImporter *import, GF_XMLNode *n, GF_StyleReco } } -char *ttxt_parse_string(GF_MediaImporter *import, char *str, Bool strip_lines) -{ - u32 i=0; - u32 k=0; - u32 len = (u32) strlen(str); - u32 state = 0; - - if (!strip_lines) { - for (i=0; iesd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); import->esd->slConfig->timestampResolution = 1000; import->esd->decoderConfig->streamType = GF_STREAM_TEXT; - import->esd->decoderConfig->objectTypeIndication = 0x08; + import->esd->decoderConfig->objectTypeIndication = GPAC_OTI_TEXT_MPEG4; if (import->esd->OCRESID) gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_OCR, import->esd->OCRESID); } gf_text_import_set_language(import, track); @@ -1846,7 +2230,7 @@ static GF_Err gf_text_import_texml(GF_MediaImporter *import) if (!import->esd->slConfig) import->esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); import->esd->slConfig->timestampResolution = timescale; import->esd->decoderConfig->streamType = GF_STREAM_TEXT; - import->esd->decoderConfig->objectTypeIndication = 0x08; + import->esd->decoderConfig->objectTypeIndication = GPAC_OTI_TEXT_MPEG4; if (import->esd->OCRESID) gf_isom_set_track_reference(import->dest, track, GF_ISOM_REF_OCR, import->esd->OCRESID); } DTS = 0; @@ -2137,7 +2521,7 @@ static GF_Err gf_text_import_texml(GF_MediaImporter *import) s = gf_isom_text_to_sample(samp); gf_isom_delete_text_sample(samp); - s->IsRAP = isRAP; + s->IsRAP = isRAP ? RAP : RAP_NO; s->DTS = DTS; gf_isom_add_sample(import->dest, track, descIndex, s); gf_isom_sample_del(&s); @@ -2165,8 +2549,8 @@ GF_Err gf_import_timed_text(GF_MediaImporter *import) if (import->streamFormat) { if (!strcmp(import->streamFormat, "VTT")) fmt = GF_TEXT_IMPORT_WEBVTT; else if (!strcmp(import->streamFormat, "TTML")) fmt = GF_TEXT_IMPORT_TTML; + if ((strstr(import->in_name, ".swf") || strstr(import->in_name, ".SWF")) && !stricmp(import->streamFormat, "SVG")) fmt = GF_TEXT_IMPORT_SWF_SVG; } - if ((strstr(import->in_name, ".swf") || strstr(import->in_name, ".SWF")) && !stricmp(import->streamFormat, "SVG")) fmt = GF_TEXT_IMPORT_SWF_SVG; if (!fmt) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[TTXT Import] Input %s does not look like a supported text format - ignoring\n", import->in_name)); return GF_NOT_SUPPORTED; diff --git a/src/media_tools/webvtt.c b/src/media_tools/webvtt.c index f61be75..1021975 100644 --- a/src/media_tools/webvtt.c +++ b/src/media_tools/webvtt.c @@ -23,6 +23,7 @@ * */ +#include #include #include #include @@ -90,6 +91,7 @@ void vtcu_del(GF_Box *s) if (box->id) gf_isom_box_del((GF_Box *)box->id); if (box->settings) gf_isom_box_del((GF_Box *)box->settings); if (box->payload) gf_isom_box_del((GF_Box *)box->payload); + if (box->time) gf_isom_box_del((GF_Box *)box->time); gf_free(s); } @@ -191,6 +193,10 @@ GF_Err vtcu_Write(GF_Box *s, GF_BitStream *bs) e = gf_isom_box_write((GF_Box *)cuebox->id, bs); if (e) return e; } + if (cuebox->time) { + e = gf_isom_box_write((GF_Box *)cuebox->time, bs); + if (e) return e; + } if (cuebox->settings) { e = gf_isom_box_write((GF_Box *)cuebox->settings, bs); if (e) return e; @@ -242,6 +248,11 @@ GF_Err vtcu_Size(GF_Box *s) if (e) return e; cuebox->size += cuebox->id->size; } + if (cuebox->time) { + e = gf_isom_box_size((GF_Box *)cuebox->time); + if (e) return e; + cuebox->size += cuebox->time->size; + } if (cuebox->settings) { e = gf_isom_box_size((GF_Box *)cuebox->settings); if (e) return e; @@ -291,7 +302,7 @@ static GF_Err webvtt_write_cue(GF_BitStream *bs, GF_WebVTTCue *cue) if (cue->text) { cuebox->payload = (GF_StringBox *)boxstring_new_with_data(GF_ISOM_BOX_TYPE_PAYL, cue->text); } - + /* TODO: check if a time box should be written */ e = gf_isom_box_size((GF_Box *)cuebox); if (!e) e = gf_isom_box_write((GF_Box *)cuebox, bs); @@ -338,7 +349,7 @@ GF_ISOSample *gf_isom_webvtt_to_sample(void *s) } gf_bs_get_content(bs, &res->data, &res->dataLength); gf_bs_del(bs); - res->IsRAP = 1; + res->IsRAP = RAP; return res; } #endif /*GPAC_DISABLE_ISOM_WRITE*/ @@ -364,6 +375,7 @@ GF_Err vtcu_dump(GF_Box *a, FILE * trace) if (cuebox->id) boxstring_dump((GF_Box *)cuebox->id, trace); if (cuebox->settings) boxstring_dump((GF_Box *)cuebox->settings, trace); if (cuebox->payload) boxstring_dump((GF_Box *)cuebox->payload, trace); + if (cuebox->time) boxstring_dump((GF_Box *)cuebox->time, trace); gf_box_dump_done("WebVTTCueBox", a, trace); return GF_OK; } @@ -387,117 +399,6 @@ GF_Err wvtt_dump(GF_Box *a, FILE * trace) } #endif /* GPAC_DISABLE_ISOM_DUMP */ -GF_WebVTTSampleEntryBox *gf_webvtt_isom_get_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex) -{ - GF_WebVTTSampleEntryBox *wvtt; - GF_TrackBox *trak; - - if (!descriptionIndex) return NULL; - - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return NULL; - - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_TEXT: - break; - default: - return NULL; - } - - wvtt = (GF_WebVTTSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, descriptionIndex - 1); - if (!wvtt) return NULL; - switch (wvtt->type) { - case GF_ISOM_BOX_TYPE_WVTT: - break; - default: - return NULL; - } - return wvtt; -} - -GF_Err gf_isom_update_webvtt_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, const char *config) -{ -#ifndef GPAC_DISABLE_ISOM_WRITE - GF_Err e; - GF_WebVTTSampleEntryBox *wvtt; - GF_TrackBox *trak; - - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return GF_BAD_PARAM; - - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return GF_BAD_PARAM; - - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_TEXT: - break; - default: - return GF_BAD_PARAM; - } - - wvtt = (GF_WebVTTSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, descriptionIndex - 1); - if (!wvtt) return GF_BAD_PARAM; - switch (wvtt->type) { - case GF_ISOM_BOX_TYPE_WVTT: - break; - default: - return GF_BAD_PARAM; - } - if (wvtt) { - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - - wvtt->config = (GF_StringBox *)boxstring_new_with_data(GF_ISOM_BOX_TYPE_VTTC, config); - } else { - e = GF_BAD_PARAM; - } - return e; -#else - return GF_NOT_SUPPORTED; -#endif -} - -GF_Err gf_isom_new_webvtt_description(GF_ISOFile *movie, u32 trackNumber, GF_TextSampleDescriptor *desc, char *URLname, char *URNname, u32 *outDescriptionIndex) -{ -#ifndef GPAC_DISABLE_ISOM_WRITE - GF_TrackBox *trak; - GF_Err e; - u32 dataRefIndex; - GF_WebVTTSampleEntryBox *wvtt; - - e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE); - if (e) return e; - - trak = gf_isom_get_track_from_file(movie, trackNumber); - if (!trak || !trak->Media) return GF_BAD_PARAM; - - switch (trak->Media->handler->handlerType) { - case GF_ISOM_MEDIA_TEXT: - break; - default: - return GF_BAD_PARAM; - } - - //get or create the data ref - e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - if (!dataRefIndex) { - e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex); - if (e) return e; - } - if (!movie->keep_utc) - trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time(); - - wvtt = (GF_WebVTTSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_WVTT); - wvtt->dataReferenceIndex = dataRefIndex; - gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, wvtt); - if (outDescriptionIndex) *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); - return e; -#else - return GF_NOT_SUPPORTED; -#endif -} - #endif /*GPAC_DISABLE_ISOM*/ #ifndef GPAC_DISABLE_MEDIA_IMPORT @@ -570,8 +471,11 @@ static GF_Err gf_webvtt_cue_add_property(GF_WebVTTCue *cue, GF_WebVTTCueProperty case WEBVTT_PAYLOAD: prop = &cue->text; break; - case WEBVTT_TIME: - prop = &cue->time; + case WEBVTT_POSTCUE_TEXT: + prop = &cue->post_text; + break; + case WEBVTT_PRECUE_TEXT: + prop = &cue->pre_text; break; } if (*prop) { @@ -598,8 +502,9 @@ void gf_webvtt_cue_del(GF_WebVTTCue * cue) if (cue) { if (cue->id) gf_free(cue->id); if (cue->settings) gf_free(cue->settings); - if (cue->time) gf_free(cue->time); if (cue->text) gf_free(cue->text); + if (cue->pre_text) gf_free(cue->pre_text); + if (cue->post_text) gf_free(cue->post_text); gf_free(cue); } } @@ -656,14 +561,14 @@ GF_Err gf_webvtt_parser_init(GF_WebVTTParser *parser, const char *input_file, parser->state = WEBVTT_PARSER_STATE_WAITING_CUE; } } - parser->vtt_in = gf_f64_open(input_file, "rt"); - gf_f64_seek(parser->vtt_in, 0, SEEK_END); - parser->file_size = gf_f64_tell(parser->vtt_in); - gf_f64_seek(parser->vtt_in, 0, SEEK_SET); + parser->vtt_in = gf_fopen(input_file, "rt"); + gf_fseek(parser->vtt_in, 0, SEEK_END); + parser->file_size = gf_ftell(parser->vtt_in); + gf_fseek(parser->vtt_in, 0, SEEK_SET); parser->unicode_type = gf_text_get_utf_type(parser->vtt_in); if (parser->unicode_type<0) { - fclose(parser->vtt_in); + gf_fclose(parser->vtt_in); return GF_NOT_SUPPORTED; } @@ -683,7 +588,7 @@ void gf_webvtt_parser_reset(GF_WebVTTParser *parser) gf_webvtt_sample_del((GF_WebVTTSample *)gf_list_get(parser->samples, 0)); gf_list_rem(parser->samples, 0); } - if (parser->vtt_in) fclose(parser->vtt_in); + if (parser->vtt_in) gf_fclose(parser->vtt_in); parser->file_size = 0; parser->last_duration = 0; parser->on_header_parsed = NULL; @@ -1163,7 +1068,7 @@ GF_Err gf_webvtt_parser_parse(GF_WebVTTParser *parser, u32 duration) gf_webvtt_add_cue_to_samples(parser, parser->samples, cue); cue = NULL; - gf_set_progress("Importing WebVTT", gf_f64_tell(parser->vtt_in), parser->file_size); + gf_set_progress("Importing WebVTT", gf_ftell(parser->vtt_in), parser->file_size); if ((duration && (end >= duration)) || !sOK) { do_parse = GF_FALSE; break; @@ -1210,7 +1115,7 @@ GF_Err gf_webvtt_dump_header_boxed(FILE *dump, const char *data, u32 dataLength, *dumpedLength = 0; bs = gf_bs_new(data, dataLength, GF_BITSTREAM_READ); e = gf_isom_parse_box(&box, bs); - if (!box || (box->type != GF_ISOM_BOX_TYPE_VTTC && box->type != GF_ISOM_BOX_TYPE_STTC)) return GF_BAD_PARAM; + if (!box || (box->type != GF_ISOM_BOX_TYPE_VTTC)) return GF_BAD_PARAM; config = (GF_StringBox *)box; if (config->string) { fprintf(dump, "%s", config->string); @@ -1226,7 +1131,7 @@ GF_Err gf_webvtt_dump_header(FILE *dump, GF_ISOFile *file, u32 track, u32 index) GF_WebVTTSampleEntryBox *wvtt; wvtt = gf_webvtt_isom_get_description(file, track, index); if (!wvtt) return GF_BAD_PARAM; - fprintf(dump, "%s\n", wvtt->config->string); + fprintf(dump, "%s\n\n", wvtt->config->string); return GF_OK; } @@ -1256,6 +1161,8 @@ GF_Err gf_webvtt_dump_iso_sample(FILE *dump, u32 timescale, GF_ISOSample *iso_sa gf_webvtt_timestamp_set(&ts, (iso_sample->DTS * 1000) / timescale); gf_webvtt_timestamp_dump(&ts, dump, GF_FALSE); fprintf(dump, " --> NEXT\n\n"); + } else if (box->type == GF_ISOM_BOX_TYPE_VTTA) { + fprintf(dump, "%s\n\n", ((GF_StringBox *)box)->string); } gf_isom_box_del(box); } @@ -1276,6 +1183,9 @@ GF_List *gf_webvtt_parse_cues_from_data(const char *data, u32 dataLength, u64 st GF_WebVTTCue *cue; GF_VTTCueBox *cuebox; GF_BitStream *bs; + char *pre_text; + cue = NULL; + pre_text = NULL; cues = gf_list_new(); bs = gf_bs_new(data, dataLength, GF_BITSTREAM_READ); while(gf_bs_available(bs)) @@ -1287,6 +1197,11 @@ GF_List *gf_webvtt_parse_cues_from_data(const char *data, u32 dataLength, u64 st if (box->type == GF_ISOM_BOX_TYPE_VTCU) { cuebox = (GF_VTTCueBox *)box; cue = gf_webvtt_cue_new(); + if (pre_text) { + gf_webvtt_cue_add_property(cue, WEBVTT_PRECUE_TEXT, pre_text, (u32) strlen(pre_text)); + gf_free(pre_text); + pre_text = NULL; + } gf_list_add(cues, cue); gf_webvtt_timestamp_set(&cue->start, start); if (cuebox->id) { @@ -1298,6 +1213,13 @@ GF_List *gf_webvtt_parse_cues_from_data(const char *data, u32 dataLength, u64 st if (cuebox->payload) { gf_webvtt_cue_add_property(cue, WEBVTT_PAYLOAD, cuebox->payload->string, (u32) strlen(cuebox->payload->string)); } + } else if (box->type == GF_ISOM_BOX_TYPE_VTTA) { + GF_StringBox *sbox = (GF_StringBox *)box; + if (cue) { + gf_webvtt_cue_add_property(cue, WEBVTT_POSTCUE_TEXT, sbox->string, (u32) strlen(sbox->string)); + } else { + pre_text = gf_strdup(sbox->string); + } } gf_isom_box_del(box); } @@ -1317,42 +1239,48 @@ GF_Err gf_webvtt_merge_cues(GF_WebVTTParser *parser, u64 start, GF_List *cues) wsample->start = start; prev_wsample = (GF_WebVTTSample *)gf_list_last(parser->samples); - if (gf_list_count(cues)) { - while (gf_list_count(cues)) { - GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, 0); - gf_list_rem(cues, 0); - /* add the cue to the current sample */ - gf_list_add(wsample->cues, cue); - /* update with the previous sample */ - if (prev_wsample) { - Bool found = GF_FALSE; - while (!found && gf_list_count(prev_wsample->cues)) { - GF_WebVTTCue *old_cue = (GF_WebVTTCue *)gf_list_get(prev_wsample->cues, 0); - gf_list_rem(prev_wsample->cues, 0); - if ( - ((!cue->id && !old_cue->id) || (old_cue->id && cue->id && !strcmp(old_cue->id, cue->id))) && - ((!cue->settings && !old_cue->settings) || (old_cue->settings && cue->settings && !strcmp(old_cue->settings, cue->settings))) && - ((!cue->text && !old_cue->text) || (old_cue->text && cue->text && !strcmp(old_cue->text, cue->text))) - ) { - /* if it is the same cue, update its start with the initial start */ - cue->start = old_cue->start; - has_continuation_cue = GF_TRUE; - found = GF_TRUE; - /* delete the old cue */ - gf_webvtt_cue_del(old_cue); + while (gf_list_count(cues)) { + GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, 0); + gf_list_rem(cues, 0); + /* add the cue to the current sample */ + gf_list_add(wsample->cues, cue); + /* update with the previous sample */ + if (prev_wsample) { + Bool found = GF_FALSE; + while (!found && gf_list_count(prev_wsample->cues)) { + GF_WebVTTCue *old_cue = (GF_WebVTTCue *)gf_list_get(prev_wsample->cues, 0); + gf_list_rem(prev_wsample->cues, 0); + if ( + ((!cue->id && !old_cue->id) || (old_cue->id && cue->id && !strcmp(old_cue->id, cue->id))) && + ((!cue->settings && !old_cue->settings) || (old_cue->settings && cue->settings && !strcmp(old_cue->settings, cue->settings))) && + ((!cue->text && !old_cue->text) || (old_cue->text && cue->text && !strcmp(old_cue->text, cue->text))) + ) { + /* if it is the same cue, update its start with the initial start */ + cue->start = old_cue->start; + has_continuation_cue = GF_TRUE; + found = GF_TRUE; + if (old_cue->pre_text) { + cue->pre_text = old_cue->pre_text; + old_cue->pre_text = NULL; + } + if (old_cue->post_text) { + cue->post_text = old_cue->post_text; + old_cue->post_text = NULL; + } + /* delete the old cue */ + gf_webvtt_cue_del(old_cue); + } else { + /* finalize the end cue time */ + if (gf_webvtt_timestamp_is_zero(&old_cue->end)) { + gf_webvtt_timestamp_set(&old_cue->end, wsample->start); + } + /* transfer the cue */ + if (!has_continuation_cue) { + /* the cue can be safely serialized while keeping the order */ + parser->on_cue_read(parser->user, old_cue); } else { - /* finalize the end cue time */ - if (gf_webvtt_timestamp_is_zero(&old_cue->end)) { - gf_webvtt_timestamp_set(&old_cue->end, wsample->start); - } - /* transfer the cue */ - if (!has_continuation_cue) { - /* the cue can be safely serialized while keeping the order */ - parser->on_cue_read(parser->user, old_cue); - } else { - /* keep the cue in the current sample to respect cue start ordering */ - gf_list_add(wsample->cues, old_cue); - } + /* keep the cue in the current sample to respect cue start ordering */ + gf_list_add(wsample->cues, old_cue); } } } @@ -1432,7 +1360,12 @@ static void gf_webvtt_dump_cue(void *user, GF_WebVTTCue *cue) { FILE *dump = (FILE *)user; if (!cue || !dump) return; - if (cue->id) fprintf(dump, "%s", cue->id); + if (cue->pre_text) { + fprintf(dump, "%s", cue->pre_text); + fprintf(dump, "\n"); + fprintf(dump, "\n"); + } + if (cue->id) fprintf(dump, "%s\n", cue->id); if (cue->start.hour || cue->end.hour) { gf_webvtt_timestamp_dump(&cue->start, dump, GF_TRUE); fprintf(dump, " --> "); @@ -1448,6 +1381,12 @@ static void gf_webvtt_dump_cue(void *user, GF_WebVTTCue *cue) fprintf(dump, "\n"); if (cue->text) fprintf(dump, "%s", cue->text); fprintf(dump, "\n"); + fprintf(dump, "\n"); + if (cue->post_text) { + fprintf(dump, "%s", cue->post_text); + fprintf(dump, "\n"); + fprintf(dump, "\n"); + } } static GF_Err gf_webvtt_dump_cues(FILE *dump, GF_List *cues) @@ -1477,7 +1416,7 @@ GF_Err gf_webvtt_dump_iso_track(GF_MediaExporter *dumper, char *szName, u32 trac u64 duration; GF_WebVTTParser *parser; - out = szName ? gf_f64_open(szName, "wt") : stdout; + out = szName ? gf_fopen(szName, "wt") : stdout; if (!out) return GF_IO_ERR;// gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); parser = gf_webvtt_parser_new(); @@ -1505,7 +1444,7 @@ GF_Err gf_webvtt_dump_iso_track(GF_MediaExporter *dumper, char *szName, u32 trac exit: gf_webvtt_parser_del(parser); - if (szName) fclose(out); + if (szName) gf_fclose(out); return e; } diff --git a/src/odf/desc_private.c b/src/odf/desc_private.c index f90244e..a689f52 100644 --- a/src/odf/desc_private.c +++ b/src/odf/desc_private.c @@ -202,6 +202,11 @@ GF_Err gf_odf_delete_descriptor(GF_Descriptor *desc) case GF_ODF_LANG_TAG: return gf_odf_del_lang((GF_Language *)desc); + case GF_ODF_ESD_INC_TAG: + return gf_odf_del_esd_inc((GF_ES_ID_Inc *)desc); + case GF_ODF_ESD_REF_TAG: + return gf_odf_del_esd_ref((GF_ES_ID_Ref *)desc); + #ifndef GPAC_MINIMAL_ODF case GF_ODF_CC_TAG: @@ -212,10 +217,6 @@ GF_Err gf_odf_delete_descriptor(GF_Descriptor *desc) return gf_odf_del_cc_name((GF_CC_Name *)desc); case GF_ODF_CI_TAG: return gf_odf_del_ci((GF_CIDesc *)desc); - case GF_ODF_ESD_INC_TAG: - return gf_odf_del_esd_inc((GF_ES_ID_Inc *)desc); - case GF_ODF_ESD_REF_TAG: - return gf_odf_del_esd_ref((GF_ES_ID_Ref *)desc); case GF_ODF_TEXT_TAG: return gf_odf_del_exp_text((GF_ExpandedTextual *)desc); case GF_ODF_EXT_PL_TAG: diff --git a/src/odf/ipmpx_parse.c b/src/odf/ipmpx_parse.c index 4d5e9e4..af64096 100644 --- a/src/odf/ipmpx_parse.c +++ b/src/odf/ipmpx_parse.c @@ -176,19 +176,19 @@ void GF_IPMPX_ParseFileData(char *fileName, char **out_data, u32 *out_data_size) if (*out_data) gf_free(*out_data); *out_data = NULL; *out_data_size = 0; - f = gf_f64_open(fileName, "rb"); + f = gf_fopen(fileName, "rb"); if (!f) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IPMPX Parse] cannot open data file %s - skipping\n", fileName)); return; } - gf_f64_seek(f, 0, SEEK_END); - assert(gf_f64_tell(f) < 1<<31); - size = (u32) gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + assert(gf_ftell(f) < 1<<31); + size = (u32) gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); *out_data = (char*)gf_malloc(sizeof(char) * size); size = (u32) fread(*out_data, sizeof(char), size, f); *out_data_size = size; - fclose(f); + gf_fclose(f); } void GF_IPMPX_ParseBin128(char *val, bin128 *data) diff --git a/src/odf/odf_code.c b/src/odf/odf_code.c index 8ca9aaf..2618509 100644 --- a/src/odf/odf_code.c +++ b/src/odf/odf_code.c @@ -28,6 +28,7 @@ #define DATE_CODING_BIT_LEN 40 +#ifndef GPAC_MINIMAL_ODF static GFINLINE GF_Err OD_ReadUTF8String(GF_BitStream *bs, char **string, Bool isUTF8, u32 *read) { @@ -62,6 +63,8 @@ static GFINLINE void OD_WriteUTF8String(GF_BitStream *bs, char *string, Bool isU } } +#endif // GPAC_MINIMAL_ODF + /*use to parse strings read the length as well - Warning : the alloc is done here !!*/ GF_Err gf_odf_read_url_string(GF_BitStream *bs, char **string, u32 *readBytes) { @@ -1640,6 +1643,7 @@ GF_Err gf_odf_del_muxinfo(GF_MuxInfo *mi) { if (!mi) return GF_BAD_PARAM; if (mi->file_name) gf_free(mi->file_name); + if (mi->src_url) gf_free(mi->src_url); if (mi->streamFormat) gf_free(mi->streamFormat); if (mi->textNode) gf_free(mi->textNode); if (mi->fontNode) gf_free(mi->fontNode); @@ -1737,9 +1741,6 @@ GF_Err gf_odf_del_ui_cfg(GF_UIConfig *desc) - - - GF_Descriptor *gf_odf_new_cc() { GF_CCDescriptor *newDesc = (GF_CCDescriptor *) gf_malloc(sizeof(GF_CCDescriptor)); diff --git a/src/odf/odf_parse.c b/src/odf/odf_parse.c index 392d031..eca6248 100644 --- a/src/odf/odf_parse.c +++ b/src/odf/odf_parse.c @@ -158,22 +158,22 @@ void OD_ParseFileData(char *fileName, char **out_data, u32 *out_data_size) if (*out_data) gf_free(*out_data); *out_data = NULL; *out_data_size = 0; - f = gf_f64_open(fileName, "rb"); + f = gf_fopen(fileName, "rb"); if (!f) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ODF Parse] cannot open data file %s - skipping\n", fileName)); return; } - gf_f64_seek(f, 0, SEEK_END); - assert(gf_f64_tell(f) < 1<<31); - size = (u32) gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + assert(gf_ftell(f) < 1<<31); + size = (u32) gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); *out_data_size = size; *out_data = (char*)gf_malloc(sizeof(char) * (size_t)size); readen = fread(*out_data, sizeof(char), (size_t)size, f); if (readen != size) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[ODF Parse] readen size=%d does not match size=%d in %s\n", readen, size, fileName)); } - fclose(f); + gf_fclose(f); } void OD_ParseBin128(char *val, bin128 *data) @@ -282,11 +282,11 @@ GF_Err gf_odf_set_field(GF_Descriptor *desc, char *fieldName, char *val) /*XMT may use string*/ if (!ret) { if (!stricmp(val, "MPEG4Systems1")) { - dcd->objectTypeIndication = 0x01; + dcd->objectTypeIndication = GPAC_OTI_OD_V1; ret = 1; } else if (!stricmp(val, "MPEG4Systems2")) { - dcd->objectTypeIndication = 0x02; + dcd->objectTypeIndication = GPAC_OTI_SCENE_BIFS_V2; ret = 1; } else if (!stricmp(val, "MPEG4Visual")) { diff --git a/src/scene_manager/encode_isom.c b/src/scene_manager/encode_isom.c index 0dae42a..85eab9c 100644 --- a/src/scene_manager/encode_isom.c +++ b/src/scene_manager/encode_isom.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifndef GPAC_DISABLE_LASER #include #include @@ -228,8 +229,14 @@ static GF_Err gf_sm_import_stream(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_ESD if (!mux->file_name) return GF_OK; memset(&import, 0, sizeof(GF_MediaImporter)); - strcpy(szName, mux->file_name); - ext = strrchr(szName, '.'); + if (mux->src_url) { + ext = gf_url_concatenate(mux->src_url, mux->file_name); + strcpy(szName, ext ? ext : mux->file_name); + if (ext) gf_free(ext); + } else { + strcpy(szName, mux->file_name); + } + ext = strrchr(szName, '.'); /*get track types for AVI*/ if (ext && !strnicmp(ext, ".avi", 4)) { @@ -298,6 +305,13 @@ static GF_Err gf_sm_import_stream_special(GF_SceneManager *ctx, GF_ESD *esd) e = GF_OK; /*SRT/SUB BIFS import if text node unspecified*/ if (mux->textNode) { + if (mux->src_url) { + char *src = gf_url_concatenate(mux->src_url, mux->file_name); + if (src) { + gf_free(mux->file_name); + mux->file_name = src; + } + } e = gf_sm_import_bifs_subtitle(ctx, esd, mux); gf_sm_remove_mux_info(esd); } @@ -493,6 +507,7 @@ static GF_Err gf_sm_encode_scene(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEnc is_in_iod = 1; goto force_scene_rap; } + gf_bifs_encoder_set_source_url(bifs_enc, opts->src_url); #else return GF_NOT_SUPPORTED; #endif @@ -696,7 +711,7 @@ force_scene_rap: esd->decoderConfig->decoderSpecificInfo->data = data; esd->decoderConfig->decoderSpecificInfo->dataLength = data_len; - esd->decoderConfig->objectTypeIndication = 0x09; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_LASER; } #endif /*create stream description*/ @@ -710,7 +725,7 @@ force_scene_rap: if (!sc) { samp = gf_isom_sample_new(); - samp->IsRAP = 1; + samp->IsRAP = RAP; #ifndef GPAC_DISABLE_BIFS_ENC if (bifs_enc) @@ -790,7 +805,7 @@ force_scene_rap: #endif rap_sample->DTS = last_rap + rap_delay; - rap_sample->IsRAP = 1; + rap_sample->IsRAP = RAP; last_rap = rap_sample->DTS; @@ -828,7 +843,7 @@ force_scene_rap: if (lsr_enc) e = gf_laser_encoder_get_rap(lsr_enc, &car_samp->data, &car_samp->dataLength); #endif - car_samp->IsRAP = 2; + car_samp->IsRAP = RAP_REDUNDANT; while (1) { car_samp->DTS = last_rap+rap_delay; if (car_samp->DTS==prev_dts) car_samp->DTS++; @@ -885,7 +900,7 @@ force_scene_rap: samp = gf_isom_sample_new(); last_rap = samp->DTS = au->timing - init_offset; - samp->IsRAP = 1; + samp->IsRAP = RAP; /*RAP generation*/ #ifndef GPAC_DISABLE_BIFS_ENC if (bifs_enc) @@ -1000,7 +1015,7 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media delete_desc = 1; esd = gf_odf_desc_esd_new(2); esd->ESID = sc->ESID; - esd->decoderConfig->objectTypeIndication = 1; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_OD_V1; esd->decoderConfig->streamType = GF_STREAM_OD; } @@ -1010,7 +1025,7 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media if (!esd->slConfig->timestampResolution) esd->slConfig->timestampResolution = 1000; track = gf_isom_new_track(mp4, sc->ESID, GF_ISOM_MEDIA_OD, esd->slConfig->timestampResolution); if (!sc->ESID) sc->ESID = gf_isom_get_track_id(mp4, track); - if (!esd->decoderConfig->objectTypeIndication) esd->decoderConfig->objectTypeIndication = 1; + if (!esd->decoderConfig->objectTypeIndication) esd->decoderConfig->objectTypeIndication = GPAC_OTI_OD_V1; gf_isom_set_track_enabled(mp4, track, 1); /*no DSI required*/ /*create stream description*/ @@ -1164,7 +1179,7 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media while (samp->DTS >= rap_delay + last_rap) { GF_ISOSample *rap_sample = gf_isom_sample_new(); rap_sample->DTS = last_rap + rap_delay; - rap_sample->IsRAP = 1; + rap_sample->IsRAP = RAP; if (samp->DTS == last_rap + rap_delay) { GF_ODCom *com; @@ -1228,7 +1243,7 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media samp->dataLength = 0; e = gf_odf_codec_get_au(rap_codec, &samp->data, &samp->dataLength); if (e) goto err_exit; - samp->IsRAP = 1; + samp->IsRAP = RAP; e = gf_isom_add_sample_shadow(mp4, track, samp); if (e) goto err_exit; @@ -1263,7 +1278,7 @@ static GF_Err gf_sm_encode_od(GF_SceneManager *ctx, GF_ISOFile *mp4, char *media if (last_not_shadow && rap_shadow) { samp = gf_isom_sample_new(); samp->DTS = last_not_shadow; - samp->IsRAP = 1; + samp->IsRAP = RAP; e = gf_odf_codec_encode(rap_codec, 2); if (!e) e = gf_odf_codec_get_au(rap_codec, &samp->data, &samp->dataLength); if (!e) e = gf_isom_add_sample_shadow(mp4, track, samp); diff --git a/src/scene_manager/loader_bt.c b/src/scene_manager/loader_bt.c index 08284f3..d4c2b5d 100644 --- a/src/scene_manager/loader_bt.c +++ b/src/scene_manager/loader_bt.c @@ -33,6 +33,7 @@ #include /*for key codes...*/ #include +#include #if !defined(GPAC_DISABLE_LOADER_BT) && !defined(GPAC_DISABLE_ZLIB) @@ -165,7 +166,7 @@ void gf_bt_check_line(GF_BTParser *parser) } next_line: - parser->line_start_pos = gztell(parser->gz_in); + parser->line_start_pos = (s32) gztell(parser->gz_in); parser->line_buffer[0] = 0; if (parser->unicode_type) { u8 c1, c2; @@ -201,13 +202,13 @@ next_line: break; } else if (is_ret && wchar!='\n') { - u32 fpos = gztell(parser->gz_in); + u32 fpos = (u32) gztell(parser->gz_in); gzseek(parser->gz_in, fpos-2, SEEK_SET); is_ret = 1; break; } if (wchar==' ') { - last_space_pos_stream = gztell(parser->gz_in); + last_space_pos_stream = (u32) gztell(parser->gz_in); last_space_pos = (u32) (dst - l); } dst++; @@ -259,7 +260,7 @@ next_line: break; } } - pos = gztell(parser->gz_in); + pos = (u32) gztell(parser->gz_in); gzseek(parser->gz_in, pos-rew, SEEK_SET); } } @@ -280,7 +281,7 @@ next_line: parser->line++; { - u32 pos = gztell(parser->gz_in); + u32 pos = (u32) gztell(parser->gz_in); if (pos>=parser->file_pos) { parser->file_pos = pos; if (parser->line>1) gf_set_progress("BT Parsing", pos, parser->file_size); @@ -678,28 +679,27 @@ GF_Err gf_bt_parse_bool(GF_BTParser *parser, const char *name, SFBool *val) GF_Err gf_bt_parse_color(GF_BTParser *parser, const char *name, SFColor *col) { Float f; + u32 val; char *str = gf_bt_get_next(parser, 0); if (!str) return parser->last_error = GF_IO_ERR; if (gf_bt_check_externproto_field(parser, str)) return GF_OK; - /*HTML code*/ - if (str[0]=='$') { - u32 val; - sscanf(str+1, "%x", &val); - col->red = INT2FIX((val>>16) & 0xFF) / 255; - col->green = INT2FIX((val>>8) & 0xFF) / 255; - col->blue = INT2FIX(val & 0xFF) / 255; + if (sscanf(str, "%f", &f) == 1) { + col->red = FLT2FIX(f); + /*many VRML files use ',' separator*/ + gf_bt_check_code(parser, ','); + gf_bt_parse_float(parser, name, & col->green); + gf_bt_check_code(parser, ','); + gf_bt_parse_float(parser, name, & col->blue); return parser->last_error; } - if (sscanf(str, "%f", &f) != 1) { - return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number expected", name); + val = gf_color_parse(str); + if (!val) { + return gf_bt_report(parser, GF_BAD_PARAM, "%s: Number or name expected", name); } - col->red = FLT2FIX(f); - /*many VRML files use ',' separator*/ - gf_bt_check_code(parser, ','); - gf_bt_parse_float(parser, name, & col->green); - gf_bt_check_code(parser, ','); - gf_bt_parse_float(parser, name, & col->blue); + col->red = INT2FIX((val>>16) & 0xFF) / 255; + col->green = INT2FIX((val>>8) & 0xFF) / 255; + col->blue = INT2FIX(val & 0xFF) / 255; return parser->last_error; } @@ -3062,12 +3062,8 @@ GF_Descriptor *gf_bt_parse_descriptor(GF_BTParser *parser, char *name) } } else if (desc->tag==GF_ODF_MUXINFO_TAG) { GF_MuxInfo *mi = (GF_MuxInfo *)desc; - if (mi->file_name) { - char *res_name = gf_url_concatenate(parser->load->fileName, (const char *) mi->file_name); - if (res_name) { - gf_free(mi->file_name); - mi->file_name = res_name; - } + if (! mi->src_url) { + mi->src_url = gf_strdup(parser->load->fileName); } } return desc; @@ -3489,11 +3485,11 @@ static GF_Err gf_sm_load_bt_initialize(GF_SceneLoader *load, const char *str, Bo parser->last_error = GF_OK; if (load->fileName) { - FILE *test = gf_f64_open(load->fileName, "rb"); + FILE *test = gf_fopen(load->fileName, "rb"); if (!test) return GF_URL_ERROR; - gf_f64_seek(test, 0, SEEK_END); - size = (u32) gf_f64_tell(test); - fclose(test); + gf_fseek(test, 0, SEEK_END); + size = (u32) gf_ftell(test); + gf_fclose(test); gzInput = gzopen(load->fileName, "rb"); if (!gzInput) return GF_IO_ERR; diff --git a/src/scene_manager/loader_isom.c b/src/scene_manager/loader_isom.c index a031637..d1aa979 100644 --- a/src/scene_manager/loader_isom.c +++ b/src/scene_manager/loader_isom.c @@ -271,7 +271,7 @@ static GF_Err gf_sm_load_run_isom(GF_SceneLoader *load) } samp->DTS += init_offset; - au = gf_sm_stream_au_new(sc, samp->DTS, ((Double)(s64) samp->DTS) / sc->timeScale, samp->IsRAP); + au = gf_sm_stream_au_new(sc, samp->DTS, ((Double)(s64) samp->DTS) / sc->timeScale, (samp->IsRAP==RAP) ? 1 : 0); if (esd->decoderConfig->streamType==GF_STREAM_SCENE) { #ifndef GPAC_DISABLE_BIFS @@ -318,7 +318,7 @@ exit: gf_laser_decoder_del(lsr_dec); #endif if (esd) gf_odf_desc_del((GF_Descriptor *) esd); - if (logs) fclose(logs); + if (logs) gf_fclose(logs); return e; } diff --git a/src/scene_manager/loader_qt.c b/src/scene_manager/loader_qt.c index 84ebf7b..863abbc 100644 --- a/src/scene_manager/loader_qt.c +++ b/src/scene_manager/loader_qt.c @@ -171,9 +171,9 @@ GF_Err gf_sm_load_init_qt(GF_SceneLoader *load) gf_list_add(odU->objectDescriptors, od); samp = gf_isom_get_sample(src, tk, i+1, &di); - img = gf_f64_open(mi->file_name, "wb"); + img = gf_fopen(mi->file_name, "wb"); gf_fwrite(samp->data, samp->dataLength, 1, img); - fclose(img); + gf_fclose(img); gf_isom_sample_del(&samp); } gf_isom_delete(src); diff --git a/src/scene_manager/loader_svg.c b/src/scene_manager/loader_svg.c index d33c86f..da2bc2c 100644 --- a/src/scene_manager/loader_svg.c +++ b/src/scene_manager/loader_svg.c @@ -226,17 +226,17 @@ static void svg_process_media_href(GF_SVG_Parser *parser, GF_Node *elt, XMLRI *i u64 size; char *buffer; FILE *f; - f = gf_f64_open(iri->string, "rb"); + f = gf_fopen(iri->string, "rb"); if (!f) { return; } - gf_f64_seek(f, 0, SEEK_END); - size = gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_END); + size = gf_ftell(f); + gf_fseek(f, 0, SEEK_SET); buffer = gf_malloc(sizeof(char) * (size_t)(size+1)); size = fread(buffer, sizeof(char), (size_t)size, f); - fclose(f); + gf_fclose(f); if (tag==TAG_SVG_script) { @@ -1310,7 +1310,7 @@ static GF_ESD *lsr_parse_header(GF_SVG_Parser *parser, const char *name, const c gf_odf_desc_del((GF_Descriptor *)esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) lsrc; esd->decoderConfig->streamType = GF_STREAM_SCENE; - esd->decoderConfig->objectTypeIndication = 0x09; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_LASER; esd->slConfig->timestampResolution = lsrc->time_resolution ? lsrc->time_resolution : 1000; return esd; } @@ -1471,10 +1471,10 @@ static void svg_node_start(void *sax_cbck, const char *name, const char *name_sp strcat(szName, "_temp.nhml"); mux->file_name = gf_strdup(szName); st->nhml_info = mux->file_name; - nhml = gf_f64_open(st->nhml_info, "wt"); + nhml = gf_fopen(st->nhml_info, "wt"); fprintf(nhml, "\n"); fprintf(nhml, "\n", ts_res, ST, OTI, st->id); - fclose(nhml); + gf_fclose(nhml); mux->delete_file = GF_TRUE; } } @@ -1500,7 +1500,7 @@ static void svg_node_start(void *sax_cbck, const char *name, const char *name_sp if (!st || !st->nhml_info) { return; } - nhml = gf_f64_open(st->nhml_info, "a+t"); + nhml = gf_fopen(st->nhml_info, "a+t"); fprintf(nhml, "\n"); - fclose(nhml); + gf_fclose(nhml); return; } if (!strcmp(name, "endOfStream") ) { @@ -1524,9 +1524,9 @@ static void svg_node_start(void *sax_cbck, const char *name, const char *name_sp if (!st || !st->nhml_info) { return; } - nhml = gf_f64_open(st->nhml_info, "a+t"); + nhml = gf_fopen(st->nhml_info, "a+t"); fprintf(nhml, "\n"); - fclose(nhml); + gf_fclose(nhml); return; } diff --git a/src/scene_manager/loader_xmt.c b/src/scene_manager/loader_xmt.c index 43677ce..9a716e7 100644 --- a/src/scene_manager/loader_xmt.c +++ b/src/scene_manager/loader_xmt.c @@ -893,7 +893,7 @@ static u32 xmt_parse_sf_field(GF_XMTParser *parser, GF_FieldInfo *info, GF_Node break; case GF_SG_VRML_SFTIME: res = xmt_parse_time(parser, info->name, (SFTime *)info->far_ptr, a_value); - xmt_check_time_offset(parser, n, info); + if (n) xmt_check_time_offset(parser, n, info); break; case GF_SG_VRML_SFCOLOR: res = xmt_parse_float(parser, info->name, & ((SFColor *)info->far_ptr)->red, a_value); @@ -1917,16 +1917,15 @@ GF_Descriptor *xmt_parse_descriptor(GF_XMTParser *parser, char *name, const GF_X else if (!strcmp(att->name, "ES_ID")) xmt_desc_name = att->value; else if (!strcmp(att->name, "OCR_ES_ID")) ocr_ref = att->value; else if (!strcmp(att->name, "dependsOn_ES_ID")) dep_ref = att->value; - else if ((desc->tag==GF_ODF_MUXINFO_TAG) && (!stricmp(att->name, "fileName") || !stricmp(att->name, "url"))) { - char *res_name = gf_url_concatenate(parser->load->fileName, (const char *)att->value); - e = gf_odf_set_field(desc, att->name, res_name ? res_name : att->value); - if (e) xmt_report(parser, e, "Warning: %s not a valid attribute for descriptor %s", att->name, name); - if (res_name) - gf_free(res_name); - } else { + else { e = gf_odf_set_field(desc, att->name, att->value); if (e) xmt_report(parser, e, "Warning: %s not a valid attribute for descriptor %s", att->name, name); - } + //store src path but do not concatenate, othewise we break BT<->XMT conversion ... + if ((desc->tag==GF_ODF_MUXINFO_TAG) && (!stricmp(att->name, "fileName") || !stricmp(att->name, "url"))) { + GF_MuxInfo *mux = (GF_MuxInfo *) desc; + if (!mux->src_url) mux->src_url = gf_strdup(parser->load->fileName); + } + } } if (binaryID || xmt_desc_name) { if ((tag == GF_ODF_IOD_TAG) || (tag == GF_ODF_OD_TAG)) @@ -2705,7 +2704,7 @@ static void xmt_node_end(void *sax_cbck, const char *name, const char *name_spac parser->command_buffer = NULL; } else { //empty - if ((parser->command->tag==GF_SG_ROUTE_INSERT) && !parser->command->fromNodeID) { + if (parser->command && (parser->command->tag==GF_SG_ROUTE_INSERT) && !parser->command->fromNodeID) { gf_list_del_item(parser->scene_au->commands, parser->command); } parser->command = NULL; diff --git a/src/scene_manager/scene_dump.c b/src/scene_manager/scene_dump.c index 8343279..333d4a6 100644 --- a/src/scene_manager/scene_dump.c +++ b/src/scene_manager/scene_dump.c @@ -53,7 +53,7 @@ struct _scenedump u32 indent; char *filename; - u32 dump_mode; + GF_SceneDumpFormat dump_mode; u16 CurrentESID; u8 ind_char; Bool XMLDump, X3DDump, LSRDump; @@ -81,7 +81,7 @@ void gf_dump_svg_element(GF_SceneDumper *sdump, GF_Node *n, GF_Node *parent, Boo GF_Err gf_sm_dump_command_list(GF_SceneDumper *sdump, GF_List *comList, u32 indent, Bool skip_first_replace); GF_EXPORT -GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char indent_char, u32 dump_mode) +GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char indent_char, GF_SceneDumpFormat dump_mode) { GF_SceneDumper *tmp; if (!graph) return NULL; @@ -93,14 +93,16 @@ GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char ind #ifndef GPAC_DISABLE_SVG if ((graph->RootNode && (graph->RootNode->sgprivate->tag>=GF_NODE_RANGE_LAST_VRML) ) || (dump_mode==GF_SM_DUMP_LASER) || (dump_mode==GF_SM_DUMP_SVG)) { - tmp->XMLDump = 1; - if (dump_mode==GF_SM_DUMP_LASER) tmp->LSRDump = 1; + tmp->XMLDump = GF_TRUE; + if (dump_mode==GF_SM_DUMP_LASER) { + tmp->LSRDump = GF_TRUE; + } if (_rad_name) { const char* ext_name = tmp->LSRDump ? ".xsr" : ".svg"; - tmp->filename = gf_malloc(strlen(_rad_name ? _rad_name : "") + strlen(ext_name) + 1); + tmp->filename = (char *)gf_malloc(strlen(_rad_name ? _rad_name : "") + strlen(ext_name) + 1); strcpy(tmp->filename, _rad_name ? _rad_name : ""); strcat(tmp->filename, ext_name); - tmp->trace = gf_f64_open(tmp->filename, "wt"); + tmp->trace = gf_fopen(tmp->filename, "wt"); if (!tmp->trace) { gf_free(tmp); return NULL; @@ -132,16 +134,16 @@ GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char ind switch (dump_mode) { case GF_SM_DUMP_X3D_XML: ext_name = ".x3d"; - tmp->XMLDump = 1; - tmp->X3DDump = 1; + tmp->XMLDump = GF_TRUE; + tmp->X3DDump = GF_TRUE; break; case GF_SM_DUMP_XMTA: ext_name = ".xmt"; - tmp->XMLDump = 1; + tmp->XMLDump = GF_TRUE; break; case GF_SM_DUMP_X3D_VRML: ext_name = ".x3dv"; - tmp->X3DDump = 1; + tmp->X3DDump = GF_TRUE; break; case GF_SM_DUMP_VRML: ext_name = ".wrl"; @@ -150,10 +152,10 @@ GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char ind ext_name = ".bt"; break; } - tmp->filename = gf_malloc(strlen(_rad_name ? _rad_name : "") + strlen(ext_name) + 1); + tmp->filename = (char *)gf_malloc(strlen(_rad_name ? _rad_name : "") + strlen(ext_name) + 1); strcpy(tmp->filename, _rad_name ? _rad_name : ""); strcat(tmp->filename, ext_name); - tmp->trace = gf_f64_open(tmp->filename, "wt"); + tmp->trace = gf_fopen(tmp->filename, "wt"); if (!tmp->trace) { gf_free(tmp); return NULL; @@ -162,14 +164,14 @@ GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, char ind tmp->trace = stdout; switch (dump_mode) { case GF_SM_DUMP_X3D_XML: - tmp->XMLDump = 1; - tmp->X3DDump = 1; + tmp->XMLDump = GF_TRUE; + tmp->X3DDump = GF_TRUE; break; case GF_SM_DUMP_XMTA: - tmp->XMLDump = 1; + tmp->XMLDump = GF_TRUE; break; case GF_SM_DUMP_X3D_VRML: - tmp->X3DDump = 1; + tmp->X3DDump = GF_TRUE; break; default: break; @@ -201,7 +203,7 @@ void gf_sm_dumper_del(GF_SceneDumper *sdump) } gf_list_del(sdump->mem_def_nodes); gf_list_del(sdump->inserted_routes); - if (sdump->trace != stdout) fclose(sdump->trace); + if (sdump->trace != stdout) gf_fclose(sdump->trace); if (sdump->filename) { gf_free(sdump->filename); sdump->filename = NULL; @@ -3413,7 +3415,7 @@ static void ReorderAUContext(GF_List *sample_list, GF_AUContext *au, Bool lsr_du GF_EXPORT -GF_Err gf_sm_dump(GF_SceneManager *ctx, char *rad_name, u32 dump_mode) +GF_Err gf_sm_dump(GF_SceneManager *ctx, char *rad_name, GF_SceneDumpFormat dump_mode) { GF_Err e; GF_List *sample_list; diff --git a/src/scene_manager/scene_engine.c b/src/scene_manager/scene_engine.c index 563e6ff..7990048 100644 --- a/src/scene_manager/scene_engine.c +++ b/src/scene_manager/scene_engine.c @@ -382,14 +382,14 @@ start: #endif sprintf(file_name, "%s.svg", rad_name); - file = gf_f64_open(file_name, "rb"); + file = gf_fopen(file_name, "rb"); if (!file) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot open SVG dump file %s\n", file_name)); e = GF_IO_ERR; goto exit; } - gf_f64_seek(file, 0, SEEK_END); - fsize = gf_f64_tell(file); + gf_fseek(file, 0, SEEK_END); + fsize = gf_ftell(file); if (fsize == 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] SVG dump %s is empty\n", file_name)); @@ -398,9 +398,9 @@ start: /* First, read the dump in a buffer */ buffer = gf_malloc((size_t)fsize * sizeof(char)); - gf_f64_seek(file, 0, SEEK_SET); + gf_fseek(file, 0, SEEK_SET); fsize = fread(buffer, sizeof(char), (size_t)fsize, file); - fclose(file); + gf_fclose(file); file = NULL; /* Then, set DIMS unit header - TODO: notify redundant units*/ @@ -457,7 +457,7 @@ start: exit: if (!seng->dump_path) gf_free(cache_dir); if (buffer) gf_free(buffer); - if (file) fclose(file); + if (file) gf_fclose(file); return e; } @@ -720,7 +720,11 @@ GF_Err gf_seng_encode_from_commands(GF_SceneEngine *seng, u16 ESID, Bool disable GF_Command *com = gf_list_get(commands, 0); gf_list_rem(commands, 0); switch (com->tag) { +#ifndef GPAC_DISABLE_VRML case GF_SG_SCENE_REPLACE: + new_au->flags |= GF_SM_AU_RAP; + break; +#endif case GF_SG_LSR_NEW_SCENE: new_au->flags |= GF_SM_AU_RAP; break; diff --git a/src/scene_manager/scene_manager.c b/src/scene_manager/scene_manager.c index 55549c4..7dab0ca 100644 --- a/src/scene_manager/scene_manager.c +++ b/src/scene_manager/scene_manager.c @@ -633,12 +633,12 @@ GF_Err gf_sm_load_init(GF_SceneLoader *load) } else #endif { - ext = strrchr(load->fileName, '.'); + ext = (char *)strrchr(load->fileName, '.'); if (!ext) return GF_NOT_SUPPORTED; if (!stricmp(ext, ".gz")) { char *anext; ext[0] = 0; - anext = strrchr(load->fileName, '.'); + anext = (char *)strrchr(load->fileName, '.'); ext[0] = '.'; ext = anext; } @@ -754,17 +754,17 @@ void gf_sm_update_bitwrapper_buffer(GF_Node *node, const char *fileName) if (!strnicmp(buffer, "file://", 7)) { char *url = gf_url_concatenate(fileName, buffer+7); if (url) { - FILE *f = fopen(url, "rb"); + FILE *f = gf_fopen(url, "rb"); if (f) { fseek(f, 0, SEEK_END); - data_size = ftell(f); + data_size = (u32) ftell(f); fseek(f, 0, SEEK_SET); data = gf_malloc(sizeof(char)*data_size); if (data) { size_t s = fread(data, 1, data_size, f); assert(s == data_size); } - fclose(f); + gf_fclose(f); } gf_free(url); } diff --git a/src/scene_manager/swf_bifs.c b/src/scene_manager/swf_bifs.c index cb1009f..959168d 100644 --- a/src/scene_manager/swf_bifs.c +++ b/src/scene_manager/swf_bifs.c @@ -1163,7 +1163,7 @@ static GF_Err swf_init_od(SWFReader *read, Bool root_only) esd = (GF_ESD *) gf_odf_desc_esd_new(0); if (!esd) return GF_OUT_OF_MEM; esd->decoderConfig->streamType = GF_STREAM_SCENE; - esd->decoderConfig->objectTypeIndication = 1; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS; esd->slConfig->timestampResolution = read->bifs_es->timeScale; esd->ESID = 1; gf_list_add(read->load->ctx->root_od->ESDescriptors, esd); @@ -1185,7 +1185,7 @@ static GF_Err swf_init_od(SWFReader *read, Bool root_only) esd = (GF_ESD *) gf_odf_desc_esd_new(0); if (!esd) return GF_OUT_OF_MEM; esd->decoderConfig->streamType = GF_STREAM_OD; - esd->decoderConfig->objectTypeIndication = 1; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS; esd->slConfig->timestampResolution = read->od_es->timeScale = read->bifs_es->timeScale; esd->ESID = 2; esd->OCRESID = 1; @@ -1253,13 +1253,13 @@ static GF_Err swf_bifs_define_sprite(SWFReader *read, u32 nb_frames) /*always depends on main scene*/ esd->dependsOnESID = 1; esd->decoderConfig->streamType = GF_STREAM_SCENE; - esd->decoderConfig->objectTypeIndication = 1; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS; esd->slConfig->timestampResolution = read->bifs_es->timeScale; gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = NULL; gf_list_add(od->ESDescriptors, esd); - /*by default insert OD at begining*/ + /*by default insert OD at beginning*/ e = swf_insert_od(read, 0, od); if (e) { gf_odf_desc_del((GF_Descriptor *) od); @@ -1384,7 +1384,7 @@ static GF_Err swf_bifs_setup_sound(SWFReader *read, SWFSound *snd, Bool soundstr gf_list_add(esd->extensionDescriptors, mux); - /*by default insert OD at begining*/ + /*by default insert OD at beginning*/ e = swf_insert_od(read, 0, od); if (e) { gf_odf_desc_del((GF_Descriptor *) od); @@ -1476,7 +1476,7 @@ static GF_Err swf_bifs_setup_image(SWFReader *read, u32 ID, char *fileName) gf_list_add(esd->extensionDescriptors, mux); - /*by default insert OD at begining*/ + /*by default insert OD at beginning*/ e = swf_insert_od(read, 0, od); if (e) { gf_odf_desc_del((GF_Descriptor *) od); @@ -1690,7 +1690,7 @@ static GF_Err swf_bifs_place_obj(SWFReader *read, u32 depth, u32 ID, u32 prev_id f->pos = depth; f->fieldIndex = 2; /*children index*/ f->new_node = par; - gf_node_register(f->new_node, com->node); + gf_node_register(f->new_node, NULL); gf_list_add(read->bifs_au->commands, com); if (ID==prev_id) return GF_OK; @@ -1735,7 +1735,7 @@ static GF_Err swf_bifs_remove_obj(SWFReader *read, u32 depth, u32 ID) f->pos = depth; f->fieldIndex = 2; /*children index*/ f->new_node = gf_sg_find_node_by_name(read->load->scene_graph, "Shape0"); - gf_node_register(f->new_node, com->node); + gf_node_register(f->new_node, NULL); gf_list_add(read->bifs_au->commands, com); /*check if this is a sprite*/ if (ID) @@ -2203,7 +2203,7 @@ GF_Err swf_to_bifs_init(SWFReader *read) esd->ESID = esd->OCRESID = 3; esd->dependsOnESID = 1; esd->decoderConfig->streamType = GF_STREAM_SCENE; - esd->decoderConfig->objectTypeIndication = 1; + esd->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS; esd->slConfig->timestampResolution = read->bifs_es->timeScale; gf_odf_desc_del((GF_Descriptor *) esd->decoderConfig->decoderSpecificInfo); esd->decoderConfig->decoderSpecificInfo = NULL; diff --git a/src/scene_manager/swf_parse.c b/src/scene_manager/swf_parse.c index 21698b0..78cd692 100644 --- a/src/scene_manager/swf_parse.c +++ b/src/scene_manager/swf_parse.c @@ -1716,7 +1716,7 @@ static GF_Err swf_def_edit_text(SWFReader *read) static void swf_delete_sound_stream(SWFReader *read) { if (!read->sound_stream) return; - if (read->sound_stream->output) fclose(read->sound_stream->output); + if (read->sound_stream->output) gf_fclose(read->sound_stream->output); if (read->sound_stream->szFileName) gf_free(read->sound_stream->szFileName); gf_free(read->sound_stream); read->sound_stream = NULL; @@ -1809,7 +1809,7 @@ static GF_Err swf_def_sound(SWFReader *read) } else { snd->szFileName = gf_strdup(szName); } - snd->output = gf_f64_open(snd->szFileName, "wb"); + snd->output = gf_fopen(snd->szFileName, "wb"); alloc_size = 4096; frame = (char*)gf_malloc(sizeof(char)*4096); @@ -1976,7 +1976,7 @@ static GF_Err swf_soundstream_block(SWFReader *read) /*error at setup*/ if (!read->sound_stream->output) { - read->sound_stream->output = gf_f64_open(read->sound_stream->szFileName, "wb"); + read->sound_stream->output = gf_fopen(read->sound_stream->szFileName, "wb"); if (!read->sound_stream->output) return swf_func_skip(read); } @@ -2061,7 +2061,7 @@ static GF_Err swf_def_bits_jpeg(SWFReader *read, u32 version) } if (version!=3) - file = gf_f64_open(szName, "wb"); + file = gf_fopen(szName, "wb"); if (version==1 && read->jpeg_hdr_size) { /*remove JPEG EOI*/ @@ -2093,7 +2093,7 @@ static GF_Err swf_def_bits_jpeg(SWFReader *read, u32 version) gf_fwrite(buf+skip, 1, size-skip, file); } if (version!=3) - fclose(file); + gf_fclose(file); if (version==3) { #ifndef GPAC_DISABLE_AV_PARSERS @@ -2137,9 +2137,9 @@ static GF_Err swf_def_bits_jpeg(SWFReader *read, u32 version) buf = gf_realloc(buf, sizeof(char)*osize); gf_img_png_enc(raw, w, h, h*4, GF_PIXEL_RGBA, (char *)buf, &osize); - file = gf_f64_open(szName, "wb"); + file = gf_fopen(szName, "wb"); gf_fwrite(buf, 1, osize, file); - fclose(file); + gf_fclose(file); gf_free(raw); #endif //GPAC_DISABLE_AV_PARSERS @@ -2457,7 +2457,8 @@ void gf_swf_reader_del(SWFReader *read) gf_bs_del(read->bs); if (read->mem) gf_free(read->mem); - read->finalize(read); + if (read->finalize) + read->finalize(read); while (gf_list_count(read->display_list)) { DispShape *s = (DispShape *)gf_list_get(read->display_list, 0); @@ -2480,7 +2481,7 @@ void gf_swf_reader_del(SWFReader *read) while (gf_list_count(read->sounds)) { SWFSound *snd = (SWFSound *)gf_list_get(read->sounds, 0); gf_list_rem(read->sounds, 0); - if (snd->output) fclose(snd->output); + if (snd->output) gf_fclose(snd->output); if (snd->szFileName) gf_free(snd->szFileName); gf_free(snd); } @@ -2489,7 +2490,7 @@ void gf_swf_reader_del(SWFReader *read) if (read->jpeg_hdr) gf_free(read->jpeg_hdr); if (read->localPath) gf_free(read->localPath); - fclose(read->input); + gf_fclose(read->input); gf_free(read); } @@ -2505,7 +2506,7 @@ SWFReader *gf_swf_reader_new(const char *localPath, const char *inputName) { SWFReader *read; FILE *input; - input = gf_f64_open(inputName, "rb"); + input = gf_fopen(inputName, "rb"); if (!input) return NULL; GF_SAFEALLOC(read, SWFReader); @@ -2536,7 +2537,7 @@ SWFReader *gf_swf_reader_new(const char *localPath, const char *inputName) GF_Err gf_swf_reader_set_user_mode(SWFReader *read, void *user, GF_Err (*add_sample)(void *user, const char *data, u32 length, u64 timestamp, Bool isRap), - GF_Err (*add_header)(void *user, const char *data, u32 length)) + GF_Err (*add_header)(void *user, const char *data, u32 length, Bool isHeader)) { if (!read) return GF_BAD_PARAM; read->user = user; @@ -2573,7 +2574,7 @@ GF_Err gf_swf_read_header(SWFReader *read) swf_align(read); read->frame_rate = swf_get_16(read)>>8; read->frame_count = swf_get_16(read); - GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("SWF Import - Scene Size %gx%g - %d frames @ %d FPS", read->width, read->height, read->frame_count, read->frame_rate)); + GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("SWF Import - Scene Size %gx%g - %d frames @ %d FPS\n", read->width, read->height, read->frame_count, read->frame_rate)); return GF_OK; } @@ -2601,10 +2602,29 @@ GF_Err gf_sm_load_init_swf(GF_SceneLoader *load) read->no_as = 1; } + e = GF_NOT_SUPPORTED; if (!(load->swf_import_flags & GF_SM_SWF_USE_SVG)) { +#ifndef GPAC_DISABLE_VRML e = swf_to_bifs_init(read); +#endif } else { +#ifndef GPAC_DISABLE_SVG + char svgFileName[GF_MAX_PATH]; + FILE *svgFile; + if (load->svgOutFile) { + if (load->localPath) { + sprintf(svgFileName, "%s%c%s.svg", load->localPath, GF_PATH_SEPARATOR, load->svgOutFile); + } else { + sprintf(svgFileName, "%s.svg", load->svgOutFile); + } + svgFile = gf_fopen(svgFileName, "wt"); + if (!svgFile) return GF_BAD_PARAM; + } else { + svgFile = stdout; + } + gf_swf_reader_set_user_mode(read, svgFile, swf_svg_write_text_sample, swf_svg_write_text_header); e = swf_to_svg_init(read, read->flags, load->swf_flatten_limit); +#endif } if (e) goto exit; diff --git a/src/scene_manager/swf_svg.c b/src/scene_manager/swf_svg.c index 1426260..edc563e 100644 --- a/src/scene_manager/swf_svg.c +++ b/src/scene_manager/swf_svg.c @@ -30,7 +30,7 @@ #include #include -#ifndef GPAC_DISABLE_VRML +#ifndef GPAC_DISABLE_VVG #ifndef GPAC_DISABLE_SWF_IMPORT @@ -468,6 +468,11 @@ static GF_Err swf_svg_show_frame(SWFReader *read) static void swf_svg_finalize(SWFReader *read) { + swf_svg_print(read, "\n"); + read->add_header(read->user, read->svg_data, read->svg_data_size, GF_FALSE); + gf_free(read->svg_data); + read->svg_data = NULL; + read->svg_data_size = 0; } static GF_Err swf_svg_define_button(SWFReader *read, SWF_Button *btn) @@ -475,7 +480,7 @@ static GF_Err swf_svg_define_button(SWFReader *read, SWF_Button *btn) return GF_OK; } -Bool swf_svg_action(SWFReader *read, SWFAction *act) +static Bool swf_svg_action(SWFReader *read, SWFAction *act) { return GF_TRUE; } @@ -516,7 +521,7 @@ GF_Err swf_to_svg_init(SWFReader *read, u32 swf_flags, Float swf_flatten_angle) read->print_stream_header = GF_FALSE; /* update sample description */ - read->add_header(read->user, read->svg_data, read->svg_data_size); + read->add_header(read->user, read->svg_data, read->svg_data_size, GF_TRUE); gf_free(read->svg_data); read->svg_data = NULL; read->svg_data_size = 0; @@ -524,6 +529,31 @@ GF_Err swf_to_svg_init(SWFReader *read, u32 swf_flags, Float swf_flatten_angle) return GF_OK; } +GF_Err swf_svg_write_text_sample(void *user, const char *data, u32 length, u64 timestamp, Bool isRap) +{ + FILE *svgFile = (FILE *)user; + u32 lengthWritten; + + lengthWritten = (u32)fwrite(data, 1, length, svgFile); + if (length != lengthWritten) { + return GF_BAD_PARAM; + } else { + return GF_OK; + } +} + +GF_Err swf_svg_write_text_header(void *user, const char *data, u32 length, Bool isHeader) +{ + FILE *svgFile = (FILE *)user; + u32 lengthWritten; + + lengthWritten = (u32)fwrite(data, 1, length, svgFile); + if (length != lengthWritten) { + return GF_BAD_PARAM; + } else { + return GF_OK; + } +} #endif /*GPAC_DISABLE_SWF_IMPORT*/ -#endif /*GPAC_DISABLE_VRML*/ +#endif /*GPAC_DISABLE_SVG*/ diff --git a/src/scene_manager/text_to_bifs.c b/src/scene_manager/text_to_bifs.c index 42c80bb..f31fb6f 100644 --- a/src/scene_manager/text_to_bifs.c +++ b/src/scene_manager/text_to_bifs.c @@ -53,7 +53,7 @@ static GF_Err gf_text_guess_format(char *filename, u32 *fmt) { char szLine[2048], szTest[10]; u32 val; - FILE *test = gf_f64_open(filename, "rt"); + FILE *test = gf_fopen(filename, "rt"); if (!test) return GF_URL_ERROR; while (fgets(szLine, 2048, test) != NULL) { @@ -78,7 +78,7 @@ static GF_Err gf_text_guess_format(char *filename, u32 *fmt) } if (strstr(szLine, "x-quicktime-tx3g")) *fmt = GF_TEXT_IMPORT_TEXML; } - fclose(test); + gf_fclose(test); return GF_OK; } @@ -142,7 +142,7 @@ static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxI } } - srt_in = gf_f64_open(mux->file_name, "rt"); + srt_in = gf_fopen(mux->file_name, "rt"); if (!srt_in) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot open input file %s\n", mux->file_name)); return GF_URL_ERROR; @@ -155,7 +155,7 @@ static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxI src->slConfig->timestampResolution = 1000; if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); src->decoderConfig->streamType = GF_STREAM_SCENE; - src->decoderConfig->objectTypeIndication = 1; + src->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS; e = GF_OK; state = end = 0; @@ -330,7 +330,7 @@ static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxI exit: if (e) gf_sm_stream_del(ctx, srt); - fclose(srt_in); + gf_fclose(srt_in); return e; } #endif /*GPAC_DISABLE_VRML*/ @@ -395,7 +395,7 @@ static GF_Err gf_text_import_sub_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxI } } - sub_in = gf_f64_open(mux->file_name, "rt"); + sub_in = gf_fopen(mux->file_name, "rt"); if (!sub_in) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[sub->bifs] cannot open input file %s\n", mux->file_name)); return GF_URL_ERROR; @@ -408,7 +408,7 @@ static GF_Err gf_text_import_sub_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxI src->slConfig->timestampResolution = 1000; if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); src->decoderConfig->streamType = GF_STREAM_SCENE; - src->decoderConfig->objectTypeIndication = 1; + src->decoderConfig->objectTypeIndication = GPAC_OTI_SCENE_BIFS; e = GF_OK; start = end = 0; @@ -514,7 +514,7 @@ static GF_Err gf_text_import_sub_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxI } if (e) gf_sm_stream_del(ctx, srt); - fclose(sub_in); + gf_fclose(sub_in); return e; } #endif diff --git a/src/scenegraph/base_scenegraph.c b/src/scenegraph/base_scenegraph.c index 10fc838..17603c9 100644 --- a/src/scenegraph/base_scenegraph.c +++ b/src/scenegraph/base_scenegraph.c @@ -146,17 +146,21 @@ void gf_sg_del(GF_SceneGraph *sg) gf_list_del(sg->listeners_to_add); gf_mx_del(sg->dom_evt_mx); #endif + #ifdef GPAC_HAS_SPIDERMONKEY gf_list_del(sg->scripts); sg->scripts = NULL; gf_list_del(sg->objects); sg->objects = NULL; +#ifndef GPAC_DISABLE_SVG if (sg->svg_js) { void gf_svg_script_context_del(GF_SVGJS *svg_js, GF_SceneGraph *scenegraph); gf_svg_script_context_del(sg->svg_js, sg); } #endif +#endif //GPAC_HAS_SPIDERMONKEY + #ifndef GPAC_DISABLE_VRML gf_list_del(sg->Routes); gf_list_del(sg->protos); @@ -1990,12 +1994,12 @@ GF_Err gf_node_get_field(GF_Node *node, u32 FieldIndex, GF_FieldInfo *info) if (node->sgprivate->tag==TAG_UndefinedNode) return GF_BAD_PARAM; #ifndef GPAC_DISABLE_VRML else if (node->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_field(NULL, node, info); - else if ((node->sgprivate->tag == TAG_MPEG4_Script) + else if (node->sgprivate->tag == TAG_MPEG4_Script) + return gf_sg_script_get_field(node, info); #ifndef GPAC_DISABLE_X3D - || (node->sgprivate->tag == TAG_X3D_Script) + else if (node->sgprivate->tag == TAG_X3D_Script) + return gf_sg_script_get_field(node, info); #endif - ) - return gf_sg_script_get_field(node, info); else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_MPEG4) return gf_sg_mpeg4_node_get_field(node, info); #ifndef GPAC_DISABLE_X3D else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) return gf_sg_x3d_node_get_field(node, info); @@ -2036,13 +2040,12 @@ GF_Err gf_node_get_field_by_name(GF_Node *node, char *name, GF_FieldInfo *field) else if (node->sgprivate->tag == TAG_ProtoNode) { res = gf_sg_proto_get_field_index_by_name(NULL, node, name); } - else if ((node->sgprivate->tag == TAG_MPEG4_Script) + else if (node->sgprivate->tag == TAG_MPEG4_Script) + return gf_node_get_field_by_name_enum(node, name, field); #ifndef GPAC_DISABLE_X3D - || (node->sgprivate->tag == TAG_X3D_Script) -#endif - ) { + else if (node->sgprivate->tag == TAG_X3D_Script) return gf_node_get_field_by_name_enum(node, name, field); - } +#endif else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_MPEG4) res = gf_sg_mpeg4_node_get_field_index_by_name(node, name); #ifndef GPAC_DISABLE_X3D else if (node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) res = gf_sg_x3d_node_get_field_index_by_name(node, name); @@ -2173,7 +2176,7 @@ GF_Node *gf_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *cloned_pa return NULL; } -u32 gf_xml_get_namespace_id(char *name) +GF_NamespaceType gf_xml_get_namespace_id(char *name) { if (!strcmp(name, "http://www.w3.org/XML/1998/namespace")) return GF_XMLNS_XML; else if (!strcmp(name, "http://www.w3.org/2001/xml-events")) return GF_XMLNS_XMLEV; @@ -2263,7 +2266,7 @@ u32 gf_sg_get_namespace_code_from_name(GF_SceneGraph *sg, char *name) return GF_XMLNS_UNDEFINED; } -const char *gf_sg_get_namespace_qname(GF_SceneGraph *sg, u32 xmlns_id) +const char *gf_sg_get_namespace_qname(GF_SceneGraph *sg, GF_NamespaceType xmlns_id) { GF_XMLNS *ns; u32 i, count; @@ -2278,7 +2281,7 @@ const char *gf_sg_get_namespace_qname(GF_SceneGraph *sg, u32 xmlns_id) } -const char *gf_sg_get_namespace(GF_SceneGraph *sg, u32 xmlns_id) +const char *gf_sg_get_namespace(GF_SceneGraph *sg, GF_NamespaceType xmlns_id) { GF_XMLNS *ns; u32 i, count; diff --git a/src/scenegraph/commands.c b/src/scenegraph/commands.c index 5c75a6a..45f174a 100644 --- a/src/scenegraph/commands.c +++ b/src/scenegraph/commands.c @@ -164,12 +164,15 @@ GF_EXPORT GF_Err gf_sg_command_apply(GF_SceneGraph *graph, GF_Command *com, Double time_offset) { GF_Err e; -#ifndef GPAC_DISABLE_VRML +#if !defined(GPAC_DISABLE_VRML) || !defined(GPAC_DISABLE_SVG) GF_CommandField *inf; + GF_Node *node; +#endif + +#ifndef GPAC_DISABLE_VRML GF_FieldInfo field; void *slot_ptr; GF_Node *def; - GF_Node *node; #endif if (!com || !graph) return GF_BAD_PARAM; diff --git a/src/scenegraph/dom_events.c b/src/scenegraph/dom_events.c index fb6a89f..e558e27 100644 --- a/src/scenegraph/dom_events.c +++ b/src/scenegraph/dom_events.c @@ -636,7 +636,7 @@ GF_DOMHandler *gf_dom_listener_build_ex(GF_Node *node, u32 event_type, u32 event } GF_EXPORT -GF_DOMHandler *gf_dom_listener_build(GF_Node *node, u32 event_type, u32 event_parameter) +GF_DOMHandler *gf_dom_listener_build(GF_Node *node, GF_EventType event_type, u32 event_parameter) { return gf_dom_listener_build_ex(node, event_type, event_parameter, NULL, NULL); } diff --git a/src/scenegraph/dom_smjs.c b/src/scenegraph/dom_smjs.c index 6a6ad79..669d26b 100644 --- a/src/scenegraph/dom_smjs.c +++ b/src/scenegraph/dom_smjs.c @@ -217,7 +217,7 @@ typedef enum { EVENT_JSPROPERTY_TYPEARG = -23, EVENT_JSPROPERTY_LOADED = -24, EVENT_JSPROPERTY_TOTAL = -25, - EVENT_JSPROPERTY_BUFFERLEVELVALID = -26, + EVENT_JSPROPERTY_BUFFER_ON = -26, EVENT_JSPROPERTY_BUFFERLEVEL = -27, EVENT_JSPROPERTY_BUFFERREMAININGTIME = -28, EVENT_JSPROPERTY_STATUS = -29, @@ -232,6 +232,7 @@ typedef enum { EVENT_JSPROPERTY_TYPE3D = -38, EVENT_JSPROPERTY_ERROR = -39, EVENT_JSPROPERTY_DYNAMIC_SCENE = -40, + EVENT_JSPROPERTY_URL = -41, } GF_DOMEventJSProperty; typedef enum { @@ -992,7 +993,7 @@ if (!n->sgprivate) return; SMJS_SET_PRIVATE(c, obj, NULL); gf_list_del_item(n->sgprivate->scenegraph->objects, obj); -dom_js_pre_destroy(c, n->sgprivate->scenegraph, n); +gf_sg_js_dom_pre_destroy(c, n->sgprivate->scenegraph, n); dom_unregister_node(n); } @@ -2521,28 +2522,22 @@ if (SMJS_ID_IS_INT(id)) { *vp = INT_TO_JSVAL(evt->detail); return JS_TRUE; case EVENT_JSPROPERTY_LOADED: - if (!evt->media_event) return JS_TRUE; - *vp = INT_TO_JSVAL( evt->media_event->loaded_size); + *vp = INT_TO_JSVAL( evt->media_event.loaded_size); return JS_TRUE; case EVENT_JSPROPERTY_TOTAL: - if (!evt->media_event) return JS_TRUE; - *vp = INT_TO_JSVAL( evt->media_event->total_size); + *vp = INT_TO_JSVAL( evt->media_event.total_size); return JS_TRUE; - case EVENT_JSPROPERTY_BUFFERLEVELVALID: - if (!evt->media_event) return JS_TRUE; - *vp = BOOLEAN_TO_JSVAL( evt->media_event->bufferValid ? JS_TRUE : JS_FALSE); + case EVENT_JSPROPERTY_BUFFER_ON: + *vp = BOOLEAN_TO_JSVAL( evt->media_event.bufferValid ? JS_TRUE : JS_FALSE); return JS_TRUE; case EVENT_JSPROPERTY_BUFFERLEVEL: - if (!evt->media_event) return JS_TRUE; - *vp = INT_TO_JSVAL( evt->media_event->level); + *vp = INT_TO_JSVAL( evt->media_event.level); return JS_TRUE; case EVENT_JSPROPERTY_BUFFERREMAININGTIME: - if (!evt->media_event) return JS_TRUE; - *vp = JS_MAKE_DOUBLE(c, evt->media_event->remaining_time); + *vp = JS_MAKE_DOUBLE(c, evt->media_event.remaining_time); return JS_TRUE; case EVENT_JSPROPERTY_STATUS: - if (!evt->media_event) return JS_TRUE; - *vp = INT_TO_JSVAL( evt->media_event->status); + *vp = INT_TO_JSVAL( evt->media_event.status); return JS_TRUE; /*VRML ones*/ @@ -2579,6 +2574,10 @@ if (SMJS_ID_IS_INT(id)) { case EVENT_JSPROPERTY_DYNAMIC_SCENE: *vp = INT_TO_JSVAL(evt->key_flags ? 1 : 0); return JS_TRUE; + case EVENT_JSPROPERTY_URL: + s = JS_NewStringCopyZ(c, evt->addon_url ? evt->addon_url : ""); + *vp = STRING_TO_JSVAL( s ); + return JS_TRUE; default: return JS_TRUE; @@ -2878,7 +2877,7 @@ static void xml_http_reset(XMLHTTPContext *ctx) /*we're sure the graph is a "nomade" one since we initially put the refcount to 1 ourselves*/ ctx->document->reference_count--; if (!ctx->document->reference_count) { - dom_js_pre_destroy(ctx->c, ctx->document, NULL); + gf_sg_js_dom_pre_destroy(ctx->c, ctx->document, NULL); gf_sg_del(ctx->document); } } @@ -2946,8 +2945,10 @@ static void xml_http_fire_event(XMLHTTPContext *ctx, GF_EventType evtType) static void xml_http_state_change(XMLHTTPContext *ctx) { +#ifndef GPAC_DISABLE_VRML GF_SceneGraph *scene; GF_Node *n; +#endif jsval rval; gf_sg_lock_javascript(ctx->c, GF_TRUE); @@ -3144,12 +3145,6 @@ static void xml_http_terminate(XMLHTTPContext *ctx, GF_Err error) ctx->sess = NULL; } - /*error, complete reset*/ - if (error) { - xml_http_reset(ctx); - } else { - ctx->html_status = 200; - } /*but stay in loaded mode*/ ctx->readyState = XHR_READYSTATE_DONE; xml_http_state_change(ctx); @@ -3306,11 +3301,11 @@ static GF_Err xml_http_process_local(XMLHTTPContext *ctx) FILE *responseFile; /*opera-style local host*/ - if (!strnicmp(ctx->url, "file://localhost", 16)) responseFile = gf_f64_open(ctx->url+16, "rb"); + if (!strnicmp(ctx->url, "file://localhost", 16)) responseFile = gf_fopen(ctx->url+16, "rb"); /*regular-style local host*/ - else if (!strnicmp(ctx->url, "file://", 7)) responseFile = gf_f64_open(ctx->url+7, "rb"); + else if (!strnicmp(ctx->url, "file://", 7)) responseFile = gf_fopen(ctx->url+7, "rb"); /* other types: e.g. "C:\" */ - else responseFile = gf_f64_open(ctx->url, "rb"); + else responseFile = gf_fopen(ctx->url, "rb"); if (!responseFile) { ctx->html_status = 404; @@ -3327,13 +3322,13 @@ static GF_Err xml_http_process_local(XMLHTTPContext *ctx) par.msg_type = GF_NETIO_WAIT_FOR_REPLY; xml_http_on_data(ctx, &par); - gf_f64_seek(responseFile, 0, SEEK_END); - fsize = gf_f64_tell(responseFile); - gf_f64_seek(responseFile, 0, SEEK_SET); + gf_fseek(responseFile, 0, SEEK_END); + fsize = gf_ftell(responseFile); + gf_fseek(responseFile, 0, SEEK_SET); ctx->data = (char *)gf_malloc(sizeof(char)*(size_t)(fsize+1)); fsize = fread(ctx->data, sizeof(char), (size_t)fsize, responseFile); - fclose(responseFile); + gf_fclose(responseFile); ctx->data[fsize] = 0; ctx->size = (u32)fsize; @@ -4396,7 +4391,7 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global) SMJS_PROPERTY_SPEC("typeArg", EVENT_JSPROPERTY_TYPEARG, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("loaded", EVENT_JSPROPERTY_LOADED, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("total", EVENT_JSPROPERTY_TOTAL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), - SMJS_PROPERTY_SPEC("bufferLevelValid", EVENT_JSPROPERTY_BUFFERLEVELVALID, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("buffering", EVENT_JSPROPERTY_BUFFER_ON, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("bufferLevel", EVENT_JSPROPERTY_BUFFERLEVEL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("bufferRemainingTime",EVENT_JSPROPERTY_BUFFERREMAININGTIME, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("status", EVENT_JSPROPERTY_STATUS, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), @@ -4413,6 +4408,7 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global) SMJS_PROPERTY_SPEC("type3d", EVENT_JSPROPERTY_TYPE3D, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("error", EVENT_JSPROPERTY_ERROR, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC("dynamic_scene", EVENT_JSPROPERTY_DYNAMIC_SCENE, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), + SMJS_PROPERTY_SPEC("url", EVENT_JSPROPERTY_URL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0), SMJS_PROPERTY_SPEC(0, 0, 0, 0, 0), }; @@ -4542,7 +4538,8 @@ void dom_js_load(GF_SceneGraph *scene, JSContext *c, JSObject *global) void html_media_element_js_finalize(JSContext *c, GF_Node *n); -void dom_js_pre_destroy(JSContext *c, GF_SceneGraph *sg, GF_Node *n) +GF_EXPORT +void gf_sg_js_dom_pre_destroy(JSContext *c, GF_SceneGraph *sg, GF_Node *n) { u32 i, count; if (n) { diff --git a/src/scenegraph/svg_attributes.c b/src/scenegraph/svg_attributes.c index 67ac417..444c260 100644 --- a/src/scenegraph/svg_attributes.c +++ b/src/scenegraph/svg_attributes.c @@ -24,6 +24,7 @@ */ #include +#include #include #include @@ -166,7 +167,15 @@ static const struct dom_event_def { /*GPAC internals*/ { GF_EVENT_SCENE_ATTACHED, "gpac_scene_attached", GF_DOM_EVENT_GPAC}, + { GF_EVENT_SCENE_SIZE, "gpac_scene_size", GF_DOM_EVENT_GPAC}, { GF_EVENT_VP_RESIZE, "gpac_vp_changed", GF_DOM_EVENT_GPAC}, + { GF_EVENT_ADDON_DETECTED, "gpac_addon_found", GF_DOM_EVENT_GPAC}, + { GF_EVENT_MAIN_ADDON_STATE, "gpac_main_addon_state", GF_DOM_EVENT_GPAC}, + { GF_EVENT_STREAMLIST, "gpac_streamlist_changed", GF_DOM_EVENT_GPAC}, + { GF_EVENT_TIMESHIFT_DEPTH, "gpac_timeshift_depth_changed", GF_DOM_EVENT_GPAC}, + + +#if 0 { GF_EVENT_DBLCLICK, "gpac_dbl_click", GF_DOM_EVENT_GPAC}, { GF_EVENT_SIZE, "gpac_size_changed", GF_DOM_EVENT_GPAC}, { GF_EVENT_SCENE_SIZE, "gpac_scene_size", GF_DOM_EVENT_GPAC}, @@ -177,7 +186,7 @@ static const struct dom_event_def { { GF_EVENT_REFRESH, "gpac_move", GF_DOM_EVENT_GPAC}, { GF_EVENT_QUIT, "gpac_quit", GF_DOM_EVENT_GPAC}, { GF_EVENT_PASTE_TEXT, "gpac_paste", GF_DOM_EVENT_GPAC}, - { GF_EVENT_COPY_TEXT, "gpac_paste", GF_DOM_EVENT_GPAC}, + { GF_EVENT_COPY_TEXT, "gpac_copy", GF_DOM_EVENT_GPAC}, { GF_EVENT_CONNECT, "gpac_on_connect", GF_DOM_EVENT_GPAC}, { GF_EVENT_DURATION, "gpac_on_duration", GF_DOM_EVENT_GPAC}, { GF_EVENT_EOS, "gpac_eos", GF_DOM_EVENT_GPAC}, @@ -195,7 +204,11 @@ static const struct dom_event_def { { GF_EVENT_DROPFILE, "gpac_dropfile", GF_DOM_EVENT_GPAC}, { GF_EVENT_TEXT_EDITING_START, "gpac_textedit_start", GF_DOM_EVENT_GPAC}, { GF_EVENT_TEXT_EDITING_END, "gpac_textedit_end", GF_DOM_EVENT_GPAC}, - { GF_EVENT_ADDON_DETECTED, "gpac_addon_found", GF_DOM_EVENT_GPAC} + { GF_EVENT_QUALITY_SWITCHED, "gpac_quality_switch", GF_DOM_EVENT_GPAC}, + { GF_EVENT_TIMESHIFT_OVERFLOW, "gpac_timeshift_overflow", GF_DOM_EVENT_GPAC}, + { GF_EVENT_TIMESHIFT_UPDATE, "gpac_timeshift_update", GF_DOM_EVENT_GPAC} +#endif + }; GF_EXPORT @@ -448,14 +461,15 @@ static const struct predef_keyid { GF_EXPORT -const char *gf_dom_get_key_name(u32 key_identifier) +const char *gf_dom_get_key_name(GF_KeyCode key_identifier) { u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid); - if (!key_identifier || count<=key_identifier) return "Unknown"; + if (!key_identifier || count<= (u32) key_identifier) return "Unknown"; return predefined_key_identifiers[key_identifier-1].name; } +GF_EXPORT GF_KeyCode gf_dom_get_key_type(char *key_name) { if (strlen(key_name) == 1) { @@ -550,162 +564,6 @@ GF_KeyCode gf_dom_get_key_type(char *key_name) } /* Basic SVG datatype parsing functions */ -static const struct predef_col { - const char *name; - u8 r; - u8 g; - u8 b; -} predefined_colors[] = -{ - {"aliceblue",240, 248, 255}, - {"antiquewhite",250, 235, 215}, - {"aqua", 0, 255, 255}, - {"aquamarine",127, 255, 212}, - {"azure",240, 255, 255}, - {"beige",245, 245, 220}, - {"bisque",255, 228, 196}, - {"black", 0, 0, 0}, - {"blanchedalmond",255, 235, 205}, - {"blue", 0, 0, 255}, - {"blueviolet",138, 43, 226}, - {"brown",165, 42, 42}, - {"burlywood",222, 184, 135}, - {"cadetblue", 95, 158, 160}, - {"chartreuse",127, 255, 0}, - {"chocolate",210, 105, 30}, - {"coral",255, 127, 80}, - {"lightpink",255, 182, 193}, - {"lightsalmon",255, 160, 122}, - {"lightseagreen", 32, 178, 170}, - {"lightskyblue",135, 206, 250}, - {"lightslategray",119, 136, 153}, - {"lightslategrey",119, 136, 153}, - {"lightsteelblue",176, 196, 222}, - {"lightyellow",255, 255, 224}, - {"lime", 0, 255, 0}, - {"limegreen", 50, 205, 50}, - {"linen",250, 240, 230}, - {"magenta",255, 0, 255}, - {"maroon",128, 0, 0}, - {"mediumaquamarine",102, 205, 170}, - {"mediumblue", 0, 0, 205}, - {"mediumorchid",186, 85, 211}, - {"cornflowerblue",100, 149, 237}, - {"cornsilk",255, 248, 220}, - {"crimson",220, 20, 60}, - {"cyan", 0, 255, 255}, - {"darkblue", 0, 0, 139}, - {"darkcyan", 0, 139, 139}, - {"darkgoldenrod",184, 134, 11}, - {"darkgray",169, 169, 169}, - {"darkgreen", 0, 100, 0}, - {"darkgrey",169, 169, 169}, - {"darkkhaki",189, 183, 107}, - {"darkmagenta",139, 0, 139}, - {"darkolivegreen", 85, 107, 47}, - {"darkorange",255, 140, 0}, - {"darkorchid",153, 50, 204}, - {"darkred",139, 0, 0}, - {"darksalmon",233, 150, 122}, - {"darkseagreen",143, 188, 143}, - {"darkslateblue", 72, 61, 139}, - {"darkslategray", 47, 79, 79}, - {"darkslategrey", 47, 79, 79}, - {"darkturquoise", 0, 206, 209}, - {"darkviolet",148, 0, 211}, - {"deeppink",255, 20, 147}, - {"deepskyblue", 0, 191, 255}, - {"dimgray",105, 105, 105}, - {"dimgrey",105, 105, 105}, - {"dodgerblue", 30, 144, 255}, - {"firebrick",178, 34, 34}, - {"floralwhite",255, 250, 240}, - {"forestgreen", 34, 139, 34}, - {"fuchsia",255, 0, 255}, - {"gainsboro",220, 220, 220}, - {"ghostwhite",248, 248, 255}, - {"gold",255, 215, 0}, - {"goldenrod",218, 165, 32}, - {"gray",128, 128, 128}, - {"grey",128, 128, 128}, - {"green", 0, 128, 0}, - {"greenyellow",173, 255, 47}, - {"honeydew",240, 255, 240}, - {"hotpink",255, 105, 180}, - {"indianred",205, 92, 92}, - {"indigo", 75, 0, 130}, - {"ivory",255, 255, 240}, - {"khaki",240, 230, 140}, - {"lavender",230, 230, 25}, - {"lavenderblush",255, 240, 245}, - {"mediumpurple",147, 112, 219}, - {"mediumseagreen", 60, 179, 113}, - {"mediumslateblue",123, 104, 238}, - {"mediumspringgreen", 0, 250, 154}, - {"mediumturquoise", 72, 209, 204}, - {"mediumvioletred",199, 21, 133}, - {"midnightblue", 25, 25, 112}, - {"mintcream",245, 255, 250}, - {"mistyrose",255, 228, 225}, - {"moccasin",255, 228, 181}, - {"navajowhite",255, 222, 173}, - {"navy", 0, 0, 128}, - {"oldlace",253, 245, 230}, - {"olive",128, 128, 0}, - {"olivedrab",107, 142, 35}, - {"orange",255, 165, 0}, - {"orangered",255, 69, 0}, - {"orchid",218, 112, 214}, - {"palegoldenrod",238, 232, 170}, - {"palegreen",152, 251, 152}, - {"paleturquoise",175, 238, 238}, - {"palevioletred",219, 112, 147}, - {"papayawhip",255, 239, 213}, - {"peachpuff",255, 218, 185}, - {"peru",205, 133, 63}, - {"pink",255, 192, 203}, - {"plum",221, 160, 221}, - {"powderblue",176, 224, 230}, - {"purple",128, 0, 128}, - {"red",255, 0, 0}, - {"rosybrown",188, 143, 143}, - {"royalblue", 65, 105, 225}, - {"saddlebrown",139, 69, 19}, - {"salmon",250, 128, 114}, - {"sandybrown",244, 164, 96}, - {"seagreen", 46, 139, 87}, - {"seashell",255, 245, 238}, - {"sienna",160, 82, 45}, - {"silver",192, 192, 192}, - {"skyblue",135, 206, 235}, - {"slateblue",106, 90, 205}, - {"slategray",112, 128, 144}, - {"slategrey",112, 128, 144}, - {"snow",255, 250, 250}, - {"springgreen", 0, 255, 127}, - {"steelblue", 70, 130, 180}, - {"tan",210, 180, 140}, - {"teal", 0, 128, 128}, - {"lawngreen",124, 252, 0}, - {"lemonchiffon",255, 250, 205}, - {"lightblue",173, 216, 230}, - {"lightcoral",240, 128, 128}, - {"lightcyan",224, 255, 255}, - {"lightgoldenrodyellow",250, 250, 210}, - {"lightgray",211, 211, 211}, - {"lightgreen",144, 238, 144}, - {"lightgrey",211, 211, 211}, - {"thistle",216, 191, 216}, - {"tomato",255, 99, 71}, - {"turquoise", 64, 224, 208}, - {"violet",238, 130, 238}, - {"wheat",245, 222, 179}, - {"white",255, 255, 255}, - {"whitesmoke",245, 245, 245}, - {"yellow",255, 255, 0}, - {"yellowgreen",154, 205, 50} - -}; /* Basic SVG datatype parsing functions */ @@ -747,17 +605,16 @@ static const struct sys_col { /* parses an color from a named color HTML or CSS 2 */ static void svg_parse_named_color(SVG_Color *col, char *attribute_content) { - u32 i, count; - count = sizeof(predefined_colors) / sizeof(struct predef_col); - for (i=0; ired = INT2FIX(predefined_colors[i].r) / 255; - col->green = INT2FIX(predefined_colors[i].g) / 255; - col->blue = INT2FIX(predefined_colors[i].b) / 255; - col->type = SVG_COLOR_RGBCOLOR; - return; - } + u32 i, count, val; + val = gf_color_parse(attribute_content); + if (val) { + col->red = INT2FIX((val>>16) & 0xFF) / 255; + col->green = INT2FIX((val>>8) & 0xFF) / 255; + col->blue = INT2FIX(val & 0xFF) / 255; + col->type = SVG_COLOR_RGBCOLOR; + return; } + count = sizeof(system_colors) / sizeof(struct sys_col); for (i=0; ifieldType != DOM_String_datatype && strlen(attribute_content)) { u32 i, len; - /*remove spaces at the begining*/ + /*remove spaces at the beginning*/ while (attribute_content[0] && (strchr("\r\n\t ", attribute_content[0]))) attribute_content++; @@ -3859,20 +3716,14 @@ static char *svg_dump_color(SVG_Color *col) } } } else { - u32 i, count = sizeof(predefined_colors) / sizeof(struct predef_col); - u32 r, g, b; + u8 r, g, b; + const char *name; r = FIX2INT(255*col->red); g = FIX2INT(255*col->green); b = FIX2INT(255*col->blue); - for (i=0; ijs_ctx, scenegraph, NULL); + gf_sg_js_dom_pre_destroy(svg_js->js_ctx, scenegraph, NULL); /*user-defined extensions*/ gf_sg_load_script_extensions(scenegraph, svg_js->js_ctx, svg_js->global, GF_TRUE); gf_sg_ecmascript_del(svg_js->js_ctx); @@ -2586,7 +2586,7 @@ static void svg_script_predestroy(GF_Node *n, void *eff, Bool is_destroy) svg_js->nb_scripts--; /*detach this script from our object cache*/ - dom_js_pre_destroy(svg_js->js_ctx, n->sgprivate->scenegraph, n); + gf_sg_js_dom_pre_destroy(svg_js->js_ctx, n->sgprivate->scenegraph, n); if (!svg_js->nb_scripts) { gf_svg_script_context_del(svg_js, n->sgprivate->scenegraph); @@ -2670,7 +2670,7 @@ static Bool svg_js_load_script(GF_Node *script, char *file) GF_SVGJS *svg_js; svg_js = script->sgprivate->scenegraph->svg_js; - jsf = gf_f64_open(file, "rb"); + jsf = gf_fopen(file, "rb"); if (!jsf) { GF_JSAPIParam par; GF_SceneGraph *scene = script->sgprivate->scenegraph; @@ -2680,18 +2680,18 @@ static Bool svg_js_load_script(GF_Node *script, char *file) abs_url = (char *) par.uri.url; if (abs_url) { - jsf = gf_f64_open(abs_url, "rb"); + jsf = gf_fopen(abs_url, "rb"); gf_free(abs_url); } } if (!jsf) return GF_FALSE; - gf_f64_seek(jsf, 0, SEEK_END); - fsize = (u32) gf_f64_tell(jsf); - gf_f64_seek(jsf, 0, SEEK_SET); + gf_fseek(jsf, 0, SEEK_END); + fsize = (u32) gf_ftell(jsf); + gf_fseek(jsf, 0, SEEK_SET); jsscript = (char *)gf_malloc(sizeof(char)*(size_t)(fsize+1)); fsize = (u32) fread(jsscript, sizeof(char), (size_t)fsize, jsf); - fclose(jsf); + gf_fclose(jsf); jsscript[fsize] = 0; /*for handler, only load code*/ diff --git a/src/scenegraph/vrml_proto.c b/src/scenegraph/vrml_proto.c index 9753601..3ea8a78 100644 --- a/src/scenegraph/vrml_proto.c +++ b/src/scenegraph/vrml_proto.c @@ -312,6 +312,7 @@ GF_Err gf_sg_proto_get_field(GF_Proto *proto, GF_Node *node, GF_FieldInfo *info) info->fieldType = field->FieldType; info->eventType = field->EventType; + info->on_event_in = field->on_event_in; /*SF/MF nodes need pointers to field object - cf gf_sg_proto_create_node*/ if (gf_sg_vrml_get_sf_type(field->FieldType) == GF_SG_VRML_SFNODE) { info->far_ptr = &field->field_pointer; @@ -404,12 +405,10 @@ GF_Node *gf_vrml_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *clon count = gf_node_get_field_count(orig); is_script = 0; - if ((orig->sgprivate->tag==TAG_MPEG4_Script) + if (orig->sgprivate->tag==TAG_MPEG4_Script) is_script = 1; #ifndef GPAC_DISABLE_X3D - || (orig->sgprivate->tag==TAG_X3D_Script) + else if (orig->sgprivate->tag==TAG_X3D_Script) is_script = 1; #endif - ) - is_script = 1; if (is_script) gf_sg_script_prepare_clone(node, orig); @@ -691,12 +690,12 @@ void gf_sg_proto_instanciate(GF_ProtoInstance *proto_node) if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue; } - if ((route->ToNode->sgprivate->tag==TAG_MPEG4_Script) + if (route->ToNode->sgprivate->tag==TAG_MPEG4_Script) + gf_sg_route_activate(route); #ifndef GPAC_DISABLE_X3D - || (route->ToNode->sgprivate->tag==TAG_X3D_Script) + else if (route->ToNode->sgprivate->tag==TAG_X3D_Script) + gf_sg_route_activate(route); #endif - ) - gf_sg_route_activate(route); } #if 0 @@ -1310,4 +1309,23 @@ Bool gf_node_is_proto_root(GF_Node *node) return 0; } + +GF_EXPORT +GF_Err gf_node_set_proto_eventin_handler(GF_Node *node, u32 fieldIndex, void (*event_in_cbk)(GF_Node *pThis, struct _route *route) ) +{ + GF_ProtoInstance *inst; + GF_ProtoField *field; + if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM; + + inst = (GF_ProtoInstance *) node; + field = (GF_ProtoField*)gf_list_get(inst->fields, fieldIndex); + if (!field) return GF_BAD_PARAM; + + if (field->EventType!=GF_SG_EVENT_IN) return GF_BAD_PARAM; + field->on_event_in = event_in_cbk; + return GF_OK; +} + + + #endif /*GPAC_DISABLE_VRML*/ diff --git a/src/scenegraph/vrml_route.c b/src/scenegraph/vrml_route.c index 98938e1..dcc2cb8 100644 --- a/src/scenegraph/vrml_route.c +++ b/src/scenegraph/vrml_route.c @@ -349,6 +349,11 @@ Bool gf_sg_route_activate(GF_Route *r) break; } + //don't notify dest change for generic function since the dest is not a node + if (r->ToField.fieldType==GF_SG_VRML_GENERIC_FUNCTION) { + ret = 0; + } + #ifndef GPAC_DISABLE_LOG if (gf_log_tool_level_on(GF_LOG_INTERACT, GF_LOG_DEBUG)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[VRML Route] field copy/casted\n")); @@ -450,5 +455,47 @@ void gf_node_event_out_str(GF_Node *node, const char *eventName) } } +typedef struct +{ + GF_Route r; + void ( *route_callback) (void *param, GF_FieldInfo *from_field); +} GF_RouteToFunction; + +static void on_route_to_function(GF_Node *node, GF_Route *r) +{ + GF_RouteToFunction *rf = (GF_RouteToFunction *)r; + rf->route_callback(r->ToNode, &r->FromField); +} + +GF_EXPORT +void gf_sg_route_new_to_callback(GF_SceneGraph *sg, GF_Node *fromNode, u32 fromField, void *cbk, void ( *route_callback) (void *param, GF_FieldInfo *from_field) ) +{ + GF_Route *r; + GF_RouteToFunction *rf; + GF_SAFEALLOC(rf, GF_RouteToFunction); + if (!rf) return; + rf->route_callback = route_callback; + + r = (GF_Route *)rf; + r->FromNode = fromNode; + r->FromField.fieldIndex = fromField; + gf_node_get_field(r->FromNode, fromField, &r->FromField); + + r->ToNode = (GF_Node *) cbk; + r->ToField.fieldType = GF_SG_VRML_GENERIC_FUNCTION; + r->ToField.on_event_in = on_route_to_function; + r->ToField.eventType = GF_SG_EVENT_IN; + r->ToField.far_ptr = NULL; + + r->is_setup = 1; + r->graph = sg; + + if (!fromNode->sgprivate->interact) GF_SAFEALLOC(fromNode->sgprivate->interact, struct _node_interactive_ext); + if (!fromNode->sgprivate->interact->routes) fromNode->sgprivate->interact->routes = gf_list_new(); + gf_list_add(fromNode->sgprivate->interact->routes, r); + gf_list_add(fromNode->sgprivate->scenegraph->Routes, r); +} + + #endif /*GPAC_DISABLE_VRML*/ diff --git a/src/scenegraph/vrml_smjs.c b/src/scenegraph/vrml_smjs.c index 4197871..3a87f20 100644 --- a/src/scenegraph/vrml_smjs.c +++ b/src/scenegraph/vrml_smjs.c @@ -145,7 +145,7 @@ typedef struct JSObject *obj; jsval fun; -} GF_RouteToFunction; +} GF_RouteToScript; #define _ScriptMessage(_c, _msg) { \ @@ -203,6 +203,8 @@ typedef struct /*extensions are loaded for the lifetime of the runtime NOT of the context - this avoids nasty crashes with multiple contexts in SpiderMonkey (root'ing bug with InitStandardClasses)*/ GF_List *extensions; + + GF_List *allocated_contexts; } GF_JSRuntime; static GF_JSRuntime *js_rt = NULL; @@ -341,6 +343,7 @@ JSContext *gf_sg_ecmascript_new(GF_SceneGraph *sg) } GF_SAFEALLOC(js_rt, GF_JSRuntime); js_rt->js_runtime = js_runtime; + js_rt->allocated_contexts = gf_list_new(); js_rt->mx = gf_mx_new("JavaScript"); GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[ECMAScript] ECMAScript runtime allocated %p\n", js_runtime)); gf_sg_load_script_modules(sg); @@ -363,6 +366,8 @@ JSContext *gf_sg_ecmascript_new(GF_SceneGraph *sg) JS_ClearRuntimeThread(js_rt->js_runtime); } #endif + + gf_list_add(js_rt->allocated_contexts, ctx); gf_mx_v(js_rt->mx); return ctx; @@ -378,6 +383,9 @@ void gf_sg_ecmascript_del(JSContext *ctx) #endif #endif + gf_sg_js_call_gc(ctx); + + gf_list_del_item(js_rt->allocated_contexts, ctx); JS_DestroyContext(ctx); if (js_rt) { js_rt->nb_inst --; @@ -385,6 +393,7 @@ void gf_sg_ecmascript_del(JSContext *ctx) JS_DestroyRuntime(js_rt->js_runtime); JS_ShutDown(); gf_sg_unload_script_modules(); + gf_list_del(js_rt->allocated_contexts); gf_mx_del(js_rt->mx); gf_free(js_rt); js_rt = NULL; @@ -430,14 +439,8 @@ JSBool gf_sg_js_has_instance(JSContext *c, JSObject *obj, jsval val, JSBool *vp) GF_Node *dom_get_element(JSContext *c, JSObject *obj); #endif -#ifndef GPAC_DISABLE_VRML - -/*MPEG4 & X3D tags (for node tables & script handling)*/ -#include -#include - -void gf_sg_script_to_node_field(struct JSContext *c, jsval v, GF_FieldInfo *field, GF_Node *owner, GF_JSField *parent); +JSBool gf_sg_script_to_node_field(struct JSContext *c, jsval v, GF_FieldInfo *field, GF_Node *owner, GF_JSField *parent); jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_Node *parent, Bool force_evaluate); static void JSScript_NodeModified(GF_SceneGraph *sg, GF_Node *node, GF_FieldInfo *info, GF_Node *script); @@ -468,6 +471,12 @@ void do_js_gc(JSContext *c, GF_Node *node) } +#ifndef GPAC_DISABLE_VRML + +/*MPEG4 & X3D tags (for node tables & script handling)*/ +#include +#include + void SFColor_fromHSV(SFColor *col) { Fixed f, q, t, p, hue, sat, val; @@ -569,17 +578,36 @@ static GFINLINE GF_ScriptPriv *JS_GetScriptStack(JSContext *c) static void script_error(JSContext *c, const char *msg, JSErrorReport *jserr) { - GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JavaScript] Error: %s - line %d (%s)", msg, jserr->lineno, jserr->linebuf)); + if (jserr->linebuf) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JavaScript] Error: %s - line %d (%s) - file %s\n", msg, jserr->lineno, jserr->linebuf, jserr->filename)); + } else if (jserr->filename) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JavaScript] Error: %s - line %d - file %s\n", msg, jserr->lineno, jserr->filename)); + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JavaScript] Error: %s - line %d\n", msg, jserr->lineno)); + } } static JSBool SMJS_FUNCTION(JSPrint) { SMJS_ARGS + if (!argc) return JS_FALSE; + if (JSVAL_IS_STRING(argv[0])) { char *str = SMJS_CHARS(c, argv[0]); _ScriptMessage(c, str); SMJS_FREE(c, str); } + if (JSVAL_IS_INT(argv[0]) && (argc>1) && JSVAL_IS_STRING(argv[1]) ) { + u32 level = JSVAL_TO_INT(argv[0]); + char *str = SMJS_CHARS(c, argv[1]); + if (level > GF_LOG_DEBUG) level = GF_LOG_DEBUG; + if (str[0] == '[') { + GF_LOG(level, GF_LOG_CONSOLE, ("%s\n", str)); + } else { + GF_LOG(level, GF_LOG_CONSOLE, ("[JS] %s\n", str)); + } + SMJS_FREE(c, str); + } return JS_TRUE; } @@ -692,7 +720,7 @@ static JSBool SMJS_FUNCTION(loadScript) char *url; GF_Node *node = JS_GetContextPrivate(c); SMJS_ARGS - jsval aval; + jsval aval; if (!argc || !JSVAL_IS_STRING(argv[0])) return JS_TRUE; if ((argc>1) && JSVAL_IS_BOOLEAN(argv[1])) no_complain = (JSVAL_TO_BOOLEAN(argv[1])==JS_TRUE) ? 1 : 0; @@ -700,7 +728,7 @@ static JSBool SMJS_FUNCTION(loadScript) url = SMJS_CHARS(c, argv[0]); if (url) { JSScriptFromFile(node, url, no_complain, &aval); - SMJS_SET_RVAL(aval); + SMJS_SET_RVAL(aval); } SMJS_FREE(c, url); return JS_TRUE; @@ -788,18 +816,18 @@ static void on_route_to_object(GF_Node *node, GF_Route *_r) GF_FieldInfo t_info; GF_ScriptPriv *priv; JSObject *obj; - GF_RouteToFunction *r = (GF_RouteToFunction *)_r; + GF_RouteToScript *r = (GF_RouteToScript *)_r; if (!node) return; priv = gf_node_get_private(node); if (!priv) return; if (!r->FromNode) { if (r->obj) { -// gf_js_remove_root(priv->js_ctx, &r->obj); +// gf_js_remove_root(priv->js_ctx, &r->obj, GF_JSGC_OBJECT); r->obj=NULL; } if ( ! JSVAL_IS_VOID(r->fun)) { -// gf_js_remove_root(priv->js_ctx, &r->fun); +// gf_js_remove_root(priv->js_ctx, &r->fun, GF_JSGC_OBJECT); r->fun=JSVAL_NULL; } return; @@ -914,12 +942,12 @@ static JSBool SMJS_FUNCTION(addRoute) else { u32 i = 0; const char *fun_name; - GF_RouteToFunction *r = NULL; + GF_RouteToScript *r = NULL; if (!JSVAL_IS_OBJECT(argv[3]) || !JS_ObjectIsFunction(c, JSVAL_TO_OBJECT(argv[3])) ) return JS_FALSE; fun_name = JS_GetFunctionName( JS_ValueToFunction(c, argv[3] ) ); if (fun_name && n1->sgprivate->interact && n1->sgprivate->interact->routes ) { - while ( (r = (GF_RouteToFunction*)gf_list_enum(n1->sgprivate->interact->routes, &i) )) { + while ( (r = (GF_RouteToScript*)gf_list_enum(n1->sgprivate->interact->routes, &i) )) { if ( (r->FromNode == n1) && (r->FromField.fieldIndex == f_id1) && (r->ToNode == (GF_Node*)JS_GetScript(c)) @@ -930,7 +958,7 @@ static JSBool SMJS_FUNCTION(addRoute) } if ( !r ) { - GF_SAFEALLOC(r, GF_RouteToFunction) + GF_SAFEALLOC(r, GF_RouteToScript) if (!r) return JS_FALSE; r->FromNode = n1; r->FromField.fieldIndex = f_id1; @@ -944,10 +972,10 @@ static JSBool SMJS_FUNCTION(addRoute) r->ToField.name = fun_name; r->obj = JSVAL_TO_OBJECT( argv[2] ) ; - // gf_js_add_root(c, & r->obj); +// gf_js_add_root(c, & r->obj, GF_JSGC_OBJECT); r->fun = argv[3]; - // gf_js_add_root(c, &r->fun); +// gf_js_add_root(c, &r->fun, GF_JSGC_OBJECT); r->is_setup = 1; r->graph = n1->sgprivate->scenegraph; @@ -975,7 +1003,7 @@ static JSBool SMJS_FUNCTION(deleteRoute) SMJS_ARGS if (argc!=4) return JS_FALSE; - if (!JSVAL_IS_OBJECT(argv[0]) || !GF_JS_InstanceOf(c, JSVAL_TO_OBJECT(argv[0]), &js_rt->SFNodeClass, NULL) ) return JS_FALSE; + if (!JSVAL_IS_OBJECT(argv[0]) || JSVAL_IS_NULL(argv[0]) || !GF_JS_InstanceOf(c, JSVAL_TO_OBJECT(argv[0]), &js_rt->SFNodeClass, NULL) ) return JS_FALSE; if (JSVAL_IS_STRING(argv[1]) && JSVAL_IS_NULL(argv[2]) && JSVAL_IS_NULL(argv[3])) { ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(argv[0])); @@ -1140,58 +1168,6 @@ static JSBool SMJS_FUNCTION(createVrmlFromString) #endif } -static JSBool SMJS_FUNCTION(getOption) -{ - JSString *s; - GF_JSAPIParam par; - GF_Node *sc_node = JS_GetContextPrivate(c); - Bool res; - SMJS_ARGS - if (argc < 2) return JS_FALSE; - - if (!JSVAL_IS_STRING(argv[0])) return JS_FALSE; - if (!JSVAL_IS_STRING(argv[1])) return JS_FALSE; - - par.gpac_cfg.section = SMJS_CHARS(c, argv[0]); - par.gpac_cfg.key = SMJS_CHARS(c, argv[1]); - par.gpac_cfg.key_val = NULL; - - res = ScriptAction(c, NULL, GF_JSAPI_OP_GET_OPT, sc_node->sgprivate->scenegraph->RootNode, &par); - SMJS_FREE(c, (char *)par.gpac_cfg.section); - SMJS_FREE(c, (char *)par.gpac_cfg.key); - if (!res) return JS_FALSE; - - s = JS_NewStringCopyZ(c, par.gpac_cfg.key_val ? (const char *)par.gpac_cfg.key_val : ""); - if (!s) return JS_FALSE; - SMJS_SET_RVAL( STRING_TO_JSVAL(s) ); - return JS_TRUE; -} - -static JSBool SMJS_FUNCTION(setOption) -{ - GF_JSAPIParam par; - GF_Node *sc_node = JS_GetContextPrivate(c); - Bool res; - SMJS_ARGS - if (argc < 3) return JS_FALSE; - - if (!JSVAL_IS_STRING(argv[0])) return JS_FALSE; - if (!JSVAL_IS_STRING(argv[1])) return JS_FALSE; - if (!JSVAL_IS_STRING(argv[2])) return JS_FALSE; - - par.gpac_cfg.section = SMJS_CHARS(c, argv[0]); - par.gpac_cfg.key = SMJS_CHARS(c, argv[1]); - par.gpac_cfg.key_val = SMJS_CHARS(c, argv[2]); - - res = ScriptAction(c, NULL, GF_JSAPI_OP_SET_OPT, sc_node->sgprivate->scenegraph->RootNode, &par); - SMJS_FREE(c, (char *)par.gpac_cfg.section); - SMJS_FREE(c, (char *)par.gpac_cfg.key); - SMJS_FREE(c, (char *)par.gpac_cfg.key_val); - - if (!res) return JS_FALSE; - return JS_TRUE; -} - void gf_node_event_out_proto(GF_Node *node, u32 FieldIndex); void Script_FieldChanged(JSContext *c, GF_Node *parent, GF_JSField *parent_owner, GF_FieldInfo *field) @@ -1377,7 +1353,11 @@ static void JS_ObjectDestroyed(JSContext *c, JSObject *obj, GF_JSField *ptr, Boo */ if (ptr->obj && is_js_call) { GF_ScriptPriv *priv; - if (ptr->js_ctx) c = ptr->js_ctx; + if (ptr->js_ctx) { + if (gf_list_find(js_rt->allocated_contexts, ptr->js_ctx) < 0) + return; + c = ptr->js_ctx; + } priv = JS_GetScriptStack(c); gf_list_del_item(priv->js_cache, obj); } @@ -1420,7 +1400,7 @@ static JSBool SMJS_FUNCTION(field_toString) break; case GF_SG_VRML_MFFLOAT: case GF_SG_VRML_MFTIME: - JS_ValueToNumber(c, item, &d); + SMJS_GET_NUMBER(item, d); sprintf(temp, "%g", d); strcat(str, temp); break; @@ -1570,7 +1550,8 @@ GF_FieldInfo info; GF_JSField *ptr; GF_ScriptPriv *priv; -if (! GF_JS_InstanceOf(c, obj, &js_rt->SFNodeClass, NULL) ) return JS_FALSE; +if (! GF_JS_InstanceOf(c, obj, &js_rt->SFNodeClass, NULL) ) + return JS_FALSE; ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); assert(ptr->field.fieldType==GF_SG_VRML_SFNODE); n = * ((GF_Node **)ptr->field.far_ptr); @@ -1899,8 +1880,9 @@ static JSBool SMJS_FUNCTION(SFVec2fConstructor) jsdouble x = 0.0, y = 0.0; SMJS_ARGS SMJS_OBJ_CONSTRUCTOR(&js_rt->SFVec2fClass) - if (argc > 0) JS_ValueToNumber(c, argv[0], &x); - if (argc > 1) JS_ValueToNumber(c, argv[1], &y); + if (argc > 0) SMJS_GET_NUMBER(argv[0], x); + if (argc > 1) SMJS_GET_NUMBER(argv[1], y); + SFVec2f_Create(c, obj, FLT2FIX( x), FLT2FIX( y)); return JS_TRUE; } @@ -1941,7 +1923,8 @@ if (SMJS_ID_IS_INT(id)) { GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec2f\n")); return JS_FALSE; } - JS_ValueToNumber(c, *vp, &d); + + SMJS_GET_NUMBER(*vp, d); switch (SMJS_ID_TO_INT(id)) { case 0: @@ -2017,7 +2000,7 @@ static JSBool SMJS_FUNCTION(vec2f_multiply) if (argc<=0) return JS_FALSE; v1 = ((GF_JSField *) SMJS_GET_PRIVATE(c, obj))->field.far_ptr; pNew = JS_NewObject(c, &js_rt->SFVec2fClass._class, 0, SMJS_GET_PARENT(c, obj)); - JS_ValueToNumber(c, argv[0], &d ); + SMJS_GET_NUMBER(argv[0], d ); v = FLT2FIX( d); SFVec2f_Create(c, pNew, gf_mulfix(v1->x , v), gf_mulfix(v1->y, v) ); SMJS_SET_RVAL( OBJECT_TO_JSVAL(pNew) ); @@ -2034,7 +2017,7 @@ static JSBool SMJS_FUNCTION(vec2f_divide) if (argc<=0) return JS_FALSE; v1 = ((GF_JSField *) SMJS_GET_PRIVATE(c, obj))->field.far_ptr; pNew = JS_NewObject(c, &js_rt->SFVec2fClass._class, 0, SMJS_GET_PARENT(c, obj)); - JS_ValueToNumber(c, argv[0], &d ); + SMJS_GET_NUMBER(argv[0], d ); v = FLT2FIX(d); SFVec2f_Create(c, pNew, gf_divfix(v1->x, v), gf_divfix(v1->y, v)); SMJS_SET_RVAL( OBJECT_TO_JSVAL(pNew) ); @@ -2098,9 +2081,9 @@ static JSBool SMJS_FUNCTION(SFVec3fConstructor) SMJS_ARGS jsdouble x = 0.0, y = 0.0, z = 0.0; SMJS_OBJ_CONSTRUCTOR(&js_rt->SFVec3fClass) - if (argc > 0) JS_ValueToNumber(c, argv[0], &x); - if (argc > 1) JS_ValueToNumber(c, argv[1], &y); - if (argc > 2) JS_ValueToNumber(c, argv[2], &z); + if (argc > 0) SMJS_GET_NUMBER(argv[0], x); + if (argc > 1) SMJS_GET_NUMBER(argv[1], y); + if (argc > 2) SMJS_GET_NUMBER(argv[2], z); SFVec3f_Create(c, obj, FLT2FIX( x), FLT2FIX( y), FLT2FIX( z)); return JS_TRUE; } @@ -2137,12 +2120,15 @@ if (!ptr) { return JS_TRUE; } - if (! JSVAL_IS_NUMBER(*vp)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec3f\n")); - return JS_FALSE; - } +if (! JSVAL_IS_NUMBER(*vp)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec3f\n")); + return JS_FALSE; +} + +if (SMJS_ID_IS_INT(id) && SMJS_ID_TO_INT(id) >= 0 && SMJS_ID_TO_INT(id) < 3) { + + SMJS_GET_NUMBER(*vp, d); -if (SMJS_ID_IS_INT(id) && SMJS_ID_TO_INT(id) >= 0 && SMJS_ID_TO_INT(id) < 3 && JS_ValueToNumber(c, *vp, &d)) { switch (SMJS_ID_TO_INT(id)) { case 0: v = FLT2FIX( d); @@ -2222,7 +2208,7 @@ static JSBool SMJS_FUNCTION(vec3f_multiply) v1 = ((GF_JSField *) SMJS_GET_PRIVATE(c, obj))->field.far_ptr; pNew = JS_NewObject(c, &js_rt->SFVec3fClass._class, 0, SMJS_GET_PARENT(c, obj)); - JS_ValueToNumber(c, argv[0], &d ); + SMJS_GET_NUMBER(argv[0], d ); v = FLT2FIX(d); SFVec3f_Create(c, pNew, gf_mulfix(v1->x, v), gf_mulfix(v1->y, v), gf_mulfix(v1->z, v) ); SMJS_SET_RVAL( OBJECT_TO_JSVAL(pNew) ); @@ -2239,7 +2225,7 @@ static JSBool SMJS_FUNCTION(vec3f_divide) if (argc<=0) return JS_FALSE; v1 = ((GF_JSField *) SMJS_GET_PRIVATE(c, obj))->field.far_ptr; pNew = JS_NewObject(c, &js_rt->SFVec3fClass._class, 0, SMJS_GET_PARENT(c, obj)); - JS_ValueToNumber(c, argv[0], &d ); + SMJS_GET_NUMBER(argv[0], d ); v = FLT2FIX(d); SFVec3f_Create(c, pNew, gf_divfix(v1->x, v), gf_divfix(v1->y, v), gf_divfix(v1->z, v)); SMJS_SET_RVAL( OBJECT_TO_JSVAL(pNew) ); @@ -2330,10 +2316,10 @@ static JSBool SMJS_FUNCTION(SFRotationConstructor) return JS_TRUE; } if ((argc>0) && JSVAL_IS_NUMBER(argv[0])) { - if (argc > 0) JS_ValueToNumber(c, argv[0], &x); - if (argc > 1) JS_ValueToNumber(c, argv[1], &y); - if (argc > 2) JS_ValueToNumber(c, argv[2], &z); - if (argc > 3) JS_ValueToNumber(c, argv[3], &a); + if (argc > 0) SMJS_GET_NUMBER(argv[0], x); + if (argc > 1) SMJS_GET_NUMBER(argv[1], y); + if (argc > 2) SMJS_GET_NUMBER(argv[2], z); + if (argc > 3) SMJS_GET_NUMBER(argv[3], a); SFRotation_Create(c, obj, FLT2FIX(x), FLT2FIX(y), FLT2FIX(z), FLT2FIX(a)); return JS_TRUE; } @@ -2343,7 +2329,7 @@ static JSBool SMJS_FUNCTION(SFRotationConstructor) if (! GF_JS_InstanceOf(c, an_obj, &js_rt->SFVec3fClass, NULL)) return JS_FALSE; v1 = * (SFVec3f *) ((GF_JSField *) SMJS_GET_PRIVATE(c, an_obj))->field.far_ptr; if (JSVAL_IS_DOUBLE(argv[1])) { - JS_ValueToNumber(c, argv[1], &a); + SMJS_GET_NUMBER(argv[1], a); SFRotation_Create(c, obj, v1.x, v1.y, v1.z, FLT2FIX(a)); return JS_TRUE; } @@ -2399,11 +2385,13 @@ if (!ptr) { return JS_TRUE; } - if (! JSVAL_IS_NUMBER(*vp)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec3f\n")); - return JS_FALSE; - } -if (SMJS_ID_IS_INT(id) && SMJS_ID_TO_INT(id) >= 0 && SMJS_ID_TO_INT(id) < 4 && JS_ValueToNumber(c, *vp, &d)) { +if (! JSVAL_IS_NUMBER(*vp)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec3f\n")); + return JS_FALSE; +} +if (SMJS_ID_IS_INT(id) && SMJS_ID_TO_INT(id) >= 0 && SMJS_ID_TO_INT(id) < 4 ) { + SMJS_GET_NUMBER(*vp, d); + switch (SMJS_ID_TO_INT(id)) { case 0: v = FLT2FIX(d); @@ -2539,7 +2527,7 @@ static JSBool SMJS_FUNCTION(rot_slerp) v1 = *(SFRotation *) ((GF_JSField *) SMJS_GET_PRIVATE(c, obj))->field.far_ptr; v2 = *(SFRotation *) ((GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(argv[0])))->field.far_ptr; - JS_ValueToNumber(c, argv[1], &d ); + SMJS_GET_NUMBER(argv[1], d ); q1 = gf_quat_from_rotation(v1); q2 = gf_quat_from_rotation(v2); q1 = gf_quat_slerp(q1, q2, FLT2FIX( d)); @@ -2570,9 +2558,9 @@ static JSBool SMJS_FUNCTION(SFColorConstructor) SMJS_ARGS jsdouble r = 0.0, g = 0.0, b = 0.0; SMJS_OBJ_CONSTRUCTOR(&js_rt->SFColorClass) - if (argc > 0) JS_ValueToNumber(c, argv[0], &r); - if (argc > 1) JS_ValueToNumber(c, argv[1], &g); - if (argc > 2) JS_ValueToNumber(c, argv[2], &b); + if (argc > 0) SMJS_GET_NUMBER(argv[0], r); + if (argc > 1) SMJS_GET_NUMBER(argv[1], g); + if (argc > 2) SMJS_GET_NUMBER(argv[2], b); SFColor_Create(c, obj, FLT2FIX( r), FLT2FIX( g), FLT2FIX( b)); return JS_TRUE; } @@ -2609,11 +2597,12 @@ if (!ptr) { return JS_TRUE; } - if (! JSVAL_IS_NUMBER(*vp)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec3f\n")); - return JS_FALSE; - } -if (SMJS_ID_IS_INT(id) && SMJS_ID_TO_INT(id) >= 0 && SMJS_ID_TO_INT(id) < 3 && JS_ValueToNumber(c, *vp, &d)) { +if (! JSVAL_IS_NUMBER(*vp)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML JS] Value is not a number while assigning SFVec3f\n")); + return JS_FALSE; +} +if (SMJS_ID_IS_INT(id) && SMJS_ID_TO_INT(id) >= 0 && SMJS_ID_TO_INT(id) < 3 ) { + SMJS_GET_NUMBER(*vp, d); switch (SMJS_ID_TO_INT(id)) { case 0: v = FLT2FIX(d); @@ -2647,9 +2636,9 @@ static JSBool SMJS_FUNCTION(color_setHSV) GF_JSField *ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); if (argc != 3) return JS_FALSE; v1 = ((GF_JSField *) SMJS_GET_PRIVATE(c, obj))->field.far_ptr; - JS_ValueToNumber( c, argv[0], &h); - JS_ValueToNumber( c, argv[1], &s); - JS_ValueToNumber( c, argv[2], &v); + SMJS_GET_NUMBER(argv[0], h); + SMJS_GET_NUMBER(argv[1], s); + SMJS_GET_NUMBER(argv[2], v); hsv.red = FLT2FIX( h); hsv.green = FLT2FIX( s); hsv.blue = FLT2FIX( v); @@ -2682,11 +2671,11 @@ static void setup_js_array(JSContext *c, JSObject *obj, GF_JSField *ptr, uintN a ptr->obj = obj; ptr->js_list = JS_NewArrayObject(c, (jsint) argc, argv); -/* - gf_js_add_root(c, &ptr->js_list, GF_JSGC_OBJECT); - ptr->is_rooted = 1; - gf_list_add(priv->js_cache, obj); -*/ + /* + gf_js_add_root(c, &ptr->js_list, GF_JSGC_OBJECT); + ptr->is_rooted = 1; + gf_list_add(priv->js_cache, obj); + */ } #define MFARRAY_CONSTRUCTOR(__classp, _fieldType) \ @@ -2782,300 +2771,303 @@ return JS_TRUE; //this could be overloaded for each MF type... static SMJS_FUNC_PROP_SET(array_setElement) - u32 ind; - jsuint len; - jsdouble d; - GF_JSField *from; - JSBool ret; - GF_JSClass *the_sf_class = NULL; - JSString *str; - char *str_val; - void *sf_slot; - Bool is_append = 0; - GF_JSField *ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); - ind = SMJS_ID_TO_INT(id); +u32 ind; +jsuint len; +jsdouble d; +GF_JSField *from; +JSBool ret; +GF_JSClass *the_sf_class = NULL; +JSString *str; +char *str_val; +void *sf_slot; +Bool is_append = 0; +GF_JSField *ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); +ind = SMJS_ID_TO_INT(id); - ret = JS_GetArrayLength(c, ptr->js_list, &len); - if (ret==JS_FALSE) return JS_FALSE; +ret = JS_GetArrayLength(c, ptr->js_list, &len); +if (ret==JS_FALSE) return JS_FALSE; - if (gf_sg_vrml_is_sf_field(ptr->field.fieldType)) return JS_FALSE; +if (!ptr->js_list && gf_sg_vrml_is_sf_field(ptr->field.fieldType)) return JS_FALSE; - switch (ptr->field.fieldType) { - case GF_SG_VRML_MFVEC2F: - the_sf_class = &js_rt->SFVec2fClass; - break; - case GF_SG_VRML_MFVEC3F: - the_sf_class = &js_rt->SFVec3fClass; - break; - case GF_SG_VRML_MFCOLOR: - the_sf_class = &js_rt->SFColorClass; - break; - case GF_SG_VRML_MFROTATION: - the_sf_class = &js_rt->SFRotationClass; - break; - } - /*dynamic expend*/ - if (ind>=len) { - is_append = 1; - ret = JS_SetArrayLength(c, ptr->js_list, len+1); - if (ret==JS_FALSE) return JS_FALSE; - while (lenfield.fieldType) { - case GF_SG_VRML_MFBOOL: - a_val = BOOLEAN_TO_JSVAL(0); - break; - case GF_SG_VRML_MFINT32: - a_val = INT_TO_JSVAL(0); - break; - case GF_SG_VRML_MFFLOAT: - case GF_SG_VRML_MFTIME: - a_val = JS_MAKE_DOUBLE(c, 0); - break; - case GF_SG_VRML_MFSTRING: - case GF_SG_VRML_MFURL: - a_val = STRING_TO_JSVAL( JS_NewStringCopyZ(c, "") ); - break; - case GF_SG_VRML_MFVEC2F: - case GF_SG_VRML_MFVEC3F: - case GF_SG_VRML_MFCOLOR: - case GF_SG_VRML_MFROTATION: - a_val = OBJECT_TO_JSVAL( SMJS_CONSTRUCT_OBJECT(c, the_sf_class, obj) ); - break; - default: - a_val = INT_TO_JSVAL(0); - break; - } - - if (ptr->field.fieldType!=GF_SG_VRML_MFNODE) { - gf_sg_vrml_mf_insert(ptr->field.far_ptr, ptr->field.fieldType, &sf_slot, len); - JS_SetElement(c, ptr->js_list, len, &a_val); - } - len++; +switch (ptr->field.fieldType) { +case GF_SG_VRML_MFVEC2F: + the_sf_class = &js_rt->SFVec2fClass; + break; +case GF_SG_VRML_MFVEC3F: + the_sf_class = &js_rt->SFVec3fClass; + break; +case GF_SG_VRML_MFCOLOR: + the_sf_class = &js_rt->SFColorClass; + break; +case GF_SG_VRML_MFROTATION: + the_sf_class = &js_rt->SFRotationClass; + break; +} +/*dynamic expend*/ +if (ind>=len) { + is_append = 1; + ret = JS_SetArrayLength(c, ptr->js_list, len+1); + if (ret==JS_FALSE) return JS_FALSE; + while (lenfield.fieldType) { + case GF_SG_VRML_MFBOOL: + a_val = BOOLEAN_TO_JSVAL(0); + break; + case GF_SG_VRML_MFINT32: + a_val = INT_TO_JSVAL(0); + break; + case GF_SG_VRML_MFFLOAT: + case GF_SG_VRML_MFTIME: + a_val = JS_MAKE_DOUBLE(c, 0); + break; + case GF_SG_VRML_MFSTRING: + case GF_SG_VRML_MFURL: + a_val = STRING_TO_JSVAL( JS_NewStringCopyZ(c, "") ); + break; + case GF_SG_VRML_MFVEC2F: + case GF_SG_VRML_MFVEC3F: + case GF_SG_VRML_MFCOLOR: + case GF_SG_VRML_MFROTATION: + a_val = OBJECT_TO_JSVAL( SMJS_CONSTRUCT_OBJECT(c, the_sf_class, obj) ); + break; + default: + a_val = INT_TO_JSVAL(0); + break; } - if (ptr->field.far_ptr && (ptr->field.fieldType!=GF_SG_VRML_MFNODE)) - gf_sg_vrml_mf_insert(ptr->field.far_ptr, ptr->field.fieldType, &sf_slot, ind); - } - if (ptr->field.far_ptr && (ptr->field.fieldType!=GF_SG_VRML_MFNODE)) { - u32 items = ((GenMFField *)ptr->field.far_ptr)->count; - while (ind>=items) { - gf_sg_vrml_mf_insert(ptr->field.far_ptr, ptr->field.fieldType, &sf_slot, ind); - items++; + if (ptr->field.fieldType!=GF_SG_VRML_MFNODE) { + gf_sg_vrml_mf_insert(ptr->field.far_ptr, ptr->field.fieldType, &sf_slot, len); + JS_SetElement(c, ptr->js_list, len, &a_val); } + len++; } + if (ptr->field.far_ptr && (ptr->field.fieldType!=GF_SG_VRML_MFNODE)) + gf_sg_vrml_mf_insert(ptr->field.far_ptr, ptr->field.fieldType, &sf_slot, ind); +} - /*assign object*/ - if (ptr->field.fieldType==GF_SG_VRML_MFNODE) { - JSObject *o; - if (JSVAL_IS_VOID(*vp)) return JS_FALSE; - if (JSVAL_IS_NULL(*vp) ) return JS_FALSE; - o = JSVAL_TO_OBJECT(*vp); - if (!GF_JS_InstanceOf(c, o, &js_rt->SFNodeClass, NULL) ) return JS_FALSE; - } else if (the_sf_class) { - if (JSVAL_IS_VOID(*vp)) return JS_FALSE; - if (!GF_JS_InstanceOf(c, JSVAL_TO_OBJECT(*vp), the_sf_class, NULL) ) return JS_FALSE; - } else if (ptr->field.fieldType==GF_SG_VRML_MFBOOL) { - if (!JSVAL_IS_BOOLEAN(*vp)) return JS_FALSE; - } else if (ptr->field.fieldType==GF_SG_VRML_MFINT32) { - if (!JSVAL_IS_INT(*vp)) return JS_FALSE; - } else if (ptr->field.fieldType==GF_SG_VRML_MFFLOAT) { - if (!JSVAL_IS_NUMBER(*vp)) return JS_FALSE; - } else if (ptr->field.fieldType==GF_SG_VRML_MFTIME) { - if (!JSVAL_IS_NUMBER(*vp)) return JS_FALSE; - } else if (ptr->field.fieldType==GF_SG_VRML_MFSTRING) { - if (!JSVAL_IS_STRING(*vp)) return JS_FALSE; - } else if (ptr->field.fieldType==GF_SG_VRML_MFURL) { - if (!JSVAL_IS_STRING(*vp)) return JS_FALSE; - } - - - /*rewrite MFNode entry*/ - if (ptr->field.fieldType==GF_SG_VRML_MFNODE) { - GF_Node *prev_n, *new_n; +if (ptr->field.far_ptr && (ptr->field.fieldType!=GF_SG_VRML_MFNODE)) { + u32 items = ((GenMFField *)ptr->field.far_ptr)->count; + while (ind>=items) { + gf_sg_vrml_mf_insert(ptr->field.far_ptr, ptr->field.fieldType, &sf_slot, ind); + items++; + } +} - if (!ptr->owner) return JS_TRUE; +/*assign object*/ +if (ptr->field.fieldType==GF_SG_VRML_MFNODE) { + JSObject *o; + if (JSVAL_IS_VOID(*vp)) return JS_FALSE; + if (JSVAL_IS_NULL(*vp) ) return JS_FALSE; + o = JSVAL_TO_OBJECT(*vp); + if (!GF_JS_InstanceOf(c, o, &js_rt->SFNodeClass, NULL) ) return JS_FALSE; +} else if (the_sf_class) { + if (JSVAL_IS_VOID(*vp)) return JS_FALSE; + if (!GF_JS_InstanceOf(c, JSVAL_TO_OBJECT(*vp), the_sf_class, NULL) ) return JS_FALSE; +} else if (ptr->field.fieldType==GF_SG_VRML_MFBOOL) { + if (!JSVAL_IS_BOOLEAN(*vp)) return JS_FALSE; +} else if (ptr->field.fieldType==GF_SG_VRML_MFINT32) { + if (!JSVAL_IS_INT(*vp)) return JS_FALSE; +} else if (ptr->field.fieldType==GF_SG_VRML_MFFLOAT) { + if (!JSVAL_IS_NUMBER(*vp)) return JS_FALSE; +} else if (ptr->field.fieldType==GF_SG_VRML_MFTIME) { + if (!JSVAL_IS_NUMBER(*vp)) return JS_FALSE; +} else if (ptr->field.fieldType==GF_SG_VRML_MFSTRING) { + if (!JSVAL_IS_STRING(*vp)) return JS_FALSE; +} else if (ptr->field.fieldType==GF_SG_VRML_MFURL) { + if (!JSVAL_IS_STRING(*vp)) return JS_FALSE; +} + + +/*rewrite MFNode entry*/ +if (ptr->field.fieldType==GF_SG_VRML_MFNODE) { + GF_Node *prev_n, *new_n; - /*get new node*/ - from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); - new_n = *(GF_Node**)from->field.far_ptr; - prev_n = NULL; + if (!ptr->owner) return JS_TRUE; - if (!is_append) { - /*get and delete previous node if any, but unregister later*/ - prev_n = gf_node_list_del_child_idx( (GF_ChildNodeItem **)ptr->field.far_ptr, ind); - } + /*get new node*/ + from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); + new_n = *(GF_Node**)from->field.far_ptr; + prev_n = NULL; - if (new_n) { - gf_node_list_insert_child( (GF_ChildNodeItem **)ptr->field.far_ptr , new_n, ind); - gf_node_register(new_n, ptr->owner); + if (!is_append) { + /*get and delete previous node if any, but unregister later*/ + prev_n = gf_node_list_del_child_idx( (GF_ChildNodeItem **)ptr->field.far_ptr, ind); + } - /*node created from script and inserted in the tree, root it*/ - if (!from->is_rooted) - node_get_binding(JS_GetScriptStack(c), new_n, 0); - } - /*unregister previous node*/ - if (prev_n) gf_node_unregister(prev_n, ptr->owner); + if (new_n) { + gf_node_list_insert_child( (GF_ChildNodeItem **)ptr->field.far_ptr , new_n, ind); + gf_node_register(new_n, ptr->owner); - Script_FieldChanged(c, NULL, ptr, NULL); - return JS_TRUE; + /*node created from script and inserted in the tree, root it*/ + if (!from->is_rooted) + node_get_binding(JS_GetScriptStack(c), new_n, 0); } + /*unregister previous node*/ + if (prev_n) gf_node_unregister(prev_n, ptr->owner); - ret = JS_SetElement(c, ptr->js_list, ind, vp); - if (ret==JS_FALSE) return JS_FALSE; + Script_FieldChanged(c, NULL, ptr, NULL); + return JS_TRUE; +} - if (!ptr->owner) return JS_TRUE; +ret = JS_SetElement(c, ptr->js_list, ind, vp); +if (ret==JS_FALSE) return JS_FALSE; - /*rewrite MF slot*/ - switch (ptr->field.fieldType) { - case GF_SG_VRML_MFBOOL: - ((MFBool *)ptr->field.far_ptr)->vals[ind] = (Bool) JSVAL_TO_BOOLEAN(*vp); - break; - case GF_SG_VRML_MFINT32: - ((MFInt32 *)ptr->field.far_ptr)->vals[ind] = (s32) JSVAL_TO_INT(*vp); - break; - case GF_SG_VRML_MFFLOAT: - JS_ValueToNumber(c, *vp, &d); - ((MFFloat *)ptr->field.far_ptr)->vals[ind] = FLT2FIX(d); - break; - case GF_SG_VRML_MFTIME: - JS_ValueToNumber(c, *vp, &d); - ((MFTime *)ptr->field.far_ptr)->vals[ind] = d; - break; - case GF_SG_VRML_MFSTRING: - if (((MFString *)ptr->field.far_ptr)->vals[ind]) { - gf_free(((MFString *)ptr->field.far_ptr)->vals[ind]); - ((MFString *)ptr->field.far_ptr)->vals[ind] = NULL; - } - str = JSVAL_IS_STRING(*vp) ? JSVAL_TO_STRING(*vp) : JS_ValueToString(c, *vp); - str_val = SMJS_CHARS_FROM_STRING(c, str); - ((MFString *)ptr->field.far_ptr)->vals[ind] = gf_strdup(str_val); - SMJS_FREE(c, str_val); - break; +if (!ptr->owner) return JS_TRUE; - case GF_SG_VRML_MFURL: - if (((MFURL *)ptr->field.far_ptr)->vals[ind].url) { - gf_free(((MFURL *)ptr->field.far_ptr)->vals[ind].url); - ((MFURL *)ptr->field.far_ptr)->vals[ind].url = NULL; - } - str = JSVAL_IS_STRING(*vp) ? JSVAL_TO_STRING(*vp) : JS_ValueToString(c, *vp); - str_val = SMJS_CHARS_FROM_STRING(c, str); - ((MFURL *)ptr->field.far_ptr)->vals[ind].url = gf_strdup(str_val); - ((MFURL *)ptr->field.far_ptr)->vals[ind].OD_ID = 0; - SMJS_FREE(c, str_val); - break; +/*rewrite MF slot*/ +switch (ptr->field.fieldType) { +case GF_SG_VRML_MFBOOL: + ((MFBool *)ptr->field.far_ptr)->vals[ind] = (Bool) JSVAL_TO_BOOLEAN(*vp); + break; +case GF_SG_VRML_MFINT32: + ((MFInt32 *)ptr->field.far_ptr)->vals[ind] = (s32) JSVAL_TO_INT(*vp); + break; +case GF_SG_VRML_MFFLOAT: + SMJS_GET_NUMBER(*vp, d); + ((MFFloat *)ptr->field.far_ptr)->vals[ind] = FLT2FIX(d); + break; +case GF_SG_VRML_MFTIME: + SMJS_GET_NUMBER(*vp, d); + ((MFTime *)ptr->field.far_ptr)->vals[ind] = d; + break; +case GF_SG_VRML_MFSTRING: + if (((MFString *)ptr->field.far_ptr)->vals[ind]) { + gf_free(((MFString *)ptr->field.far_ptr)->vals[ind]); + ((MFString *)ptr->field.far_ptr)->vals[ind] = NULL; + } + str = JSVAL_IS_STRING(*vp) ? JSVAL_TO_STRING(*vp) : JS_ValueToString(c, *vp); + str_val = SMJS_CHARS_FROM_STRING(c, str); + ((MFString *)ptr->field.far_ptr)->vals[ind] = gf_strdup(str_val); + SMJS_FREE(c, str_val); + break; - case GF_SG_VRML_MFVEC2F: - from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); - gf_sg_vrml_field_copy(& ((MFVec2f *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); - break; - case GF_SG_VRML_MFVEC3F: - from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); - gf_sg_vrml_field_copy(& ((MFVec3f *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); - break; - case GF_SG_VRML_MFROTATION: - from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); - gf_sg_vrml_field_copy(& ((MFRotation *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); - break; - case GF_SG_VRML_MFCOLOR: - from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); - gf_sg_vrml_field_copy(& ((MFColor *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); - break; +case GF_SG_VRML_MFURL: + if (((MFURL *)ptr->field.far_ptr)->vals[ind].url) { + gf_free(((MFURL *)ptr->field.far_ptr)->vals[ind].url); + ((MFURL *)ptr->field.far_ptr)->vals[ind].url = NULL; } + str = JSVAL_IS_STRING(*vp) ? JSVAL_TO_STRING(*vp) : JS_ValueToString(c, *vp); + str_val = SMJS_CHARS_FROM_STRING(c, str); + ((MFURL *)ptr->field.far_ptr)->vals[ind].url = gf_strdup(str_val); + ((MFURL *)ptr->field.far_ptr)->vals[ind].OD_ID = 0; + SMJS_FREE(c, str_val); + break; - Script_FieldChanged(c, NULL, ptr, NULL); - return JS_TRUE; +case GF_SG_VRML_MFVEC2F: + from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); + gf_sg_vrml_field_copy(& ((MFVec2f *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); + break; +case GF_SG_VRML_MFVEC3F: + from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); + gf_sg_vrml_field_copy(& ((MFVec3f *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); + break; +case GF_SG_VRML_MFROTATION: + from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); + gf_sg_vrml_field_copy(& ((MFRotation *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); + break; +case GF_SG_VRML_MFCOLOR: + from = (GF_JSField *) SMJS_GET_PRIVATE(c, JSVAL_TO_OBJECT(*vp)); + gf_sg_vrml_field_copy(& ((MFColor *)ptr->field.far_ptr)->vals[ind], from->field.far_ptr, from->field.fieldType); + break; +} + +Script_FieldChanged(c, NULL, ptr, NULL); +return JS_TRUE; } static SMJS_FUNC_PROP_SET( array_setLength) - u32 len, i, sftype; - JSBool ret; - GF_JSClass *the_sf_class; - GF_JSField *ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); - if (!JSVAL_IS_INT(*vp) || JSVAL_TO_INT(*vp) < 0) return JS_FALSE; +u32 len, i, sftype, old_len; +JSBool ret; +GF_JSClass *the_sf_class; +GF_JSField *ptr = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); +if (!JSVAL_IS_INT(*vp) || JSVAL_TO_INT(*vp) < 0) return JS_FALSE; /*avoids gcc warning*/ #ifndef GPAC_CONFIG_DARWIN if (!id) id=0; #endif - len = JSVAL_TO_INT(*vp); +len = JSVAL_TO_INT(*vp); - if (!len) { - if (ptr->field.fieldType==GF_SG_VRML_MFNODE) { - gf_node_unregister_children(ptr->owner, *(GF_ChildNodeItem**)ptr->field.far_ptr); - *(GF_ChildNodeItem**)ptr->field.far_ptr = NULL; - } else { - gf_sg_vrml_mf_reset(ptr->field.far_ptr, ptr->field.fieldType); - } - JS_SetArrayLength(c, ptr->js_list, 0); - Script_FieldChanged(c, NULL, ptr, NULL); - return JS_TRUE; +if (!len) { + if (ptr->field.fieldType==GF_SG_VRML_MFNODE) { + gf_node_unregister_children(ptr->owner, *(GF_ChildNodeItem**)ptr->field.far_ptr); + *(GF_ChildNodeItem**)ptr->field.far_ptr = NULL; + } else { + gf_sg_vrml_mf_reset(ptr->field.far_ptr, ptr->field.fieldType); } + JS_SetArrayLength(c, ptr->js_list, 0); + Script_FieldChanged(c, NULL, ptr, NULL); + return JS_TRUE; +} - ret = JS_SetArrayLength(c, ptr->js_list, len); - if (ret==JS_FALSE) return ret; +ret = JS_GetArrayLength(c, ptr->js_list, &old_len); +if (ret==JS_FALSE) return ret; - the_sf_class = NULL; - switch (ptr->field.fieldType) { - case GF_SG_VRML_MFVEC2F: - the_sf_class = &js_rt->SFVec2fClass; - break; - case GF_SG_VRML_MFVEC3F: - the_sf_class = &js_rt->SFVec3fClass; - break; - case GF_SG_VRML_MFCOLOR: - the_sf_class = &js_rt->SFColorClass; - break; - case GF_SG_VRML_MFROTATION: - the_sf_class = &js_rt->SFRotationClass; - break; - case GF_SG_VRML_MFNODE: - { - u32 c = gf_node_list_get_count(*(GF_ChildNodeItem**)ptr->field.far_ptr); - while (len < c) { - GF_Node *n = gf_node_list_del_child_idx((GF_ChildNodeItem**)ptr->field.far_ptr, c-1); - if (n) gf_node_unregister(n, ptr->owner); - c--; - } - if (len>c) { - GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML] MFARRAY EXPANSION NOT SUPPORTED!!!\n")); - } +ret = JS_SetArrayLength(c, ptr->js_list, len); +if (ret==JS_FALSE) return ret; + +the_sf_class = NULL; +switch (ptr->field.fieldType) { +case GF_SG_VRML_MFVEC2F: + the_sf_class = &js_rt->SFVec2fClass; + break; +case GF_SG_VRML_MFVEC3F: + the_sf_class = &js_rt->SFVec3fClass; + break; +case GF_SG_VRML_MFCOLOR: + the_sf_class = &js_rt->SFColorClass; + break; +case GF_SG_VRML_MFROTATION: + the_sf_class = &js_rt->SFRotationClass; + break; +case GF_SG_VRML_MFNODE: +{ + u32 c = gf_node_list_get_count(*(GF_ChildNodeItem**)ptr->field.far_ptr); + while (len < c) { + GF_Node *n = gf_node_list_del_child_idx((GF_ChildNodeItem**)ptr->field.far_ptr, c-1); + if (n) gf_node_unregister(n, ptr->owner); + c--; } - return JS_TRUE; + if (len>c) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[VRML] MFARRAY EXPANSION NOT SUPPORTED!!!\n")); } +} +return JS_TRUE; +} - sftype = gf_sg_vrml_get_sf_type(ptr->field.fieldType); - for (i=0; ifield.fieldType); +for (i=old_len; ijs_list, i, &a_val); } - return JS_TRUE; + JS_SetElement(c, ptr->js_list, i, &a_val); +} +return JS_TRUE; } static SMJS_FUNC_PROP_GET( array_getLength) @@ -3368,8 +3360,6 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script) SMJS_FUNCTION_SPEC("createVrmlFromString", createVrmlFromString, 1), SMJS_FUNCTION_SPEC("setDescription", setDescription, 1), SMJS_FUNCTION_SPEC("print", JSPrint, 1), - SMJS_FUNCTION_SPEC("getOption", getOption, 2), - SMJS_FUNCTION_SPEC("setOption", setOption, 3), SMJS_FUNCTION_SPEC("getScript", getScript, 0), SMJS_FUNCTION_SPEC("getProto", getProto, 0), SMJS_FUNCTION_SPEC("loadScript", loadScript, 1), @@ -3520,7 +3510,7 @@ void gf_sg_script_init_sm_api(GF_ScriptPriv *sc, GF_Node *script) -void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF_Node *owner, GF_JSField *parent) +JSBool gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF_Node *owner, GF_JSField *parent) { jsdouble d; Bool changed; @@ -3530,8 +3520,8 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF jsval item; u32 i; - if (JSVAL_IS_VOID(val)) return; - if ((field->fieldType != GF_SG_VRML_SFNODE) && JSVAL_IS_NULL(val)) return; + if (JSVAL_IS_VOID(val)) return JS_TRUE; + if ((field->fieldType != GF_SG_VRML_SFNODE) && JSVAL_IS_NULL(val)) return JS_TRUE; switch (field->fieldType) { @@ -3541,7 +3531,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF *((SFBool *) field->far_ptr) = JSVAL_TO_BOOLEAN(val); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFINT32: { @@ -3549,29 +3539,29 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF * ((SFInt32 *) field->far_ptr) = JSVAL_TO_INT(val); Script_FieldChanged(c, owner, parent, field); } else if (JSVAL_IS_NUMBER(val) ) { - JS_ValueToNumber(c, val, &d ); + SMJS_GET_NUMBER(val, d ); *((SFInt32 *) field->far_ptr) = (s32) d; Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFFLOAT: { if (JSVAL_IS_NUMBER(val) ) { - JS_ValueToNumber(c, val, &d ); + SMJS_GET_NUMBER(val, d ); *((SFFloat *) field->far_ptr) = FLT2FIX( d); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFTIME: { if (JSVAL_IS_NUMBER(val) ) { - JS_ValueToNumber(c, val, &d ); + SMJS_GET_NUMBER(val, d ); *((SFTime *) field->far_ptr) = (Double) d; Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFSTRING: { @@ -3585,7 +3575,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF Script_FieldChanged(c, owner, parent, field); } SMJS_FREE(c, str_val); - return; + return JS_TRUE; } case GF_SG_VRML_SFURL: { @@ -3597,7 +3587,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF ((SFURL*)field->far_ptr)->OD_ID = 0; Script_FieldChanged(c, owner, parent, field); SMJS_FREE(c, str_val); - return; + return JS_TRUE; } case GF_SG_VRML_MFSTRING: if (JSVAL_IS_STRING(val)) { @@ -3609,7 +3599,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF ((MFString*)field->far_ptr)->vals[0] = gf_strdup(str_val); Script_FieldChanged(c, owner, parent, field); SMJS_FREE(c, str_val); - return; + return JS_TRUE; } case GF_SG_VRML_MFURL: if (JSVAL_IS_STRING(val)) { @@ -3622,7 +3612,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF ((MFURL*)field->far_ptr)->vals[0].OD_ID = 0; Script_FieldChanged(c, owner, parent, field); SMJS_FREE(c, str_val); - return; + return JS_TRUE; } default: @@ -3630,7 +3620,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF } //from here we must have an object - if (! JSVAL_IS_OBJECT(val)) return; + if (! JSVAL_IS_OBJECT(val)) return JS_FALSE; obj = JSVAL_TO_OBJECT(val) ; switch (field->fieldType) { @@ -3641,7 +3631,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF gf_sg_vrml_field_copy(field->far_ptr, p->field.far_ptr, GF_SG_VRML_SFVEC2F); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFVEC3F: { @@ -3650,7 +3640,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF gf_sg_vrml_field_copy(field->far_ptr, p->field.far_ptr, GF_SG_VRML_SFVEC3F); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFROTATION: { @@ -3659,7 +3649,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF gf_sg_vrml_field_copy(field->far_ptr, p->field.far_ptr, GF_SG_VRML_SFROTATION); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFCOLOR: { @@ -3668,7 +3658,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF gf_sg_vrml_field_copy(field->far_ptr, p->field.far_ptr, GF_SG_VRML_SFCOLOR); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFNODE: { @@ -3686,7 +3676,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF gf_node_register(n, owner); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } case GF_SG_VRML_SFIMAGE: { @@ -3695,7 +3685,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF gf_sg_vrml_field_copy(field->far_ptr, p->field.far_ptr, GF_SG_VRML_SFIMAGE); Script_FieldChanged(c, owner, parent, field); } - return; + return JS_TRUE; } default: break; @@ -3716,7 +3706,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF /* && !GF_JS_InstanceOf(c, obj, &MFVec4fClass, NULL) */ - ) return; + ) return JS_TRUE; p = (GF_JSField *) SMJS_GET_PRIVATE(c, obj); @@ -3746,7 +3736,7 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF Script_FieldChanged(c, owner, parent, field); /*and mark the field as changed*/ JSScript_NodeModified(owner->sgprivate->scenegraph, owner, field, NULL); - return; + return JS_TRUE; } /*again, check text changes*/ @@ -3774,13 +3764,13 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF break; case GF_SG_VRML_MFFLOAT: if (JSVAL_IS_NUMBER(item)) { - JS_ValueToNumber(c, item, &d); + SMJS_GET_NUMBER(item, d); ((MFFloat *)field->far_ptr)->vals[i] = FLT2FIX( d); } break; case GF_SG_VRML_MFTIME: if (JSVAL_IS_NUMBER(item)) { - JS_ValueToNumber(c, item, &d); + SMJS_GET_NUMBER(item, d); ((MFTime *)field->far_ptr)->vals[i] = d; } break; @@ -3836,10 +3826,11 @@ void gf_sg_script_to_node_field(JSContext *c, jsval val, GF_FieldInfo *field, GF break; default: - return; + return JS_TRUE; } } if (changed) Script_FieldChanged(c, owner, parent, field); + return JS_TRUE; } @@ -4037,8 +4028,8 @@ jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_No } } + obj = NULL; -#if 1 /*look into object bank in case we already have this object*/ if (parent && parent->sgprivate->interact && parent->sgprivate->interact->js_binding) { i=0; @@ -4048,25 +4039,40 @@ jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_No /*make sure we use the same JS context*/ (jsf->js_ctx == priv->js_ctx) && (jsf->owner == parent) -#if 0 - && (jsf->field.fieldIndex == field->fieldIndex) - /*type check needed for MFNode entries*/ - && (jsf->field.fieldType==field->fieldType) -#else && (jsf->field.far_ptr==field->far_ptr) -#endif ) { + Bool do_rebuild = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[VRML JS] found cached jsobj %p (field %s) in script %s bank (%d entries)\n", obj, field->name, gf_node_get_log_name((GF_Node*)JS_GetScript(priv->js_ctx)), gf_list_count(priv->js_cache) ) ); if (!force_evaluate && !jsf->field.NDTtype) return OBJECT_TO_JSVAL(obj); + switch (field->fieldType) { + //we need to rewrite these + case GF_SG_VRML_MFVEC2F: + case GF_SG_VRML_MFVEC3F: + case GF_SG_VRML_MFROTATION: + case GF_SG_VRML_MFCOLOR: + if (force_evaluate) { + do_rebuild = 1; + break; + } + default: + break; + } + if (do_rebuild) { + JS_SetArrayLength(priv->js_ctx, jsf->js_list, 0); + break; + } + gf_sg_script_update_cached_object(priv, obj, jsf, field, parent); return OBJECT_TO_JSVAL(obj); } + obj = NULL; } } -#endif - GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[VRML JS] creating jsobj %s.%s\n", gf_node_get_name(parent), field->name) ); + if (!obj) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_SCRIPT, ("[VRML JS] creating jsobj %s.%s\n", gf_node_get_name(parent), field->name) ); + } switch (field->fieldType) { case GF_SG_VRML_SFVEC2F: @@ -4180,8 +4186,10 @@ jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_No case GF_SG_VRML_MFVEC2F: { MFVec2f *f = (MFVec2f *) field->far_ptr; - obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFVec2fClass, priv->js_obj); - SETUP_MF_FIELD + if (!obj) { + obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFVec2fClass, priv->js_obj); + SETUP_MF_FIELD + } for (i=0; icount; i++) { JSObject *pf = JS_NewObject(priv->js_ctx, &js_rt->SFVec2fClass._class, 0, obj); newVal = OBJECT_TO_JSVAL(pf); @@ -4194,8 +4202,10 @@ jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_No case GF_SG_VRML_MFVEC3F: { MFVec3f *f = (MFVec3f *) field->far_ptr; - obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFVec3fClass, priv->js_obj); - SETUP_MF_FIELD + if (!obj) { + obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFVec3fClass, priv->js_obj); + SETUP_MF_FIELD + } for (i=0; icount; i++) { JSObject *pf = JS_NewObject(priv->js_ctx, &js_rt->SFVec3fClass._class, 0, obj); newVal = OBJECT_TO_JSVAL(pf); @@ -4208,8 +4218,10 @@ jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_No case GF_SG_VRML_MFROTATION: { MFRotation *f = (MFRotation*) field->far_ptr; - obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFRotationClass, priv->js_obj); - SETUP_MF_FIELD + if (!obj) { + obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFRotationClass, priv->js_obj); + SETUP_MF_FIELD + } for (i=0; icount; i++) { JSObject *pf = JS_NewObject(priv->js_ctx, &js_rt->SFRotationClass._class, 0, obj); newVal = OBJECT_TO_JSVAL(pf); @@ -4222,8 +4234,10 @@ jsval gf_sg_script_to_smjs_field(GF_ScriptPriv *priv, GF_FieldInfo *field, GF_No case GF_SG_VRML_MFCOLOR: { MFColor *f = (MFColor *) field->far_ptr; - obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFColorClass, priv->js_obj); - SETUP_MF_FIELD + if (!obj) { + obj = SMJS_CONSTRUCT_OBJECT(priv->js_ctx, &js_rt->MFColorClass, priv->js_obj); + SETUP_MF_FIELD + } for (i=0; icount; i++) { JSObject *pf = JS_NewObject(priv->js_ctx, &js_rt->SFColorClass._class, 0, obj); newVal = OBJECT_TO_JSVAL(pf); @@ -4390,7 +4404,7 @@ static void JS_PreDestroy(GF_Node *node) gf_sg_lock_javascript(priv->js_ctx, 1); - if (priv->event) gf_js_remove_root(priv->js_ctx, &priv->event, GF_JSGC_OBJECT); + if (priv->the_event) gf_js_remove_root(priv->js_ctx, &priv->the_event, GF_JSGC_OBJECT); /*unprotect all cached objects from GC*/ JS_ReleaseRootObjects(priv); @@ -4398,7 +4412,7 @@ static void JS_PreDestroy(GF_Node *node) gf_sg_load_script_extensions(node->sgprivate->scenegraph, priv->js_ctx, priv->js_obj, 1); #ifndef GPAC_DISABLE_SVG - dom_js_pre_destroy(priv->js_ctx, node->sgprivate->scenegraph, NULL); + gf_sg_js_dom_pre_destroy(priv->js_ctx, node->sgprivate->scenegraph, NULL); #endif gf_sg_lock_javascript(priv->js_ctx, 0); @@ -4549,19 +4563,19 @@ static Bool vrml_js_load_script(M_Script *script, char *file, Bool primary_scrip uintN attr; JSBool found; - jsf = gf_f64_open(file, "rb"); + jsf = gf_fopen(file, "rb"); if (!jsf) return 0; - gf_f64_seek(jsf, 0, SEEK_END); - fsize = gf_f64_tell(jsf); - gf_f64_seek(jsf, 0, SEEK_SET); + gf_fseek(jsf, 0, SEEK_END); + fsize = gf_ftell(jsf); + gf_fseek(jsf, 0, SEEK_SET); jsscript = gf_malloc(sizeof(char)*(size_t)(fsize+1)); fsize = fread(jsscript, sizeof(char), (size_t)fsize, jsf); - fclose(jsf); + gf_fclose(jsf); jsscript[fsize] = 0; *rval = JSVAL_NULL; - ret = JS_EvaluateScript(priv->js_ctx, priv->js_obj, jsscript, (u32) (sizeof(char)*fsize), 0, 0, rval); + ret = JS_EvaluateScript(priv->js_ctx, priv->js_obj, jsscript, (u32) (sizeof(char)*fsize), file, 0, rval); if (ret==JS_FALSE) success = 0; if (success && primary_script @@ -4692,8 +4706,8 @@ static void JSScript_LoadVRML(GF_Node *node) /*initialize DOM*/ dom_js_load(node->sgprivate->scenegraph, priv->js_ctx, priv->js_obj); /*create event object, and remember it*/ - priv->event = dom_js_define_event(priv->js_ctx, priv->js_obj); - gf_js_add_root(priv->js_ctx, &priv->event, GF_JSGC_OBJECT); + priv->the_event = dom_js_define_event(priv->js_ctx, priv->js_obj); + gf_js_add_root(priv->js_ctx, &priv->the_event, GF_JSGC_OBJECT); #endif gf_sg_load_script_extensions(node->sgprivate->scenegraph, priv->js_ctx, priv->js_obj, 0); @@ -4900,12 +4914,14 @@ void gf_sg_handle_dom_event_for_vrml(GF_Node *node, GF_DOM_Event *event, GF_Node GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[DOM Events] Executing script code from VRML handler\n")); priv = JS_GetScriptStack(hdl->js_context); - prev_event = SMJS_GET_PRIVATE(priv->js_ctx, priv->event); + gf_sg_lock_javascript(priv->js_ctx, 1); + + prev_event = SMJS_GET_PRIVATE(priv->js_ctx, priv->the_event); /*break loops*/ - if (prev_event && (prev_event->type==event->type) && (prev_event->target==event->target)) + if (prev_event && (prev_event->type==event->type) && (prev_event->target==event->target)) { + gf_sg_lock_javascript(priv->js_ctx, 0); return; - - gf_sg_lock_javascript(priv->js_ctx, 1); + } evt = gf_dom_new_event(priv->js_ctx); if (!evt) { @@ -4916,8 +4932,7 @@ void gf_sg_handle_dom_event_for_vrml(GF_Node *node, GF_DOM_Event *event, GF_Node prev_type = event->is_vrml; event->is_vrml = 1; - SMJS_SET_PRIVATE(priv->js_ctx, priv->event, event); - + SMJS_SET_PRIVATE(priv->js_ctx, priv->the_event, event); SMJS_SET_PRIVATE(priv->js_ctx, evt, event); argv[0] = OBJECT_TO_JSVAL(evt); @@ -4936,7 +4951,7 @@ void gf_sg_handle_dom_event_for_vrml(GF_Node *node, GF_DOM_Event *event, GF_Node } event->is_vrml = prev_type; - SMJS_SET_PRIVATE(priv->js_ctx, priv->event, prev_event); + SMJS_SET_PRIVATE(priv->js_ctx, priv->the_event, prev_event); gf_sg_lock_javascript(priv->js_ctx, 0); @@ -5064,7 +5079,7 @@ Bool gf_sg_try_lock_javascript(struct JSContext *cx) GF_Err gf_scene_execute_script(GF_SceneGraph *sg, const char *com) { -#ifdef GPAC_HAS_SPIDERMONKEY +#if defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG) u32 tag; GF_Err e; GF_Node *root = gf_sg_get_root_node(sg); diff --git a/src/scenegraph/vrml_tools.c b/src/scenegraph/vrml_tools.c index b70ca67..464f0e5 100644 --- a/src/scenegraph/vrml_tools.c +++ b/src/scenegraph/vrml_tools.c @@ -1543,12 +1543,12 @@ u32 gf_node_get_num_fields_in_mode(GF_Node *Node, u8 IndexMode) { assert(Node); if (Node->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_num_fields(Node, IndexMode); - else if ((Node->sgprivate->tag == TAG_MPEG4_Script) + else if (Node->sgprivate->tag == TAG_MPEG4_Script) + return gf_sg_script_get_num_fields(Node, IndexMode); #ifndef GPAC_DISABLE_X3D - || (Node->sgprivate->tag == TAG_X3D_Script) + else if (Node->sgprivate->tag == TAG_X3D_Script) + return gf_sg_script_get_num_fields(Node, IndexMode); #endif - ) - return gf_sg_script_get_num_fields(Node, IndexMode); else if (Node->sgprivate->tag <= GF_NODE_RANGE_LAST_MPEG4) return gf_sg_mpeg4_node_get_field_count(Node, IndexMode); #ifndef GPAC_DISABLE_X3D else if (Node->sgprivate->tag <= GF_NODE_RANGE_LAST_X3D) return gf_sg_x3d_node_get_field_count(Node); diff --git a/src/scenegraph/webvtt_smjs.c b/src/scenegraph/webvtt_smjs.c index 72b7452..6d971e7 100644 --- a/src/scenegraph/webvtt_smjs.c +++ b/src/scenegraph/webvtt_smjs.c @@ -28,7 +28,8 @@ #include #include -#ifdef GPAC_HAS_SPIDERMONKEY +#if defined(GPAC_HAS_SPIDERMONKEY) && !defined(GPAC_DISABLE_SVG) + #include @@ -120,7 +121,7 @@ GF_Err gf_webvtt_js_addCue(GF_Node *node, const char *id, } GF_EXPORT -GF_Err gf_webvtt_js_removeCues() +GF_Err gf_webvtt_js_removeCues(GF_Node *node) { return GF_BAD_PARAM; } diff --git a/src/scenegraph/xml_ns.c b/src/scenegraph/xml_ns.c index 73591c3..6724725 100644 --- a/src/scenegraph/xml_ns.c +++ b/src/scenegraph/xml_ns.c @@ -657,7 +657,7 @@ const char *gf_xml_get_element_name(GF_Node *n) return "UndefinedNode"; } -u32 gf_xml_get_element_namespace(GF_Node *n) +GF_NamespaceType gf_xml_get_element_namespace(GF_Node *n) { u32 i, count; if (n->sgprivate->tag==TAG_DOMFullNode) { @@ -1036,28 +1036,28 @@ static u32 check_existing_file(char *base_file, char *ext, char *data, u32 data_ sprintf(szFile, "%s%04X%s", base_file, idx, ext); - f = gf_f64_open(szFile, "rb"); + f = gf_fopen(szFile, "rb"); if (!f) return 0; - gf_f64_seek(f, 0, SEEK_END); - fsize = gf_f64_tell(f); + gf_fseek(f, 0, SEEK_END); + fsize = gf_ftell(f); if (fsize==data_size) { u32 offset=0; char cache[1024]; - gf_f64_seek(f, 0, SEEK_SET); + gf_fseek(f, 0, SEEK_SET); while (fsize) { u32 read = (u32) fread(cache, 1, 1024, f); fsize -= read; if (memcmp(cache, data+offset, sizeof(char)*read)) break; offset+=read; } - fclose(f); + gf_fclose(f); f = NULL; /*same file*/ if (!fsize) return 2; } if (f) - fclose(f); + gf_fclose(f); return 1; } @@ -1136,7 +1136,7 @@ GF_Err gf_node_store_embedded_data(XMLRI *iri, const char *cache_dir, const char strcat(szFile, ext); if (!existing) { - f = gf_f64_open(szFile, "wb"); + f = gf_fopen(szFile, "wb"); if (!f) { gf_free(data); gf_free(iri->string); @@ -1144,7 +1144,7 @@ GF_Err gf_node_store_embedded_data(XMLRI *iri, const char *cache_dir, const char return GF_IO_ERR; } gf_fwrite(data, data_size, 1, f); - fclose(f); + gf_fclose(f); } gf_free(data); gf_free(iri->string); diff --git a/src/terminal/channel.c b/src/terminal/channel.c index 7ae2553..16c8a6b 100644 --- a/src/terminal/channel.c +++ b/src/terminal/channel.c @@ -36,9 +36,13 @@ void gf_es_buffer_off(GF_Channel *ch) { /*just in case*/ if (ch->BufferOn) { - ch->BufferOn = 0; + ch->BufferOn = GF_FALSE; gf_clock_buffer_off(ch->clock); - GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: buffering off at STB %d (OTB %d) (nb buffering on clock: %d)\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), gf_clock_time(ch->clock), ch->clock->Buffering)); + GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s) : buffering off at STB %d (OTB %d) (nb buffering on clock: %d)\n", ch->esd->ESID, ch->odm->net_service->url, gf_term_get_time(ch->odm->term), gf_clock_time(ch->clock), ch->clock->Buffering)); + //if one of the stream is done buffering, force data timeout for the clock to be the buffer time + //at the end of the buffering period + if ((ch->clock->data_timeout==ch->odm->term->net_data_timeout) && (ch->BufferTime>=(s32) ch->MaxBuffer)) + ch->clock->data_timeout = ch->BufferTime; } } @@ -53,12 +57,12 @@ void gf_es_buffer_on(GF_Channel *ch) if (!ch->BufferOn) { ch->BufferOn = 1; gf_clock_buffer_on(ch->clock); - GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: buffering on at %d (nb buffering on clock: %d)\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->clock->Buffering)); + GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): buffering on at %d (nb buffering on clock: %d)\n", ch->esd->ESID, ch->odm->net_service->url, gf_term_get_time(ch->odm->term), ch->clock->Buffering)); } } /*reset channel*/ -static void Channel_Reset(GF_Channel *ch, Bool for_start) +static void gf_es_reset(GF_Channel *ch, Bool for_start) { gf_es_lock(ch, 1); @@ -67,6 +71,7 @@ static void Channel_Reset(GF_Channel *ch, Bool for_start) ch->pck_sn = 0; ch->stream_state = 1; ch->IsRap = 0; + ch->SeekFlag = 0; ch->IsEndOfStream = 0; ch->skip_carousel_au = 0; @@ -131,7 +136,7 @@ GF_Channel *gf_es_new(GF_ESD *esd) tmp->ocr_scale /= esd->slConfig->OCRResolution; } - Channel_Reset(tmp, 0); + gf_es_reset(tmp, 0); return tmp; } @@ -178,7 +183,7 @@ void gf_es_reconfig_sl(GF_Channel *ch, GF_SLConfig *slc, Bool use_m2ts_sections) /*destroy channel*/ void gf_es_del(GF_Channel *ch) { - Channel_Reset(ch, 0); + gf_es_reset(ch, 0); if (ch->AU_buffer_pull) { ch->AU_buffer_pull->data = NULL; gf_db_unit_del(ch->AU_buffer_pull); @@ -219,7 +224,7 @@ GF_Err gf_es_start(GF_Channel *ch) gf_clock_reset(ch->clock); /*reset channel*/ - Channel_Reset(ch, 1); + gf_es_reset(ch, 1); /*create pull buffer if needed*/ if (ch->is_pulling && !ch->AU_buffer_pull) ch->AU_buffer_pull = gf_db_unit_new(); @@ -255,12 +260,12 @@ GF_Err gf_es_stop(GF_Channel *ch) gf_es_buffer_off(ch); ch->es_state = GF_ESM_ES_CONNECTED; - Channel_Reset(ch, 0); + gf_es_reset(ch, 0); return GF_OK; } -void Channel_WaitRAP(GF_Channel *ch) +static void gf_es_wait_rap(GF_Channel *ch) { ch->pck_sn = 0; @@ -275,6 +280,7 @@ void Channel_WaitRAP(GF_Channel *ch) void gf_es_reset_buffers(GF_Channel *ch) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): reseting buffers (%d AUs)\n", ch->esd->ESID, ch->odm->net_service->url, ch->AU_Count)); gf_mx_p(ch->mx); if (ch->buffer) gf_free(ch->buffer); @@ -293,15 +299,17 @@ void gf_es_reset_buffers(GF_Channel *ch) } -void gf_es_reset_timing(GF_Channel *ch) +void gf_es_reset_timing(GF_Channel *ch, Bool reset_buffer) { struct _decoding_buffer *au = ch->AU_buffer_first; gf_mx_p(ch->mx); - if (ch->buffer) gf_free(ch->buffer); - ch->buffer = NULL; - ch->len = ch->allocSize = 0; - + if (reset_buffer) { + if (ch->buffer) gf_free(ch->buffer); + ch->buffer = NULL; + ch->len = ch->allocSize = 0; + } + while (au) { au->CTS = au->DTS = 0; au = au->next; @@ -311,9 +319,13 @@ void gf_es_reset_timing(GF_Channel *ch) gf_mx_v(ch->mx); } -static Bool Channel_NeedsBuffering(GF_Channel *ch, u32 ForRebuffering) +static Bool gf_es_needs_buffering(GF_Channel *ch, u32 ForRebuffering) { - if (!ch->MaxBuffer || ch->IsEndOfStream) return 0; + if (!ch->MaxBuffer || ch->IsEndOfStream) + return 0; + //not controled by the buffer level but by the service + if (ch->is_pulling) + return 1; /*for rebuffering, check we're not below min buffer*/ if (ForRebuffering) { @@ -329,8 +341,6 @@ static Bool Channel_NeedsBuffering(GF_Channel *ch, u32 ForRebuffering) /*data timeout (no data sent)*/ if (now > ch->last_au_time + ch->clock->data_timeout) { gf_term_message(ch->odm->term, ch->service->url, "Data timeout - aborting buffering", GF_OK); - ch->MinBuffer = ch->MaxBuffer = 0; - ch->au_duration = 0; gf_scene_buffering_info(ch->odm->parentscene ? ch->odm->parentscene : ch->odm->subscene); return 0; } else { @@ -365,22 +375,27 @@ static Bool Channel_NeedsBuffering(GF_Channel *ch, u32 ForRebuffering) return 0; } -static void Channel_UpdateBuffering(GF_Channel *ch, Bool update_info) +void gf_es_update_buffering(GF_Channel *ch, Bool update_info) { - if (update_info && ch->MaxBuffer) gf_scene_buffering_info(ch->odm->parentscene ? ch->odm->parentscene : ch->odm->subscene); + if (update_info) { + if (ch->MaxBuffer) gf_scene_buffering_info(ch->odm->parentscene ? ch->odm->parentscene : ch->odm->subscene); - gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_PROGRESS); - gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_TIME_UPDATE); + gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_PROGRESS); + gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_TIME_UPDATE); + } - if (!Channel_NeedsBuffering(ch, 0)) { + if (!gf_es_needs_buffering(ch, 0)) { gf_es_buffer_off(ch); - if (ch->MaxBuffer && update_info) gf_scene_buffering_info(ch->odm->parentscene ? ch->odm->parentscene : ch->odm->subscene); - gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_PLAYING); + if (update_info) { + if (ch->MaxBuffer && update_info) gf_scene_buffering_info(ch->odm->parentscene ? ch->odm->parentscene : ch->odm->subscene); + + gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_PLAYING); + } } } -static void Channel_UpdateBufferTime(GF_Channel *ch) +static void gf_es_update_buffer_time(GF_Channel *ch) { if (!ch->AU_buffer_first || !ch->IsClockInit) { ch->BufferTime = 0; @@ -404,12 +419,16 @@ static void Channel_UpdateBufferTime(GF_Channel *ch) ch->BufferTime = 50*ch->AU_Count; } } else { - s32 bt = ch->AU_buffer_last->DTS - gf_clock_time(ch->clock); + s32 bt; + if (ch->clock->speed >= 0) + bt = ch->AU_buffer_last->DTS - gf_clock_time(ch->clock); + else { + bt = gf_clock_time(ch->clock); + bt -= ch->AU_buffer_last->DTS; + } + if (bt>0) { ch->BufferTime = (u32) bt; - if (ch->clock->speed != FIX_ONE) { - ch->BufferTime = FIX2INT( gf_divfix( INT2FIX(ch->AU_buffer_last->DTS - ch->AU_buffer_first->DTS) , ch->clock->speed)) ; - } } else { ch->BufferTime = 0; } @@ -419,7 +438,7 @@ static void Channel_UpdateBufferTime(GF_Channel *ch) } /*dispatch the AU in the DB*/ -static void Channel_DispatchAU(GF_Channel *ch, u32 duration) +static void gf_es_dispatch_au(GF_Channel *ch, u32 duration) { u32 time; GF_DBUnit *au; @@ -432,6 +451,14 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) return; } + if (ch->odm->codec && ch->odm->codec->decode_only_rap && !ch->IsRap) { + if (ch->buffer) { + gf_free(ch->buffer); + ch->buffer = NULL; + } + return; + } + au = gf_db_unit_new(); if (!au) { gf_free(ch->buffer); @@ -443,6 +470,8 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) au->CTS = ch->CTS; au->DTS = ch->DTS; if (ch->IsRap) au->flags |= GF_DB_AU_RAP; + if (ch->SeekFlag) au->flags |= GF_DB_AU_IS_SEEK; + if (ch->CTS_past_offset) { au->CTS = ch->CTS_past_offset; au->flags |= GF_DB_AU_CTS_IN_PAST; @@ -455,8 +484,11 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) au->data = ch->buffer; au->dataLength = ch->len; au->PaddingBits = ch->padingBits; + au->sender_ntp = ch->sender_ntp; + ch->sender_ntp = 0; ch->IsRap = 0; + ch->SeekFlag = 0; ch->padingBits = 0; au->next = NULL; ch->buffer = NULL; @@ -470,6 +502,23 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) gf_es_lock(ch, 1); + + if( (ch->MaxBuffer && (ch->BufferTime > (s32) ( 100*ch->MaxBuffer)) ) + || (ch->AU_Count>10000) + ) { + if (ch->AU_Count>10000) { + GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): Something really wrong, too many AUs (%d) in decoding buffer - trashing buffers\n", ch->esd->ESID, ch->odm->net_service->url, ch->AU_Count)); + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): Something really wrong, decoding buffer exceeded (%d ms vs %d max) - trashing buffers\n", ch->esd->ESID, ch->odm->net_service->url, ch->BufferTime, ch->MaxBuffer)); + + } + gf_db_unit_del(ch->AU_buffer_first->next); + ch->AU_buffer_first->next = NULL; + ch->AU_buffer_last = ch->AU_buffer_first; + ch->AU_Count = 1; + ch->BufferTime = 0; + } + if (ch->service && ch->service->cache) { GF_SLHeader slh; memset(&slh, 0, sizeof(GF_SLHeader)); @@ -486,7 +535,8 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) ch->AU_buffer_last = au; ch->AU_Count = 1; } else { - if (!ch->recompute_dts && (ch->AU_buffer_last->DTS<=au->DTS)) { + //if speed negative always append to buffer + if ((ch->clock->speed < 0) || (!ch->recompute_dts && (ch->AU_buffer_last->DTS <= au->DTS))) { ch->AU_buffer_last->next = au; ch->AU_buffer_last = ch->AU_buffer_last->next; } @@ -603,7 +653,7 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) au_prev = au_prev->next; } assert(au_prev); - if (au_prev->next->DTS==au->DTS) { + if (au_prev->next && (au_prev->next->DTS==au->DTS)) { gf_free(au->data); gf_free(au); } else { @@ -615,11 +665,11 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) ch->AU_Count += 1; } - Channel_UpdateBufferTime(ch); + gf_es_update_buffer_time(ch); ch->au_duration = 0; if (duration) ch->au_duration = (u32) ((u64)1000 * duration / ch->ts_res); - GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s) - Dispatch AU DTS %d - CTS %d - RAP %d - size %d time %d Buffer %d Nb AUs %d - First AU relative timing %d\n", ch->esd->ESID, ch->odm->net_service->url, au->DTS, au->CTS, au->flags&1, au->dataLength, gf_clock_real_time(ch->clock), ch->BufferTime, ch->AU_Count, ch->AU_buffer_first ? ch->AU_buffer_first->DTS - gf_clock_time(ch->clock) : 0 )); + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s) - Dispatch AU DTS %d - CTS %d - RAP %d - Seek %d - size %d time %d Buffer %d Nb AUs %d - First AU relative timing %d\n", ch->esd->ESID, ch->odm->net_service->url, au->DTS, au->CTS, au->flags & GF_DB_AU_RAP, (au->flags & GF_DB_AU_IS_SEEK) ? 1 :0, au->dataLength, gf_clock_real_time(ch->clock), ch->BufferTime, ch->AU_Count, ch->AU_buffer_first ? ch->AU_buffer_first->DTS - gf_clock_time(ch->clock) : 0 )); /*little optimisation: if direct dispatching is possible, try to decode the AU we must lock the media scheduler to avoid deadlocks with other codecs accessing the scene or @@ -667,10 +717,12 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) } } + gf_es_lock(ch, 0); + time = gf_term_get_time(ch->odm->term); if (ch->BufferOn) { ch->last_au_time = time; - Channel_UpdateBuffering(ch, 1); + gf_es_update_buffering(ch, 1); } else { /*trigger the data progress every 500 ms*/ if (ch->last_au_time + 500 > time) { @@ -678,11 +730,25 @@ static void Channel_DispatchAU(GF_Channel *ch, u32 duration) ch->last_au_time = time; } } +} - gf_es_lock(ch, 0); + +static void gf_es_init_clock(GF_Channel *ch, u32 TS) +{ + ch->clock->clock_init = 0; + + gf_clock_set_time(ch->clock, TS); + //once the clock is init, reset any seek request at parent scene level + if (ch->odm->parentscene ) + ch->odm->parentscene->root_od->media_start_time = 0; + //this is the root + else ch->odm->media_start_time = 0; + + ch->IsClockInit = 1; } -void Channel_ReceiveSkipSL(GF_ClientService *serv, GF_Channel *ch, const char *StreamBuf, u32 StreamLength) + +void gf_es_receive_skip_sl(GF_ClientService *serv, GF_Channel *ch, const char *StreamBuf, u32 StreamLength) { GF_DBUnit *au; if (!StreamLength) return; @@ -700,8 +766,7 @@ void Channel_ReceiveSkipSL(GF_ClientService *serv, GF_Channel *ch, const char *S /*if channel owns the clock, start it*/ if (ch->clock && !ch->IsClockInit) { if (gf_es_owns_clock(ch)) { - gf_clock_set_time(ch->clock, 0); - ch->IsClockInit = 1; + gf_es_init_clock(ch, 0); ch->seed_ts = 0; } if (ch->clock->clock_init && !ch->IsClockInit) { @@ -720,56 +785,43 @@ void Channel_ReceiveSkipSL(GF_ClientService *serv, GF_Channel *ch, const char *S ch->AU_Count += 1; } - Channel_UpdateBufferTime(ch); + gf_es_update_buffer_time(ch); if (ch->BufferOn) { ch->last_au_time = gf_term_get_time(ch->odm->term); - Channel_UpdateBuffering(ch, 1); + gf_es_update_buffering(ch, 1); } gf_es_lock(ch, 0); } - static void gf_es_check_timing(GF_Channel *ch) { /*the first data received inits the clock - this is needed to handle clock dependencies on non-initialized streams (eg, bifs/od depends on audio/video clock)*/ if (!ch->clock->clock_init) { if (!ch->clock->use_ocr) { - gf_clock_set_time(ch->clock, ch->CTS); + gf_es_init_clock(ch, ch->DTS); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Forcing clock initialization at STB %d - AU DTS %d CTS %d\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->DTS, ch->CTS)); - ch->IsClockInit = 1; } } /*channel is the OCR, force a re-init of the clock since we cannot assume the AU used to init the clock was not sent ahead of time*/ else if (gf_es_owns_clock(ch)) { if (!ch->clock->use_ocr) { - ch->clock->clock_init = 0; - gf_clock_set_time(ch->clock, ch->DTS); + gf_es_init_clock(ch, ch->DTS); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: initializing clock at STB %d - AU DTS %d - %d buffering - OTB %d\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->DTS, ch->clock->Buffering, gf_clock_time(ch->clock) )); - ch->IsClockInit = 1; } } - /*if channel is not the OCR, shift all time stamps to match the current time at clock init*/ else if (!ch->IsClockInit ) { -// ch->ts_offset += gf_clock_real_time(ch->clock); - if (ch->clock->clock_init) { - ch->IsClockInit = 1; - if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { -// ch->ts_offset += gf_clock_real_time(ch->clock) - ch->CTS; - } - } + ch->IsClockInit = 1; } /*deal with some broken DMB streams were the timestamps on BIFS/OD are not set (0) or completely out of sync of the OCR clock (usually audio). If the audio codec (BSAC ...) is not found, we force re-initializing of the clock so that video can play back correctly*/ else if (gf_clock_time(ch->clock) * 1000 < ch->DTS) { - ch->clock->clock_init = 0; - gf_clock_set_time(ch->clock, ch->DTS); + gf_es_init_clock(ch, ch->DTS); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: re-initializing clock at STB %d - AU DTS %d - %d buffering\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), ch->DTS, ch->clock->Buffering)); - ch->IsClockInit = 1; } } @@ -785,8 +837,7 @@ void gf_es_dispatch_raw_media_au(GF_Channel *ch, char *payload, u32 payload_size now = gf_clock_real_time(ch->clock); if (cts + ch->MinBuffer < now) { if (ch->MinBuffer && (ch->is_raw_channel==2)) { - ch->clock->clock_init = 0; - gf_clock_set_time(ch->clock, cts); + gf_es_init_clock(ch, cts); GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] Raw Frame dispatched at OTB %u but frame TS is %u ms - adjusting clock\n", ch->odm->OD->objectDescriptorID, now, cts)); } else { GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] Raw Frame dispatched at OTB %u but frame TS is %u ms - DROPPING\n", ch->odm->OD->objectDescriptorID, now, cts)); @@ -847,7 +898,7 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo if (ch->es_state != GF_ESM_ES_RUNNING) return; if (ch->skip_sl) { - Channel_ReceiveSkipSL(serv, ch, payload, payload_size); + gf_es_receive_skip_sl(serv, ch, payload, payload_size); return; } if (ch->is_raw_channel) { @@ -871,8 +922,13 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo hdr = *header; } + //if PCR is not trusted and this is not a PCR discontinuity, ignore it + if (ch->clock->broken_pcr && (hdr.m2ts_pcr == 1)) { + hdr.OCRflag = 0; + } + /*we ignore OCRs for the moment*/ - if (hdr.OCRflag) { + if (hdr.OCRflag==1) { if (!ch->IsClockInit) { /*channel is the OCR, re-initialize the clock with the proper OCR*/ if (gf_es_owns_clock(ch)) { @@ -897,7 +953,8 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo ch->clock->clock_init = 0; ch->prev_pcr_diff = 0; - gf_clock_set_time(ch->clock, OCR_TS); + gf_es_init_clock(ch, OCR_TS); + /*many TS streams deployed with HLS have broken PCRs - we will check their consistency when receiving the first AU with DTS/CTS on this channel*/ ch->clock->probe_ocr = 1; @@ -913,9 +970,11 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo gf_es_receive_sl_packet(serv, ch, payload, payload_size, header, reception_status); return; } else { + Bool discontinuity = (hdr.m2ts_pcr==2) ? GF_TRUE : GF_FALSE; u32 ck; u32 OCR_TS; s32 pcr_diff, pcr_pcrprev_diff; + if (hdr.m2ts_pcr) { OCR_TS = (u32) ( hdr.objectClockReference / 27000); } else { @@ -926,20 +985,29 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo pcr_diff = (s32) OCR_TS - (s32) ck; pcr_pcrprev_diff = pcr_diff - ch->prev_pcr_diff; - GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %u got OCR %u (original TS "LLU") - diff %d%s (diff with prev OCR %d)\n", ch->esd->ESID, gf_clock_real_time(ch->clock), OCR_TS, hdr.objectClockReference, pcr_diff, (hdr.m2ts_pcr==2) ? " - PCR Discontinuity flag" : "", pcr_pcrprev_diff)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %u got OCR %u (original TS "LLU") - diff %d%s (diff with prev OCR %d)\n", ch->esd->ESID, gf_clock_real_time(ch->clock), OCR_TS, hdr.objectClockReference, pcr_diff, discontinuity ? " - PCR Discontinuity flag" : "", pcr_pcrprev_diff)); //PCR loop or disc - use 10 sec as a threshold - it may happen that video is sent up to 4 or 5 seconds ahead of the PCR in some systems - if (ch->IsClockInit && ABS(pcr_pcrprev_diff) > 10000) { + //1- check the PCR diff is greater than 10 seconds + //2- check the diff between this PCR diff and last PCR diff is greater than 10 seconds + //the first test is used to avoid disc detecting when the TS is sent in burst (eg DASH): + if (ch->IsClockInit && (ABS(pcr_diff) > 10000) && (ABS(pcr_pcrprev_diff) > 10000) ) { + discontinuity = GF_TRUE; + } + + if (discontinuity) { GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: At OTB %u detected PCR %s (PCR diff %d - last PCR diff %d)\n", ch->esd->ESID, gf_clock_real_time(ch->clock), (hdr.m2ts_pcr==2) ? "discontinuity" : "looping", pcr_diff, ch->prev_pcr_diff)); gf_clock_discontinuity(ch->clock, ch->odm->parentscene, (hdr.m2ts_pcr==2) ? GF_TRUE : GF_FALSE); //and re-init timing gf_es_receive_sl_packet(serv, ch, payload, payload_size, header, reception_status); //do not probe OCR after a discontinuity - ch->clock->probe_ocr = 0; + ch->clock->probe_ocr = (hdr.m2ts_pcr==2) ? 0 : 1; + ch->last_pcr = hdr.objectClockReference; return; } else { ch->prev_pcr_diff = pcr_diff; + ch->last_pcr = hdr.objectClockReference; } } if (!payload_size) return; @@ -948,7 +1016,7 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo /*check state*/ if (!ch->codec_resilient && (reception_status==GF_CORRUPTED_DATA)) { - Channel_WaitRAP(ch); + gf_es_wait_rap(ch); return; } @@ -980,12 +1048,12 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo if (ch->pck_sn == (u32) (1<esd->slConfig->packetSeqNumLength) ) { if (hdr.packetSequenceNumber) { GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: packet loss, droping & wait RAP\n", ch->esd->ESID)); - Channel_WaitRAP(ch); + gf_es_wait_rap(ch); return; } } else if (ch->pck_sn + 1 != hdr.packetSequenceNumber) { GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: packet loss, droping & wait RAP\n", ch->esd->ESID)); - Channel_WaitRAP(ch); + gf_es_wait_rap(ch); return; } } @@ -1025,7 +1093,7 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo } if (ch->codec_resilient) { if (!ch->IsClockInit && !ch->skip_time_check_for_pending) gf_es_check_timing(ch); - Channel_DispatchAU(ch, 0); + gf_es_dispatch_au(ch, 0); } else { gf_free(ch->buffer); ch->buffer = NULL; @@ -1035,6 +1103,7 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo } if (init_ts) { + if (hdr.sender_ntp) ch->sender_ntp = hdr.sender_ntp; /*Get CTS */ if (ch->esd->slConfig->useTimestampsFlag) { if (hdr.compositionTimeStampFlag) { @@ -1066,21 +1135,26 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo } if (ch->odm->parentscene && ch->odm->parentscene->root_od->addon) { - ch->DTS = (u32) gf_scene_adjust_timestamp_for_addon(ch->odm->parentscene, ch->DTS, ch->odm->parentscene->root_od->addon); - ch->CTS = (u32) gf_scene_adjust_timestamp_for_addon(ch->odm->parentscene, ch->CTS, ch->odm->parentscene->root_od->addon); + s64 res = gf_scene_adjust_timestamp_for_addon(ch->odm->parentscene->root_od->addon, ch->CTS); + if (res<0) return; + ch->CTS = (u32) res; + + res = gf_scene_adjust_timestamp_for_addon(ch->odm->parentscene->root_od->addon, ch->DTS); + if (res<0) res=0; + ch->DTS = (u32) res; + } if (ch->clock->probe_ocr && gf_es_owns_clock(ch)) { s32 diff_ts = ch->DTS; diff_ts -= ch->clock->init_time; if (ABS(diff_ts) > 10000) { - GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d: invalid clock reference detected - DTS %d but OCR %d - using DTS as OCR\n", ch->esd->ESID, ch->DTS, ch->clock->init_time)); - ch->clock->clock_init = 0; - gf_clock_set_time(ch->clock, ch->DTS-1000); + GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] ES%d: invalid clock reference detected - DTS %d but OCR %d - using DTS as OCR\n", ch->esd->ESID, ch->DTS, ch->clock->init_time)); + gf_es_init_clock(ch, ch->DTS-1000); + ch->clock->broken_pcr = 1; } ch->clock->probe_ocr = 0; } - ch->no_timestamps = 0; } else { ch->no_timestamps = 1; @@ -1119,6 +1193,11 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo } else { ch->AULength = 0; } + + //temp hack + if (ch->odm->lower_layer_odm) + hdr.randomAccessPointFlag = 1; + /*carousel for repeated AUs.*/ if (ch->carousel_type) { /* not used : Bool use_rap = hdr.randomAccessPointFlag; */ @@ -1202,18 +1281,26 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo /*no carousel signaling, tune-in at first RAP*/ else if (hdr.randomAccessPointFlag) { - ch->stream_state = 0; - GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: RAP AU received\n", ch->esd->ESID)); + if (ch->stream_state) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): RAP AU received\n", ch->esd->ESID, ch->odm->net_service->url)); + ch->stream_state = 0; + } } /*waiting for RAP, return*/ else if (ch->stream_state) { - GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: Waiting for RAP - skipping AU (DTS %d)\n", ch->esd->ESID, ch->DTS)); - return; + if (ch->esd->dependsOnESID || ch->odm->lower_layer_odm) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): Considering AU is RAP on enhancement layer\n", ch->esd->ESID, ch->odm->net_service->url)); + ch->stream_state = 0; + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d (%s): Waiting for RAP - skipping AU (DTS %d)\n", ch->esd->ESID, ch->odm->net_service->url, ch->DTS)); + return; + } } } /*update the RAP marker on a packet base (to cope with AVC/H264 NALU->AU reconstruction)*/ if (hdr.randomAccessPointFlag) ch->IsRap = 1; + if (hdr.seekFlag) ch->SeekFlag = 1; /*get AU end state*/ OldLength = ch->buffer ? ch->len : 0; @@ -1223,7 +1310,6 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo /*init clock if end of AU or if header is valid*/ if ((EndAU || init_ts) && !ch->IsClockInit && !ch->skip_time_check_for_pending) { - ch->skip_time_check_for_pending = 0; gf_es_check_timing(ch); } @@ -1232,17 +1318,17 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo if (!payload_size && EndAU && ch->buffer) { GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: Empty packet, flushing buffer\n", ch->esd->ESID)); - Channel_DispatchAU(ch, 0); + gf_es_dispatch_au(ch, 0); return; } if (!payload_size) return; - /*missed begining, unusable*/ + /*missed beginning, unusable*/ if (!ch->buffer && !NewAU) { if (ch->esd->slConfig->useAccessUnitStartFlag) { GF_LOG(GF_LOG_ERROR, GF_LOG_SYNC, ("[SyncLayer] ES%d: missed begin of AU\n", ch->esd->ESID)); } - if (ch->codec_resilient) NewAU = 1; + if (ch->codec_resilient) NewAU = GF_TRUE; else return; } @@ -1289,7 +1375,7 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo /*restart*/ if (evt.restart_requested) { if (ch->odm->parentscene->is_dynamic_scene) { - gf_scene_restart_dynamic(ch->odm->parentscene, 0); + gf_scene_restart_dynamic(ch->odm->parentscene, 0, 0, 0); } else { mediacontrol_restart(ch->odm); } @@ -1320,7 +1406,7 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo if (hdr.paddingFlag) ch->padingBits = hdr.paddingBits; } - if (EndAU) Channel_DispatchAU(ch, hdr.au_duration); + if (EndAU) gf_es_dispatch_au(ch, hdr.au_duration); gf_es_lock(ch, 0); } @@ -1330,12 +1416,12 @@ void gf_es_receive_sl_packet(GF_ClientService *serv, GF_Channel *ch, char *paylo void gf_es_on_eos(GF_Channel *ch) { if (!ch || ch->IsEndOfStream) return; - ch->IsEndOfStream = 1; + ch->IsEndOfStream = GF_TRUE; /*flush buffer*/ gf_es_buffer_off(ch); if (ch->len) - Channel_DispatchAU(ch, 0); + gf_es_dispatch_au(ch, 0); GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Channel %d is end of stream\n", ch->odm->OD->objectDescriptorID, (u32) ch->esd->ESID)); gf_odm_on_eos(ch->odm, ch); @@ -1366,17 +1452,11 @@ GF_DBUnit *gf_es_get_au(GF_Channel *ch) /*we must update buffering before fetching in order to stop buffering for streams with very few updates (especially streams with one update, like most of OD streams)*/ - if (ch->BufferOn && ch->AU_buffer_first) Channel_UpdateBuffering(ch, 0); + if (ch->BufferOn && ch->AU_buffer_first) gf_es_update_buffering(ch, 0); gf_mx_v(ch->mx); -#if 0 - if (ch->odm->parentscene->active_addon && !ch->odm->parentscene->active_addon->started) { - return NULL; - } -#endif - if (ch->BufferOn) { - if (ch->first_au_fetched || !ch->AU_buffer_first || !ch->AU_buffer_first->next || !ch->odm->parentscene->active_addon || !ch->odm->parentscene->active_addon->started) + if (ch->first_au_fetched || !ch->AU_buffer_first || !ch->AU_buffer_first->next) return NULL; } return ch->AU_buffer_first; @@ -1461,7 +1541,7 @@ GF_DBUnit *gf_es_get_au(GF_Channel *ch) /*restart*/ if (evt.restart_requested) { if (ch->odm->parentscene->is_dynamic_scene) { - gf_scene_restart_dynamic(ch->odm->parentscene, 0); + gf_scene_restart_dynamic(ch->odm->parentscene, 0, 0, 0); } else { mediacontrol_restart(ch->odm); } @@ -1488,15 +1568,16 @@ GF_DBUnit *gf_es_get_au(GF_Channel *ch) } ch->AU_buffer_pull->CTS = (u32) ch->CTS; ch->AU_buffer_pull->DTS = (u32) ch->DTS; + ch->AU_buffer_pull->sender_ntp = ch->sender_ntp; ch->AU_buffer_pull->PaddingBits = ch->padingBits; if (ch->pull_forced_buffer) { assert(ch->BufferOn); ch->pull_forced_buffer=0; gf_es_buffer_off(ch); - Channel_UpdateBuffering(ch, 1); + gf_es_update_buffering(ch, 1); } else if (is_new_data && !ch->first_au_fetched) { - Channel_UpdateBuffering(ch, 1); + gf_es_update_buffering(ch, 1); } return ch->AU_buffer_pull; @@ -1569,10 +1650,10 @@ void gf_es_drop_au(GF_Channel *ch) if (!ch->AU_buffer_first) ch->AU_buffer_last = NULL; - Channel_UpdateBufferTime(ch); + gf_es_update_buffer_time(ch); /*if we get under our limit, rebuffer EXCEPT WHEN EOS is signaled*/ - if (!ch->IsEndOfStream && Channel_NeedsBuffering(ch, 1)) { + if (!ch->IsEndOfStream && gf_es_needs_buffering(ch, 1)) { gf_es_buffer_on(ch); gf_term_service_media_event(ch->odm, GF_EVENT_MEDIA_WAITING); } @@ -1592,7 +1673,7 @@ void gf_es_lock(GF_Channel *ch, u32 LockIt) } /*refresh all ODs when an non-interactive stream is found*/ -static void refresh_non_interactive_clocks(GF_ObjectManager *odm) +static void gf_es_refresh_non_interactive_clocks(GF_ObjectManager *odm) { u32 i, j; GF_Channel *ch; @@ -1655,7 +1736,7 @@ void gf_es_on_connect(GF_Channel *ch) if (gf_term_service_command(ch->service, &com)!=GF_OK) { ch->clock->no_time_ctrl = 1; ch->odm->flags |= GF_ODM_NO_TIME_CTRL; - refresh_non_interactive_clocks(ch->odm); + gf_es_refresh_non_interactive_clocks(ch->odm); } /*signal channel state*/ @@ -1713,11 +1794,17 @@ void gf_es_on_connect(GF_Channel *ch) } /*get duration*/ + memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_CHAN_DURATION; com.base.on_channel = ch; if (gf_term_service_command(ch->service, &com) == GF_OK) { - if (com.duration.duration>=0) + if (com.duration.duration>=0) { gf_odm_set_duration(ch->odm, ch, (u64) (1000*com.duration.duration)); + } + + if ((com.duration.duration<=0) && (com.duration.time_shift_buffer>0)) { + gf_odm_set_timeshift_depth(ch->odm, ch, com.duration.time_shift_buffer); + } } } diff --git a/src/terminal/clock.c b/src/terminal/clock.c index c601713..b73f6ba 100644 --- a/src/terminal/clock.c +++ b/src/terminal/clock.c @@ -33,7 +33,6 @@ GF_Clock *NewClock(GF_Terminal *term) tmp->mx = gf_mx_new("Clock"); tmp->term = term; tmp->speed = FIX_ONE; - if (term->play_state) tmp->Paused = 1; tmp->data_timeout = term->net_data_timeout; return tmp; } @@ -59,7 +58,7 @@ GF_Clock *gf_clock_find(GF_List *Clocks, u16 clockID, u16 ES_ID) return NULL; } -GF_Clock *CK_LookForClockDep(GF_Scene *scene, u16 clockID) +static GF_Clock *gf_ck_look_for_clock_dep(GF_Scene *scene, u16 clockID) { u32 i, j; GF_Channel *ch; @@ -82,7 +81,7 @@ GF_Clock *CK_LookForClockDep(GF_Scene *scene, u16 clockID) } /*remove clocks created due to out-of-order OCR dependencies*/ -void CK_ResolveClockDep(GF_List *clocks, GF_Scene *scene, GF_Clock *ck, u16 Clock_ESID) +static void gf_ck_resolve_clock_dep(GF_List *clocks, GF_Scene *scene, GF_Clock *ck, u16 Clock_ESID) { u32 i, j; GF_Clock *clock; @@ -135,7 +134,7 @@ GF_Clock *gf_clock_attach(GF_List *clocks, GF_Scene *scene, u16 clockID, u16 ES_ /*ck dep can only be solved if in the main service*/ check_dep = (scene->root_od->net_service && scene->root_od->net_service->Clocks==clocks) ? GF_TRUE : GF_FALSE; /*this partly solves a->b->c*/ - if (!tmp && check_dep) tmp = CK_LookForClockDep(scene, clockID); + if (!tmp && check_dep) tmp = gf_ck_look_for_clock_dep(scene, clockID); if (!tmp) { tmp = NewClock(scene->root_od->term); tmp->clockID = clockID; @@ -143,7 +142,7 @@ GF_Clock *gf_clock_attach(GF_List *clocks, GF_Scene *scene, u16 clockID, u16 ES_ } else { if (tmp->clockID == ES_ID) tmp->clockID = clockID; /*this finally solves a->b->c*/ - if (check_dep && (tmp->clockID != ES_ID)) CK_ResolveClockDep(clocks, scene, tmp, ES_ID); + if (check_dep && (tmp->clockID != ES_ID)) gf_ck_resolve_clock_dep(clocks, scene, tmp, ES_ID); } if (hasOCR >= 0) tmp->use_ocr = hasOCR; return tmp; @@ -160,6 +159,8 @@ void gf_clock_reset(GF_Clock *ck) ck->init_time = 0; ck->StartTime = 0; ck->has_seen_eos = 0; + ck->media_time_at_init = 0; + ck->has_media_time_shift = 0; } void gf_clock_stop(GF_Clock *ck) @@ -173,20 +174,11 @@ void gf_clock_set_time(GF_Clock *ck, u32 TS) if (!ck->clock_init) { ck->init_time = TS; ck->clock_init = 1; + ck->broken_pcr = 0; ck->drift = 0; /*update starttime and pausetime even in pause mode*/ ck->PauseTime = ck->StartTime = gf_term_get_time(ck->term); - if (ck->term->play_state) ck->Paused ++; } -#if 0 - /*TODO: test with pure OCR streams*/ - else if (ck->use_ocr) { - /*just update the drift - we could also apply a drift algo*/ - u32 now = gf_clock_real_time(ck); - s32 drift = (s32) TS - (s32) now; - ck->drift += drift; - } -#endif } @@ -220,19 +212,29 @@ u32 gf_clock_real_time(GF_Clock *ck) assert(ck); if (!ck->clock_init) return ck->StartTime; time = ck->Paused > 0 ? ck->PauseTime : gf_term_get_time(ck->term); + #ifdef GPAC_FIXED_POINT - time = ck->discontinuity_time + ck->init_time + (time - ck->StartTime) * FIX2INT(100*ck->speed) / 100; + + if ((ck->speed < 0) && ((s32) ck->init_time < FIX2INT( (-ck->speed * 100) * (time - ck->StartTime)) / 100 ) ) { + time = 0; + } else { + time = ck->discontinuity_time + ck->init_time + (time - ck->StartTime) * FIX2INT(100*ck->speed) / 100; + } + #else + if ((ck->speed < 0) && ((s32) ck->init_time < (-ck->speed) * (time - ck->StartTime))) { time = 0; - } - else { + } else { time = ck->discontinuity_time + (u32) ( ck->init_time + ck->speed * (time - ck->StartTime) ); } + #endif + return time; } +GF_EXPORT u32 gf_clock_time(GF_Clock *ck) { u32 time = gf_clock_real_time(ck); @@ -240,10 +242,20 @@ u32 gf_clock_time(GF_Clock *ck) return time - ck->drift; } -u32 gf_clock_elapse_time(GF_Clock *ck) +u32 gf_clock_media_time(GF_Clock *ck) { - if (ck->no_time_ctrl) return gf_clock_time(ck) - ck->init_time; - return gf_clock_time(ck); + u32 t; + if (!ck) return 0; + if (!ck->has_seen_eos && ck->last_TS_rendered) t = ck->last_TS_rendered; + else t = gf_clock_time(ck); + //if media time is not mapped, we consider that the timestamps are aligned with the media time + if (ck->has_media_time_shift) { + if (t>ck->init_time) t -= ck->init_time; + else t=0; + + t += ck->media_time_at_init; + } + return t; } @@ -302,7 +314,7 @@ void gf_clock_discontinuity(GF_Clock *ck, GF_Scene *scene, Bool is_pcr_discontin i=0; while ((ch = (GF_Channel*)gf_list_enum(scene->root_od->channels, &i))) { if (ch->clock == ck) { - gf_es_reset_timing(ch); + gf_es_reset_timing(ch, is_pcr_discontinuity); } } j=0; @@ -313,28 +325,27 @@ void gf_clock_discontinuity(GF_Clock *ck, GF_Scene *scene, Bool is_pcr_discontin i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) { if (ch->clock == ck) { - //on clock looping we force emptying all buffer - //on clock disc we should only reset timing, but this needs further debugging - if (!is_pcr_discontinuity && odm->codec && gf_term_lock_codec(odm->codec, GF_TRUE, GF_FALSE)) { - gf_es_reset_buffers(ch); - ch->IsClockInit = 0; - gf_term_lock_codec(odm->codec, GF_FALSE, GF_FALSE); - GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] Reinitializing buffers for ES%d\n", ch->esd->ESID)); - } else { -// gf_es_reset_timing(ch); -// ch->IsClockInit = 0; - - gf_es_reset_buffers(ch); - ch->IsClockInit = 0; - - GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] Reinitializing timing for ES%d\n", ch->esd->ESID)); - } + gf_es_reset_timing(ch, is_pcr_discontinuity); + + ch->CTS = ch->DTS = 0; + GF_LOG(GF_LOG_WARNING, GF_LOG_SYNC, ("[SyncLayer] Reinitializing timing for ES%d\n", ch->esd->ESID)); if (ch->odm->codec && ch->odm->codec->CB) gf_cm_reset_timing(ch->odm->codec->CB); - } } } - gf_clock_reset(ck); + + gf_scene_reset_addons(scene); + + if (ck->has_media_time_shift) { + u32 new_media_time = ck->media_time_at_init + gf_clock_time(ck) - ck->init_time; + + gf_clock_reset(ck); + + ck->has_media_time_shift = 1; + ck->media_time_at_init = new_media_time; + } else { + gf_clock_reset(ck); + } } diff --git a/src/terminal/decoder.c b/src/terminal/decoder.c index 81fd459..66820b2 100644 --- a/src/terminal/decoder.c +++ b/src/terminal/decoder.c @@ -47,7 +47,7 @@ GF_Codec *gf_codec_new(GF_ObjectManager *odm, GF_ESD *base_layer, s32 PL, GF_Err case GPAC_OTI_VIDEO_SHVC: case GPAC_OTI_VIDEO_SVC: odm->scalable_addon = 1; - odm->parentscene->root_od->addon->scalable_type = 1; + odm->parentscene->root_od->addon->addon_type = GF_ADDON_TYPE_SCALABLE; *e = GF_OK; //fixme - we need a way to signal dependencies accross services!! base_layer->dependsOnESID = 0xFFFF; @@ -116,7 +116,8 @@ GF_Err gf_codec_add_channel(GF_Codec *codec, GF_Channel *ch) GF_CodecCapability cap; u32 min, max; - + if (ch && ch->odm && !ch->is_pulling && (ch->MaxBuffer <= ch->odm->term->low_latency_buffer_max)) + codec->flags |= GF_ESM_CODEC_IS_LOW_LATENCY; /*only for valid codecs (eg not OCR)*/ if (codec->decio) { @@ -351,39 +352,44 @@ Bool gf_codec_remove_channel(GF_Codec *codec, struct _es_channel *ch) } -static void codec_update_stats(GF_Codec *codec, u32 dataLength, u64 dec_time, u32 DTS) +static void codec_update_stats(GF_Codec *codec, u32 dataLength, u64 dec_time, u32 DTS, Bool is_rap) { codec->total_dec_time += dec_time; codec->last_frame_time = gf_sys_clock(); if (!codec->nb_dec_frames) { codec->first_frame_time = codec->last_frame_time; - codec->min_frame_dur = 0; + codec->min_frame_dur = (u32) -1; } codec->nb_dec_frames++; - if (dec_time>codec->max_dec_time) codec->max_dec_time = dec_time; + if (is_rap) { + codec->nb_iframes ++; + if (dec_time>codec->max_iframes_time) codec->max_iframes_time = (u32) dec_time; + codec->total_iframes_time += dec_time; + } + if (dec_time>codec->max_dec_time) codec->max_dec_time = (u32) dec_time; - if (DTS - codec->last_unit_dts > codec->min_frame_dur) { - codec->min_frame_dur = DTS - codec->last_unit_dts; + + if (DTS - codec->last_unit_dts < codec->min_frame_dur) { + //might happen with some AVI with ffmpeg ... + if (DTS > codec->last_unit_dts) + codec->min_frame_dur = DTS - codec->last_unit_dts; } if (dataLength) { - if (codec->last_stat_start + 2000 <= DTS) { - if (!codec->cur_bit_size) { - codec->last_stat_start = DTS; - } else { + if (!codec->cur_bit_size || (codec->stat_start > DTS)) { + codec->stat_start = DTS; + codec->cur_bit_size = 8*dataLength; + } else { + if (codec->last_stat_start + 2000 <= DTS) { codec->avg_bit_rate = (u32) (codec->cur_bit_size * (1000.0 / (DTS-codec->last_stat_start) ) ); if (codec->avg_bit_rate > codec->max_bit_rate) codec->max_bit_rate = codec->avg_bit_rate; codec->last_stat_start = DTS; codec->cur_bit_size = 0; } + codec->cur_bit_size += 8*dataLength; } - codec->cur_bit_size += 8*dataLength; - if (!codec->tot_bit_size) { - codec->stat_start = DTS; - } - codec->tot_bit_size += 8*dataLength; } } @@ -452,7 +458,7 @@ refetch_AU: *nextAU = AU; *activeChannel = ch; curCTS = AU->CTS; - } + } //we allow for +/- 1ms drift due to timestamp rounding when converting to milliseconds units else if (cts_diff<=1) { GF_DBUnit *baseAU = *nextAU; @@ -529,18 +535,23 @@ refetch_AU: } } //scalable addon, browse channels in scalable object - if (current_odm->scalable_odm) { + if (current_odm->upper_layer_odm) { if (*nextAU) { - gf_scene_check_addon_restart(current_odm->scalable_odm->parentscene->root_od->addon, (*nextAU)->CTS, (*nextAU)->DTS); + if (gf_scene_check_addon_restart(current_odm->upper_layer_odm->parentscene->root_od->addon, (*nextAU)->CTS, (*nextAU)->DTS)) { + //due to some issues in openhevc we reset the decoder when we restart the scalable addon + GF_CodecCapability cap; + cap.CapCode = GF_CODEC_WAIT_RAP; + gf_codec_set_capability(codec, cap); + } } - current_odm = current_odm->scalable_odm; + current_odm = current_odm->upper_layer_odm; src_channels = current_odm->channels; scalable_check = 1; goto browse_scalable; } - if (scalable_check==1) { - GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Warning, could not find enhancement layer for this AU\n")); + if (*nextAU && (scalable_check==1)) { + GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Warning, could not find enhancement layer for this AU (DTS %d) \n", (*nextAU)->DTS )); } if (codec->is_reordering && *nextAU && codec->first_frame_dispatched) { @@ -618,7 +629,7 @@ static GF_Err SystemCodec_Process(GF_Codec *codec, u32 TimeAvailable) u32 obj_time, mm_level, au_time, cts; u64 now; GF_Scene *scene_locked; - Bool check_next_unit; + Bool check_next_unit = GF_FALSE; GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio; GF_Err e = GF_OK; @@ -628,7 +639,8 @@ static GF_Err SystemCodec_Process(GF_Codec *codec, u32 TimeAvailable) "frame dropping" is done by preventing the compositor from redrawing after an update and decoding following AU so that the compositor is always woken up once all late systems AUs are decoded. This flag is overriden when seeking*/ - check_next_unit = (codec->odm->term->flags & GF_TERM_DROP_LATE_FRAMES) ? 1 : 0; + if ( (codec->odm->term->flags & GF_TERM_DROP_LATE_FRAMES) || (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY) ) + check_next_unit = GF_TRUE; check_unit: @@ -702,7 +714,7 @@ check_unit: else { codec->last_unit_cts = AU->CTS; /*we're droping the frame*/ - if (scene_locked) codec->nb_droped ++; + if (scene_locked) codec->nb_dropped ++; mm_level = GF_CODEC_LEVEL_NORMAL; } @@ -717,7 +729,7 @@ check_unit: /*current media time for system objects is the clock time, since the media is likely to have random updates in time*/ - codec->odm->current_time = gf_clock_time(codec->ck); + codec->odm->media_current_time = obj_time - codec->ck->init_time; now = gf_sys_clock_high_res(); if (codec->odm->term->bench_mode==2) { @@ -727,9 +739,9 @@ check_unit: } now = gf_sys_clock_high_res() - now; - GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d at %d decoded AU TS %d in "LLU" us\n", sdec->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, codec->odm->current_time, AU->CTS, now)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d at %d decoded AU TS %d in "LLU" us\n", sdec->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, obj_time, AU->CTS, now)); - codec_update_stats(codec, AU->dataLength, now, AU->DTS); + codec_update_stats(codec, AU->dataLength, now, AU->DTS, (AU->flags & GF_DB_AU_RAP)); codec->prev_au_size = AU->dataLength; /*destroy this AU*/ @@ -810,10 +822,12 @@ static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable) if (!started) return GF_OK; } - codec->odm->current_time = codec->last_unit_cts = gf_clock_time(codec->ck); + codec->odm->media_current_time = codec->last_unit_cts = gf_clock_time(codec->ck); + codec->odm->media_current_time += codec->ck->media_time_at_init; + codec->odm->media_current_time -= codec->ck->init_time; /*lock scene*/ - GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[PrivateDec] Codec %s Processing at %d\n", sdec->module_name , codec->odm->current_time)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[PrivateDec] Codec %s Processing at %d\n", sdec->module_name, codec->last_unit_cts)); if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK; @@ -821,7 +835,7 @@ static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable) if (codec->odm->term->bench_mode == 2) { e = GF_OK; } else { - e = sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, codec->odm->current_time, GF_CODEC_LEVEL_NORMAL); + e = sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, codec->last_unit_cts, GF_CODEC_LEVEL_NORMAL); } now = gf_sys_clock_high_res() - now; codec->last_unit_dts ++; @@ -835,7 +849,7 @@ static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable) gf_clock_resume(ch->clock); } - codec_update_stats(codec, 0, now, codec->odm->current_time); + codec_update_stats(codec, 0, now, codec->last_unit_cts, 0); gf_mx_v(scene_locked->root_od->term->compositor->mx); @@ -898,11 +912,6 @@ GF_Err gf_codec_resize_composition_buffer(GF_Codec *dec, u32 NewSize) u32 unit_size, audio_buf_len, unit_count; GF_CodecCapability cap; unit_size = NewSize; - /*a bit ugly, make some extra provision for speed >1. this is the drawback of working with pre-allocated memory - for composition, we may get into cases where there will never be enough data for high speeds... - FIXME - WE WILL NEED TO MOVE TO DYNAMIC CU BLOCKS IN ORDER TO SUPPORT ANY SPEED, BUT WHAT IS THE IMPACT - FOR LOW RESOURCES DEVICES ??*/ -// audio_buf_len = 1000; audio_buf_len = 200; cap.CapCode = GF_CODEC_BUFFER_MAX; @@ -919,7 +928,13 @@ GF_Err gf_codec_resize_composition_buffer(GF_Codec *dec, u32 NewSize) dec->CB->Min = unit_count/3; if (!dec->CB->Min) dec->CB->Min = 1; } - if ((dec->type==GF_STREAM_VISUAL) && dec->odm->parentscene->is_dynamic_scene && !dec->odm->parentscene->root_od->addon) { + + //reset bitrate compute + dec->cur_bit_size = 0; + dec->last_stat_start = 0; + + //if dynamic scene, set size + if ((dec->type==GF_STREAM_VISUAL) && dec->odm->parentscene->is_dynamic_scene) { gf_scene_force_size_to_video(dec->odm->parentscene, dec->odm->mo); } return GF_OK; @@ -936,6 +951,7 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) u32 first, obj_time, unit_size; GF_MediaDecoder *mdec = (GF_MediaDecoder*)codec->decio; GF_Err e = GF_OK; + s32 cts_diff; CU = NULL; /*if video codec muted don't decode (try to saves ressources) @@ -944,13 +960,19 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) //cannot output frame, do nothing (we force a channel query before for pull mode) if (codec->CB->Capacity == codec->CB->UnitCount) { - if (codec->CB->UnitCount > 1) return GF_OK; - else if (codec->direct_vout) return GF_OK; + if (codec->Status==GF_ESM_CODEC_PAUSE) { + gf_term_stop_codec(codec, 1); + } + if (codec->CB->UnitCount > 1) return GF_OK; + else if (codec->direct_vout) return GF_OK; } entryTime = gf_sys_clock_high_res(); - if (!codec->odm->term->bench_mode && (codec->odm->term->flags & GF_TERM_DROP_LATE_FRAMES)) - drop_late_frames = 1; + + if (!codec->odm->term->bench_mode) { + if ((codec->odm->term->flags & GF_TERM_DROP_LATE_FRAMES) || (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY)) + drop_late_frames = GF_TRUE; + } /*fetch next AU in DTS order for this codec*/ @@ -1030,15 +1052,65 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) } + + if (codec->ck->speed != codec->check_speed) { + //decrease in speed + if (ABS(codec->check_speed) > ABS(codec->ck->speed)) { + codec->decode_only_rap = 0; + codec->drop_modulo = 0; + codec->drop_count = 0; + } + codec->check_speed = codec->ck->speed; + codec->consecutive_late_frames = 0; + codec->consecutive_ontime_frames = 0; + + if (codec->type==GF_STREAM_AUDIO) { + if (ABS(FIX2FLT(codec->ck->speed)) > 8) { + codec->decode_only_rap = 2; + GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] Speed %g too hight for audio decoder/renderer - skipping decode\n", codec->decio->module_name, FIX2FLT(codec->ck->speed))); + } + } else { + //dynamically decided based on late frames found + } + } + TimeAvailable*=1000; /*try to refill the full buffer*/ first = 1; while (codec->CB->Capacity > codec->CB->UnitCount) { + Bool force_skip = 0; + + if (codec->decode_only_rap) { + //check whether we have to skip decoding this frame + if (AU->flags & GF_DB_AU_RAP) { + if (codec->decode_only_rap==2) { + if (AU->CTS > obj_time + 500) + return GF_OK; + force_skip = 1; + } else if (codec->drop_modulo) { + codec->drop_count ++; + if (codec->drop_count >= codec->drop_modulo) { + codec->drop_count = 0; + } else { + force_skip = 1; + } + } + } else { + force_skip = 1; + } + } + /*set media processing level*/ ch->last_au_was_seek = 0; mmlevel = GF_CODEC_LEVEL_NORMAL; - /*SEEK: if the last frame had the same TS, we are seeking. Ask the codec to drop*/ - if (!ch->skip_sl && codec->last_unit_cts && (codec->last_unit_cts == AU->CTS) && !ch->esd->dependsOnESID) { + + /*explicit seek*/ + if (AU->flags & GF_DB_AU_IS_SEEK) { + mmlevel = GF_CODEC_LEVEL_SEEK; + ch->last_au_was_seek = 1; + } + /*implicit seek: if the last frame had the same TS, we are seeking. Ask the codec to drop*/ + else if (!ch->skip_sl && codec->last_unit_cts && (codec->last_unit_cts == AU->CTS) && !ch->esd->dependsOnESID) { mmlevel = GF_CODEC_LEVEL_SEEK; ch->last_au_was_seek = 1; /*object clock is paused by media control or terminal is paused: exact frame seek*/ @@ -1055,12 +1127,50 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) } } /*only perform drop in normal playback*/ - else if ((codec->ck->speed>0) && (codec->CB->Status == CB_PLAY)) { + else if (!force_skip && (codec->ck->speed >= 0) && (codec->CB->Status == CB_PLAY)) { /*extremely late, set the level to drop NOTE: the 100 ms safety gard is to avoid discarding audio*/ if (!ch->skip_sl && (AU->CTS + (codec->is_reordering ? 1000 : 100) < obj_time) ) { mmlevel = GF_CODEC_LEVEL_DROP; - GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d: frame too late (%d vs %d) - using drop level\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS, obj_time)); + GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: frame too late (CTS %d vs time %d) - using drop level\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS, obj_time)); + +//above 1 out of this threshold frames only shown, move to I-frame only mode. 50 = 1 frame shown out of 2 GOPs at 25hz +#define IFRAME_MODE_THRESHOLD 50 + + codec->consecutive_late_frames++; + codec->consecutive_ontime_frames = 0; + if (codec->check_speed > 1) { + Double speed = (Double) FIX2FLT(codec->ck->speed); + u32 nb_check_frames = codec->decode_only_rap ? 5 : 30; + + if (codec->consecutive_late_frames >= nb_check_frames) { + if (!codec->decode_only_rap) { + codec->drop_modulo += 2; + codec->drop_count = 0; + + GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive late frames at speed %g - increasing frame drop modulo to %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_late_frames, speed, codec->drop_modulo)); + if (codec->drop_modulo > IFRAME_MODE_THRESHOLD) { + + GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive late frames at speed %g with drop modulo %d - moving to I-frame only decoding\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_late_frames, speed, codec->drop_modulo)); + codec->drop_modulo = 0; + codec->drop_count = 0; + codec->decode_only_rap = 1; + } + } else { + codec->drop_modulo += 2; + codec->drop_count = 0; + + GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive late frames at speed %g in I-frame only mode - decoding only one I-frame out of %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_late_frames, speed, codec->drop_modulo)); + } + codec->consecutive_late_frames = 0; + } + //very late even in I-frame mode, drop it + else if (codec->decode_only_rap) { + if (obj_time - AU->CTS > 2000) { + force_skip = 1; + } + } + } if (ch->resync_drift && (AU->CTS + ch->resync_drift < obj_time)) { ch->clock->StartTime += (obj_time - AU->CTS); @@ -1071,17 +1181,37 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) /*we are late according to the media manager*/ else if (codec->PriorityBoost) { mmlevel = GF_CODEC_LEVEL_VERY_LATE; + codec->consecutive_late_frames = 0; + codec->consecutive_ontime_frames ++; } /*otherwise we must have an idea of the load in order to set the right level use the composition buffer for that, only on the first frame*/ - else if (first) { - //if the CB is almost empty set to very late - if (codec->CB->UnitCount <= codec->CB->Min+1) { - mmlevel = GF_CODEC_LEVEL_VERY_LATE; - } else if (codec->CB->UnitCount * 2 <= codec->CB->Capacity) { - mmlevel = GF_CODEC_LEVEL_LATE; + else { + codec->consecutive_late_frames = 0; + codec->consecutive_ontime_frames ++; + if (first) { + //if the CB is almost empty set to very late + if (codec->CB->UnitCount <= codec->CB->Min+1) { + mmlevel = GF_CODEC_LEVEL_VERY_LATE; + } else if (codec->CB->UnitCount * 2 <= codec->CB->Capacity) { + mmlevel = GF_CODEC_LEVEL_LATE; + } + first = 0; + } + } + + if (codec->check_speed > 1) { + u32 nb_check_frames = codec->decode_only_rap ? 5 : 30; + //try to decrease the drop rate, but never switch back from I-frame mode only for a given speed + if (codec->consecutive_ontime_frames > nb_check_frames) { + if (codec->drop_modulo) { + codec->drop_modulo -= 2; + codec->drop_count = 0; + GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive on-time frames - Decreasing drop modulo %d (I-frame only mode %d)\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_ontime_frames, codec->drop_modulo, codec->decode_only_rap)); + codec->consecutive_late_frames = 0; + codec->consecutive_ontime_frames = 0; + } } - first = 0; } } @@ -1097,6 +1227,7 @@ static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable) return GF_OK; } + scalable_retry: now = gf_sys_clock_high_res(); @@ -1107,6 +1238,9 @@ scalable_retry: } else if (codec->odm->term->bench_mode==2) { unit_size = 0; gf_cm_abort_buffering(codec->CB); + } else if (force_skip) { + unit_size = 0; + GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d: force drop requested in fast playback for AU CTS %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS)); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d ES%d at %d decoding frame DTS %d CTS %d size %d (%d in channels)\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_real_time(ch->clock), AU->DTS, AU->CTS, AU->dataLength, ch->AU_Count)); e = mdec->ProcessData(mdec, AU->data, AU->dataLength, ch->esd->ESID, &CU->TS, CU->data, &unit_size, AU->PaddingBits, mmlevel); @@ -1136,9 +1270,9 @@ scalable_retry: case GF_PACKED_FRAMES: /*in seek do dispatch output otherwise we will only see the I-frame preceding the seek point*/ if (mmlevel == GF_CODEC_LEVEL_DROP) { - if (drop_late_frames) { + if (drop_late_frames && (codec->CB->UnitCount>1) ) { unit_size = 0; - codec->nb_droped++; + codec->nb_dropped++; } else ch->clock->last_TS_rendered = codec->CB->LastRenderedTS; } @@ -1162,7 +1296,7 @@ scalable_retry: } AU->CTS += deltaTS; } - codec_update_stats(codec, 0, now, 0); + codec_update_stats(codec, 0, now, 0, 0); continue; /*for all cases below, don't release the composition buffer until we are sure we are not @@ -1177,6 +1311,7 @@ scalable_retry: gf_sc_set_video_pending_frame(codec->odm->term->compositor); } } + CU->sender_ntp = AU->sender_ntp; } #if 0 /*if no size and the decoder is not using the composition memory - if the object is in intitial buffering resume it!!*/ @@ -1187,7 +1322,7 @@ scalable_retry: } #endif - codec_update_stats(codec, AU->dataLength, now, AU->DTS); + codec_update_stats(codec, AU->dataLength, now, AU->DTS, (AU->flags & GF_DB_AU_RAP)); if (ch->skip_sl) { if (codec->bytes_per_sec) { codec->cur_audio_bytes += unit_size; @@ -1231,11 +1366,13 @@ scalable_retry: } #endif - /*store current CTS*/ + /*store current CTS - we need to have exclusive access in case a PCR discontinuity remaps timestamps while we decode*/ + gf_es_lock(ch, GF_TRUE); cts = AU->CTS; prev_ch = ch; gf_es_drop_au(ch); + gf_es_lock(ch, GF_FALSE); AU = NULL; if (e) { @@ -1255,16 +1392,42 @@ scalable_retry: if (mmlevel >= GF_CODEC_LEVEL_DROP) { if (drop_late_frames || (mmlevel == GF_CODEC_LEVEL_SEEK) ) { unit_size = 0; - if (drop_late_frames) codec->nb_droped++; + if (drop_late_frames) codec->nb_dropped++; } else - ch->clock->last_TS_rendered = codec->CB->LastRenderedTS; + prev_ch->clock->last_TS_rendered = codec->CB->LastRenderedTS; + } else { + prev_ch->clock->last_TS_rendered = 0; + } + + + if (!codec->decode_only_rap && codec->drop_modulo) { + codec->drop_count++; + if (codec->drop_count==codec->drop_modulo) { + codec->drop_count = 0; + } else { + unit_size = 0; + } + } + + cts_diff = (s32) cts; + cts_diff -= (s32) CU->TS; + if (cts_diff < 0) cts_diff = -cts_diff; + //the decoder is dispathing CTS in the previous time base , override the timestamp ... + if (cts_diff > 20000 ) { + GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[%s] decoded frame CTS %d but input frame CTS %d, lilely due to clock discontinuity\n", codec->decio->module_name, CU->TS, cts)); + CU->TS = cts; } UnlockCompositionUnit(codec, CU, unit_size); + if (unit_size) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[%s] at %d dispatched frame CTS %d in CB\n", codec->decio->module_name, gf_clock_real_time(prev_ch->clock), CU->TS)); + } if (!ch || !AU) { GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because no more input data\n", codec->decio->module_name)); return GF_OK; } + if (force_skip) continue; + now = gf_sys_clock_high_res() - entryTime; /*escape from decoding loop only if above critical limit - this is to avoid starvation on audio*/ if (!ch->esd->dependsOnESID && (codec->CB->UnitCount > codec->CB->Min)) { @@ -1452,7 +1615,10 @@ void gf_codec_set_status(GF_Codec *codec, u32 Status) { if (!codec) return; - if (Status == GF_ESM_CODEC_PAUSE) codec->Status = GF_ESM_CODEC_STOP; + if (Status == GF_ESM_CODEC_PAUSE) { + //stay in PLAY mode if we have a composition buffer, so that the "pause" state still output an initial picture + codec->Status = codec->CB ? GF_ESM_CODEC_PAUSE : GF_ESM_CODEC_STOP; + } else if (Status == GF_ESM_CODEC_BUFFER) codec->Status = GF_ESM_CODEC_PLAY; else if (Status == GF_ESM_CODEC_PLAY) { codec->last_unit_cts = 0; @@ -1460,9 +1626,13 @@ void gf_codec_set_status(GF_Codec *codec, u32 Status) codec->Status = Status; codec->last_stat_start = codec->cur_bit_size = codec->max_bit_rate = codec->avg_bit_rate = 0; codec->nb_dec_frames = 0; - codec->total_dec_time = codec->max_dec_time = 0; + codec->nb_iframes = 0; + codec->max_iframes_time = 0; + codec->total_iframes_time = 0; + codec->total_dec_time = 0; + codec->max_dec_time = 0; codec->cur_audio_bytes = codec->cur_video_frames = 0; - codec->nb_droped = 0; + codec->nb_dropped = 0; codec->nb_repeted_frames = 0; codec->recomputed_cts = 0; codec->first_frame_dispatched = 0; @@ -1470,7 +1640,8 @@ void gf_codec_set_status(GF_Codec *codec, u32 Status) codec->nb_dispatch_skipped = 0; memset(codec->last_unit_signature, 0, sizeof(codec->last_unit_signature)); } - else codec->Status = Status; + else + codec->Status = Status; if (!codec->CB) return; @@ -1478,6 +1649,9 @@ void gf_codec_set_status(GF_Codec *codec, u32 Status) switch (Status) { case GF_ESM_CODEC_PLAY: gf_cm_set_status(codec->CB, CB_PLAY); + if (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY) { + gf_cm_abort_buffering(codec->CB); + } return; case GF_ESM_CODEC_PAUSE: gf_cm_set_status(codec->CB, CB_PAUSE); diff --git a/src/terminal/media_control.c b/src/terminal/media_control.c index 8bb7b5b..7c735e9 100644 --- a/src/terminal/media_control.c +++ b/src/terminal/media_control.c @@ -1,3 +1,5 @@ + + /* * GPAC - Multimedia Framework C SDK * @@ -65,7 +67,7 @@ void mediacontrol_restart(GF_ObjectManager *odm) scene_ck = gf_odm_get_media_clock(odm->parentscene->root_od); if (gf_odm_shares_clock(odm, scene_ck)) { if (odm->parentscene->is_dynamic_scene) - gf_scene_restart_dynamic(odm->parentscene, 0); + gf_scene_restart_dynamic(odm->parentscene, 0, 0, 0); return; } @@ -109,8 +111,6 @@ void mediacontrol_restart(GF_ObjectManager *odm) } -#ifndef GPAC_DISABLE_VRML - Bool MC_URLChanged(MFURL *old_url, MFURL *new_url) { u32 i; @@ -130,7 +130,7 @@ Bool MC_URLChanged(MFURL *old_url, MFURL *new_url) /*resume all objects*/ -void mediacontrol_resume(GF_ObjectManager *odm) +void mediacontrol_resume(GF_ObjectManager *odm, Bool resume_to_live) { u32 i; GF_ObjectManager *ctrl_od; @@ -154,8 +154,20 @@ void mediacontrol_resume(GF_ObjectManager *odm) i=0; while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) { - if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck)) continue; - gf_odm_resume(ctrl_od); + if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck)) + continue; + + if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + gf_clock_resume(ck); + if (resume_to_live) + gf_scene_select_main_addon(in_scene, ctrl_od, GF_FALSE, 0); + } + + if (ctrl_od->subscene) { + mediacontrol_resume(ctrl_od, resume_to_live); + } else { + gf_odm_resume(ctrl_od); + } } } @@ -172,7 +184,10 @@ void mediacontrol_pause(GF_ObjectManager *odm) /*otherwise locate all objects sharing the clock*/ ck = gf_odm_get_media_clock(odm); - if (!ck) return; + if (!ck) { + odm->flags |= GF_ODM_PAUSE_QUEUED; + return; + } in_scene = odm->parentscene; if (odm->subscene) { @@ -185,14 +200,25 @@ void mediacontrol_pause(GF_ObjectManager *odm) i=0; while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) { - if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck)) continue; - gf_odm_pause(ctrl_od); + if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck)) + continue; + + if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + gf_clock_pause(ck); + gf_scene_select_main_addon(in_scene, ctrl_od, GF_TRUE, gf_clock_time(ck) ); + } + + if (ctrl_od->subscene) { + mediacontrol_pause(ctrl_od); + } else { + gf_odm_pause(ctrl_od); + } } } /*pause all objects*/ -void MC_SetSpeed(GF_ObjectManager *odm, Fixed speed) +void mediacontrol_set_speed(GF_ObjectManager *odm, Fixed speed) { u32 i; GF_ObjectManager *ctrl_od; @@ -208,18 +234,44 @@ void MC_SetSpeed(GF_ObjectManager *odm, Fixed speed) in_scene = odm->parentscene; if (odm->subscene) { assert(odm->subscene->root_od==odm); -// assert( gf_odm_shares_clock(odm, ck) ); - gf_odm_set_speed(odm, speed); in_scene = odm->subscene; + + //dynamic scene with speed direction, we need to re-start everything to issue new PLAY requests + if (in_scene->is_dynamic_scene && (gf_mulfix(ck->speed, speed) < 0)) { + u32 time = gf_clock_time(ck); + gf_clock_set_speed(ck, speed); + + //enable main addon + if (speed<0) { + i=0; + while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) { + if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + gf_scene_select_main_addon(in_scene, ctrl_od, GF_TRUE, gf_clock_time(ck) ); + break; + } + } + } + gf_scene_restart_dynamic(in_scene, time, 0, 1); + return; + } + gf_clock_set_speed(ck, speed); + gf_odm_set_speed(odm, speed, GF_TRUE); } i=0; while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) { if (!gf_odm_shares_clock(ctrl_od, ck)) continue; - gf_odm_set_speed(ctrl_od, speed); + + if (ctrl_od->subscene) { + mediacontrol_set_speed(ctrl_od, speed); + } else { + gf_odm_set_speed(ctrl_od, speed, GF_TRUE); + } } } +#ifndef GPAC_DISABLE_VRML + void MC_GetRange(MediaControlStack *ctrl, Double *start_range, Double *end_range) { u32 i; @@ -327,12 +379,20 @@ void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy) gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url); stack->current_seg = 0; - shall_restart = need_restart = 1; + //do not restart if no mediaStartTime and speed is 1 + if ((stack->control->mediaStartTime>0) || gf_list_count(stack->seg) || (stack->control->mediaSpeed != FIX_ONE) ) { + shall_restart = need_restart = 1; + } else { + shall_restart = need_restart = 0; + //URL changed, we are by default in PLAY mode. + stack->media_speed = 1; + } + stack->ck = gf_odm_get_media_clock(stack->stream->odm); } /*control has been removed and we were paused, resume*/ else if (stack->paused) { - mediacontrol_resume((GF_ObjectManager *) prev->odm); + mediacontrol_resume((GF_ObjectManager *) prev->odm, 0); stack->paused = 0; } /*MediaControl has been detached*/ @@ -347,6 +407,7 @@ void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy) if (!stack->stream || !stack->stream->odm) { if (stack->control->url.count) gf_term_invalidate_compositor(stack->parent->root_od->term); stack->stream = NULL; + stack->changed = 0; return; } stack->ck = gf_odm_get_media_clock(stack->stream->odm); @@ -387,17 +448,21 @@ void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy) /*check for changes*/ if (!stack->is_init) { + need_restart = 0; /*not linked yet*/ if (!odm) return; stack->media_speed = stack->control->mediaSpeed; stack->enabled = stack->control->enabled; stack->media_start = stack->control->mediaStartTime; - stack->media_stop = stack->control->mediaStopTime; + if (stack->media_stop != stack->control->mediaStopTime) { + if (stack->control->mediaStopTime) need_restart = 1; + stack->media_stop = stack->control->mediaStopTime; + } stack->is_init = 1; stack->paused = 0; /*the object has already been started, and media start time is not 0, restart*/ if (stack->stream->num_open) { - if ( (stack->media_start > 0) || (gf_list_count(stack->seg)>0 ) ) { + if (need_restart || (stack->media_start > 0) || (gf_list_count(stack->seg)>0 ) || (stack->media_speed!=FIX_ONE ) ) { mediacontrol_restart(odm); } else if (stack->media_speed == 0) { mediacontrol_pause(odm); @@ -415,14 +480,14 @@ void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy) } /*else resume if paused*/ else if (stack->control->mediaSpeed && stack->paused) { - mediacontrol_resume(odm); + mediacontrol_resume(odm, 0); stack->paused = 0; need_restart += shall_restart; } /*else set speed*/ else if (stack->media_speed && stack->control->mediaSpeed) { /*don't set speed if we have to restart the media ...*/ - if (!shall_restart) MC_SetSpeed(odm, stack->control->mediaSpeed); + if (!shall_restart) mediacontrol_set_speed(odm, stack->control->mediaSpeed); need_restart += shall_restart; } /*init state was paused*/ @@ -482,6 +547,10 @@ void MC_Modified(GF_Node *node) /*do not reevaluate if mediaStartTime is reset to -1 (current time)*/ if (stack->control->mediaStartTime!=-1.0) stack->changed = 2; + /*check mediaStopTime <0 (timeshift buffer control)*/ + } else if (stack->media_stop != stack->control->mediaStopTime) { + if (stack->control->mediaStopTime<=0) + stack->changed = 2; } // else stack->changed = 1; } @@ -547,7 +616,7 @@ void gf_odm_remove_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl) if (odm->media_ctrl == ctrl) { /*we're about to release the media control from this object - if paused, force a resume (as if no MC was set)*/ if (ctrl->paused) - mediacontrol_resume(odm); + mediacontrol_resume(odm, 0); gf_odm_set_mediacontrol(odm, NULL); } } @@ -612,7 +681,7 @@ Bool gf_odm_check_segment_switch(GF_ObjectManager *odm) /*if next seg start is before cur seg end*/ && (cur->startTime + cur->Duration > next->startTime) /*if next seg start is already passed*/ - && (1000*next->startTime < odm->current_time) + && (1000*next->startTime < odm->media_current_time) /*then next segment was taken into account when requesting play*/ ) { cur = next; diff --git a/src/terminal/media_control.h b/src/terminal/media_control.h index 84cef6d..b8a6f58 100644 --- a/src/terminal/media_control.h +++ b/src/terminal/media_control.h @@ -36,7 +36,9 @@ /*restart object and takes care of media control/clock dependencies*/ void mediacontrol_restart(GF_ObjectManager *odm); void mediacontrol_pause(GF_ObjectManager *odm); -void mediacontrol_resume(GF_ObjectManager *odm); +//resumes object. +//If @resume_to_live is set, will deactivate main addon acting as PVR +void mediacontrol_resume(GF_ObjectManager *odm, Bool resume_to_live); Bool MC_URLChanged(MFURL *old_url, MFURL *new_url); diff --git a/src/terminal/media_manager.c b/src/terminal/media_manager.c index f7c0353..b81f204 100644 --- a/src/terminal/media_manager.c +++ b/src/terminal/media_manager.c @@ -121,7 +121,6 @@ static CodecEntry *mm_get_codec(GF_List *list, GF_Codec *codec) void gf_term_add_codec(GF_Terminal *term, GF_Codec *codec) { u32 i, count; - Bool locked; Bool threaded; CodecEntry *cd; CodecEntry *ptr, *next; @@ -132,7 +131,7 @@ void gf_term_add_codec(GF_Terminal *term, GF_Codec *codec) /*caution: the mutex can be grabbed by a decoder waiting for a mutex owned by the calling thread this happens when several scene codecs are running concurently and triggering play/pause on media*/ - locked = gf_mx_try_lock(term->mm_mx); + gf_mx_p(term->mm_mx); cd = mm_get_codec(term->codecs, codec); if (cd) goto exit; @@ -221,7 +220,7 @@ void gf_term_add_codec(GF_Terminal *term, GF_Codec *codec) gf_list_add(term->codecs, cd); exit: - if (locked) gf_mx_v(term->mm_mx); + gf_mx_v(term->mm_mx); return; } @@ -371,11 +370,11 @@ u32 MM_Loop(void *par) else left = term->frame_duration; if (do_scene) { - u32 ms_until_next=0; + s32 ms_until_next=0; u32 time_taken = gf_sys_clock(); - gf_sc_draw_frame(term->compositor, &ms_until_next); + gf_sc_draw_frame(term->compositor, 0, &ms_until_next); time_taken = gf_sys_clock() - time_taken; - if (ms_until_nextframe_duration/2) { + if (ms_until_next< (s32) term->frame_duration/2) { left = 0; } else if (left>time_taken) left -= time_taken; @@ -433,7 +432,7 @@ u32 RunSingleDec(void *ptr) return 0; } -/*NOTE: when starting/stoping a decoder we only lock the decoder mutex, NOT the media manager. This +/*NOTE: when starting/stopping a decoder we only lock the decoder mutex, NOT the media manager. This avoids deadlocking in case a system codec waits for the scene graph and the compositor requests a stop/start on a media*/ void gf_term_start_codec(GF_Codec *codec, Bool is_resume) @@ -449,7 +448,7 @@ void gf_term_start_codec(GF_Codec *codec, Bool is_resume) if (ce->mx) gf_mx_p(ce->mx); /*clean decoder memory and wait for RAP*/ - if (codec->CB) gf_cm_reset(codec->CB); + if (!is_resume && codec->CB) gf_cm_reset(codec->CB); if (!is_resume) { cap.CapCode = GF_CODEC_WAIT_RAP; @@ -515,8 +514,20 @@ void gf_term_stop_codec(GF_Codec *codec, Bool is_pause) } } - /*set status directly and don't touch CB state*/ - codec->Status = GF_ESM_CODEC_STOP; + /*for audio codec force CB to stop state to discard any pending AU. Not doing so would lead to a wrong estimation of the clock drift + when resuming the object*/ + if (codec->type==GF_STREAM_AUDIO) { + gf_codec_set_status(codec, GF_ESM_CODEC_STOP); + } + //if video is in a dynamic scene, reset the CB if user stop (eg codec was not in EOS). Otherwise (bifs,svg) we may want to keep the last decoded image + else if ((codec->Statusodm && codec->odm->parentscene && codec->odm->parentscene->is_dynamic_scene && codec->CB && (codec->CB->Capacity>1)) { + gf_codec_set_status(codec, GF_ESM_CODEC_STOP); + } + /*otherwise set status directly and don't touch CB state*/ + else { + codec->Status = GF_ESM_CODEC_STOP; + } + /*don't wait for end of thread since this can be triggered within the decoding thread*/ if (ce->flags & GF_MM_CE_RUNNING) { ce->flags &= ~GF_MM_CE_RUNNING; @@ -665,12 +676,11 @@ u32 gf_term_process_step(GF_Terminal *term) } if (term->flags & GF_TERM_NO_COMPOSITOR_THREAD) { - u32 ms_until_next; - gf_sc_draw_frame(term->compositor, &ms_until_next); - if (ms_until_nextcompositor->frame_duration/2) { + s32 ms_until_next; + gf_sc_draw_frame(term->compositor, 0, &ms_until_next); + if (ms_until_next < (s32) term->compositor->frame_duration/2) { time_taken=0; } - } time_taken = gf_sys_clock() - time_taken; if (time_taken > term->compositor->frame_duration) { @@ -706,8 +716,18 @@ GF_Err gf_term_process_flush(GF_Terminal *term) gf_mx_v(term->mm_mx); } - if (!gf_sc_draw_frame(term->compositor, NULL)) - break; + if (!gf_sc_draw_frame(term->compositor, 1, NULL)) { + if (!term->root_scene || !term->root_scene->root_od) + break; + + //wait for audio to be flushed + if (gf_sc_check_audio_pending(term->compositor) ) + continue; + + //force end of buffer + if (gf_scene_check_clocks(term->root_scene->root_od->net_service, term->root_scene, 1)) + break; + } if (! (term->user->init_flags & GF_TERM_NO_REGULATION)) break; @@ -715,3 +735,10 @@ GF_Err gf_term_process_flush(GF_Terminal *term) return GF_OK; } +GF_EXPORT +GF_Err gf_term_process_flush_video(GF_Terminal *term) +{ + if (!(term->flags & GF_TERM_NO_COMPOSITOR_THREAD) ) return GF_BAD_PARAM; + gf_sc_flush_video(term->compositor); + return GF_OK; +} diff --git a/src/terminal/media_memory.c b/src/terminal/media_memory.c index 358b877..e000d6f 100644 --- a/src/terminal/media_memory.c +++ b/src/terminal/media_memory.c @@ -27,6 +27,7 @@ #include #include +#include #include "media_memory.h" #include "media_control.h" @@ -43,16 +44,12 @@ GF_DBUnit *gf_db_unit_new() void gf_db_unit_del(GF_DBUnit *db) { - if (!db) return; - if (db->next) gf_db_unit_del(db->next); - db->next = NULL; - if (db->data) { - /* memset(db->data, 0, db->dataLength); */ - gf_free(db->data); - } - db->dataLength = 0; - db->data = NULL; - gf_free(db); + while (db) { + GF_DBUnit *next = db->next; + if (db->data) gf_free(db->data); + gf_free(db); + db = next; + } } static GF_CMUnit *gf_cm_unit_new() @@ -531,7 +528,7 @@ GF_CMUnit *gf_cm_get_output(GF_CompositionMemory *cb) GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] Switching composition memory to stop state - time %d\n", cb->odm->OD->objectDescriptorID, (u32) cb->odm->media_stop_time)); cb->Status = CB_STOP; - cb->odm->current_time = (u32) cb->odm->media_stop_time; + cb->odm->media_current_time = (u32) cb->odm->media_stop_time; #ifndef GPAC_DISABLE_VRML /*force update of media time*/ mediasensor_update_timing(cb->odm, 1); @@ -543,13 +540,17 @@ GF_CMUnit *gf_cm_get_output(GF_CompositionMemory *cb) /*update the timing*/ if ((cb->Status != CB_STOP) && cb->odm && cb->odm->codec) { - cb->odm->current_time = cb->output->TS; + if (cb->odm->codec->ck->has_media_time_shift) { + cb->odm->media_current_time = cb->output->TS + cb->odm->codec->ck->media_time_at_init - cb->odm->codec->ck->init_time; + } else { + cb->odm->media_current_time = cb->output->TS; + } /*handle visual object - EOS if no more data (we keep the last CU for rendering, so check next one)*/ - if (cb->HasSeenEOS && (!cb->output->next->dataLength || (cb->Capacity==1))) { + if (cb->HasSeenEOS && (cb->odm->codec->type == GF_STREAM_VISUAL) && (!cb->output->next->dataLength || (cb->Capacity==1))) { GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Switching composition memory to stop state - time %d\n", cb->odm->OD->objectDescriptorID, (u32) cb->odm->media_stop_time)); cb->Status = CB_STOP; - cb->odm->current_time = (u32) cb->odm->media_stop_time; + cb->odm->media_current_time = (u32) cb->odm->media_stop_time; #ifndef GPAC_DISABLE_VRML /*force update of media time*/ mediasensor_update_timing(cb->odm, 1); @@ -557,11 +558,16 @@ GF_CMUnit *gf_cm_get_output(GF_CompositionMemory *cb) gf_odm_signal_eos(cb->odm); } } + if (cb->output->sender_ntp) { + cb->LastRenderedNTPDiff = gf_net_get_ntp_diff_ms(cb->output->sender_ntp); + cb->LastRenderedNTP = cb->output->sender_ntp; + } + return cb->output; } -/*drop the output CU*/ +/*mark the output as reusable and init clock*/ void gf_cm_output_kept(GF_CompositionMemory *cb) { assert(cb->UnitCount); @@ -578,10 +584,8 @@ void gf_cm_output_kept(GF_CompositionMemory *cb) /*drop the output CU*/ void gf_cm_drop_output(GF_CompositionMemory *cb) { + //check if clock has to be resumed gf_cm_output_kept(cb); - if (cb->Status!=CB_PLAY) { - return; - } /*WARNING: in RAW mode, we (for the moment) only have one unit - setting output->dataLength to 0 means the input is available for the raw channel - we have to make sure the output is completely reseted before releasing the sema*/ @@ -633,6 +637,7 @@ void gf_cm_set_status(GF_CompositionMemory *cb, u32 Status) case CB_STOP: cb->Status = CB_BUFFER; gf_clock_buffer_on(cb->odm->codec->ck); + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB status changed - ODM%d: buffering on at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering)); break; case CB_PAUSE: cb->Status = CB_PLAY; @@ -658,6 +663,7 @@ void gf_cm_set_status(GF_CompositionMemory *cb, u32 Status) cb->Status = Status; if (Status==CB_BUFFER) { gf_clock_buffer_on(cb->odm->codec->ck); + GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB status changed - ODM%d: buffering on at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering)); } } @@ -708,7 +714,7 @@ Bool gf_cm_is_running(GF_CompositionMemory *cb) Bool gf_cm_is_eos(GF_CompositionMemory *cb) { - if ( (cb->Status == CB_STOP) || (cb->HasSeenEOS && (cb->UnitCount==0)) ) + if (cb->HasSeenEOS && ((cb->Status == CB_STOP) || (cb->UnitCount==0)) ) return 1; return 0; } diff --git a/src/terminal/media_memory.h b/src/terminal/media_memory.h index c079bed..5231305 100644 --- a/src/terminal/media_memory.h +++ b/src/terminal/media_memory.h @@ -43,7 +43,9 @@ enum /*hack for some DMB streams not signaling TS for BIFS*/ GF_DB_AU_NO_TIMESTAMPS = 1<<2, /*for debuging AU reassembly in scalable coding*/ - GF_DB_AU_REAGGREGATED = 1<<3 + GF_DB_AU_REAGGREGATED = 1<<3, + /*set for AUs that need dispatching but should not be displayed*/ + GF_DB_AU_IS_SEEK = 1<<4, }; /*compressed media unit*/ @@ -59,6 +61,7 @@ typedef struct _decoding_buffer u8 flags; /*amount of padding bits*/ u8 PaddingBits; + u64 sender_ntp; u32 dataLength; char *data; @@ -95,6 +98,8 @@ typedef struct _composition_unit { u32 dataLength; char* data; + + u64 sender_ntp; } GF_CMUnit; @@ -130,6 +135,9 @@ struct _composition_memory u32 LastRenderedTS; u8 *pY, *pU, *pV; + + u64 LastRenderedNTP; + s32 LastRenderedNTPDiff; }; /*a composition buffer only has fixed-size unit*/ diff --git a/src/terminal/media_object.c b/src/terminal/media_object.c index 4d99873..d3a3717 100644 --- a/src/terminal/media_object.c +++ b/src/terminal/media_object.c @@ -32,6 +32,7 @@ #include "media_memory.h" #include "media_control.h" #include +#include #ifndef GPAC_DISABLE_SVG @@ -209,170 +210,175 @@ GF_MediaObject *gf_mo_new() return mo; } - GF_EXPORT Bool gf_mo_get_visual_info(GF_MediaObject *mo, u32 *width, u32 *height, u32 *stride, u32 *pixel_ar, u32 *pixelFormat, Bool *is_flipped) { - GF_CodecCapability cap; if ((mo->type != GF_MEDIA_OBJECT_VIDEO) && (mo->type!=GF_MEDIA_OBJECT_TEXT)) return GF_FALSE; - if (width) { - cap.CapCode = GF_CODEC_WIDTH; - gf_codec_get_capability(mo->odm->codec, &cap); - *width = cap.cap.valueInt; - } - if (height) { - cap.CapCode = GF_CODEC_HEIGHT; - gf_codec_get_capability(mo->odm->codec, &cap); - *height = cap.cap.valueInt; - } - if (mo->type==GF_MEDIA_OBJECT_TEXT) return GF_TRUE; + if (width) *width = mo->width; + if (height) *height = mo->height; + if (stride) *stride = mo->stride; + if (pixel_ar) *pixel_ar = mo->pixel_ar; + if (pixelFormat) *pixelFormat = mo->pixelformat; + if (is_flipped) *is_flipped = mo->is_flipped; + return GF_TRUE; +} - if (is_flipped) { - cap.CapCode = GF_CODEC_FLIP; - cap.cap.valueInt = 0; - gf_codec_get_capability(mo->odm->codec, &cap); - *is_flipped = cap.cap.valueInt ? GF_TRUE : GF_FALSE; - } +GF_EXPORT +Bool gf_mo_get_audio_info(GF_MediaObject *mo, u32 *sample_rate, u32 *bits_per_sample, u32 *num_channels, u32 *channel_config) +{ + if (!mo->odm || !mo->odm->codec || (mo->type != GF_MEDIA_OBJECT_AUDIO)) return GF_FALSE; - if (stride) { - cap.CapCode = GF_CODEC_STRIDE; - gf_codec_get_capability(mo->odm->codec, &cap); - *stride = cap.cap.valueInt; - } - if (pixelFormat) { - cap.CapCode = GF_CODEC_PIXEL_FORMAT; - gf_codec_get_capability(mo->odm->codec, &cap); - *pixelFormat = cap.cap.valueInt; + if (sample_rate) *sample_rate = mo->sample_rate; + if (bits_per_sample) *bits_per_sample = mo->bits_per_sample; + if (num_channels) *num_channels = mo->num_channels; + if (channel_config) *channel_config = mo->channel_config; + return GF_TRUE; +} + +static void gf_mo_update_visual_info(GF_MediaObject *mo) +{ + GF_CodecCapability cap; + if ((mo->type != GF_MEDIA_OBJECT_VIDEO) && (mo->type!=GF_MEDIA_OBJECT_TEXT)) return; + + cap.CapCode = GF_CODEC_WIDTH; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->width = cap.cap.valueInt; + + cap.CapCode = GF_CODEC_HEIGHT; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->height = cap.cap.valueInt; + + if (mo->type==GF_MEDIA_OBJECT_TEXT) return; + + cap.CapCode = GF_CODEC_FLIP; + cap.cap.valueInt = 0; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->is_flipped = cap.cap.valueInt ? GF_TRUE : GF_FALSE; + + cap.CapCode = GF_CODEC_STRIDE; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->stride = cap.cap.valueInt; - if (mo->odm && mo->odm->parentscene->is_dynamic_scene) { + cap.CapCode = GF_CODEC_PIXEL_FORMAT; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->pixelformat = cap.cap.valueInt; + + cap.CapCode = GF_CODEC_FPS; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->odm->codec->fps = cap.cap.valueFloat; + + if (mo->odm && mo->odm->parentscene->is_dynamic_scene) { #ifndef GPAC_DISABLE_VRML - const char *name = gf_node_get_name(gf_event_target_get_node(gf_mo_event_target_get(mo, 0))); - if (name && !strcmp(name, "DYN_VIDEO")) { - const char *opt; - u32 r, g, b, a; - M_Background2D *back = (M_Background2D *) gf_sg_find_node_by_name(mo->odm->parentscene->graph, "DYN_BACK"); - if (back) { - switch (cap.cap.valueInt) { - case GF_PIXEL_ARGB: - case GF_PIXEL_RGBA: - case GF_PIXEL_YUVA: - opt = gf_cfg_get_key(mo->odm->term->user->config, "Compositor", "BackColor"); - if (!opt) { - gf_cfg_set_key(mo->odm->term->user->config, "Compositor", "BackColor", "FF999999"); - opt = "FF999999"; - } - sscanf(opt, "%02X%02X%02X%02X", &a, &r, &g, &b); - back->backColor.red = INT2FIX(r)/255; - back->backColor.green = INT2FIX(g)/255; - back->backColor.blue = INT2FIX(b)/255; - break; - default: - back->backColor.red = back->backColor.green = back->backColor.blue = 0; - break; + const char *name = gf_node_get_name(gf_event_target_get_node(gf_mo_event_target_get(mo, 0))); + if (name && !strcmp(name, "DYN_VIDEO")) { + const char *opt; + u32 r, g, b, a; + M_Background2D *back = (M_Background2D *) gf_sg_find_node_by_name(mo->odm->parentscene->graph, "DYN_BACK"); + if (back) { + switch (cap.cap.valueInt) { + case GF_PIXEL_ARGB: + case GF_PIXEL_RGBA: + case GF_PIXEL_YUVA: + opt = gf_cfg_get_key(mo->odm->term->user->config, "Compositor", "BackColor"); + if (!opt) { + gf_cfg_set_key(mo->odm->term->user->config, "Compositor", "BackColor", "FF999999"); + opt = "FF999999"; } - gf_node_dirty_set((GF_Node *)back, 0, GF_TRUE); + sscanf(opt, "%02X%02X%02X%02X", &a, &r, &g, &b); + back->backColor.red = INT2FIX(r)/255; + back->backColor.green = INT2FIX(g)/255; + back->backColor.blue = INT2FIX(b)/255; + break; + default: + back->backColor.red = back->backColor.green = back->backColor.blue = 0; + break; } + gf_node_dirty_set((GF_Node *)back, 0, GF_TRUE); } -#endif } +#endif } /*get PAR settings*/ - if (pixel_ar) { - cap.CapCode = GF_CODEC_PAR; - gf_codec_get_capability(mo->odm->codec, &cap); - *pixel_ar = cap.cap.valueInt; - if (! (*pixel_ar & 0x0000FFFF)) *pixel_ar = 0; - if (! (*pixel_ar & 0xFFFF0000)) *pixel_ar = 0; - - /**/ - if (! *pixel_ar) { - GF_Channel *ch; - GF_NetworkCommand com; - com.base.command_type = GF_NET_CHAN_GET_PIXEL_AR; - ch = (GF_Channel *)gf_list_get(mo->odm->channels, 0); - if (!ch) return GF_FALSE; - - com.base.on_channel = ch; - com.par.hSpacing = com.par.vSpacing = 0; - if (gf_term_service_command(ch->service, &com) == GF_OK) { - if ((com.par.hSpacing>65535) || (com.par.vSpacing>65535)) { - com.par.hSpacing>>=16; - com.par.vSpacing>>=16; - } - if (com.par.hSpacing|| com.par.vSpacing) - *pixel_ar = (com.par.hSpacing<<16) | com.par.vSpacing; + cap.CapCode = GF_CODEC_PAR; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->pixel_ar = cap.cap.valueInt; + if (! (mo->pixel_ar & 0x0000FFFF)) mo->pixel_ar = 0; + if (! (mo->pixel_ar & 0xFFFF0000)) mo->pixel_ar = 0; + + /**/ + if (! mo->pixel_ar) { + GF_Channel *ch; + GF_NetworkCommand com; + com.base.command_type = GF_NET_CHAN_GET_PIXEL_AR; + ch = (GF_Channel *)gf_list_get(mo->odm->channels, 0); + if (!ch) return; + + com.base.on_channel = ch; + com.par.hSpacing = com.par.vSpacing = 0; + if (gf_term_service_command(ch->service, &com) == GF_OK) { + if ((com.par.hSpacing>65535) || (com.par.vSpacing>65535)) { + com.par.hSpacing>>=16; + com.par.vSpacing>>=16; } + if (com.par.hSpacing|| com.par.vSpacing) + mo->pixel_ar = (com.par.hSpacing<<16) | com.par.vSpacing; } } - return GF_TRUE; } -GF_EXPORT -Bool gf_mo_get_audio_info(GF_MediaObject *mo, u32 *sample_rate, u32 *bits_per_sample, u32 *num_channels, u32 *channel_config) +static void gf_mo_update_audio_info(GF_MediaObject *mo) { GF_CodecCapability cap; - if (!mo->odm || !mo->odm->codec || (mo->type != GF_MEDIA_OBJECT_AUDIO)) return GF_FALSE; + if (!mo->odm || !mo->odm->codec || (mo->type != GF_MEDIA_OBJECT_AUDIO)) return; if (mo->odm->term->bench_mode==2) { - if (sample_rate) *sample_rate = 44100; - if (bits_per_sample) *bits_per_sample = 16; - if (num_channels) *num_channels = 2; - if (channel_config) *channel_config = 0; - return GF_TRUE; - } - if (sample_rate) { - cap.CapCode = GF_CODEC_SAMPLERATE; - gf_codec_get_capability(mo->odm->codec, &cap); - *sample_rate = cap.cap.valueInt; - } - if (num_channels) { - cap.CapCode = GF_CODEC_NB_CHAN; - gf_codec_get_capability(mo->odm->codec, &cap); - *num_channels = cap.cap.valueInt; - } - if (bits_per_sample) { - cap.CapCode = GF_CODEC_BITS_PER_SAMPLE; - gf_codec_get_capability(mo->odm->codec, &cap); - *bits_per_sample = cap.cap.valueInt; - } - if (channel_config) { - cap.CapCode = GF_CODEC_CHANNEL_CONFIG; - gf_codec_get_capability(mo->odm->codec, &cap); - *channel_config = cap.cap.valueInt; + mo->sample_rate = 44100; + mo->bits_per_sample = 16; + mo->num_channels = 2; + mo->channel_config = 0; + return; } - return GF_TRUE; + cap.CapCode = GF_CODEC_SAMPLERATE; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->sample_rate = cap.cap.valueInt; + + cap.CapCode = GF_CODEC_NB_CHAN; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->num_channels = cap.cap.valueInt; + + cap.CapCode = GF_CODEC_BITS_PER_SAMPLE; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->bits_per_sample = cap.cap.valueInt; + + cap.CapCode = GF_CODEC_CHANNEL_CONFIG; + gf_codec_get_capability(mo->odm->codec, &cap); + mo->channel_config = cap.cap.valueInt; + + mo->odm->codec->bytes_per_sec = mo->sample_rate * mo->num_channels * mo->bits_per_sample / 8; } void gf_mo_update_caps(GF_MediaObject *mo) { - GF_CodecCapability cap; - mo->flags &= ~GF_MO_IS_INIT; if (mo->type == GF_MEDIA_OBJECT_VIDEO) { - cap.CapCode = GF_CODEC_FPS; - gf_codec_get_capability(mo->odm->codec, &cap); - mo->odm->codec->fps = cap.cap.valueFloat; - } - else if (mo->type == GF_MEDIA_OBJECT_AUDIO) { - u32 sr, nb_ch, bps; - sr = nb_ch = bps = 0; - gf_mo_get_audio_info(mo, &sr, &bps, &nb_ch, NULL); - mo->odm->codec->bytes_per_sec = sr * nb_ch * bps / 8; + gf_mo_update_visual_info(mo); + } else if (mo->type == GF_MEDIA_OBJECT_AUDIO) { + gf_mo_update_audio_info(mo); } } GF_EXPORT -char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestamp, u32 *size, s32 *ms_until_pres, s32 *ms_until_next) +char *gf_mo_fetch_data(GF_MediaObject *mo, GF_MOFetchMode resync, Bool *eos, u32 *timestamp, u32 *size, s32 *ms_until_pres, s32 *ms_until_next) { GF_Codec *codec; - Bool force_decode = GF_FALSE; + u32 force_decode_mode = 0; u32 obj_time; GF_CMUnit *CU; s32 diff; - Bool bench_mode; + Bool bench_mode, skip_resync; *eos = GF_FALSE; *timestamp = mo->timestamp; @@ -405,6 +411,8 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam gf_odm_lock(mo->odm, 0); return NULL; } + if (resync==GF_MO_FETCH_PAUSED) + resync=GF_MO_FETCH; bench_mode = mo->odm->term->bench_mode; @@ -415,29 +423,36 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: Resizing output buffer %d -> %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->CB->UnitSize, codec->force_cb_resize)); gf_codec_resize_composition_buffer(codec, codec->force_cb_resize); codec->force_cb_resize=0; - force_decode = GF_TRUE; + //decode and resize CB + force_decode_mode = 1; } } - /*fast forward, bench mode with composition memory: force decode if no data is available*/ - if (! *eos && ((codec->ck->speed > FIX_ONE) || (codec->odm->term->bench_mode && !codec->CB->no_allocation) || (codec->type==GF_STREAM_AUDIO) ) ) - force_decode = GF_TRUE; - + /*fast forward, bench mode with composition memory: force one decode if no data is available*/ + if (! *eos && ((codec->ck->speed > FIX_ONE) || (codec->odm->term->bench_mode && !codec->CB->no_allocation) || (codec->type==GF_STREAM_AUDIO) ) ) { + force_decode_mode = 2; + } - if (force_decode) { - u32 retry=100; + if (force_decode_mode) { + u32 retry = 100; gf_odm_lock(mo->odm, 0); while (retry) { if (gf_term_lock_codec(codec, GF_TRUE, GF_TRUE)) { gf_codec_process(codec, 1); gf_term_lock_codec(codec, GF_FALSE, GF_TRUE); - break; } +// if (force_decode_mode==2) break; + + CU = gf_cm_get_output(codec->CB); + if (CU) + break; + retry--; - gf_sleep(0); + //we will wait max 100 ms for the CB to be re-fill + gf_sleep(1); } - if (!retry && codec->force_cb_resize) { - GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] At %d could not resize and decode next frame in one pass - blank frame after TS %d\n", mo->odm->OD->objectDescriptorID, gf_clock_time(codec->ck), mo->timestamp)); + if (!retry && (force_decode_mode==1)) { + GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] At %d could not resize, decode and fetch next frame in 100 ms - blank frame after TS %d\n", mo->odm->OD->objectDescriptorID, gf_clock_time(codec->ck), mo->timestamp)); } if (!gf_odm_lock_mo(mo)) return NULL; @@ -454,10 +469,10 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam /*note this assert is NOT true when recomputing DTS from CTS on the fly (MPEG1/2 RTP and H264/AVC RTP)*/ //assert(CU->TS >= codec->CB->LastRenderedTS); - if (codec->CB->UnitCount<=1) resync = GF_FALSE; + if (codec->CB->UnitCount<=1) resync = GF_MO_FETCH; if (bench_mode && resync) { - resync = GF_FALSE; + resync = GF_MO_FETCH; if (mo->timestamp == CU->TS) { if (CU->next->dataLength) { gf_cm_drop_output(codec->CB); @@ -470,9 +485,22 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam /*resync*/ obj_time = gf_clock_time(codec->ck); - //no drop mode: all frames are presented, we discard the current output only if already presented and next frame time is mature - if ((codec->ck->speed>0) && !(mo->odm->term->flags & GF_TERM_DROP_LATE_FRAMES) && (mo->type==GF_MEDIA_OBJECT_VIDEO)) { - resync=GF_FALSE; + skip_resync = GF_FALSE; + //no drop mode, only for speed = 1: all frames are presented, we discard the current output only if already presented and next frame time is mature + if ((codec->ck->speed == FIX_ONE) && (mo->type==GF_MEDIA_OBJECT_VIDEO) && !(codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY) ) { + if (!(mo->odm->term->flags & GF_TERM_DROP_LATE_FRAMES)) { + //if the next AU is at most 1 sec from the current clock use no drop mode + if (CU->next->dataLength && (CU->next->TS + 1000 >= obj_time)) { + skip_resync = GF_TRUE; + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Frame TS %d too late in no-drop mode, enabling drop\n", mo->odm->OD->objectDescriptorID, obj_time, CU->TS)); + } + } + } + + + if (skip_resync) { + resync=GF_MO_FETCH; if (/*gf_clock_is_started(mo->odm->codec->ck) && */ (mo->timestamp==CU->TS) && CU->next->dataLength && (CU->next->TS <= obj_time) ) { gf_cm_drop_output(codec->CB); CU = gf_cm_get_output(codec->CB); @@ -484,15 +512,13 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam } if (resync) { - u32 nb_droped = 0; + u32 nb_dropped = 0; while (1) { - u32 diff; - if (CU->TS*codec->ck->speed >= obj_time*codec->ck->speed) break; if (!CU->next->dataLength) { - if (force_decode) { + if (force_decode_mode) { obj_time = gf_clock_time(codec->ck); gf_odm_lock(mo->odm, 0); if (gf_term_lock_codec(codec, GF_TRUE, GF_TRUE)) { @@ -507,28 +533,16 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam } } - diff = codec->ck->speed > 0 ? CU->next->TS - CU->TS : CU->TS - CU->next->TS; - - if (codec->ck->speed>0) { - if (CU->TS + codec->CB->Capacity*diff > obj_time) { - break; - } - } else { - if (CU->TS + codec->CB->Capacity*diff < obj_time) { - break; - } - } - /*figure out closest time*/ if (codec->ck->speed*CU->next->TS > codec->ck->speed*obj_time) { *eos = GF_FALSE; break; } - nb_droped ++; - if (nb_droped>1) { + nb_dropped ++; + if (nb_dropped>1) { GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] At OTB %u dropped frame TS %u\n", mo->odm->OD->objectDescriptorID, obj_time, CU->TS)); - codec->nb_droped++; + codec->nb_dropped++; } /*discard*/ CU->RenderedLength = CU->dataLength = 0; @@ -549,7 +563,7 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam } else { mo->ms_until_next = 1; } - diff = mo->speed > 0 ? (s32) (CU->TS) - (s32) obj_time : (s32) obj_time - (s32) (CU->TS); + diff = (mo->speed >= 0) ? (s32) (CU->TS) - (s32) obj_time : (s32) obj_time - (s32) (CU->TS); mo->ms_until_pres = FIX2INT(diff * mo->speed); @@ -559,14 +573,30 @@ char *gf_mo_fetch_data(GF_MediaObject *mo, Bool resync, Bool *eos, u32 *timestam mediasensor_update_timing(mo->odm, 0); #endif - if (mo->odm->parentscene->is_dynamic_scene) - mo->odm->parentscene->root_od->current_time = mo->odm->current_time; + if (mo->odm->parentscene->is_dynamic_scene) { + GF_Scene *s = mo->odm->parentscene; + while (s && s->root_od->addon) { + s = s->root_od->parentscene; + } + s->root_od->media_current_time = mo->odm->media_current_time; + } +#ifndef GPAC_DISABLE_LOG + if (gf_log_tool_level_on(GF_LOG_MEDIA, GF_LOG_DEBUG)) { + GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d (%s)] At OTB %u fetch frame TS %u size %d (previous TS %d) - %d unit in CB - UTC "LLU" ms - %d ms until CTS is due - %d ms until next frame\n", mo->odm->OD->objectDescriptorID, mo->odm->net_service->url, gf_clock_time(codec->ck), CU->TS, mo->framesize, mo->timestamp, codec->CB->UnitCount, gf_net_get_utc(), mo->ms_until_pres, mo->ms_until_next )); + if (CU->sender_ntp) { + s32 ntp_diff = gf_net_get_ntp_diff_ms(CU->sender_ntp); + GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d (%s)] Frame TS NTP diff with sender %d ms\n", mo->odm->OD->objectDescriptorID, mo->odm->net_service->url, ntp_diff)); + } + } +#endif mo->timestamp = CU->TS; /*signal EOS after rendering last frame, not while rendering it*/ *eos = GF_FALSE; - GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d (%s)] At OTB %u fetch frame TS %u size %d (previous TS %d) - %d unit in CB - UTC "LLU" ms - %d ms until CTS is due - %d ms until next frame\n", mo->odm->OD->objectDescriptorID, mo->odm->net_service->url, gf_clock_time(codec->ck), CU->TS, mo->framesize, mo->timestamp, codec->CB->UnitCount, gf_net_get_utc(), mo->ms_until_pres, mo->ms_until_next )); + } else if (*eos) { + //already rendered the last frame, consider we no longer have pending late frame on this stream + mo->ms_until_pres = 0; } /*also adjust CU time based on consummed bytes in input, since some codecs output very large audio chunks*/ @@ -687,6 +717,23 @@ void gf_mo_get_object_time(GF_MediaObject *mo, u32 *obj_time) gf_odm_lock(mo->odm, 0); } +GF_EXPORT +s32 gf_mo_get_clock_drift(GF_MediaObject *mo) +{ + s32 res = 0; + if (!gf_odm_lock_mo(mo)) return 0; + + /*regular media codec...*/ + if (mo->odm->codec) { + res = mo->odm->codec->ck->drift; + } + /*BIFS object */ + else if (mo->odm->subscene && mo->odm->subscene->scene_codec) { + res = mo->odm->subscene->scene_codec->ck->drift; + } + gf_odm_lock(mo->odm, 0); + return res; +} GF_EXPORT void gf_mo_play(GF_MediaObject *mo, Double clipBegin, Double clipEnd, Bool can_loop) @@ -721,7 +768,7 @@ void gf_mo_play(GF_MediaObject *mo, Double clipBegin, Double clipEnd, Bool can_l } if (clipEnd>=clipBegin) { mo->odm->media_stop_time = (u64) (clipEnd*1000); - if (mo->odm->duration && (mo->odm->media_stop_time > mo->odm->duration)) { + if (mo->odm->duration && (mo->odm->media_stop_time >=0) && ((u64) mo->odm->media_stop_time > mo->odm->duration)) { mo->odm->media_stop_time = 0; } } else { @@ -734,9 +781,6 @@ void gf_mo_play(GF_MediaObject *mo, Double clipBegin, Double clipEnd, Bool can_l if (is_restart) { mediacontrol_restart(mo->odm); } else { - /*FIXME - this breaks inital loading on JPEG and PNG files ...*/ -// if (mo->odm->subscene && mo->odm->subscene->is_dynamic_scene) mo->odm->flags |= GF_ODM_REGENERATE_SCENE; - gf_odm_start(mo->odm, (res>=0) ? 1 : 0); } } else if (mo->odm) { @@ -908,13 +952,16 @@ Bool gf_mo_is_same_url(GF_MediaObject *obj, MFURL *an_url, Bool *keep_fragment, } } + gf_term_lock_media_queue(obj->odm->term, 1); while ( (ns = (GF_ClientService*)gf_list_enum(obj->odm->term->net_services, &j)) ) { /*sub-service of an existing service - don't touch any fragment*/ if (gf_term_service_can_handle_url(ns, an_url->vals[i].url)) { *keep_fragment = GF_TRUE; + gf_term_lock_media_queue(obj->odm->term, 0); return GF_FALSE; } } + gf_term_lock_media_queue(obj->odm->term, 0); } } @@ -973,7 +1020,7 @@ void gf_mo_resume(GF_MediaObject *mo) { #ifndef GPAC_DISABLE_VRML if (!mo || !mo->num_open || !mo->odm) return; - mediacontrol_resume(mo->odm); + mediacontrol_resume(mo->odm, 0); #endif } @@ -989,6 +1036,11 @@ void gf_mo_set_speed(GF_MediaObject *mo, Fixed speed) mo->speed = speed; return; } + //override startup speed if asked to + if (mo->odm->set_speed) { + speed = mo->odm->set_speed; + mo->odm->set_speed = 0; + } #ifndef GPAC_DISABLE_VRML /*if media control forbidd that*/ ctrl = gf_odm_get_mediacontrol(mo->odm); @@ -996,7 +1048,7 @@ void gf_mo_set_speed(GF_MediaObject *mo, Fixed speed) #endif if (mo->odm->net_service && mo->odm->net_service->owner && (mo->odm->net_service->owner->flags & GF_ODM_INHERIT_TIMELINE)) return; - gf_odm_set_speed(mo->odm, speed); + gf_odm_set_speed(mo->odm, speed, GF_TRUE); } GF_EXPORT @@ -1184,7 +1236,7 @@ u32 gf_mo_get_last_frame_time(GF_MediaObject *mo) GF_EXPORT Bool gf_mo_is_private_media(GF_MediaObject *mo) { - if (mo->odm && mo->odm->codec && mo->odm->codec->decio && (mo->odm->codec->decio->InterfaceType==GF_PRIVATE_MEDIA_DECODER_INTERFACE)) return GF_TRUE; + if (mo && mo->odm && mo->odm->codec && mo->odm->codec->decio && (mo->odm->codec->decio->InterfaceType==GF_PRIVATE_MEDIA_DECODER_INTERFACE)) return GF_TRUE; return GF_FALSE; } diff --git a/src/terminal/media_sensor.c b/src/terminal/media_sensor.c index 7f6e41d..e985d63 100644 --- a/src/terminal/media_sensor.c +++ b/src/terminal/media_sensor.c @@ -35,6 +35,7 @@ void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy) { GF_TraverseState *tr_state = (GF_TraverseState *)rs; GF_Clock *ck; + Bool do_update_clock = 1; MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node); if (is_destroy) { @@ -69,8 +70,7 @@ void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy) if (st->stream->odm->subscene->scene_codec) ck = st->stream->odm->subscene->scene_codec->ck; /*dynamic scene*/ else ck = st->stream->odm->subscene->dyn_ck; - /*since audio may be used alone through an inline scene, we need to refresh the graph*/ - if (ck && !ck->has_seen_eos && st->stream->odm->state) gf_term_invalidate_compositor(st->stream->odm->term); + if (st->stream->odm->subscene->is_dynamic_scene) do_update_clock = 0; } /*check anim streams*/ else if (st->stream->odm->codec && (st->stream->odm->codec->type==GF_STREAM_SCENE)) ck = st->stream->odm->codec->ck; @@ -78,9 +78,17 @@ void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy) else if (st->stream->odm->ocr_codec) ck = st->stream->odm->ocr_codec->ck; if (ck && gf_clock_is_started(ck) ) { - st->stream->odm->current_time = gf_clock_time(ck); + if (do_update_clock) + st->stream->odm->media_current_time = gf_clock_media_time(ck); mediasensor_update_timing(st->stream->odm, 0); } + //if main addon is VoD , fire a timeshift update + else if (st->stream->odm->subscene && st->stream->odm->subscene->sys_clock_at_main_activation) { + GF_Event evt; + memset(&evt, 0, sizeof(evt)); + evt.type = GF_EVENT_TIMESHIFT_UPDATE; + gf_term_send_event(st->stream->odm->term, &evt); + } } void InitMediaSensor(GF_Scene *scene, GF_Node *node) @@ -121,7 +129,7 @@ void MS_Modified(GF_Node *node) } -static void media_sensor_activate(MediaSensorStack *media_sens, GF_Segment *desc) +static void media_sensor_activate_segment(MediaSensorStack *media_sens, GF_Segment *desc) { media_sens->sensor->isActive = 1; gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); @@ -146,7 +154,7 @@ void mediasensor_update_timing(GF_ObjectManager *odm, Bool is_eos) ms_count = gf_list_count(odm->ms_stack); if (!ms_count) return; - time = odm->current_time / 1000.0; + time = odm->media_current_time / 1000.0; //dirty hack to get timing of frame when very late (openhevc debug) if (odm->subscene && odm->subscene->dyn_ck && odm->subscene->dyn_ck->last_TS_rendered) time = odm->subscene->dyn_ck->last_TS_rendered / 1000.0; @@ -236,7 +244,7 @@ void mediasensor_update_timing(GF_ObjectManager *odm, Bool is_eos) } if (!media_sens->sensor->isActive) { - media_sensor_activate(media_sens, desc); + media_sensor_activate_segment(media_sens, desc); GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Activating media sensor time %g - segment %s\n", odm->OD->objectDescriptorID, time, desc->SegmentName)); } diff --git a/src/terminal/mpeg4_inline.c b/src/terminal/mpeg4_inline.c index 0c4d197..8c547ab 100644 --- a/src/terminal/mpeg4_inline.c +++ b/src/terminal/mpeg4_inline.c @@ -68,8 +68,10 @@ static Bool gf_inline_set_scene(M_Inline *root) } /*assign inline scene as private stack of inline node, and remember inline node for event propagation*/ gf_node_set_private((GF_Node *)root, mo->odm->subscene); + /*play*/ gf_mo_play(mo, 0, -1, GF_FALSE); + return GF_TRUE; } @@ -125,8 +127,8 @@ void gf_inline_on_modified(GF_Node *node) } else { gf_term_lock_media_queue(scene->root_od->term, GF_TRUE); - /*external media are completely unloaded*/ - if (scene->root_od->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID) { + /*external media are completely unloaded, except addons which are only declared once */ + if (!scene->root_od->addon && (scene->root_od->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID)) { scene->root_od->action_type = GF_ODM_ACTION_DELETE; } else { scene->root_od->action_type = GF_ODM_ACTION_STOP; @@ -206,12 +208,17 @@ void gf_scene_mpeg4_inline_restart(GF_Scene *scene) if (scene->root_od->media_ctrl) current_seg = scene->root_od->media_ctrl->current_seg; if (scene->is_dynamic_scene) { - u32 from = 0; + s64 from = 0; if (scene->root_od->media_ctrl) { - scene->root_od->media_ctrl->current_seg = current_seg; - from = (u32) (scene->root_od->media_ctrl->media_start * 1000); + if (scene->root_od->media_ctrl->media_stop<=0) { + from = (s64) (scene->root_od->media_ctrl->media_stop * 1000) - 1; + } + else if (scene->root_od->media_ctrl->media_start>=0) { + scene->root_od->media_ctrl->current_seg = current_seg; + from = (s64) (scene->root_od->media_ctrl->media_start * 1000); + } } - gf_scene_restart_dynamic(scene, from); + gf_scene_restart_dynamic(scene, from, 0, 0); } else { /*we cannot use gf_mo_restart since it only sets the needs_restart for inline scenes. The rational is that gf_mo_restart can be called from the parent scene (OK) or from the scene itself, in @@ -375,7 +382,7 @@ GF_SceneGraph *gf_inline_get_proto_lib(void *_is, MFURL *lib_url) while ((pl = (GF_ProtoLink*)gf_list_enum(check_scene->extern_protos, &i))) { char *url1, *url2; Bool ok; - if (!pl->mo) continue; + if (!pl->mo || !pl->mo->odm) continue; if (! pl->mo->odm->net_service) continue; if (gf_mo_get_od_id(pl->url) != GF_MEDIA_EXTERNAL_ID) continue; /*not the same url*/ diff --git a/src/terminal/network_service.c b/src/terminal/network_service.c index 1122d47..f48c6e0 100644 --- a/src/terminal/network_service.c +++ b/src/terminal/network_service.c @@ -68,6 +68,9 @@ static void term_on_connect(GF_ClientService *service, LPNETCHANNEL netch, GF_Er /*destroy service only if attached*/ if (root) { gf_term_lock_media_queue(term, 1); + //notify before disconnecting + if (root->subscene) gf_scene_notify_event(root->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, err, GF_FALSE); + service->ifce->CloseService(service->ifce); root->net_service = NULL; if (service->owner && service->nb_odm_users) service->nb_odm_users--; @@ -86,7 +89,6 @@ static void term_on_connect(GF_ClientService *service, LPNETCHANNEL netch, GF_Er evt.connect.is_connected = 0; gf_term_send_event(term, &evt); } else { - if (root->subscene) gf_scene_notify_event(root->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, err, GF_FALSE); /*try to reinsert OD for VRML/X3D with multiple URLs: 1- first remove from parent scene without destroying object, this will trigger a re-setup if other URLs are present @@ -186,13 +188,17 @@ static void term_on_disconnect(GF_ClientService *service, LPNETCHANNEL netch, GF GF_ObjectManager *root; GF_Channel *ch; GF_Terminal *term = service->term; - + /*may be null upon destroy*/ root = service->owner; if (root && (root->net_service != service)) { if (root->net_service) gf_term_message(term, service->url, "Incompatible module type", GF_SERVICE_ERROR); return; } + //reset global seek time + if (term->root_scene && term->root_scene->root_od) + term->root_scene->root_od->media_start_time = 0; + /*this is service disconnect*/ if (!netch) { if (service->subservice_disconnect) { @@ -270,10 +276,15 @@ static void term_on_media_add(GF_ClientService *service, GF_Descriptor *media_de return; } scene = root->subscene ? root->subscene : root->parentscene; + if (scene->root_od->addon && (scene->root_od->addon->addon_type == GF_ADDON_TYPE_MAIN)) { + no_scene_check = 1; + scene->root_od->flags |= GF_ODM_REGENERATE_SCENE; + } GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Service %s] %s\n", service->url, media_desc ? "Adding new media object" : "Regenerating scene graph")); if (!media_desc) { - if (!no_scene_check) gf_scene_regenerate(scene); + if (!no_scene_check) + gf_scene_regenerate(scene); return; } @@ -317,7 +328,11 @@ static void term_on_media_add(GF_ClientService *service, GF_Descriptor *media_de if (mo->odm->OD) { if (od->objectDescriptorID && is_same_od(mo->odm->OD, od)) { /*reassign OD ID*/ - mo->OD_ID = od->objectDescriptorID; + if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) { + od->objectDescriptorID = mo->OD_ID; + } else { + mo->OD_ID = od->objectDescriptorID; + } gf_odf_desc_del(media_desc); gf_term_lock_net(term, 0); return; @@ -399,8 +414,11 @@ static void term_on_media_add(GF_ClientService *service, GF_Descriptor *media_de odm = gf_odm_new(); odm->term = term; odm->parentscene = scene; + gf_mx_p(scene->mx_resources); gf_list_add(scene->resources, odm); + gf_mx_v(scene->mx_resources); } + odm->flags |= GF_ODM_NOT_SETUP; odm->OD = od; odm->mo = the_mo; odm->flags |= GF_ODM_NOT_IN_OD_STREAM; @@ -433,22 +451,31 @@ static void gather_buffer_level(GF_ObjectManager *odm, GF_ClientService *service if (ch->es_state != GF_ESM_ES_RUNNING) continue; if (com->base.on_channel && (com->base.on_channel != ch)) continue; if (/*!ch->MaxBuffer || */ch->dispatch_after_db || ch->bypass_sl_and_db || ch->IsEndOfStream) continue; - //perform buffer management only on base layer -this is because we don't signal which ESs are on/off in the underlying service ... - if (ch->esd->dependsOnESID) continue; + + //if not in hybrid mode, perform buffer management only on base layer -this is because we don't signal which ESs are on/off in the underlying service ... + if (ch->esd->dependsOnESID) { + if (!ch->odm->lower_layer_odm) continue; + if (ch->odm->net_service == ch->odm->lower_layer_odm->net_service) continue; + } + + gf_es_update_buffering(ch, 0); + if (ch->MaxBuffer>com->buffer.max) com->buffer.max = ch->MaxBuffer; if (ch->MinBufferbuffer.min) com->buffer.min = ch->MinBuffer; + if (ch->IsClockInit) { - if (ch->BufferTime > (s32) *max_buffer_time) - *max_buffer_time = ch->BufferTime; + s32 buf_time = (s32) (ch->BufferTime / FIX2FLT(ch->clock->speed) ); + if (!buf_time && ch->BufferTime) buf_time = ch->BufferTime; + + if (buf_time > (s32) *max_buffer_time) + *max_buffer_time = buf_time ; /*if we don't have more units (compressed or not) than requested max for the composition memory, request more data*/ if (ch->odm->codec && ch->odm->codec->CB && (odm->codec->CB->UnitCount + ch->AU_Count <= odm->codec->CB->Capacity)) { com->buffer.occupancy = 0; - } else if ( (u32) ch->BufferTime < com->buffer.occupancy) { - com->buffer.occupancy = ch->BufferTime; + } else if ( (u32) buf_time < com->buffer.occupancy ) { + com->buffer.occupancy = buf_time; } - } else { - com->buffer.occupancy = 0; } } } @@ -459,7 +486,8 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G GF_Terminal *term = service->term; if (com->command_type==GF_NET_BUFFER_QUERY) { - GF_List *od_list; + GF_Scene *scene; + u32 i, max_buffer_time; GF_ObjectManager *odm; com->buffer.max = 0; @@ -470,28 +498,27 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G } /*browse all channels in the scene, running on this service, and get buffer info*/ - od_list = NULL; + scene = NULL; if (service->owner->subscene) { - od_list = service->owner->subscene->resources; + scene = service->owner->subscene; } else if (service->owner->parentscene) { - od_list = service->owner->parentscene->resources; + scene = service->owner->parentscene; } - if (!od_list) { + if (!scene) { com->buffer.occupancy = 0; return; } - /*get exclusive access to media scheduler, to make sure ODs are not being - manipulated*/ - gf_mx_p(term->mm_mx); + /*get exclusive access to scene resources , to make sure ODs are not being inserted/remove*/ + gf_mx_p(scene->mx_resources); + max_buffer_time=0; - if (!gf_list_count(od_list)) + if (!gf_list_count(scene->resources)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; - while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { - if (!odm->codec) continue; + while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { gather_buffer_level(odm, service, com, &max_buffer_time); } - gf_mx_v(term->mm_mx); + gf_mx_v(scene->mx_resources); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; //in bench mode return the 1 if one of the buffer is full (eg sleep until all buffers are not full), 0 otherwise @@ -531,7 +558,7 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G } com->send_event.res = 0; - if (term->user->EventProc) com->send_event.res = term->user->EventProc(term->user->opaque, &com->send_event.evt); + gf_term_send_event(term, &com->send_event.evt); return; } @@ -557,7 +584,20 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G gf_scene_notify_associated_media_timeline(scene, &com->addon_time); return; } - + if (com->command_type==GF_NET_SERVICE_SEEK) { + GF_Scene *scene = NULL; + if (service->owner->subscene) { + scene = service->owner->subscene; + } else if (service->owner->parentscene) { + scene = service->owner->parentscene; + } + if (scene && scene->is_dynamic_scene) { + gf_sc_lock(term->compositor, 1); + gf_scene_restart_dynamic(scene, (u64) (com->play.start_range*1000), 0, 0); + gf_sc_lock(term->compositor, 0); + } + return; + } if (!com->base.on_channel) return; @@ -571,6 +611,19 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; + case GF_NET_CHAN_SET_MEDIA_TIME: + if (gf_es_owns_clock(ch) || !ch->clock->has_media_time_shift) { + Double mtime = com->map_time.media_time; + if (ch->clock->clock_init) { + Double t = (Double) com->map_time.timestamp; + t /= ch->esd->slConfig->timestampResolution; + t -= ((Double) ch->clock->init_time) /1000; + mtime += t; + } + ch->clock->media_time_at_init = (u32) (1000*mtime); + ch->clock->has_media_time_shift = 1; + } + return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: @@ -624,7 +677,7 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; - com->buffer.occupancy = ch->BufferTime; + com->buffer.occupancy = (u32) (ch->BufferTime / FIX2FLT(ch->clock->speed) ); } break; case GF_NET_CHAN_DRM_CFG: @@ -642,14 +695,21 @@ static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, G gf_es_reset_buffers(ch); break; case GF_NET_CHAN_PAUSE: + ch->MaxBuffer = com->buffer.max; + ch->MinBuffer = com->buffer.min; + ch->BufferTime = com->buffer.max; gf_es_buffer_on(ch); break; case GF_NET_CHAN_RESUME: + ch->BufferTime = ch->MaxBuffer; + gf_es_update_buffering(ch, 1); gf_es_buffer_off(ch); break; case GF_NET_CHAN_BUFFER: - ch->BufferTime = 100 * com->buffer.occupancy / com->buffer.max; - gf_scene_buffering_info(ch->odm->parentscene ? ch->odm->parentscene : ch->odm->subscene); + ch->MaxBuffer = com->buffer.max; + ch->MinBuffer = com->buffer.min; + ch->BufferTime = com->buffer.max * com->buffer.occupancy / 100; + gf_es_update_buffering(ch, 1); break; default: return; @@ -911,7 +971,11 @@ static GF_InputService *gf_term_can_handle_service(GF_Terminal *term, const char } exit: if (!ifce) { - GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Did not find any input plugin for URL %s (%s)\n", sURL ? sURL : url, mime_type ? mime_type : "no mime type")); + if (*ret_code) { + GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Error fetching mime type for URL %s: %s\n", sURL ? sURL : url, gf_error_to_string(*ret_code) )); + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Did not find any input plugin for URL %s (%s) \n", sURL ? sURL : url, mime_type ? mime_type : "no mime type")); + } if (sURL) gf_free(sURL); if ( (*ret_code) == GF_OK) (*ret_code) = GF_NOT_SUPPORTED; *out_url = NULL; @@ -939,8 +1003,10 @@ GF_ClientService *gf_term_service_new(GF_Terminal *term, struct _od_manager *own char *mime; GF_ClientService *serv; GF_InputService *ifce = gf_term_can_handle_service(term, url, parent_url, 0, &sURL, ret_code, &download_session, &mime); - if (!ifce) return NULL; - + if (!ifce) { + if (owner->subscene) gf_scene_notify_event(owner->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, *ret_code, GF_FALSE); + return NULL; + } GF_SAFEALLOC(serv, GF_ClientService); serv->term = term; serv->owner = owner; @@ -951,7 +1017,9 @@ GF_ClientService *gf_term_service_new(GF_Terminal *term, struct _od_manager *own serv->dnloads = gf_list_new(); serv->pending_service_session = download_session; + gf_term_lock_media_queue(term, 1); gf_list_add(term->net_services, serv); + gf_term_lock_media_queue(term, 0); serv->fn_connect_ack = term_on_connect; @@ -988,6 +1056,7 @@ Bool gf_term_service_can_handle_url(GF_ClientService *ns, char *url) return ns->ifce->CanHandleURLInService(ns->ifce, url); } +GF_EXPORT GF_Err gf_term_service_command(GF_ClientService *ns, GF_NetworkCommand *com) { if (ns) return ns->ifce->ServiceCommand(ns->ifce, com); @@ -1196,7 +1265,7 @@ void gf_service_download_update_stats(GF_DownloadSession * sess) if (serv->is_paused) { serv->is_paused = 0; #ifndef GPAC_DISABLE_VRML - mediacontrol_resume(serv->owner); + mediacontrol_resume(serv->owner, 0); #endif } } diff --git a/src/terminal/object_browser.c b/src/terminal/object_browser.c index b45e8ca..23e425f 100644 --- a/src/terminal/object_browser.c +++ b/src/terminal/object_browser.c @@ -156,7 +156,7 @@ u32 gf_term_get_current_service_id(GF_Terminal *term) static void get_codec_stats(GF_Codec *dec, GF_MediaInfo *info) { info->instant_bitrate = dec->avg_bit_rate; - info->avg_bitrate = (u32) (dec->tot_bit_size * (1000.0 / (dec->last_unit_dts-dec->stat_start)) ); + info->avg_bitrate = dec->avg_bit_rate; info->max_bitrate = dec->max_bit_rate; info->nb_dec_frames = dec->nb_dec_frames; info->max_dec_time = dec->max_dec_time; @@ -164,51 +164,70 @@ static void get_codec_stats(GF_Codec *dec, GF_MediaInfo *info) info->first_frame_time = dec->first_frame_time; info->last_frame_time = dec->last_frame_time; info->raw_media = dec->flags & GF_ESM_CODEC_IS_RAW_MEDIA; + info->au_duration = dec->min_frame_dur; + info->nb_iraps = dec->nb_iframes; + info->irap_max_dec_time = dec->max_iframes_time; + info->irap_total_dec_time = dec->total_iframes_time; + + } GF_EXPORT GF_Err gf_term_get_object_info(GF_Terminal *term, GF_ObjectManager *odm, GF_MediaInfo *info) { + GF_ObjectManager *an_odm; GF_Channel *ch; + GF_Codec *codec; + + memset(info, 0, sizeof(GF_MediaInfo)); - if (!term || !odm || !odm->OD || !info) return GF_BAD_PARAM; + if (!term || !odm || !info) return GF_BAD_PARAM; if (!gf_term_check_odm(term, odm)) return GF_BAD_PARAM; - memset(info, 0, sizeof(GF_MediaInfo)); info->od = odm->OD; info->duration = (Double) (s64)odm->duration; info->duration /= 1000; - if (odm->codec) { + codec = odm->codec; + an_odm = odm; + while (!codec) { + if (!an_odm->lower_layer_odm) break; + an_odm = an_odm->lower_layer_odm; + codec = an_odm->codec; + } + + if (codec) { /*since we don't remove ODs that failed setup, check for clock*/ - if (odm->codec->ck) { - if (odm->codec->CB) { - info->current_time = odm->current_time ? odm->current_time : odm->codec->last_unit_cts; + if (codec->ck) { + if (codec->CB) { + info->current_time = odm->media_current_time ? odm->media_current_time : codec->last_unit_cts; + info->ntp_diff = codec->CB->LastRenderedNTPDiff; } else { - info->current_time = gf_clock_time(odm->codec->ck); + info->current_time = gf_clock_media_time(codec->ck); } } info->current_time /= 1000; - info->nb_droped = odm->codec->nb_droped; + info->nb_dropped = codec->nb_dropped; } else if (odm->subscene) { if (odm->subscene->scene_codec) { if (odm->subscene->scene_codec->ck) { - info->current_time = gf_clock_time(odm->subscene->scene_codec->ck); + info->current_time = gf_clock_media_time(odm->subscene->scene_codec->ck); info->current_time /= 1000; } info->duration = (Double) (s64)odm->subscene->duration; info->duration /= 1000; - info->nb_droped = odm->subscene->scene_codec->nb_droped; + info->nb_dropped = odm->subscene->scene_codec->nb_dropped; + codec = odm->subscene->scene_codec; } else if (odm->subscene->is_dynamic_scene) { if (odm->subscene->dyn_ck) { - info->current_time = gf_clock_time(odm->subscene->dyn_ck); + info->current_time = gf_clock_media_time(odm->subscene->dyn_ck); info->current_time /= 1000; } info->generated_scene = 1; } } - if (info->current_time>info->duration) + if (info->duration && info->current_time>info->duration) info->current_time = info->duration; info->buffer = -2; @@ -233,13 +252,19 @@ GF_Err gf_term_get_object_info(GF_Terminal *term, GF_ObjectManager *odm, GF_Medi info->clock_drift = ck->drift; info->buffer = -1; + info->min_buffer = -1; + info->max_buffer = 0; buf = 0; i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) { info->db_unit_count += ch->AU_Count; - if (!ch->is_pulling) { + if (!ch->is_pulling || ch->MaxBuffer) { if (ch->MaxBuffer) info->buffer = 0; buf += ch->BufferTime; + + if (ch->MaxBuffer> info->max_buffer) info->max_buffer = ch->MaxBuffer; + if (ch->MinBuffer < info->min_buffer) info->min_buffer = ch->MinBuffer; + } if (ch->is_protected) info->protection = ch->ipmp_tool ? 1 : 2; @@ -268,31 +293,25 @@ GF_Err gf_term_get_object_info(GF_Terminal *term, GF_ObjectManager *odm, GF_Medi info->service_url = "Service not found or error"; } - if (odm->codec && odm->codec->decio) { - if (!odm->codec->decio->GetName) { - info->codec_name = odm->codec->decio->module_name; + if (codec) { + if (codec->decio && codec->decio->GetName) { + info->codec_name = codec->decio->GetName(codec->decio); } else { - info->codec_name = odm->codec->decio->GetName(odm->codec->decio); + info->codec_name = codec->decio->module_name; } - info->od_type = odm->codec->type; - if (odm->codec->CB) { - info->cb_max_count = odm->codec->CB->Capacity; - info->cb_unit_count = odm->codec->CB->UnitCount; - if (odm->codec->direct_vout) { + info->od_type = codec->type; + + if (codec->CB) { + info->cb_max_count = codec->CB->Capacity; + info->cb_unit_count = codec->CB->UnitCount; + if (codec->direct_vout) { info->direct_video_memory = 1; } } + get_codec_stats(codec, info); } - if (odm->subscene && odm->subscene->scene_codec) { - GF_BaseDecoder *dec = odm->subscene->scene_codec->decio; - assert(odm->subscene->root_od==odm) ; - info->od_type = odm->subscene->scene_codec->type; - if (!dec->GetName) { - info->codec_name = dec->module_name; - } else { - info->codec_name = dec->GetName(dec); - } + if (odm->subscene) { gf_sg_get_scene_size_info(odm->subscene->graph, &info->width, &info->height); } else if (odm->mo) { switch (info->od_type) { @@ -308,8 +327,6 @@ GF_Err gf_term_get_object_info(GF_Terminal *term, GF_ObjectManager *odm, GF_Medi break; } } - if (odm->subscene && odm->subscene->scene_codec) get_codec_stats(odm->subscene->scene_codec, info); - else if (odm->codec) get_codec_stats(odm->codec, info); ch = (GF_Channel*)gf_list_get(odm->channels, 0); if (ch && ch->esd->langDesc) info->lang = ch->esd->langDesc->langCode; diff --git a/src/terminal/object_manager.c b/src/terminal/object_manager.c index 6003987..49f9d35 100644 --- a/src/terminal/object_manager.c +++ b/src/terminal/object_manager.c @@ -57,10 +57,10 @@ GF_ObjectManager *gf_odm_new() } void gf_odm_reset_media_control(GF_ObjectManager *odm, Bool signal_reset) - { - #ifndef GPAC_DISABLE_VRML - MediaSensorStack *media_sens; - MediaControlStack *media_ctrl; +{ +#ifndef GPAC_DISABLE_VRML + MediaSensorStack *media_sens; + MediaControlStack *media_ctrl; while ((media_sens = (MediaSensorStack *)gf_list_last(odm->ms_stack))) { MS_Stop(media_sens); @@ -70,21 +70,28 @@ void gf_odm_reset_media_control(GF_ObjectManager *odm, Bool signal_reset) } while ((media_ctrl = (MediaControlStack *)gf_list_last(odm->mc_stack))) { - if (signal_reset) + if (signal_reset) gf_odm_remove_mediacontrol(odm, media_ctrl); media_ctrl->stream = NULL; media_ctrl->ck = NULL; gf_list_rem_last(odm->mc_stack); } - #endif +#endif } + void gf_odm_del(GF_ObjectManager *odm) { if (odm->addon && (odm->addon->root_od==odm)) { odm->addon->root_od = NULL; odm->addon->started = 0; } + if (odm->upper_layer_odm) { + odm->upper_layer_odm->lower_layer_odm = NULL; + } + if (odm->lower_layer_odm) { + odm->lower_layer_odm->upper_layer_odm = NULL; + } /*make sure we are not in the media queue*/ gf_term_lock_media_queue(odm->term, GF_TRUE); gf_list_del_item(odm->term->media_queue, odm); @@ -281,7 +288,11 @@ void gf_odm_disconnect(GF_ObjectManager *odm, u32 do_remove) evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = GF_FALSE; gf_term_send_event(odm->term, &evt); - } + } + //this is an extra scene not part of the main tree (eg declared from modules), don't post events + else if (odm->subscene) { + gf_scene_del(odm->subscene); + } gf_term_lock_net(term, GF_TRUE); /*delete the ODMan*/ @@ -622,7 +633,14 @@ static Bool gf_odm_should_auto_select(GF_ObjectManager *odm) u32 i, count; if (gf_codec_is_scene_or_image(odm->codec)) return GF_TRUE; - if (odm->parentscene && !odm->parentscene->is_dynamic_scene) return GF_TRUE; + if (odm->parentscene && !odm->parentscene->is_dynamic_scene) { + return GF_TRUE; + } + + if (odm->parentscene && odm->parentscene->root_od->addon) { + if (odm->parentscene->root_od->addon->addon_type == GF_ADDON_TYPE_MAIN) + return GF_FALSE; + } count = gf_list_count(odm->parentscene->resources); for (i=0; iOD->URLString = NULL; /*store original OD ID */ - if (!odm->current_time) odm->current_time = odm->OD->objectDescriptorID; + if (!odm->media_current_time) odm->media_current_time = odm->OD->objectDescriptorID; gf_odf_desc_del((GF_Descriptor *)odm->OD); odm->OD = NULL; @@ -696,9 +714,9 @@ void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv) return; } /*restore OD ID */ - if (odm->current_time) { - odm->OD->objectDescriptorID = odm->current_time; - odm->current_time = 0; + if (odm->media_current_time) { + odm->OD->objectDescriptorID = odm->media_current_time; + odm->media_current_time = 0; odm->flags |= GF_ODM_REMOTE_OD; } @@ -763,8 +781,12 @@ void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv) if (odm->parentscene) { GF_Event evt; - if (!odm->scalable_addon) + //this may result in an attempt to lock the compositor, so release the net MX before + if (!odm->scalable_addon) { + gf_term_lock_net(odm->term, GF_FALSE); gf_scene_setup_object(odm->parentscene, odm); + gf_term_lock_net(odm->term, GF_TRUE); + } /*setup node decoder*/ if (odm->mo && odm->codec && odm->codec->decio && (odm->codec->decio->InterfaceType==GF_NODE_DECODER_INTERFACE) ) { @@ -798,16 +820,17 @@ void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv) gf_term_lock_net(odm->term, GF_TRUE); } - /* start object*/ /*case 1: object is the root, always start*/ if (!odm->parentscene) { assert(odm->subscene == odm->term->root_scene); assert(odm->subscene->root_od==odm); + odm->flags &= ~GF_ODM_NOT_SETUP; gf_odm_start(odm, 0); } /*case 2: object is a pure OCR object - connect*/ else if (odm->ocr_codec) { + odm->flags &= ~GF_ODM_NOT_SETUP; gf_odm_start(odm, 0); } /*case 3: if the object is inserted from a broadcast, start it if not already done. This covers cases where the scene (BIFS, LASeR) and @@ -817,6 +840,8 @@ void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv) as can be the case with MPEG2 TS (first video packet right after the PMT) - this should be refined*/ else if ( ((odm->flags & GF_ODM_NO_TIME_CTRL) || (odm->flags & GF_ODM_NOT_IN_OD_STREAM)) && gf_odm_should_auto_select(odm) && (odm->parentscene->selected_service_id == odm->OD->ServiceID)) { Bool force_play = GF_FALSE; + //since we're about to evaluate the play state, lock the queue + gf_term_lock_media_queue(odm->term, GF_TRUE); if (odm->state==GF_ODM_STATE_STOP) { odm->flags |= GF_ODM_PREFETCH; force_play = GF_TRUE; @@ -825,36 +850,68 @@ void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv) else if ((odm->state==GF_ODM_STATE_PLAY) && (gf_list_del_item(odm->term->media_queue, odm)>=0) ) { force_play = GF_TRUE; } + gf_term_lock_media_queue(odm->term, GF_FALSE); if (force_play) { odm->flags |= GF_ODM_INITIAL_BROADCAST_PLAY; - GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Inserted from broadcast or input service - forcing play\n", odm->OD->objectDescriptorID)); + odm->parentscene->selected_service_id = odm->OD->ServiceID; + + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Inserted from input service %s - forcing play\n", odm->OD->objectDescriptorID, odm->net_service->url)); + odm->flags &= ~GF_ODM_NOT_SETUP; gf_odm_start(odm, 2); } } + odm->flags &= ~GF_ODM_NOT_SETUP; + /*for objects inserted by user (subs & co), auto select*/ if (odm->parentscene && odm->parentscene->is_dynamic_scene && (odm->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID) && (odm->flags & GF_ODM_REMOTE_OD) ) { GF_Event evt; - if (odm->OD_PL) { - gf_scene_select_object(odm->parentscene, odm); - odm->OD_PL = 0; - gf_term_lock_net(odm->term, GF_FALSE); - return; - } if (odm->addon) { + Bool role_set = 0; gf_term_lock_net(odm->term, GF_FALSE); - if (! odm->addon->scalable_type) { + if (odm->addon->addon_type >= GF_ADDON_TYPE_MAIN) return; + + //check role - for now look into URL, we need to inspect DASH roles + if (odm->mo->URLs.count && odm->mo->URLs.vals[0].url) { + char *sep = strchr(odm->mo->URLs.vals[0].url, '?'); + if (sep && strstr(sep, "role=main")) { + odm->addon->addon_type = GF_ADDON_TYPE_MAIN; + role_set = 1; + } + } + + if (!role_set) { + GF_NetworkCommand com; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_INFO; + com.info.on_channel = gf_list_get(odm->channels, 0); + gf_term_service_command(odm->net_service, &com); + + if (com.info.role && !strcmp(com.info.role, "main")) { + odm->addon->addon_type = GF_ADDON_TYPE_MAIN; + } + } + + + if (odm->addon->addon_type == GF_ADDON_TYPE_ADDITIONAL) { gf_scene_select_object(odm->parentscene, odm); } return; } + if (odm->OD_PL) { + gf_scene_select_object(odm->parentscene, odm); + odm->OD_PL = 0; + gf_term_lock_net(odm->term, GF_FALSE); + return; + } + if (odm->parentscene==odm->term->root_scene) { gf_term_lock_net(odm->term, GF_FALSE); @@ -865,10 +922,10 @@ void gf_odm_setup_object(GF_ObjectManager *odm, GF_ClientService *serv) } /*if object codec is prefered one, auto select*/ - if (odm->parentscene && odm->parentscene->is_dynamic_scene - && odm->codec && (odm->codec->oti==odm->term->prefered_audio_codec_oti) - && (odm->parentscene->selected_service_id == odm->OD->ServiceID) - ) { + if (odm->parentscene && odm->parentscene->is_dynamic_scene + && odm->codec && (odm->codec->oti==odm->term->prefered_audio_codec_oti) + && (odm->parentscene->selected_service_id == odm->OD->ServiceID) + ) { gf_scene_select_object(odm->parentscene, odm); } @@ -938,6 +995,8 @@ GF_Err gf_odm_setup_es(GF_ObjectManager *odm, GF_ESD *esd, GF_ClientService *ser scene = odm->subscene ? odm->subscene : odm->parentscene; ck_namespace = odm->net_service->Clocks; + odm->set_speed = odm->net_service->set_speed; + /*little trick for non-OD addressing: if object is a remote one, and service owner already has clocks, override OCR. This will solve addressing like file.avi#audio and file.avi#video*/ if (!esd->OCRESID && (odm->flags & GF_ODM_REMOTE_OD) && (gf_list_count(ck_namespace)==1) ) { @@ -1283,7 +1342,7 @@ GF_Err gf_odm_post_es_setup(GF_Channel *ch, GF_Codec *dec, GF_Err had_err) com.play.speed = FIX2FLT(ch->clock->speed); com.play.start_range = gf_clock_time(ch->clock); com.play.start_range /= 1000; - com.play.end_range = -1.0; + com.play.end_range = 0; gf_term_service_command(ch->service, &com); if (dec && (dec->Status!=GF_ESM_CODEC_PLAY)) gf_term_start_codec(dec, 0); gf_term_lock_net(ch->odm->term, 0); @@ -1387,6 +1446,12 @@ void gf_odm_start(GF_ObjectManager *odm, u32 media_queue_state) Bool skip_register = 1; gf_term_lock_media_queue(odm->term, 1); + if (odm->flags & GF_ODM_NOT_SETUP) { + gf_term_lock_media_queue(odm->term, 0); + return; + } + + /*only if not open & ready (not waiting for ACK on channel setup)*/ if (!odm->pending_channels && odm->OD) { /*object is not started - issue channel setup requests*/ @@ -1432,7 +1497,9 @@ void gf_odm_start(GF_ObjectManager *odm, u32 media_queue_state) if (media_queue_state==2) { odm->action_type = GF_ODM_ACTION_PLAY; + gf_term_lock_media_queue(odm->term, 0); gf_odm_play(odm); + gf_term_lock_media_queue(odm->term, 1); } else if (!skip_register && (gf_list_find(odm->term->media_queue, odm)<0)) { odm->action_type = GF_ODM_ACTION_PLAY; assert(! (odm->flags & GF_ODM_DESTROYED)); @@ -1459,6 +1526,7 @@ void gf_odm_play(GF_ObjectManager *odm) u64 range_end; Bool skip_od_st; Bool media_control_paused = 0; + Bool start_range_is_clock = 0; GF_NetworkCommand com; #ifndef GPAC_DISABLE_VRML MediaControlStack *ctrl; @@ -1515,7 +1583,7 @@ void gf_odm_play(GF_ObjectManager *odm) com.base.on_channel = ch; com.play.speed = 1.0; - + /*play from requested time (seeking or non-mpeg4 media control)*/ if (odm->media_start_time && !ch->clock->clock_init) { ck_time = (Double) (s64) odm->media_start_time; @@ -1527,23 +1595,44 @@ void gf_odm_play(GF_ObjectManager *odm) } /*play from current time*/ else { - if (odm->parentscene && odm->parentscene->root_od->addon) { - ck_time = gf_scene_adjust_time_for_addon(odm->parentscene, gf_clock_time(ch->clock), odm->parentscene->root_od->addon, &com.play.is_timestamp_based); - - if (odm->scalable_addon) { - //this is a scalable extension to an object in the parent scene - gf_scene_select_scalable_addon(odm->parentscene->root_od->parentscene, odm); + ck_time = gf_clock_media_time(ch->clock); + ck_time /= 1000; + start_range_is_clock = 1; + } + + /*handle initial start - MPEG-4 is a bit annoying here, streams are not started through OD but through + scene nodes. If the stream runs on the BIFS/OD clock, the clock is already started at this point and we're + sure to get at least a one-frame delay in PLAY, so just remove it - note we're generous but this shouldn't hurt*/ + if (ck_time<=0.5) ck_time = 0; + + + /*adjust time for addons*/ + if (odm->parentscene && odm->parentscene->root_od->addon) { + com.play.initial_broadcast_play = 0; + //addon timing is resolved against timestamps, not media time + if (start_range_is_clock) { + if (!gf_clock_is_started(ch->clock)) { + ck_time = (Double) odm->parentscene->root_od->addon->media_pts; + ck_time /= 90000; + } else { + ck_time = gf_clock_time(ch->clock); + ck_time /= 1000; } - } else { - ck_time = gf_clock_time(ch->clock); - ck_time /= 1000; } + ck_time = gf_scene_adjust_time_for_addon(odm->parentscene->root_od->addon, ck_time, &com.play.timestamp_based); + //we are having a play request for an addon without the main content being active - we no longer have timestamp info from the main content + if (!ch->clock->clock_init && com.play.timestamp_based) + com.play.timestamp_based = 2; - /*handle initial start - MPEG-4 is a bit annoying here, streams are not started through OD but through - scene nodes. If the stream runs on the BIFS/OD clock, the clock is already started at this point and we're - sure to get at least a one-frame delay in PLAY, so just remove it - note we're generous but this shouldn't hurt*/ - if (ck_time<=0.5) ck_time = 0; + if (ck_time<0) + ck_time=0; + + if (odm->scalable_addon) { + //this is a scalable extension to an object in the parent scene + gf_scene_select_scalable_addon(odm->parentscene->root_od->parentscene, odm); + } } + com.play.start_range = ck_time; if (range_end) { @@ -1554,20 +1643,24 @@ void gf_odm_play(GF_ObjectManager *odm) ) { com.play.end_range = (s64) odm->parentscene->root_od->media_stop_time / 1000.0; } else { - com.play.end_range = -1; + com.play.end_range = 0; } } com.play.speed = ch->clock->speed; #ifndef GPAC_DISABLE_VRML - /*if object shares parent scene clock, do not use media control*/ - ctrl = parent_ck ? NULL : gf_odm_get_mediacontrol(odm); + ctrl = parent_ck ? parent_ck->mc : gf_odm_get_mediacontrol(odm); /*override range and speed with MC*/ if (ctrl) { - MC_GetRange(ctrl, &com.play.start_range, &com.play.end_range); + //this is fake timeshift, eg we are playing a VoD as a timeshift service: stop and start times have already been adjusted + if (ctrl->control->mediaStopTime<0 && !odm->timeshift_depth) { + } else { + MC_GetRange(ctrl, &com.play.start_range, &com.play.end_range); + } + com.play.speed = FIX2FLT(ctrl->control->mediaSpeed); - /*if the channel doesn't control the clock, jump to current time in the controled range, not just the begining*/ + /*if the channel doesn't control the clock, jump to current time in the controled range, not just the beginning*/ if ((ch->esd->ESID!=ch->clock->clockID) && (ck_time>com.play.start_range) && (com.play.end_range>com.play.start_range) && (ck_timeclock, ctrl->control->mediaSpeed); if (odm->mo) odm->mo->speed = ctrl->control->mediaSpeed; +#if 0 /*if requested seek time AND media control, adjust start range to current play time*/ if ((com.play.speed>=0) && odm->media_start_time) { if ((com.play.start_range>=0) && (com.play.end_range>com.play.start_range)) { @@ -1589,6 +1683,8 @@ void gf_odm_play(GF_ObjectManager *odm) } com.play.start_range += ck_time; } +#endif + } #endif @@ -1618,8 +1714,8 @@ void gf_odm_play(GF_ObjectManager *odm) gf_clock_buffer_off(ch->clock); } } else { + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] CH%d: At OTB %u requesting PLAY from %g to %g (clock init %d) - speed %g\n", odm->OD->objectDescriptorID, odm->net_service->url, ch->esd->ESID, gf_clock_time(ch->clock), com.play.start_range, com.play.end_range, ch->clock->clock_init, com.play.speed)); gf_term_service_command(ch->service, &com); - GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH%d: At OTB %u requesting PLAY from %g to %g (clock init %d)\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock), com.play.start_range, com.play.end_range, ch->clock->clock_init)); } } // odm->media_start_time = 0; @@ -1645,7 +1741,10 @@ void gf_odm_play(GF_ObjectManager *odm) if (odm->flags & GF_ODM_REGENERATE_SCENE) { odm->flags &= ~GF_ODM_REGENERATE_SCENE; - gf_scene_regenerate(odm->subscene); + if (!odm->subscene->graph_attached) + gf_scene_regenerate(odm->subscene); + else + gf_scene_restart_dynamic(odm->subscene, 0, 1, 0); } } if (odm->ocr_codec) gf_term_start_codec(odm->ocr_codec, 0); @@ -1653,8 +1752,17 @@ void gf_odm_play(GF_ObjectManager *odm) if (odm->oci_codec) gf_term_start_codec(odm->oci_codec, 0); #endif - if (media_control_paused) + if (odm->flags & GF_ODM_PAUSE_QUEUED) { + odm->flags &= ~GF_ODM_PAUSE_QUEUED; + media_control_paused = 1; + } + + if (odm->parentscene && odm->parentscene->pause_at_first_frame) + media_control_paused = GF_TRUE; + + if (media_control_paused) { gf_odm_pause(odm); + } } Bool gf_odm_owns_clock(GF_ObjectManager *odm, GF_Clock *ck) @@ -1686,8 +1794,8 @@ void gf_odm_stop(GF_ObjectManager *odm, Bool force_close) #endif GF_NetworkCommand com; - - if (!odm->state) return; + //root ODs of dynamic scene may not have seen play/pause request + if (!odm->state && !odm->scalable_addon && (!odm->subscene || !odm->subscene->is_dynamic_scene) ) return; #if 0 /*Handle broadcast environment, do not stop the object if no time control and instruction @@ -1729,7 +1837,7 @@ void gf_odm_stop(GF_ObjectManager *odm, Bool force_close) /*object was not unlocked, decoders were not started*/ if (odm->state==GF_ODM_STATE_BLOCKED) { - odm->current_time = 0; + odm->media_current_time = 0; gf_sema_notify(odm->raw_frame_sema, 1); return; } @@ -1772,9 +1880,14 @@ void gf_odm_stop(GF_ObjectManager *odm, Bool force_close) if (ch->service) { com.base.on_channel = ch; gf_term_service_command(ch->service, &com); - GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH %d At OTB %u requesting STOP\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock))); + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] CH %d At OTB %u requesting STOP\n", odm->OD->objectDescriptorID, odm->net_service->url, ch->esd->ESID, gf_clock_time(ch->clock))); } } + + if (odm->parentscene && odm->parentscene->root_od->addon) { + odm->parentscene->root_od->addon->started = 0; + } + gf_term_service_media_event(odm, GF_EVENT_ABORT); /*stop channels*/ @@ -1790,7 +1903,7 @@ void gf_odm_stop(GF_ObjectManager *odm, Bool force_close) // gf_term_lock_net(odm->term, 0); odm->state = GF_ODM_STATE_STOP; - odm->current_time = 0; + odm->media_current_time = 0; #ifndef GPAC_DISABLE_VRML /*reset media sensor(s)*/ @@ -1889,12 +2002,38 @@ void gf_odm_set_duration(GF_ObjectManager *odm, GF_Channel *ch, u64 stream_durat } +void gf_odm_set_timeshift_depth(GF_ObjectManager *odm, GF_Channel *ch, u32 stream_timeshift) +{ + if (odm->codec) { + if (ch->esd->decoderConfig->streamType == odm->codec->type) + if (odm->timeshift_depth != stream_timeshift) + odm->timeshift_depth = stream_timeshift; + } else if (odm->ocr_codec) { + if (ch->esd->decoderConfig->streamType == odm->ocr_codec->type) + if (odm->timeshift_depth != stream_timeshift) + odm->timeshift_depth = stream_timeshift; + } else if (odm->subscene && odm->subscene->scene_codec) { + //if (gf_list_find(odm->subscene->scene_codec->inChannels, ch) >= 0) { + if (odm->timeshift_depth != stream_timeshift) + odm->timeshift_depth = stream_timeshift; + //} + } + + /*update scene duration*/ + gf_scene_set_timeshift_depth(odm->subscene ? odm->subscene : (odm->parentscene ? odm->parentscene : odm->term->root_scene)); +} + + GF_Clock *gf_odm_get_media_clock(GF_ObjectManager *odm) { + while (odm->lower_layer_odm) { + odm = odm->lower_layer_odm; + } if (odm->codec) return odm->codec->ck; if (odm->ocr_codec) return odm->ocr_codec->ck; if (odm->subscene && odm->subscene->scene_codec) return odm->subscene->scene_codec->ck; if (odm->subscene && odm->subscene->dyn_ck) return odm->subscene->dyn_ck; + if (odm->parentscene && odm->parentscene->dyn_ck) return odm->parentscene->dyn_ck; return NULL; } @@ -1907,6 +2046,10 @@ Bool gf_odm_shares_clock(GF_ObjectManager *odm, GF_Clock *ck) while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) { if (ch->clock == ck) return 1; } + if (odm->subscene) { + if (odm->subscene->is_dynamic_scene && odm->subscene->dyn_ck == ck) return 1; + if (odm->subscene->scene_codec && odm->subscene->scene_codec->ck == ck) return 1; + } return 0; } @@ -1921,12 +2064,21 @@ void gf_odm_pause(GF_ObjectManager *odm) #endif GF_Channel *ch; - if (odm->flags & GF_ODM_NO_TIME_CTRL) return; + //postpone until the PLAY request + if (odm->state != GF_ODM_STATE_PLAY) { + odm->flags |= GF_ODM_PAUSE_QUEUED; + return; + } + if (odm->flags & GF_ODM_PAUSED) return; + odm->flags |= GF_ODM_PAUSED; + + //cleanup - we need to enter in stop state for broadcast modes + if (odm->flags & GF_ODM_NO_TIME_CTRL) return; /*stop codecs, and update status for media codecs*/ if (odm->codec) { - gf_term_stop_codec(odm->codec, 1); + //we don't pause codec but only change its status to PAUSE - this will allow decoding until CB is full, which will turn the codec in pause mode gf_codec_set_status(odm->codec, GF_ESM_CODEC_PAUSE); } else if (odm->subscene) { if (odm->subscene->scene_codec) { @@ -1944,9 +2096,12 @@ void gf_odm_pause(GF_ObjectManager *odm) i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) { gf_clock_pause(ch->clock); + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] CH%d: At OTB %u requesting PAUSE (clock init %d)\n", odm->OD->objectDescriptorID, odm->net_service->url, ch->esd->ESID, gf_clock_time(ch->clock), ch->clock->clock_init )); + + if (odm->state != GF_ODM_STATE_PLAY) continue; + com.base.on_channel = ch; gf_term_service_command(ch->service, &com); - GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH%d: At OTB %u requesting PAUSE (clock init %d)\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock), ch->clock->clock_init )); } #ifndef GPAC_DISABLE_VRML @@ -1972,8 +2127,15 @@ void gf_odm_resume(GF_ObjectManager *odm) MediaControlStack *ctrl; #endif - if (odm->flags & GF_ODM_NO_TIME_CTRL) return; + if (odm->flags & GF_ODM_PAUSE_QUEUED) { + odm->flags &= ~GF_ODM_PAUSE_QUEUED; + return; + } + + if (!(odm->flags & GF_ODM_PAUSED)) return; + odm->flags &= ~GF_ODM_PAUSED; + if (odm->flags & GF_ODM_NO_TIME_CTRL) return; /*start codecs, and update status for media codecs*/ if (odm->codec) { @@ -1998,9 +2160,12 @@ void gf_odm_resume(GF_ObjectManager *odm) i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) { gf_clock_resume(ch->clock); + + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d %s] CH%d: At OTB %u requesting RESUME (clock init %d)\n", odm->OD->objectDescriptorID, odm->net_service->url, ch->esd->ESID, gf_clock_time(ch->clock), ch->clock->clock_init )); + if (odm->state!= GF_ODM_STATE_PLAY) continue; + com.base.on_channel = ch; gf_term_service_command(ch->service, &com); - GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] CH%d: At OTB %u requesting RESUME (clock init %d)\n", odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_time(ch->clock), ch->clock->clock_init )); #ifndef GPAC_DISABLE_VRML /*override speed with MC*/ @@ -2022,7 +2187,7 @@ void gf_odm_resume(GF_ObjectManager *odm) #endif } -void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed) +void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed, Bool adjust_clock_speed) { u32 i; GF_NetworkCommand com; @@ -2034,7 +2199,9 @@ void gf_odm_set_speed(GF_ObjectManager *odm, Fixed speed) com.play.speed = FIX2FLT(speed); i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i)) ) { - gf_clock_set_speed(ch->clock, speed); + if (adjust_clock_speed) + gf_clock_set_speed(ch->clock, speed); + com.play.on_channel = ch; gf_term_service_command(ch->service, &com); } @@ -2128,7 +2295,7 @@ void gf_odm_signal_eos(GF_ObjectManager *odm) GF_ObjectManager *root = odm->parentscene->root_od; Bool is_over = 0; - if (!gf_scene_check_clocks(root->net_service, root->subscene)) return; + if (!gf_scene_check_clocks(root->net_service, root->subscene, 0)) return; if (root->subscene->is_dynamic_scene) is_over = 1; else diff --git a/src/terminal/scene.c b/src/terminal/scene.c index 9d9399d..c684157 100644 --- a/src/terminal/scene.c +++ b/src/terminal/scene.c @@ -43,8 +43,6 @@ #include "input_sensor.h" #include "media_memory.h" -void gf_scene_reset_addons(GF_Scene *scene); - GF_EXPORT Double gf_scene_get_time(void *_is) { @@ -64,6 +62,7 @@ Double gf_scene_get_time(void *_is) } #ifndef GPAC_DISABLE_VRML + void gf_storage_save(M_Storage *storage); #endif @@ -79,6 +78,7 @@ GF_Scene *gf_scene_new(GF_Scene *parentScene) GF_SAFEALLOC(tmp, GF_Scene); if (! tmp) return NULL; + tmp->mx_resources = gf_mx_new("SceneResources"); tmp->resources = gf_list_new(); tmp->scene_objects = gf_list_new(); tmp->extra_scenes = gf_list_new(); @@ -106,6 +106,17 @@ GF_Scene *gf_scene_new(GF_Scene *parentScene) return tmp; } +static void gf_scene_reset_urls(GF_Scene *scene) +{ +#define SFURL_RESET(__url) if (__url.url) gf_free(__url.url);\ + memset(&__url, 0, sizeof(SFURL)); + + SFURL_RESET(scene->audio_url); + SFURL_RESET(scene->visual_url); + SFURL_RESET(scene->text_url); + SFURL_RESET(scene->dims_url); +} + void gf_scene_del(GF_Scene *scene) { gf_mx_p(scene->root_od->term->net_mx); @@ -161,14 +172,13 @@ void gf_scene_del(GF_Scene *scene) gf_list_del(scene->declared_addons); - if (scene->audio_url.url) gf_free(scene->audio_url.url); - if (scene->visual_url.url) gf_free(scene->visual_url.url); - if (scene->text_url.url) gf_free(scene->text_url.url); - if (scene->dims_url.url) gf_free(scene->dims_url.url); + gf_scene_reset_urls(scene); + if (scene->fragment_uri) gf_free(scene->fragment_uri); if (scene->redirect_xml_base) gf_free(scene->redirect_xml_base); gf_mx_v(scene->root_od->term->net_mx); + gf_mx_del(scene->mx_resources); gf_free(scene); } @@ -307,6 +317,9 @@ void gf_scene_disconnect(GF_Scene *scene, Bool for_shutdown) gf_sg_vrml_mf_reset(&obj->URLs, GF_SG_VRML_MFURL); gf_mo_del(obj); } + + //reset URLs + gf_scene_reset_urls(scene); gf_term_lock_compositor(scene->root_od->term, GF_FALSE); } @@ -378,7 +391,9 @@ static void gf_scene_insert_object(GF_Scene *scene, GF_MediaObject *mo, Bool loc if (sync_ref) odm->ocr_codec = (struct _generic_codec *)sync_ref; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Scene] Inserting new MediaObject %08x for resource %s\n", odm->mo, url)); + gf_mx_p(scene->mx_resources); gf_list_add(scene->resources, odm); + gf_mx_v(scene->mx_resources); if (original_parent_scene) { gf_odm_setup_object(odm, original_parent_scene->root_od->net_service); } else { @@ -683,7 +698,7 @@ GF_MediaObject *gf_scene_get_media_object_ex(GF_Scene *scene, MFURL *url, u32 ob OD_ID = gf_mo_get_od_id(url); if (!OD_ID) return NULL; - gf_term_lock_net(scene->root_od->term, GF_TRUE); + gf_mx_p(scene->mx_resources); /*we may have overriden the time lines in parent scene, thus all objects in this scene have the same clock*/ if (scene->root_od->parentscene && scene->root_od->parentscene->force_single_timeline) @@ -747,12 +762,12 @@ restart: if (!first_pass && !force_new_if_not_attached) { if (node && (gf_mo_event_target_find_by_node(obj, node)<0)) gf_mo_event_target_add_node(obj, node); - gf_term_lock_net(scene->root_od->term, GF_FALSE); + gf_mx_v(scene->mx_resources); return obj; } /*special case where the URL is requested twice for the same node: use the existing resource*/ else if (node && (gf_mo_event_target_find_by_node(obj, node)>=0)) { - gf_term_lock_net(scene->root_od->term, GF_FALSE); + gf_mx_v(scene->mx_resources); return obj; } } @@ -763,7 +778,7 @@ restart: /*we cannot create an OD manager at this point*/ if (obj_type_hint==GF_MEDIA_OBJECT_UNDEF) { - gf_term_lock_net(scene->root_od->term, GF_FALSE); + gf_mx_v(scene->mx_resources); return NULL; } @@ -791,19 +806,19 @@ restart: gf_scene_insert_object(scene, obj, lock_timelines, sync_ref, keep_fragment, original_parent_scene); /*safety check!!!*/ if (gf_list_find(scene->scene_objects, obj)<0) { - gf_term_lock_net(scene->root_od->term, GF_FALSE); + gf_mx_v(scene->mx_resources); return NULL; } if (obj->odm==NULL) { gf_list_del_item(scene->scene_objects, obj); gf_mo_del(obj); - gf_term_lock_net(scene->root_od->term, GF_FALSE); + gf_mx_v(scene->mx_resources); return NULL; } } - gf_term_lock_net(scene->root_od->term, GF_FALSE); + gf_mx_v(scene->mx_resources); return obj; } @@ -863,7 +878,7 @@ existing: /*media object playback has already been requested by the scene, trigger media start*/ if (odm->mo->num_open && !odm->state) { gf_odm_start(odm, 0); - if (odm->mo->speed != FIX_ONE) gf_odm_set_speed(odm, odm->mo->speed); + if (odm->mo->speed != FIX_ONE) gf_odm_set_speed(odm, odm->mo->speed, GF_TRUE); } if ((odm->mo->type==GF_MEDIA_OBJECT_VIDEO) && scene->is_dynamic_scene && !odm->parentscene->root_od->addon) { gf_scene_force_size_to_video(scene, odm->mo); @@ -924,6 +939,39 @@ void gf_scene_set_duration(GF_Scene *scene) } +GF_EXPORT +void gf_scene_set_timeshift_depth(GF_Scene *scene) +{ + u32 i; + u32 max_timeshift; + GF_ObjectManager *odm; + GF_Clock *ck; + + ck = gf_odm_get_media_clock(scene->root_od); + max_timeshift = scene->root_od->timeshift_depth; + i=0; + while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { + if (!odm->codec) continue; + if (!ck || gf_odm_shares_clock(odm, ck)) { + if (odm->timeshift_depth > max_timeshift) max_timeshift = odm->timeshift_depth; + } + } + if (scene->timeshift_depth == max_timeshift) return; + + scene->timeshift_depth = max_timeshift; + if (scene->is_dynamic_scene && !scene->root_od->timeshift_depth) scene->root_od->timeshift_depth = max_timeshift; + if (scene->root_od->addon && (scene->root_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + if (scene->root_od->parentscene->is_dynamic_scene && (scene->root_od->parentscene->timeshift_depth < max_timeshift)) { + scene->root_od->parentscene->timeshift_depth = max_timeshift; + scene->root_od->parentscene->root_od->timeshift_depth = max_timeshift; + gf_scene_notify_event(scene->root_od->parentscene, GF_EVENT_TIMESHIFT_DEPTH, NULL, NULL, GF_OK, GF_FALSE); + } + } else { + gf_scene_notify_event(scene, GF_EVENT_TIMESHIFT_DEPTH, NULL, NULL, GF_OK, GF_FALSE); + } +} + + GF_MediaObject *gf_scene_find_object(GF_Scene *scene, u16 ODID, char *url) { u32 i; @@ -985,7 +1033,6 @@ static void IS_UpdateVideoPos(GF_Scene *scene) { MFURL url; M_Transform2D *tr; - M_Layer2D *layer; GF_MediaObject *mo; u32 w, h, v_w, v_h; if (!scene->visual_url.OD_ID && !scene->visual_url.url) return; @@ -1001,23 +1048,21 @@ static void IS_UpdateVideoPos(GF_Scene *scene) if (!w || !h) return; gf_scene_get_video_size(mo, &v_w, &v_h); - tr->translation.x = INT2FIX((s32) (w - v_w)) / 2; - tr->translation.y = INT2FIX((s32) (h - v_h)) / 2; - gf_node_dirty_set((GF_Node *)tr, 0, 0); - - - tr = (M_Transform2D *) gf_sg_find_node_by_name(scene->graph, "ADDON_TRANS"); - if (!tr) return; - tr->translation.x = INT2FIX(v_w) / 4; - tr->translation.y = INT2FIX(v_h) / 4; + if (scene->force_size_set) { + if (v_w && v_h) { + tr->scale.x = gf_divfix(INT2FIX(w), INT2FIX(v_w)); + tr->scale.y = gf_divfix(INT2FIX(h), INT2FIX(v_h)); + } + tr->translation.x = tr->translation.y = 0; + } else { + tr->scale.x = tr->scale.y = FIX_ONE; + tr->translation.x = INT2FIX((s32) (w - v_w)) / 2; + tr->translation.y = INT2FIX((s32) (h - v_h)) / 2; + } gf_node_dirty_set((GF_Node *)tr, 0, 0); - layer = (M_Layer2D *) gf_sg_find_node_by_name(scene->graph, "ADDON_LAYER"); - if (!layer) return; - layer->size.x = INT2FIX(v_w) / 2; - layer->size.y = INT2FIX(v_h) / 2; - gf_node_dirty_set((GF_Node *)layer, 0, 0); + gf_scene_set_addon_layout_info(scene, scene->addon_position, scene->addon_size_factor); if (scene->root_od->term->root_scene == scene) { //if (scene->graph_attached) gf_sc_set_scene(scene->root_od->term->compositor, NULL); @@ -1054,14 +1099,11 @@ static void set_media_url(GF_Scene *scene, SFURL *media_url, GF_Node *node, MFU u32 count, i; GF_ObjectManager *odm = NULL; count = gf_list_count(scene->resources); - for (i=0;iresources, i); if (odm->scalable_addon || !odm->OD) continue; - if (scene->selected_service_id && (scene->selected_service_id != odm->OD->ServiceID)) - continue; - if (type==GF_STREAM_TEXT) { if (!odm->codec || ((odm->codec->type!=type) && (odm->codec->type!=GF_STREAM_ND_SUBPIC))) continue; } @@ -1087,6 +1129,24 @@ static void set_media_url(GF_Scene *scene, SFURL *media_url, GF_Node *node, MFU } } + if (scene->selected_service_id && (scene->selected_service_id != odm->OD->ServiceID)) { + //objects inserted from broadcast may have been played but not yet registered with the scene, we need to force a stop + if ((odm->mo && !odm->mo->num_open) || !odm->mo) { + if (odm->state==GF_ODM_STATE_PLAY) { + /*do not stop directly*/ + gf_term_lock_media_queue(odm->term, GF_TRUE); + /*if object not in media queue, add it*/ + if (gf_list_find(odm->term->media_queue, odm)<0) { + gf_list_add(odm->term->media_queue, odm); + } + odm->action_type = GF_ODM_ACTION_STOP; + gf_term_lock_media_queue(odm->term, GF_FALSE); + } + } + continue; + } + + media_url->OD_ID = odm->OD->objectDescriptorID; if (media_url->OD_ID==GF_MEDIA_EXTERNAL_ID) media_url->url = gf_strdup(odm->net_service->url); @@ -1100,7 +1160,8 @@ static void set_media_url(GF_Scene *scene, SFURL *media_url, GF_Node *node, MFU if (odm->mo && (type==GF_STREAM_VISUAL)) { gf_scene_get_video_size(odm->mo, &w, &h); - gf_sg_set_scene_size_info(scene->graph, w, h, 1); + if (w && h) + gf_sg_set_scene_size_info(scene->graph, w, h, 1); } break; } @@ -1135,6 +1196,38 @@ static void set_media_url(GF_Scene *scene, SFURL *media_url, GF_Node *node, MFU } +static void scene_video_mouse_move(void *param, GF_FieldInfo *field) +{ + u32 i, count; + GF_Scene *scene = (GF_Scene *) param; + SFVec2f tx_coord = * ((SFVec2f *) field->far_ptr); + + if (!scene->visual_url.OD_ID) return; + + count = gf_list_count(scene->resources); + for (i=0; iresources, i); + if (!odm->mo) continue; + + if (odm->codec && odm->mo->OD_ID && (odm->mo->OD_ID != GF_MEDIA_EXTERNAL_ID) && (odm->mo->OD_ID==scene->visual_url.OD_ID)) { + GF_Err e; + u32 w, h; + GF_CodecCapability cap; + cap.CapCode = GF_CODEC_INTERACT_COORDS; + w = FIX2INT( tx_coord.x * 0xFFFF); + h = FIX2INT( tx_coord.y * 0xFFFF); + cap.cap.valueInt = w<<16 | h; + + e = gf_codec_set_capability(odm->codec, cap); + if (e==GF_NOT_SUPPORTED) { + GF_Node *n = gf_sg_find_node_by_name(scene->graph, "DYN_TOUCH"); + if (n) ((M_TouchSensor *)n)->enabled = GF_FALSE; + } + return; + } + } +} + /*regenerates the scene graph for dynamic scene. This will also try to reload any previously presented streams. Note that in the usual case the scene is generated just once when receiving the first OD AU (ressources are NOT destroyed when seeking), but since the network may need @@ -1189,6 +1282,12 @@ void gf_scene_regenerate(GF_Scene *scene) gf_node_register(n2, n1); n1 = n2; + /*create a touch sensor for the video*/ + n2 = is_create_node(scene->graph, TAG_MPEG4_TouchSensor, "DYN_TOUCH"); + gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2); + gf_node_register(n2, n1); + gf_sg_route_new_to_callback(scene->graph, n2, 3/*"hitTexCoord_changed"*/, scene, scene_video_mouse_move); + /*create a shape and bitmap node*/ n2 = is_create_node(scene->graph, TAG_MPEG4_Shape, NULL); gf_node_list_add_child( &((GF_ParentNode *)n1)->children, n2); @@ -1222,6 +1321,11 @@ void gf_scene_regenerate(GF_Scene *scene) gf_node_list_add_child( &((GF_ParentNode *)n1)->children, (GF_Node*)dims); gf_node_register((GF_Node *)dims, n1); + /*PVR version of live content*/ + n1 = gf_sg_get_root_node(scene->graph); + addon_scene = (M_Inline *) is_create_node(scene->graph, TAG_MPEG4_Inline, "PVR_SCENE"); + gf_node_list_add_child( &((GF_ParentNode *)n1)->children, (GF_Node*)addon_scene); + gf_node_register((GF_Node *)addon_scene, (GF_Node *)n1); /*Media addon scene*/ n1 = gf_sg_get_root_node(scene->graph); @@ -1251,6 +1355,9 @@ void gf_scene_regenerate(GF_Scene *scene) dims = (M_Inline *) gf_sg_find_node_by_name(scene->graph, "DIMS_SCENE"); set_media_url(scene, &scene->dims_url, (GF_Node*)dims, &dims->url, GF_STREAM_SCENE); + n2 = gf_sg_find_node_by_name(scene->graph, "DYN_TOUCH"); + ((M_TouchSensor *)n2)->enabled = GF_TRUE; + gf_sc_lock(scene->root_od->term->compositor, 0); /*disconnect to force resize*/ @@ -1261,8 +1368,8 @@ void gf_scene_regenerate(GF_Scene *scene) gf_term_send_event(scene->root_od->term, &evt); IS_UpdateVideoPos(scene); } else { + gf_scene_notify_event(scene, scene->graph_attached ? GF_EVENT_STREAMLIST : GF_EVENT_SCENE_ATTACHED, NULL, NULL, GF_OK, GF_FALSE); scene->graph_attached = 1; - gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, GF_OK, GF_FALSE); gf_term_invalidate_compositor(scene->root_od->term); } } @@ -1276,9 +1383,6 @@ void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons) memset(&addon_info, 0, sizeof(GF_AssociatedContentLocation)); addon_info.timeline_id = -100; gf_scene_register_associated_media(scene, &addon_info); - -// gf_sg_vrml_field_copy(&dscene->url, &scene->addon_url, GF_SG_VRML_MFURL); - } else { gf_sg_vrml_mf_reset(&dscene->url, GF_SG_VRML_MFURL); } @@ -1287,9 +1391,21 @@ void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons) #else /*!!fixme - we would need an SVG scene in case no VRML support is present !!!*/ +GF_EXPORT void gf_scene_regenerate(GF_Scene *scene) {} -void gf_scene_restart_dynamic(GF_Scene *scene, u64 from_time) {} +GF_EXPORT +void gf_scene_restart_dynamic(GF_Scene *scene, s64 from_time, Bool restart_only, Bool disable_addon_check) {} +GF_EXPORT void gf_scene_select_object(GF_Scene *scene, GF_ObjectManager *odm) {} +GF_EXPORT +void gf_scene_toggle_addons(GF_Scene *scene, Bool show_addons) { } +GF_EXPORT +void gf_scene_resume_live(GF_Scene *subscene) { } +GF_EXPORT +void gf_scene_set_addon_layout_info(GF_Scene *scene, u32 position, u32 size_factor) {} +GF_EXPORT +void gf_scene_select_main_addon(GF_Scene *scene, GF_ObjectManager *odm, Bool set_on, u32 current_clock_time) { } + #endif /*GPAC_DISABLE_VRML*/ #ifndef GPAC_DISABLE_VRML @@ -1311,6 +1427,38 @@ static Bool check_odm_deactivate(SFURL *url, GF_ObjectManager *odm, GF_Node *n) return 1; } +static void odm_deactivate(GF_Node *n) +{ + GF_FieldInfo info; + + gf_node_get_field_by_name(n, "url", &info); + gf_sg_vrml_mf_reset(info.far_ptr, GF_SG_VRML_MFURL); + gf_node_get_field_by_name(n, "stopTime", &info); + *((SFTime *)info.far_ptr) = gf_node_get_scene_time(n); + gf_node_changed(n, NULL); +} + +static void odm_activate(SFURL *url, GF_Node *n) +{ + SFURL *sfu; + GF_FieldInfo info; + + gf_node_get_field_by_name(n, "url", &info); + gf_sg_vrml_mf_reset(info.far_ptr, GF_SG_VRML_MFURL); + if (url->OD_ID || url->url) { + gf_sg_vrml_mf_append(info.far_ptr, GF_SG_VRML_MFURL, (void **) &sfu); + sfu->OD_ID = url->OD_ID; + if (url->url) sfu->url = gf_strdup(url->url); + + gf_node_get_field_by_name(n, "startTime", &info); + *((SFTime *)info.far_ptr) = 0.0; + gf_node_get_field_by_name(n, "stopTime", &info); + *((SFTime *)info.far_ptr) = 0.0; + } + + gf_node_changed(n, NULL); +} + void gf_scene_set_service_id(GF_Scene *scene, u32 service_id) { if (!scene->is_dynamic_scene) return; @@ -1322,8 +1470,13 @@ void gf_scene_set_service_id(GF_Scene *scene, u32 service_id) scene->visual_url.OD_ID = 0; scene->text_url.OD_ID = 0; scene->dims_url.OD_ID = 0; - //reset clock since we change service IDs - scene->dyn_ck = NULL; + scene->force_size_set = 0; + //reset clock since we change service IDs, but request a PLAY from the current time + if (scene->dyn_ck) { + scene->root_od->media_start_time = gf_clock_media_time(scene->dyn_ck); + scene->dyn_ck = NULL; + } + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Switching %s from service %d to service %d (media time %g)\n", scene->root_od->net_service->url, scene->selected_service_id, service_id, (Double)scene->root_od->media_start_time/1000.0)); gf_scene_regenerate(scene); } gf_sc_lock(scene->root_od->term->compositor, 0); @@ -1353,9 +1506,14 @@ void gf_scene_select_object(GF_Scene *scene, GF_ObjectManager *odm) if (!odm->codec && odm->subscene) { M_Inline *dscene = (M_Inline *) gf_sg_find_node_by_name(scene->graph, "ADDON_SCENE"); + + if (odm->addon && odm->addon->addon_type==GF_ADDON_TYPE_MAIN) { + return; + } + gf_sg_vrml_field_copy(&dscene->url, &odm->mo->URLs, GF_SG_VRML_MFURL); gf_node_changed((GF_Node *)dscene, NULL); - IS_UpdateVideoPos(scene); + //do not update video pos for addons, this is done only when setting up the main video object return; } @@ -1423,27 +1581,198 @@ void gf_scene_select_object(GF_Scene *scene, GF_ObjectManager *odm) } } -void gf_scene_restart_dynamic(GF_Scene *scene, u64 from_time) +void gf_scene_select_main_addon(GF_Scene *scene, GF_ObjectManager *odm, Bool set_on, u32 current_clock_time) +{ + GF_DOM_Event devt; + const char *opt = gf_cfg_get_key(scene->root_od->term->user->config, "Systems", "DebugPVRScene"); + M_Inline *dscene = (M_Inline *) gf_sg_find_node_by_name(scene->graph, (opt && !strcmp(opt, "yes")) ? "ADDON_SCENE" : "PVR_SCENE"); + + if (scene->main_addon_selected==set_on) return; + scene->main_addon_selected = set_on; + + if (set_on) { + odm_deactivate(gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO")); + odm_deactivate(gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO")); + odm_deactivate(gf_sg_find_node_by_name(scene->graph, "DYN_TEXT")); + + + if (!odm->subscene->graph_attached) { + odm->flags &= ~GF_ODM_REGENERATE_SCENE; + gf_scene_regenerate(odm->subscene); + } else { + odm->subscene->needs_restart = 1; + } + + //main addon is vod not live, store clock + if (! odm->timeshift_depth && !scene->sys_clock_at_main_activation) { + scene->sys_clock_at_main_activation = gf_sys_clock(); + scene->obj_clock_at_main_activation = current_clock_time; + } + + + gf_sg_vrml_field_copy(&dscene->url, &odm->mo->URLs, GF_SG_VRML_MFURL); + gf_node_changed((GF_Node *)dscene, NULL); + } else { + GF_Clock *ck = scene->scene_codec ? scene->scene_codec->ck : scene->dyn_ck; + //reactivating the main content will trigger a reset on the clock - remember where we are and resume from this point + scene->root_od->media_start_time = gf_clock_media_time(ck); + + scene->sys_clock_at_main_activation = 0; + scene->obj_clock_at_main_activation = 0; + + odm_activate(&scene->audio_url, gf_sg_find_node_by_name(scene->graph, "DYN_AUDIO")); + odm_activate(&scene->visual_url, gf_sg_find_node_by_name(scene->graph, "DYN_VIDEO")); + odm_activate(&scene->text_url, gf_sg_find_node_by_name(scene->graph, "DYN_TEXT")); + + gf_sg_vrml_mf_reset(&dscene->url, GF_SG_VRML_MFURL); + gf_node_changed((GF_Node *)dscene, NULL); + } + + memset(&devt, 0, sizeof(GF_DOM_Event)); + devt.type = GF_EVENT_MAIN_ADDON_STATE; + devt.detail = set_on; + gf_scene_notify_event(scene, GF_EVENT_MAIN_ADDON_STATE, NULL, &devt, GF_OK, GF_FALSE); + +} + +GF_EXPORT +void gf_scene_set_addon_layout_info(GF_Scene *scene, u32 position, u32 size_factor) +{ + MFURL url; + M_Transform2D *tr; + M_Layer2D *layer; + GF_MediaObject *mo; + s32 w, h, v_w, v_h; + if (!scene->visual_url.OD_ID && !scene->visual_url.url) return; + + url.count = 1; + url.vals = &scene->visual_url; + mo = IS_CheckExistingObject(scene, &url, GF_MEDIA_OBJECT_VIDEO); + if (!mo) return; + + scene->addon_position = position; + scene->addon_size_factor = size_factor; + + gf_scene_get_video_size(mo, (u32 *) &v_w, (u32 *) &v_h); + w = v_w; + h = v_h; + switch (size_factor) { + case 0: + v_w /= 2; + v_h /= 2; + break; + case 1: + v_w /= 3; + v_h /= 3; + break; + case 2: + default: + v_w /= 4; + v_h /= 4; + break; + } + + layer = (M_Layer2D *) gf_sg_find_node_by_name(scene->graph, "ADDON_LAYER"); + if (!layer) return; + layer->size.x = INT2FIX(v_w); + layer->size.y = INT2FIX(v_h); + gf_node_dirty_set((GF_Node *)layer, 0, 0); + + tr = (M_Transform2D *) gf_sg_find_node_by_name(scene->graph, "ADDON_TRANS"); + if (!tr) return; + switch (position) { + case 0: + tr->translation.x = INT2FIX(w - v_w) / 2; + tr->translation.y = INT2FIX(v_h - h) / 2; + break; + case 1: + tr->translation.x = INT2FIX(w - v_w) / 2; + tr->translation.y = INT2FIX(h - v_h) / 2; + break; + case 2: + tr->translation.x = INT2FIX(v_w - w) / 2; + tr->translation.y = INT2FIX(v_h - h) / 2; + break; + case 3: + tr->translation.x = INT2FIX(v_w - w) / 2; + tr->translation.y = INT2FIX(h - v_h) / 2; + break; + } + gf_node_dirty_set((GF_Node *)tr, 0, 0); +} + +GF_EXPORT +void gf_scene_resume_live(GF_Scene *subscene) +{ + if (subscene->main_addon_selected) + mediacontrol_resume(subscene->root_od, 1); +} + +void gf_scene_restart_dynamic(GF_Scene *scene, s64 from_time, Bool restart_only, Bool disable_addon_check) { u32 i; GF_Clock *ck; GF_List *to_restart; GF_ObjectManager *odm; - - GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Restarting from "LLD"\n", LLD_CAST from_time)); + if (restart_only) { + from_time = 0; + } ck = scene->dyn_ck; if (scene->scene_codec) ck = scene->scene_codec->ck; if (!ck) return; - to_restart = gf_list_new(); - + //first pass to check if we need to enable the addon acting as time shifting + if (!disable_addon_check) { + i=0; + while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { + + if (odm->addon && (odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) { + //assign clock if not yet available + if (odm->addon->root_od->subscene && !odm->addon->root_od->subscene->dyn_ck) + odm->addon->root_od->subscene->dyn_ck = scene->dyn_ck; + + //we're timeshifting through the main addon, activate it + if (from_time < -1) { + gf_scene_select_main_addon(scene, odm, GF_TRUE, gf_clock_time(ck)); + + /*no timeshift, this is a VoD associated with the live broadcast: get current time*/ + if (! odm->timeshift_depth) { + s64 live_clock = scene->obj_clock_at_main_activation + gf_sys_clock() - scene->sys_clock_at_main_activation; + + from_time += 1; + if (live_clock + from_time < 0) from_time = 0; + else from_time = live_clock + from_time; + } + } else if (scene->main_addon_selected) { + gf_scene_select_main_addon(scene, odm, GF_FALSE, 0); + } + } + } + } + to_restart = gf_list_new(); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { if (gf_odm_shares_clock(odm, ck)) { if (odm->state != GF_ODM_STATE_BLOCKED) { - gf_list_add(to_restart, odm); + + //object is not an addon and main addon is selected, do not add + if (!odm->addon && scene->main_addon_selected) { + } + //object is an addon and enabled, restart if main and main is enabled, or if not main + else if (odm->addon && odm->addon->enabled) { + if (odm->addon->addon_type==GF_ADDON_TYPE_MAIN) { + if (scene->main_addon_selected) { + gf_list_add(to_restart, odm); + } + } else { + gf_list_add(to_restart, odm); + } + } else if (!scene->selected_service_id || (scene->selected_service_id==odm->OD->ServiceID)) { + gf_list_add(to_restart, odm); + } + if (odm->state == GF_ODM_STATE_PLAY) { gf_odm_stop(odm, 1); } @@ -1451,15 +1780,32 @@ void gf_scene_restart_dynamic(GF_Scene *scene, u64 from_time) } } - /*reset clock*/ - gf_clock_reset(ck); - if (!scene->is_dynamic_scene) gf_clock_set_time(ck, 0); + if (!restart_only) { + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Restarting from "LLD"\n", LLD_CAST from_time)); + /*reset clock*/ + gf_clock_reset(ck); + + //used by SVG for JSAPIs..; + if (!scene->is_dynamic_scene) gf_clock_set_time(ck, 0); + } else { + GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Scene] Restarting scene from current clock %d\n", gf_clock_time(ck) )); + } + /*restart objects*/ i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) { - odm->media_start_time = from_time; - gf_odm_start(odm, 0); + if (from_time<0) { + odm->media_stop_time = from_time + 1; + } else { + odm->media_start_time = from_time; + } + + if (odm->subscene && odm->subscene->is_dynamic_scene) { + gf_scene_restart_dynamic(odm->subscene, from_time, 0, 0); + } else { + gf_odm_start(odm, 0); + } } gf_list_del(to_restart); @@ -1489,31 +1835,62 @@ void gf_scene_restart_dynamic(GF_Scene *scene, u64 from_time) GF_EXPORT void gf_scene_force_size(GF_Scene *scene, u32 width, u32 height) { + Bool skip_notif = GF_FALSE; /*for now only allowed when no scene info*/ if (!scene->is_dynamic_scene) return; - GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Changing scene size to %d x %d\n", width, height)); + GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Scene] Forcing scene size to %d x %d\n", width, height)); - if (scene->root_od->term->root_scene == scene) { + if (scene->is_dynamic_scene) { GF_NetworkCommand com; memset(&com, 0, sizeof(GF_NetworkCommand)); com.base.command_type = GF_NET_SERVICE_HAS_FORCED_VIDEO_SIZE; gf_term_service_command(scene->root_od->net_service, &com); - if (com.par.width && com.par.height) { - gf_sc_set_scene_size(scene->root_od->term->compositor, width, height, 1); - if (!scene->force_size_set) { - gf_sc_set_size(scene->root_od->term->compositor, com.par.width, com.par.height); - scene->force_size_set = 1; + if (scene->root_od->term->root_scene == scene) { + if (com.par.width && com.par.height) { + gf_sc_set_scene_size(scene->root_od->term->compositor, width, height, 1); + if (!scene->force_size_set) { + gf_sc_set_size(scene->root_od->term->compositor, com.par.width, com.par.height); + scene->force_size_set = 1; + } else { + gf_sc_set_size(scene->root_od->term->compositor, 0, 0); + } } else { - gf_sc_set_size(scene->root_od->term->compositor, 0, 0); + /*need output resize*/ + gf_sg_set_scene_size_info(scene->graph, width, height, 1); + gf_sc_set_scene(scene->root_od->term->compositor, scene->graph); + gf_sc_set_size(scene->root_od->term->compositor, width, height); } + + } else if (!scene->force_size_set) { + if (com.par.width && com.par.height) { + width = com.par.width; + height = com.par.height; + } + gf_sg_set_scene_size_info(scene->graph, width, height, 1); + scene->force_size_set = 1; } else { - /*need output resize*/ - gf_sg_set_scene_size_info(scene->graph, width, height, gf_sg_use_pixel_metrics(scene->graph)); - gf_sc_set_scene(scene->root_od->term->compositor, scene->graph); - gf_sc_set_size(scene->root_od->term->compositor, width, height); + u32 w, h; + gf_sg_get_scene_size_info(scene->graph, &w, &h); + if (!com.par.width && !com.par.height && ((wgraph, width, height, 1); + } else { + GF_DOM_Event devt; + memset(&devt, 0, sizeof(GF_DOM_Event)); + devt.type = GF_EVENT_SCENE_SIZE; + devt.screen_rect.width = INT2FIX(width); + devt.screen_rect.height = INT2FIX(height); + devt.key_flags = scene->is_dynamic_scene; + + gf_scene_notify_event(scene, GF_EVENT_SCENE_SIZE, NULL, &devt, GF_OK, GF_FALSE); + + skip_notif = GF_TRUE; + + width = w; + height = h; + } } } else if (scene->root_od->parentscene && scene->root_od->parentscene->is_dynamic_scene) { @@ -1531,6 +1908,8 @@ void gf_scene_force_size(GF_Scene *scene, u32 width, u32 height) IS_UpdateVideoPos(scene); #endif + if (skip_notif) return; + gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, GF_OK, GF_FALSE); } @@ -1634,29 +2013,43 @@ GF_Node *gf_scene_get_subscene_root(GF_Node *node) } /*returns 0 if any of the clock still hasn't seen EOS*/ -Bool gf_scene_check_clocks(GF_ClientService *ns, GF_Scene *scene) +Bool gf_scene_check_clocks(GF_ClientService *ns, GF_Scene *scene, Bool check_buffering) { GF_Clock *ck; u32 i; if (scene) { GF_ObjectManager *odm; if (scene->root_od->net_service != ns) { - if (!gf_scene_check_clocks(scene->root_od->net_service, scene)) return 0; + if (!gf_scene_check_clocks(scene->root_od->net_service, scene, check_buffering)) return 0; } i=0; while ( (odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i)) ) { if (odm->net_service && (odm->net_service != ns)) { - if (!gf_scene_check_clocks(odm->net_service, NULL)) return 0; - } else if (odm->codec && odm->codec->CB && !gf_cm_is_eos(odm->codec->CB) ) { - return 0; + if (!gf_scene_check_clocks(odm->net_service, NULL, check_buffering)) return 0; + } else if (odm->codec && odm->codec->CB) { + if (!check_buffering) { + if (!gf_cm_is_eos(odm->codec->CB) ) { + return 0; + } + } else { + if (odm->codec->ck->Buffering) { + return 0; + } + } } } } i=0; while ( (ck = (GF_Clock *)gf_list_enum(ns->Clocks, &i) ) ) { - if (!ck->has_seen_eos) return 0; + if (!check_buffering) { + if (!ck->has_seen_eos) return 0; + } else { + if (ck->Buffering) return 0; + } + } - if (scene) { + + if (!check_buffering && scene) { if (scene->scene_codec && (scene->scene_codec->Status != GF_ESM_CODEC_STOP)) return 0; if (scene->od_codec && (scene->od_codec->Status != GF_ESM_CODEC_STOP)) return 0; } @@ -1805,7 +2198,13 @@ void gf_scene_generate_views(GF_Scene *scene, char *url, char *parent_path) void scene_reset_addon(GF_AddonMedia *addon, Bool disconnect) { - if (disconnect && addon->root_od) gf_odm_disconnect(addon->root_od, 1); + if (disconnect && addon->root_od) { + gf_odm_disconnect(addon->root_od, 1); + } + if (addon->root_od) { + addon->root_od->addon = NULL; + } + if (addon->url) gf_free(addon->url); gf_free(addon); } @@ -1815,11 +2214,9 @@ void gf_scene_reset_addons(GF_Scene *scene) while (gf_list_count(scene->declared_addons)) { GF_AddonMedia *addon = gf_list_last(scene->declared_addons); gf_list_rem_last(scene->declared_addons); - if (addon==scene->active_addon) continue; scene_reset_addon(addon, 0); } - if (scene->active_addon) scene_reset_addon(scene->active_addon, 0); } static void load_associated_media(GF_Scene *scene, GF_AddonMedia *addon) @@ -1846,133 +2243,169 @@ static void load_associated_media(GF_Scene *scene, GF_AddonMedia *addon) mo->odm->addon = addon; } +GF_EXPORT void gf_scene_register_associated_media(GF_Scene *scene, GF_AssociatedContentLocation *addon_info) { - GF_AddonMedia *addon; + GF_AddonMedia *addon = NULL; GF_Event evt; u32 i, count; + Bool new_addon = 0; if (!scene->is_dynamic_scene) return; count = gf_list_count(scene->declared_addons); for (i=0; ideclared_addons, i); - if (addon->timeline_id==addon_info->timeline_id) { - if (addon_info->reload_external) { - //send message to service handler - } + if ((addon_info->timeline_id>=0) && addon->timeline_id==addon_info->timeline_id) { + my_addon = 1; + } else if (addon->url && addon_info->external_URL && !strcmp(addon->url, addon_info->external_URL)) { + my_addon = 1; + //send message to service handler + } + //this is an already received addon + if (my_addon) { + if (addon_info->enable_if_defined) + addon->enabled = 1; + //restart addon - if (!addon->root_od && addon->timeline_ready) { + if (!addon->root_od && addon->timeline_ready && addon->enabled) { load_associated_media(scene, addon); } + //nothing associated, deactivate addon + if (!addon_info->external_URL) { + scene_reset_addon(addon, 1); + } else if (strcmp(addon_info->external_URL, addon->url)) { + //reconfigure addon + gf_free(addon->url); + addon->url = NULL; + break; + } return; } } if (!addon_info->external_URL) { - //NULL (nothing) will be active soon - if (addon_info->activation_countdown) return; - //otherwise reset addon - if (scene->active_addon) scene_reset_addon(scene->active_addon, 1); - scene->active_addon = NULL; return; } - GF_SAFEALLOC(addon, GF_AddonMedia); - addon->timeline_id = addon_info->timeline_id; + if (!addon) { + GF_SAFEALLOC(addon, GF_AddonMedia); + addon->timeline_id = addon_info->timeline_id; + gf_list_add(scene->declared_addons, addon); + new_addon = 1; + } + addon->is_splicing = addon_info->is_splicing; addon->activation_time = gf_scene_get_time(scene)+addon_info->activation_countdown; addon->url = gf_strdup(addon_info->external_URL); addon->media_timescale = 1; addon->timeline_ready = (addon_info->timeline_id<0) ? 1 : 0; - if (addon->timeline_ready && !scene->active_addon) scene->active_addon = addon; - gf_list_add(scene->declared_addons, addon); + if (!new_addon) return; - evt.type = GF_EVENT_ADDON_DETECTED; - evt.addon_connect.addon_url = addon->url; - addon->enabled = gf_term_send_event(scene->root_od->term,&evt); + //notify we found a new addon + + if (! scene->root_od->parentscene) { + evt.type = GF_EVENT_ADDON_DETECTED; + evt.addon_connect.addon_url = addon->url; + addon->enabled = gf_term_send_event(scene->root_od->term,&evt); + + if (addon->timeline_ready) + load_associated_media(scene, addon); + } else { + GF_DOM_Event devt; + memset(&devt, 0, sizeof(GF_DOM_Event)); + devt.type = GF_EVENT_ADDON_DETECTED; + devt.addon_url = addon->url; + addon->enabled = 0; + + gf_scene_notify_event(scene, GF_EVENT_SCENE_ATTACHED, NULL, &devt, GF_OK, GF_TRUE); + } - if (addon->timeline_ready) - load_associated_media(scene, addon); } void gf_scene_notify_associated_media_timeline(GF_Scene *scene, GF_AssociatedContentTiming *addon_time) { Double prev_time; - GF_AddonMedia *addon = scene->active_addon; - //locate the active timeline - if (!scene->active_addon || (scene->active_addon->timeline_id!=addon_time->timeline_id)) { - u32 i, count = gf_list_count(scene->declared_addons); - for (i=0; ideclared_addons, i); - if (addon->timeline_id==addon_time->timeline_id) - break; - addon = NULL; - } - if (!addon) return; + GF_AddonMedia *addon = NULL; - count = i; - for (i=0; ideclared_addons, i); - //we are adding a non splicing point: discard all previously declared addons - if (!addon->is_splicing - //this is a splicing point, discard all previsously declared splicing addons - || prev_addon->is_splicing - ) { - scene_reset_addon(prev_addon, GF_TRUE); - gf_list_rem(scene->declared_addons, i); - i--; - count--; - } - } + u32 i, count = gf_list_count(scene->declared_addons); + for (i=0; ideclared_addons, i); + if (addon->timeline_id==addon_time->timeline_id) + break; + addon = NULL; + } + if (!addon) return; - scene->active_addon = addon; - if (!scene->active_addon->timeline_ready) { - scene->active_addon->timeline_ready = GF_TRUE; - load_associated_media(scene, addon); + count = i; + for (i=0; ideclared_addons, i); + //we are adding a non splicing point: discard all previously declared addons + if (!addon->is_splicing + //this is a splicing point, discard all previsously declared splicing addons + || prev_addon->is_splicing + ) { + scene_reset_addon(prev_addon, GF_TRUE); + gf_list_rem(scene->declared_addons, i); + i--; + count--; } } - if (!scene->active_addon->root_od) return; - gf_mx_p(scene->active_addon->root_od->mx); - prev_time = (Double) scene->active_addon->media_timestamp; - prev_time /= scene->active_addon->media_timescale; - assert(scene->active_addon->timeline_id == addon_time->timeline_id); + prev_time = (Double) addon->media_timestamp; + prev_time /= addon->media_timescale; //loop has been detected if ( prev_time * addon_time->media_timescale > addon_time->media_timestamp + 1.5 * addon_time->media_timescale ) { - if (!scene->active_addon->loop_detected) { - scene->active_addon->loop_detected = GF_TRUE; + if (!addon->loop_detected) { + addon->loop_detected = GF_TRUE; GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Loop detected in addon - PTS "LLD" (CTS %d) - media time "LLD"\n", addon_time->media_pts, addon_time->media_pts/90, addon_time->media_timestamp)); - scene->active_addon->past_media_pts = addon_time->media_pts; - scene->active_addon->past_media_timestamp = addon_time->media_timestamp; - scene->active_addon->past_media_timescale = addon_time->media_timescale; - scene->active_addon->past_media_pts_scaled = addon_time->media_pts/90; - } - } else if (!scene->active_addon->loop_detected) { - scene->active_addon->media_pts = addon_time->media_pts; - scene->active_addon->media_timestamp = addon_time->media_timestamp; - scene->active_addon->media_timescale = addon_time->media_timescale; + addon->past_media_pts = addon_time->media_pts; + addon->past_media_timestamp = addon_time->media_timestamp; + addon->past_media_timescale = addon_time->media_timescale; + addon->past_media_pts_scaled = addon_time->media_pts/90; + } + } else if (!addon->loop_detected) { + addon->media_pts = addon_time->media_pts; + addon->media_timestamp = addon_time->media_timestamp; + addon->media_timescale = addon_time->media_timescale; assert(addon_time->media_timescale); - assert(!scene->active_addon->loop_detected); + assert(!addon->loop_detected); + } + + if (!addon->timeline_ready) { + addon->timeline_ready = GF_TRUE; + load_associated_media(scene, addon); + } + + if ((addon->addon_type==GF_ADDON_TYPE_MAIN) && addon->root_od && addon->root_od->duration && !addon->root_od->timeshift_depth) { + Double dur, tsb; + dur = (Double) addon->root_od->duration; + dur /= 1000; + tsb = (Double) addon->media_timestamp; + tsb /= addon->media_timescale; + if (tsb>dur) tsb = dur; + addon->root_od->parentscene->root_od->timeshift_depth = (u32) (1000*tsb); + gf_scene_set_timeshift_depth(scene); } - gf_mx_v(scene->active_addon->root_od->mx); } -void gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts) +Bool gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts) { u32 i; GF_ObjectManager*odm; GF_Scene *subscene; + GF_List *to_restart = NULL; - if (!addon || !addon->loop_detected) return; + if (!addon || !addon->loop_detected) return GF_FALSE; //warning, we need to compare to media PTS/90 since we already rounded the media_ts to milliseconds (otherwise we would get rounding errors). - if ((cts == addon->past_media_pts_scaled) || (dts>=addon->past_media_pts_scaled) ) { + if ((cts == addon->past_media_pts_scaled) || (dts >= addon->past_media_pts_scaled) ) { } else { GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Loop not yet active - CTS "LLD" DTS "LLD" media TS "LLD" \n", cts, dts, addon->past_media_pts_scaled)); - return; + return GF_FALSE; } gf_mx_p(addon->root_od->mx); @@ -1992,47 +2425,50 @@ void gf_scene_check_addon_restart(GF_AddonMedia *addon, u64 cts, u64 dts) gf_mx_v(addon->root_od->mx); + to_restart = gf_list_new(); + i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(subscene->resources, &i))) { - gf_odm_play(odm); + if (odm->state == GF_ODM_STATE_PLAY) { + gf_list_add(to_restart, odm); + } + gf_odm_stop(odm, GF_FALSE); } + i=0; + while ((odm = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) { + gf_odm_start(odm, 2); + } + gf_list_del(to_restart); + return GF_TRUE; } -Double gf_scene_adjust_time_for_addon(GF_Scene *scene, u32 clock_time, GF_AddonMedia *addon, Bool *timestamp_based) +Double gf_scene_adjust_time_for_addon(GF_AddonMedia *addon, Double clock_time, u32 *timestamp_based) { Double media_time; if (!addon->timeline_ready) return clock_time; - assert(scene->root_od->addon); - assert(scene->root_od->addon==addon); - if (timestamp_based) + if (timestamp_based) *timestamp_based = (addon->timeline_id>=0) ? 0 : 1; //get PTS diff (clock is in ms, pt is in 90k) media_time = clock_time; - media_time -= addon->media_pts/90; - media_time *= addon->media_timescale; - media_time /= 1000; - media_time += addon->media_timestamp; - media_time /= addon->media_timescale; + media_time -= addon->media_pts/90000.0; + + media_time += ((Double)addon->media_timestamp) / addon->media_timescale; GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("Addon about to start - media time %g\n", media_time)); return media_time; } -u64 gf_scene_adjust_timestamp_for_addon(GF_Scene *scene, u64 orig_ts, GF_AddonMedia *addon) +s64 gf_scene_adjust_timestamp_for_addon(GF_AddonMedia *addon, u64 orig_ts) { s64 media_ts_ms; assert(addon->timeline_ready); - assert(scene->root_od->addon); - assert(scene->root_od->addon==addon); - media_ts_ms = orig_ts; media_ts_ms -= (addon->media_timestamp*1000) / addon->media_timescale; media_ts_ms += (addon->media_pts/90); - - return (u64) media_ts_ms; + return media_ts_ms; } void gf_scene_select_scalable_addon(GF_Scene *scene, GF_ObjectManager *odm) @@ -2052,11 +2488,14 @@ void gf_scene_select_scalable_addon(GF_Scene *scene, GF_ObjectManager *odm) if ((mtype==odm_base->codec->type) && odm_base->codec) break; odm_base=NULL; - //todo check if we use compatible formats, for now we only do demos with hevc/shvc + //todo + //1- check if we use compatible formats, for now we only do demos with hevc/shvc + //2- check dependency IDs if any, for now we only do demos with 2 layers hevc/shvc } if (!odm_base) return; - odm_base->scalable_odm = odm; + odm_base->upper_layer_odm = odm; + odm->lower_layer_odm = odm_base; nalu_annex_b = 1; base_ch = gf_list_get(odm_base->channels, 0); diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index cdbe837..8b2a8e9 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -78,8 +78,11 @@ void gf_term_message_ex(GF_Terminal *term, const char *service, const char *mess evt.message.error = error; if (no_filtering) { - if (term->user->EventProc) + if (term->user->EventProc) { + term->nb_calls_in_event_proc++; term->user->EventProc(term->user->opaque, &evt); + term->nb_calls_in_event_proc--; + } } else { gf_term_send_event(term, &evt); } @@ -186,7 +189,7 @@ static Bool term_script_action(void *opaque, u32 type, GF_Node *n, GF_JSAPIParam if (ck) { Bool is_paused = ck->Paused; if (is_paused) gf_clock_resume(ck); - gf_scene_restart_dynamic(scene, 0); + gf_scene_restart_dynamic(scene, 0, 0, 0); if (is_paused) gf_clock_pause(ck); } return 1; @@ -236,9 +239,9 @@ static Bool term_find_res(GF_TermLocales *loc, char *parent, char *path, char *r loc->szAbsRelocatedPath = gf_url_concatenate(parent, path); if (!loc->szAbsRelocatedPath) loc->szAbsRelocatedPath = gf_strdup(path); - f = gf_f64_open(loc->szAbsRelocatedPath, "rb"); + f = gf_fopen(loc->szAbsRelocatedPath, "rb"); if (f) { - fclose(f); + gf_fclose(f); strcpy(localized_rel_path, path); strcpy(relocated_path, loc->szAbsRelocatedPath); return 1; @@ -350,6 +353,14 @@ static void gf_term_reload_cfg(GF_Terminal *term) } term->frame_duration = atoi(sOpt); + sOpt = gf_cfg_get_key(term->user->config, "Network", "LowLatencyBufferMax"); + if (!sOpt) { + sOpt = "500"; + gf_cfg_set_key(term->user->config, "Network", "LowLatencyBufferMax", sOpt); + } + term->low_latency_buffer_max = atoi(sOpt); + + if (!(term->user->init_flags & GF_TERM_NO_DECODER_THREAD) ) { prio = GF_THREAD_PRIORITY_NORMAL; sOpt = gf_cfg_get_key(term->user->config, "Systems", "Priority"); @@ -414,26 +425,25 @@ static Bool gf_term_get_user_pass(void *usr_cbk, const char *site_url, char *usr } -void gf_term_pause_all_clocks(GF_Terminal *term, Bool pause) -{ - u32 i, j; - GF_ClientService *ns; - /*pause all clocks on all services*/ - i=0; - while ( (ns = (GF_ClientService*)gf_list_enum(term->net_services, &i)) ) { - GF_Clock *ck; - j=0; - while ( (ck = (GF_Clock *)gf_list_enum(ns->Clocks, &j)) ) { - if (pause) gf_clock_pause(ck); - else gf_clock_resume(ck); - } - } -} - static void gf_term_set_play_state(GF_Terminal *term, u32 PlayState, Bool reset_audio, Bool pause_clocks) { + Bool resume_live = 0; + u32 prev_state; + /*only play/pause if connected*/ if (!term || !term->root_scene) return; + + prev_state = term->play_state; + + if (PlayState==GF_STATE_PLAY_LIVE) { + PlayState = GF_STATE_PLAYING; + resume_live = 1; + if (term->play_state == GF_STATE_PLAYING) { + term->play_state = GF_STATE_PAUSED; + mediacontrol_pause(term->root_scene->root_od); + } + } + /*and if not already paused/playing*/ if ((term->play_state == GF_STATE_PLAYING) && (PlayState == GF_STATE_PLAYING)) return; if ((term->play_state != GF_STATE_PLAYING) && (PlayState == GF_STATE_PAUSED)) return; @@ -444,18 +454,36 @@ static void gf_term_set_play_state(GF_Terminal *term, u32 PlayState, Bool reset_ else gf_sc_set_option(term->compositor, GF_OPT_PLAY_STATE, PlayState); - /* if the current play state in the terminal is the same as the requested play state, we don't touch the clocks - in particular, if the request is a step, if the clocks are paused, we leave them paused */ + /* step mode specific */ if (PlayState==GF_STATE_STEP_PAUSE) { - //PlayState = term->play_state ? GF_STATE_PLAYING : GF_STATE_PAUSED; + if (prev_state==GF_STATE_PLAYING) { + mediacontrol_pause(term->root_scene->root_od); + term->play_state = GF_STATE_PAUSED; + } else { + u32 diff=1; + if (term->compositor->ms_until_next_frame>0) diff = term->compositor->ms_until_next_frame; + gf_term_step_clocks(term, diff); + mediacontrol_resume(term->root_scene->root_od, 0); + mediacontrol_pause(term->root_scene->root_od); + } return; } + /* nothing to change*/ if (term->play_state == PlayState) return; term->play_state = PlayState; + if (term->root_scene->pause_at_first_frame && (PlayState == GF_STATE_PLAYING)) + term->root_scene->pause_at_first_frame = GF_FALSE; + if (!pause_clocks) return; - gf_term_pause_all_clocks(term, PlayState ? 1 : 0); + + if (PlayState != GF_STATE_PLAYING) { + mediacontrol_pause(term->root_scene->root_od); + } else { + mediacontrol_resume(term->root_scene->root_od, resume_live); + } + } static void gf_term_connect_from_time_ex(GF_Terminal * term, const char *URL, u64 startTime, Bool pause_at_first_frame, Bool secondary_scene, const char *parent_path) @@ -495,8 +523,10 @@ static void gf_term_connect_from_time_ex(GF_Terminal * term, const char *URL, u6 odm->media_start_time = startTime; /*render first visual frame and pause*/ - if (pause_at_first_frame) + if (pause_at_first_frame) { gf_term_set_play_state(term, GF_STATE_STEP_PAUSE, 0, 0); + scene->pause_at_first_frame = GF_TRUE; + } if (!strnicmp(URL, "views://", 8)) { odm->OD = (GF_ObjectDescriptor *)gf_odf_desc_new(GF_ODF_OD_TAG); @@ -532,9 +562,9 @@ void gf_term_refresh_cache(GF_Config *cfg) force_delete = 0; if (file) { - FILE *t = gf_f64_open(file, "r"); + FILE *t = gf_fopen(file, "r"); if (!t) force_delete = 1; - else fclose(t); + else gf_fclose(t); } sscanf(opt, "%u", &exp); gf_net_get_ntp(&sec, &frac); @@ -679,12 +709,12 @@ GF_Terminal *gf_term_new(GF_User *user) gf_list_add(tmp->unthreaded_extensions, ifce); } - gf_term_lock_media_queue(tmp, 1); + gf_mx_p(tmp->mm_mx); if (!gf_list_count(tmp->unthreaded_extensions)) { gf_list_del(tmp->unthreaded_extensions); tmp->unthreaded_extensions = NULL; } - gf_term_lock_media_queue(tmp, 0); + gf_mx_v(tmp->mm_mx); if (0 == gf_cfg_get_key_count(user->config, "MimeTypes")) { GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Terminal] Initializing Mime Types...")); @@ -823,8 +853,6 @@ GF_Err gf_term_del(GF_Terminal * term) return e; } - - GF_EXPORT GF_Err gf_term_step_clocks(GF_Terminal * term, u32 ms_diff) { @@ -832,20 +860,27 @@ GF_Err gf_term_step_clocks(GF_Terminal * term, u32 ms_diff) GF_ClientService *ns; /*only play/pause if connected*/ if (!term || !term->root_scene || !term->root_scene->root_od) return GF_BAD_PARAM; - if (term->play_state == GF_STATE_PLAYING) return GF_BAD_PARAM; - gf_sc_lock(term->compositor, 1); - i=0; - while ( (ns = (GF_ClientService*)gf_list_enum(term->net_services, &i)) ) { - GF_Clock *ck; - j=0; - while ( (ck = (GF_Clock *)gf_list_enum(ns->Clocks, &j)) ) { - ck->init_time += ms_diff; + if (ms_diff) { + if (term->play_state == GF_STATE_PLAYING) return GF_BAD_PARAM; + + gf_sc_lock(term->compositor, 1); + i=0; + while ( (ns = (GF_ClientService*)gf_list_enum(term->net_services, &i)) ) { + GF_Clock *ck; + j=0; + while ( (ck = (GF_Clock *)gf_list_enum(ns->Clocks, &j)) ) { + ck->init_time += ms_diff; + ck->media_time_at_init += ms_diff; + } } + term->compositor->step_mode = 1; + + gf_sc_next_frame_state(term->compositor, GF_SC_DRAW_FRAME); + gf_sc_lock(term->compositor, 0); } - term->compositor->step_mode = 1; - gf_sc_next_frame_state(term->compositor, GF_SC_DRAW_FRAME); - gf_sc_lock(term->compositor, 0); + + gf_sc_flush_next_audio(term->compositor); return GF_OK; } @@ -872,6 +907,14 @@ void gf_term_disconnect(GF_Terminal *term) { Bool handle_services; if (!term->root_scene) return; + + if (term->nb_calls_in_event_proc) { + if (!term->disconnect_request_status) + term->disconnect_request_status = 1; + + return; + } + /*resume*/ if (term->play_state != GF_STATE_PLAYING) gf_term_set_play_state(term, GF_STATE_PLAYING, 1, 1); @@ -987,7 +1030,7 @@ u32 gf_term_check_end_of_scene(GF_Terminal *term, Bool skip_interactions) if (gf_list_count(term->x3d_sensors)) return 0; } /*check no clocks are still running*/ - if (!gf_scene_check_clocks(term->root_scene->root_od->net_service, term->root_scene)) return 0; + if (!gf_scene_check_clocks(term->root_scene->root_od->net_service, term->root_scene, 0)) return 0; if (term->root_scene->is_dynamic_scene) return 1; /*ask compositor if there are sensors*/ @@ -1006,6 +1049,9 @@ u32 gf_term_get_option(GF_Terminal * term, u32 type) return gf_term_check_end_of_scene(term, 0); case GF_OPT_IS_OVER: return gf_term_check_end_of_scene(term, 1); + case GF_OPT_MAIN_ADDON: + return term->root_scene ? term->root_scene->main_addon_selected : 0; + case GF_OPT_PLAY_STATE: if (term->compositor->step_mode) return GF_STATE_STEP_PAUSE; if (term->root_scene) { @@ -1015,8 +1061,7 @@ u32 gf_term_get_option(GF_Terminal * term, u32 type) ck = term->root_scene->scene_codec->ck; if (!ck) return GF_STATE_PAUSED; } - if (ck->Buffering) - return GF_STATE_PLAYING; +// if (ck->Buffering) return GF_STATE_PLAYING; } if (term->play_state != GF_STATE_PLAYING) return GF_STATE_PAUSED; return GF_STATE_PLAYING; @@ -1065,6 +1110,15 @@ void gf_term_handle_services(GF_Terminal *term) { GF_ClientService *ns; + + if (term->disconnect_request_status == 1) { + term->disconnect_request_status = 2; + term->thread_id_handling_services = gf_th_id(); + gf_term_disconnect(term); + return; + } + + /*we could run into a deadlock if some thread has requested opening of a URL. If we cannot grab the media queue now, we'll do our management at the next cycle*/ if (!gf_mx_try_lock(term->media_queue_mx)) @@ -1087,7 +1141,9 @@ void gf_term_handle_services(GF_Terminal *term) case GF_ODM_ACTION_STOP: if (odm->mo /*&& odm->codec && odm->codec->CB && (odm->codec->CB->Capacity==1)*/) { - if (odm->mo->OD_ID==GF_MEDIA_EXTERNAL_ID) destroy = 1; + if (odm->addon) odm->flags |= GF_ODM_REGENERATE_SCENE; + + else if (odm->mo->OD_ID==GF_MEDIA_EXTERNAL_ID) destroy = 1; else if (odm->OD && (odm->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID)) destroy = 1; } if (destroy) { @@ -1178,7 +1234,7 @@ void gf_term_handle_services(GF_Terminal *term) } /*extensions*/ - gf_term_lock_media_queue(term, 1); + gf_mx_p(term->mm_mx); if (!term->reload_state && term->unthreaded_extensions) { u32 i, count; count = gf_list_count(term->unthreaded_extensions); @@ -1187,7 +1243,7 @@ void gf_term_handle_services(GF_Terminal *term) ifce->process(ifce, GF_TERM_EXT_PROCESS, NULL); } } - gf_term_lock_media_queue(term, 0); + gf_mx_v(term->mm_mx); /*need to reload*/ @@ -1250,7 +1306,7 @@ void gf_term_close_service(GF_Terminal *term, GF_ClientService *ns) /*prevent the media manager / term to access the list of services to destroy, otherwise we could unload the module while poping its CloseService() call stack which can lead to - random crashes (return adresses no longer valid) - cf any "stress mode" playback of a playlist*/ + random crashes (return addresses no longer valid) - cf any "stress mode" playback of a playlist*/ gf_term_lock_media_queue(term, 1); #if 0 @@ -1318,7 +1374,9 @@ void media_event_collect_info(GF_ClientService *net, GF_ObjectManager *odm, GF_D u32 val; if (ch->service != net) continue; - media_event->bufferValid = GF_TRUE; + if (ch->BufferOn) + media_event->bufferValid = GF_TRUE; + if (ch->BufferTime>0) { if (ch->MaxBuffer) { val = (ch->BufferTime * 100) / ch->MaxBuffer; @@ -1340,7 +1398,6 @@ void gf_term_service_media_event_with_download(GF_ObjectManager *odm, GF_EventTy { #ifndef GPAC_DISABLE_SVG u32 i, count, min_buffer, min_time; - GF_DOMMediaEvent media_event; GF_DOM_Event evt; GF_ObjectManager *an_od; GF_Scene *scene; @@ -1350,8 +1407,7 @@ void gf_term_service_media_event_with_download(GF_ObjectManager *odm, GF_EventTy count = gf_mo_event_target_count(odm->mo); //for dynamic scenes, check if we have listeners on the root object of the scene containing this media - if (!count - && odm->parentscene + if (odm->parentscene && odm->parentscene->is_dynamic_scene && odm->parentscene->root_od->mo && (odm->parentscene->root_od->net_service==odm->net_service) @@ -1368,29 +1424,32 @@ void gf_term_service_media_event_with_download(GF_ObjectManager *odm, GF_EventTy } - memset(&media_event, 0, sizeof(GF_DOMMediaEvent)); - media_event.bufferValid = GF_FALSE; - media_event.session_name = odm->net_service->url; + memset(&evt, 0, sizeof(GF_DOM_Event)); + + evt.media_event.bufferValid = GF_FALSE; + evt.media_event.session_name = odm->net_service->url; min_time = min_buffer = (u32) -1; scene = odm->subscene ? odm->subscene : odm->parentscene; /*get buffering on root OD*/ - media_event_collect_info(odm->net_service, scene->root_od, &media_event, &min_time, &min_buffer); + media_event_collect_info(odm->net_service, scene->root_od, &evt.media_event, &min_time, &min_buffer); + gf_mx_p(scene->mx_resources); /*get buffering on all ODs*/ i=0; while ((an_od = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { if (odm->net_service == an_od->net_service) - media_event_collect_info(odm->net_service, an_od, &media_event, &min_time, &min_buffer); + media_event_collect_info(odm->net_service, an_od, &evt.media_event, &min_time, &min_buffer); } + gf_mx_v(scene->mx_resources); - media_event.level = min_buffer; - media_event.remaining_time = INT2FIX(min_time) / 60; - media_event.status = 0; - media_event.loaded_size = loaded_size; - media_event.total_size = total_size; + if (min_buffer != (u32) -1) + evt.media_event.level = min_buffer; + if (min_time != (u32) -1) + evt.media_event.remaining_time = INT2FIX(min_time) / 60; + evt.media_event.status = 0; + evt.media_event.loaded_size = loaded_size; + evt.media_event.total_size = total_size; - memset(&evt, 0, sizeof(GF_DOM_Event)); - evt.media_event = &media_event; evt.type = event_type; evt.bubbles = 0; /*the spec says yes but we force it to NO*/ @@ -1551,7 +1610,7 @@ static void gf_term_connect_object(GF_Terminal *term, GF_ObjectManager *odm, cha if (net_locked) gf_term_lock_net(term, 0); - odm->net_service = gf_term_service_new(term, odm, serviceURL, reloc_result ? NULL : parent_url, &e); + odm->net_service = gf_term_service_new(term, odm, serviceURL, (odm->addon || reloc_result) ? NULL : parent_url, &e); if (!odm->net_service) { gf_term_message(term, serviceURL, "Cannot open service", e); gf_odm_disconnect(odm, 1); @@ -1638,7 +1697,7 @@ u32 gf_term_play_from_time(GF_Terminal *term, u64 from_time, u32 pause_at_first_ gf_term_set_play_state(term, GF_STATE_STEP_PAUSE, 0, 0); gf_sc_lock(term->compositor, 1); - gf_scene_restart_dynamic(term->root_scene, from_time); + gf_scene_restart_dynamic(term->root_scene, from_time, 0, 0); gf_sc_lock(term->compositor, 0); return 2; } @@ -1685,9 +1744,7 @@ u32 gf_term_get_time_in_ms(GF_Terminal *term) if (term->root_scene->scene_codec && term->root_scene->scene_codec->ck) ck = term->root_scene->scene_codec->ck; else if (term->root_scene->dyn_ck) ck = term->root_scene->dyn_ck; - if (!ck) return 0; - if (!ck->has_seen_eos && ck->last_TS_rendered) return ck->last_TS_rendered; - return gf_clock_elapse_time(ck); + return gf_clock_media_time(ck); } GF_Node *gf_term_pick_node(GF_Terminal *term, s32 X, s32 Y) @@ -1979,7 +2036,7 @@ GF_Err gf_term_paste_text(GF_Terminal *term, const char *txt, Bool probe_only) GF_EXPORT Bool gf_term_forward_event(GF_Terminal *term, GF_Event *evt, Bool consumed, Bool forward_only) { - if (!term) return 0; + if (!term) return GF_FALSE; if (term->event_filters) { GF_TermEventFilter *ef; @@ -1991,16 +2048,21 @@ Bool gf_term_forward_event(GF_Terminal *term, GF_Event *evt, Bool consumed, Bool while ((ef=gf_list_enum(term->event_filters, &i))) { if (ef->on_event(ef->udta, evt, consumed)) { term->in_event_filter --; - return 1; + return GF_TRUE; } } term->in_event_filter --; } - if (!forward_only && !consumed && term->user->EventProc) - return term->user->EventProc(term->user->opaque, evt); + if (!forward_only && !consumed && term->user->EventProc) { + Bool res; + term->nb_calls_in_event_proc++; + res = term->user->EventProc(term->user->opaque, evt); + term->nb_calls_in_event_proc--; + return res; + } - return 0; + return GF_FALSE; } GF_EXPORT @@ -2082,7 +2144,7 @@ static void set_clocks_speed(GF_Terminal *term, Fixed ratio) } GF_EXPORT -void gf_term_set_speed(GF_Terminal *term, Fixed speed) +GF_Err gf_term_set_speed(GF_Terminal *term, Fixed speed) { Double fps; u32 i, j; @@ -2091,27 +2153,56 @@ void gf_term_set_speed(GF_Terminal *term, Fixed speed) Bool restart = 0; u32 scene_time = gf_term_get_time_in_ms(term); - if (!speed) return; + if (!speed) return GF_BAD_PARAM; - /*adjust all clocks on all services*/ + if (speed<0) { + i=0; + while ( (ns = (GF_ClientService*)gf_list_enum(term->net_services, &i)) ) { + GF_NetworkCommand com; + GF_Err e; + memset(&com, 0, sizeof(GF_NetworkCommand)); + com.base.command_type = GF_NET_SERVICE_CAN_REVERSE_PLAYBACK; + e = gf_term_service_command(ns, &com); + if (e != GF_OK) { + return e; + } + } + } + + /*adjust all clocks on all services, if possible*/ i=0; while ( (ns = (GF_ClientService*)gf_list_enum(term->net_services, &i)) ) { GF_Clock *ck; + ns->set_speed = speed; j=0; while ( (ck = (GF_Clock *)gf_list_enum(ns->Clocks, &j)) ) { - if ( gf_mulfix(ck->speed,speed) < 0) restart = 1; + //we will have to reissue a PLAY command since playback direction changed + if ( gf_mulfix(ck->speed,speed) < 0) + restart = 1; gf_clock_set_speed(ck, speed); + + if (ns->owner) { + gf_odm_set_speed(ns->owner, speed, GF_FALSE); + if (ns->owner->subscene) { + u32 k=0; + GF_ObjectManager *odm; + GF_Scene *scene = ns->owner->subscene; + while ( (odm = gf_list_enum(scene->resources, &k))) { + gf_odm_set_speed(odm, speed, GF_FALSE); + } + } + } } } if (restart) { if (term->root_scene->is_dynamic_scene) { - gf_scene_restart_dynamic(term->root_scene, scene_time); + gf_scene_restart_dynamic(term->root_scene, scene_time, 0, 0); } else { } } - if (speed<0) + if (speed<0) speed = -speed; opt = gf_cfg_get_key(term->user->config, "Systems", "TimeSlice"); @@ -2125,6 +2216,8 @@ void gf_term_set_speed(GF_Terminal *term, Fixed speed) fps *= FIX2FLT(speed); if (fps>100) fps = 1000; gf_sc_set_fps(term->compositor, fps); + + return GF_OK; } GF_EXPORT @@ -2196,7 +2289,7 @@ void gf_term_process_shortcut(GF_Terminal *term, GF_Event *ev) case GF_ACTION_VERY_FAST_REWIND: case GF_ACTION_FAST_REWIND: case GF_ACTION_SLOW_REWIND: - if (term->root_scene && !(term->root_scene->root_od->flags & GF_ODM_NO_TIME_CTRL) ) { + if (0 && term->root_scene && !(term->root_scene->root_od->flags & GF_ODM_NO_TIME_CTRL) ) { s32 res; u32 dur = (u32) term->root_scene->duration ; val = gf_term_get_time_in_ms(term); @@ -2341,6 +2434,7 @@ void gf_scene_switch_quality(GF_Scene *scene, Bool up) if (!scene) return; /*send network command*/ + memset(&net_cmd, 0, sizeof(GF_NetworkCommand)); net_cmd.command_type = GF_NET_SERVICE_QUALITY_SWITCH; net_cmd.switch_quality.on_channel = NULL; net_cmd.switch_quality.up = up; @@ -2359,10 +2453,17 @@ void gf_scene_switch_quality(GF_Scene *scene, Bool up) while (NULL != (odm = gf_list_enum(scene->resources, &i))) { if (odm->codec) odm->codec->decio->SetCapabilities(odm->codec->decio, caps); - if (odm->net_service && (odm->net_service != root_service) ) + if (odm->net_service && (odm->net_service != root_service) && (!odm->subscene || !odm->subscene->is_dynamic_scene) ) odm->net_service->ifce->ServiceCommand(odm->net_service->ifce, &net_cmd); if (odm->subscene) gf_scene_switch_quality(odm->subscene, up); + + if (odm->scalable_addon) { + if (up) + gf_odm_start(odm, 0); + else + gf_odm_stop(odm, GF_FALSE); + } } } @@ -2379,4 +2480,10 @@ GF_Err gf_term_get_visual_output_size(GF_Terminal *term, u32 *width, u32 *height if (width) *width = term->compositor->vp_width; if (height) *height = term->compositor->vp_height; return GF_OK; -} \ No newline at end of file +} + +GF_EXPORT +u32 gf_term_get_clock(GF_Terminal *term) +{ + return gf_sc_ar_get_clock(term->compositor->audio_renderer); +} diff --git a/src/utils/alloc.c b/src/utils/alloc.c index 7ebde6a..a891fa7 100644 --- a/src/utils/alloc.c +++ b/src/utils/alloc.c @@ -145,27 +145,28 @@ This is only needed when building libgpac and modules when libgpac is not instal /*GPAC memory tracking*/ #ifndef GPAC_MEMORY_TRACKING -CDECL +#include +GF_EXPORT void *gf_malloc(size_t size) { return MALLOC(size); } -CDECL +GF_EXPORT void *gf_calloc(size_t num, size_t size_of) { return CALLOC(num, size_of); } -CDECL +GF_EXPORT void *gf_realloc(void *ptr, size_t size) { return REALLOC(ptr, size); } -CDECL +GF_EXPORT void gf_free(void *ptr) { FREE(ptr); } -CDECL +GF_EXPORT char *gf_strdup(const char *str) { STRDUP(str); @@ -181,8 +182,8 @@ size_t gpac_nb_alloc_blocs = 0; #define assert(p) #endif -static void register_address(void *ptr, size_t size, char *filename, int line); -static int unregister_address(void *ptr, char *filename, int line); +static void register_address(void *ptr, size_t size, const char *filename, int line); +static int unregister_address(void *ptr, const char *filename, int line); static void gf_memory_log(unsigned int level, const char *fmt, ...); enum @@ -199,28 +200,28 @@ enum GF_MEMORY_DEBUG, }; -static void *gf_mem_malloc_basic(size_t size, char *filename, int line) +static void *gf_mem_malloc_basic(size_t size, const char *filename, int line) { return MALLOC(size); } -static void *gf_mem_calloc_basic(size_t num, size_t size_of, char *filename, int line) +static void *gf_mem_calloc_basic(size_t num, size_t size_of, const char *filename, int line) { return CALLOC(num, size_of); } -static void *gf_mem_realloc_basic(void *ptr, size_t size, char *filename, int line) +static void *gf_mem_realloc_basic(void *ptr, size_t size, const char *filename, int line) { return REALLOC(ptr, size); } -static void gf_mem_free_basic(void *ptr, char *filename, int line) +static void gf_mem_free_basic(void *ptr, const char *filename, int line) { FREE(ptr); } -static char *gf_mem_strdup_basic(const char *str, char *filename, int line) +static char *gf_mem_strdup_basic(const char *str, const char *filename, int line) { STRDUP(str); } -void *gf_mem_malloc_tracker(size_t size, char *filename, int line) +void *gf_mem_malloc_tracker(size_t size, const char *filename, int line) { void *ptr = MALLOC(size); if (!ptr) { @@ -233,7 +234,7 @@ void *gf_mem_malloc_tracker(size_t size, char *filename, int line) return ptr; } -void *gf_mem_calloc_tracker(size_t num, size_t size_of, char *filename, int line) +void *gf_mem_calloc_tracker(size_t num, size_t size_of, const char *filename, int line) { size_t size = num*size_of; void *ptr = CALLOC(num, size_of); @@ -247,7 +248,7 @@ void *gf_mem_calloc_tracker(size_t num, size_t size_of, char *filename, int line return ptr; } -void gf_mem_free_tracker(void *ptr, char *filename, int line) +void gf_mem_free_tracker(void *ptr, const char *filename, int line) { int size_prev; if (ptr && (size_prev=unregister_address(ptr, filename, line))) { @@ -256,7 +257,7 @@ void gf_mem_free_tracker(void *ptr, char *filename, int line) } } -void *gf_mem_realloc_tracker(void *ptr, size_t size, char *filename, int line) +void *gf_mem_realloc_tracker(void *ptr, size_t size, const char *filename, int line) { void *ptr_g; int size_prev; @@ -283,7 +284,7 @@ void *gf_mem_realloc_tracker(void *ptr, size_t size, char *filename, int line) return ptr_g; } -char *gf_mem_strdup_tracker(const char *str, char *filename, int line) +char *gf_mem_strdup_tracker(const char *str, const char *filename, int line) { char *ptr; if (!str) return NULL; @@ -292,11 +293,11 @@ char *gf_mem_strdup_tracker(const char *str, char *filename, int line) return ptr; } -static void *(*gf_mem_malloc_proto)(size_t size, char *filename, int line) = gf_mem_malloc_basic; -static void *(*gf_mem_calloc_proto)(size_t num, size_t size_of, char *filename, int line) = gf_mem_calloc_basic; -static void *(*gf_mem_realloc_proto)(void *ptr, size_t size, char *filename, int line) = gf_mem_realloc_basic; -static void (*gf_mem_free_proto)(void *ptr, char *filename, int line) = gf_mem_free_basic; -static char *(*gf_mem_strdup_proto)(const char *str, char *filename, int line) = gf_mem_strdup_basic; +static void *(*gf_mem_malloc_proto)(size_t size, const char *filename, int line) = gf_mem_malloc_basic; +static void *(*gf_mem_calloc_proto)(size_t num, size_t size_of, const char *filename, int line) = gf_mem_calloc_basic; +static void *(*gf_mem_realloc_proto)(void *ptr, size_t size, const char *filename, int line) = gf_mem_realloc_basic; +static void (*gf_mem_free_proto)(void *ptr, const char *filename, int line) = gf_mem_free_basic; +static char *(*gf_mem_strdup_proto)(const char *str, const char *filename, int line) = gf_mem_strdup_basic; #ifndef MY_GF_EXPORT #if defined(__GNUC__) && __GNUC__ >= 4 @@ -307,30 +308,30 @@ static char *(*gf_mem_strdup_proto)(const char *str, char *filename, int line) = #endif #endif -MY_GF_EXPORT void *gf_mem_malloc(size_t size, char *filename, int line) +MY_GF_EXPORT void *gf_mem_malloc(size_t size, const char *filename, int line) { return gf_mem_malloc_proto(size, filename, line); } -MY_GF_EXPORT void *gf_mem_calloc(size_t num, size_t size_of, char *filename, int line) +MY_GF_EXPORT void *gf_mem_calloc(size_t num, size_t size_of, const char *filename, int line) { return gf_mem_calloc_proto(num, size_of, filename, line); } MY_GF_EXPORT -void *gf_mem_realloc(void *ptr, size_t size, char *filename, int line) +void *gf_mem_realloc(void *ptr, size_t size, const char *filename, int line) { return gf_mem_realloc_proto(ptr, size, filename, line); } MY_GF_EXPORT -void gf_mem_free(void *ptr, char *filename, int line) +void gf_mem_free(void *ptr, const char *filename, int line) { gf_mem_free_proto(ptr, filename, line); } MY_GF_EXPORT -char *gf_mem_strdup(const char *str, char *filename, int line) +char *gf_mem_strdup(const char *str, const char *filename, int line) { return gf_mem_strdup_proto(str, filename, line); } @@ -386,7 +387,7 @@ typedef memory_element* memory_list; /*base functions (add, find, del_item, del) are implemented upon a stack model*/ -static void gf_memory_add_stack(memory_element **p, void *ptr, int size, char *filename, int line) +static void gf_memory_add_stack(memory_element **p, void *ptr, int size, const char *filename, int line) { memory_element *element = (memory_element*)MALLOC(sizeof(memory_element)+strlen(filename)+1); element->ptr = ptr; @@ -447,7 +448,7 @@ static void gf_memory_del_stack(memory_element **p) #if GPAC_MEMORY_TRACKING_HASH_TABLE /*this list is implemented as a stack to minimise the cost of freeing recent allocations*/ -static void gf_memory_add(memory_list *p, void *ptr, int size, char *filename, int line) +static void gf_memory_add(memory_list *p, void *ptr, int size, const char *filename, int line) { unsigned int hash; if (!*p) *p = (memory_list) CALLOC(HASH_ENTRIES, sizeof(memory_element*)); @@ -525,7 +526,7 @@ static void gf_memory_del(memory_list *p) memory_list memory_add = NULL, memory_rem = NULL; GF_Mutex *gpac_allocations_lock = NULL; -static void register_address(void *ptr, size_t size, char *filename, int line) +static void register_address(void *ptr, size_t size, const char *filename, int line) { /*mutex initialization*/ if (gpac_allocations_lock == 0) { @@ -580,7 +581,7 @@ void gf_check_address(void *ptr) #endif /*returns the size of the unregistered block*/ -static int unregister_address(void *ptr, char *filename, int line) +static int unregister_address(void *ptr, const char *filename, int line) { int size = 0; /*default: failure*/ @@ -663,13 +664,20 @@ static void gf_memory_log(unsigned int level, const char *fmt, ...) } /*prints allocations sum-up*/ -void gf_memory_size() +static void print_memory_size() { unsigned int level = gpac_nb_alloc_blocs ? GF_MEMORY_ERROR : GF_MEMORY_INFO; gf_memory_log(level, "[MemTracker] Total: %d bytes allocated in %d blocks\n", gpac_allocated_memory, gpac_nb_alloc_blocs); } +GF_EXPORT +u64 gf_memory_size() +{ + return (u64) gpac_allocated_memory; +} + /*prints the state of current allocations*/ +GF_EXPORT void gf_memory_print() { /*if lists are empty, the mutex is also NULL*/ @@ -680,7 +688,7 @@ void gf_memory_print() int i=0; assert(gpac_allocations_lock); - gf_memory_log(GF_MEMORY_INFO, "\n[MemTracker] Printing the current state of allocations:\n"); + gf_memory_log(GF_MEMORY_INFO, "\n[MemTracker] Printing the current state of allocations (%d open file handles) :\n", gf_file_handles_count()); /*lock*/ gf_mx_p(gpac_allocations_lock); @@ -702,7 +710,7 @@ void gf_memory_print() curr_element = next_element; } } - gf_memory_size(); + print_memory_size(); /*unlock*/ gf_mx_v(gpac_allocations_lock); diff --git a/src/utils/base_encoding.c b/src/utils/base_encoding.c index 8ea602f..35ac057 100644 --- a/src/utils/base_encoding.c +++ b/src/utils/base_encoding.c @@ -222,7 +222,7 @@ GF_Err gf_gz_compress_payload(char **data, u32 data_len, u32 *max_size) } memcpy((*data) , dest, sizeof(char)*stream.total_out); - *max_size = stream.total_out; + *max_size = (u32) stream.total_out; gf_free(dest); deflateEnd(&stream); @@ -261,10 +261,10 @@ GF_Err gf_gz_decompress_payload(char *data, u32 data_len, char **uncompressed_da size *= 2; *uncompressed_data = gf_realloc(*uncompressed_data, sizeof(char)*size); if (!*uncompressed_data) return GF_OUT_OF_MEM; - d_stream.avail_out = (size - d_stream.total_out); + d_stream.avail_out = (u32) (size - d_stream.total_out); d_stream.next_out = (Bytef*) ( *uncompressed_data + d_stream.total_out); } - *out_size = d_stream.total_out; + *out_size = (u32) d_stream.total_out; inflateEnd(&d_stream); return e; } diff --git a/src/utils/bitstream.c b/src/utils/bitstream.c index c8a3502..68ae8f5 100644 --- a/src/utils/bitstream.c +++ b/src/utils/bitstream.c @@ -135,10 +135,10 @@ GF_BitStream *gf_bs_from_file(FILE *f, u32 mode) tmp->stream = f; /*get the size of this file (for read streams)*/ - tmp->position = gf_f64_tell(f); - gf_f64_seek(f, 0, SEEK_END); - tmp->size = gf_f64_tell(f); - gf_f64_seek(f, tmp->position, SEEK_SET); + tmp->position = gf_ftell(f); + gf_fseek(f, 0, SEEK_END); + tmp->size = gf_ftell(f); + gf_fseek(f, tmp->position, SEEK_SET); return tmp; } @@ -737,10 +737,10 @@ u64 gf_bs_available(GF_BitStream *bs) if (bs->buffer_io) bs_flush_cache(bs); - cur = gf_f64_tell(bs->stream); - gf_f64_seek(bs->stream, 0, SEEK_END); - end = gf_f64_tell(bs->stream); - gf_f64_seek(bs->stream, cur, SEEK_SET); + cur = gf_ftell(bs->stream); + gf_fseek(bs->stream, 0, SEEK_END); + end = gf_ftell(bs->stream); + gf_fseek(bs->stream, cur, SEEK_SET); return (u64) (end - cur); } @@ -805,7 +805,7 @@ void gf_bs_skip_bytes(GF_BitStream *bs, u64 nbBytes) if ((bs->bsmode == GF_BITSTREAM_FILE_WRITE) || (bs->bsmode == GF_BITSTREAM_FILE_READ)) { if (bs->buffer_io) bs_flush_cache(bs); - gf_f64_seek(bs->stream, nbBytes, SEEK_CUR); + gf_fseek(bs->stream, nbBytes, SEEK_CUR); bs->position += nbBytes; return; } @@ -839,7 +839,7 @@ void gf_bs_rewind_bits(GF_BitStream *bs, u64 nbBits) return; } -/*seek from begining of stream: use internally even when non aligned!*/ +/*seek from beginning of stream: use internally even when non aligned!*/ static GF_Err BS_SeekIntern(GF_BitStream *bs, u64 offset) { u32 i; @@ -868,7 +868,7 @@ static GF_Err BS_SeekIntern(GF_BitStream *bs, u64 offset) if (bs->buffer_io) bs_flush_cache(bs); - gf_f64_seek(bs->stream, offset, SEEK_SET); + gf_fseek(bs->stream, offset, SEEK_SET); bs->position = offset; bs->current = 0; @@ -877,7 +877,7 @@ static GF_Err BS_SeekIntern(GF_BitStream *bs, u64 offset) return GF_OK; } -/*seek from begining of stream: align before anything else*/ +/*seek from beginning of stream: align before anything else*/ GF_EXPORT GF_Err gf_bs_seek(GF_BitStream *bs, u64 offset) { @@ -890,7 +890,7 @@ GF_Err gf_bs_seek(GF_BitStream *bs, u64 offset) /*peek bits (as int!!) from orig position (ON BYTE BOUNDARIES, from 0) - only for read ...*/ GF_EXPORT -u32 gf_bs_peek_bits(GF_BitStream *bs, u32 numBits, u32 byte_offset) +u32 gf_bs_peek_bits(GF_BitStream *bs, u32 numBits, u64 byte_offset) { u64 curPos; u32 curBits, ret, current; @@ -927,10 +927,10 @@ u64 gf_bs_get_refreshed_size(GF_BitStream *bs) default: if (bs->buffer_io) bs_flush_cache(bs); - offset = gf_f64_tell(bs->stream); - gf_f64_seek(bs->stream, 0, SEEK_END); - bs->size = gf_f64_tell(bs->stream); - gf_f64_seek(bs->stream, offset, SEEK_SET); + offset = gf_ftell(bs->stream); + gf_fseek(bs->stream, 0, SEEK_END); + bs->size = gf_ftell(bs->stream); + gf_fseek(bs->stream, offset, SEEK_SET); return bs->size; } } @@ -1084,7 +1084,7 @@ void gf_bs_reassign(GF_BitStream *bs, FILE *stream) case GF_BITSTREAM_FILE_WRITE: case GF_BITSTREAM_FILE_READ: bs->stream = stream; - if (gf_f64_tell(stream) != bs->position) + if (gf_ftell(stream) != bs->position) gf_bs_seek(bs, bs->position); break; } diff --git a/src/utils/cache.c b/src/utils/cache.c index d0022c0..09d00ee 100644 --- a/src/utils/cache.c +++ b/src/utils/cache.c @@ -162,7 +162,8 @@ struct __DownloadedCacheEntryStruct Bool file_exists; u32 previousRangeContentLength; - + /*set once headers have been processed*/ + Bool headers_done; /** * Set to 1 if file is not stored on disk */ @@ -226,6 +227,21 @@ const char * gf_cache_get_mime_type ( const DownloadedCacheEntry entry ) return entry ? entry->mimeType : NULL; } + +GF_Err gf_cache_set_headers_processed(const DownloadedCacheEntry entry) +{ + if (!entry) return GF_BAD_PARAM; + entry->headers_done = GF_TRUE; + return GF_OK; +} + +Bool gf_cache_are_headers_processed(const DownloadedCacheEntry entry) +{ + if (!entry) return GF_FALSE; + return entry->headers_done; +} + + GF_Err gf_cache_set_etag_on_server(const DownloadedCacheEntry entry, const char * eTag ) { if (!entry) return GF_BAD_PARAM; @@ -346,7 +362,8 @@ const char * gf_cache_get_cache_filename( const DownloadedCacheEntry entry ) return entry ? entry->cache_filename : NULL; } -GF_Err appendHttpCacheHeaders(const DownloadedCacheEntry entry, char * httpRequest) { +GF_EXPORT +GF_Err gf_cache_append_http_headers(const DownloadedCacheEntry entry, char * httpRequest) { if (!entry || !httpRequest) return GF_BAD_PARAM; if (entry->flags) @@ -560,14 +577,35 @@ GF_Err gf_cache_close_write_cache( const DownloadedCacheEntry entry, const GF_Do if (entry->writeFilePtr) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Closing file %s, %d bytes written.\n", entry->cache_filename, entry->written_in_cache)); - if (fflush( entry->writeFilePtr ) || fclose( entry->writeFilePtr )) + + if (fflush( entry->writeFilePtr ) || gf_fclose( entry->writeFilePtr )) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Failed to flush/close file on disk\n")); e = GF_IO_ERR; - e|= gf_cache_flush_disk_cache(entry); - if (e == GF_OK && success) { - e|= gf_cache_set_last_modified_on_disk( entry, gf_cache_get_last_modified_on_server(entry)); - e|= gf_cache_set_etag_on_disk( entry, gf_cache_get_etag_on_server(entry)); } - e|= gf_cache_flush_disk_cache(entry); + if (!e) { + e = gf_cache_flush_disk_cache(entry); + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Failed to flush cache entry on disk\n")); + } + } + if (!e && success) { + e = gf_cache_set_last_modified_on_disk( entry, gf_cache_get_last_modified_on_server(entry)); + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Failed to set last-modified\n")); + } else { + e = gf_cache_set_etag_on_disk( entry, gf_cache_get_etag_on_server(entry)); + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Failed to set etag\n")); + } + } + } + if (!e) { + e = gf_cache_flush_disk_cache(entry); + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Failed to flush cache entry on disk after etag/last-modified\n")); + } + } + #if defined(_BSD_SOURCE) || _XOPEN_SOURCE >= 500 /* On UNIX, be sure to flush all the data */ sync(); @@ -618,7 +656,7 @@ GF_Err gf_cache_open_write_cache( const DownloadedCacheEntry entry, const GF_Dow } GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Opening cache file %s for write (%s)...\n", entry->cache_filename, entry->url)); - entry->writeFilePtr = gf_f64_open(entry->cache_filename, entry->continue_file ? "a+b" : "wb"); + entry->writeFilePtr = gf_fopen(entry->cache_filename, entry->continue_file ? "a+b" : "wb"); if (!entry->writeFilePtr) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Error while opening cache file %s for writting.\n", entry->cache_filename)); @@ -630,7 +668,7 @@ GF_Err gf_cache_open_write_cache( const DownloadedCacheEntry entry, const GF_Dow } entry->file_exists = 1; if (entry->continue_file ) - gf_f64_seek(entry->writeFilePtr, 0, SEEK_END); + gf_fseek(entry->writeFilePtr, 0, SEEK_END); return GF_OK; } @@ -656,7 +694,7 @@ GF_Err gf_cache_write_to_cache( const DownloadedCacheEntry entry, const GF_Downl memset(entry->mem_storage + entry->written_in_cache, 0, 2); sprintf(entry->cache_filename, "gmem://%d@%p", entry->written_in_cache, entry->mem_storage); - GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Writing %d bytes to cache\n", size)); + GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[CACHE] Storing %d bytes to memory\n", size)); return GF_OK; } @@ -689,7 +727,7 @@ GF_CacheReader gf_cache_reader_new(const DownloadedCacheEntry entry) { reader = gf_malloc(sizeof(struct __CacheReaderStruct)); if (reader == NULL) return NULL; - reader->readPtr = gf_f64_open( entry->cache_filename, "rb" ); + reader->readPtr = gf_fopen( entry->cache_filename, "rb" ); reader->readPosition = 0; if (!reader->readPtr) { gf_cache_reader_del(reader); @@ -702,7 +740,7 @@ GF_Err gf_cache_reader_del( GF_CacheReader handle ) { if (!handle) return GF_BAD_PARAM; if (handle->readPtr) - fclose(handle->readPtr); + gf_fclose(handle->readPtr); handle->readPtr = NULL; handle->readPosition = -1; return GF_OK; @@ -711,7 +749,7 @@ GF_Err gf_cache_reader_del( GF_CacheReader handle ) { s64 gf_cache_reader_seek_at( GF_CacheReader reader, u64 seekPosition) { if (!reader) return -1; - reader->readPosition = gf_f64_seek(reader->readPtr, seekPosition, SEEK_SET); + reader->readPosition = gf_fseek(reader->readPtr, seekPosition, SEEK_SET); return reader->readPosition; } @@ -743,7 +781,7 @@ GF_Err gf_cache_delete_entry ( const DownloadedCacheEntry entry ) if (entry->writeFilePtr) { /** Cache should have been close before, abornormal situation */ GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_delete_entry:%d, entry=%p, cache has not been closed properly\n", __LINE__, entry)); - fclose(entry->writeFilePtr); + gf_fclose(entry->writeFilePtr); } #ifdef ENABLE_WRITE_MX if (entry->write_mutex) { @@ -810,8 +848,8 @@ GF_Err gf_cache_delete_entry ( const DownloadedCacheEntry entry ) gf_cfg_del ( entry->properties ); entry->properties = NULL; if (propfile) { - if (GF_OK != gf_delete_file( propfile )) - GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[CACHE] gf_cache_delete_entry:%d, failed to delete file %s\n", __LINE__, propfile)); + //this may fil becaus ethe prop file is not yet flushed to disk + gf_delete_file( propfile ); gf_free ( propfile ); } } @@ -828,17 +866,17 @@ GF_Err gf_cache_delete_entry ( const DownloadedCacheEntry entry ) Bool gf_cache_check_if_cache_file_is_corrupted(const DownloadedCacheEntry entry) { - FILE *the_cache = gf_f64_open ( entry->cache_filename, "rb" ); + FILE *the_cache = gf_fopen ( entry->cache_filename, "rb" ); if ( the_cache ) { char * endPtr; const char * keyValue = gf_cfg_get_key ( entry->properties, CACHE_SECTION_NAME, CACHE_SECTION_NAME_CONTENT_SIZE ); - gf_f64_seek ( the_cache, 0, SEEK_END ); - entry->cacheSize = ( u32 ) gf_f64_tell ( the_cache ); - fclose ( the_cache ); + gf_fseek ( the_cache, 0, SEEK_END ); + entry->cacheSize = ( u32 ) gf_ftell ( the_cache ); + gf_fclose ( the_cache ); if (keyValue) { - entry->contentLength = strtoul( keyValue, &endPtr, 10); + entry->contentLength = (u32) strtoul( keyValue, &endPtr, 10); if (*endPtr!='\0' || entry->contentLength != entry->cacheSize) { entry->flags |= CORRUPTED; GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] gf_cache_create_entry:%d, Cache corrupted: file and cache info size mismatch.\n", __LINE__)); @@ -872,8 +910,8 @@ s32 gf_cache_remove_session_from_cache_entry(DownloadedCacheEntry entry, GF_Down * but we don't want to risk to have another session opening * a not fully closed cache entry */ if (entry->writeFilePtr) { - if (fclose(entry->writeFilePtr)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] gf_cache_remove_session_from_cache_entry:%d, Failed to properly fclose cache file '%s' of url '%s', cache may be corrupted !\n", __LINE__, entry->cache_filename, entry->url)); + if (gf_fclose(entry->writeFilePtr)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] gf_cache_remove_session_from_cache_entry:%d, Failed to properly close cache file '%s' of url '%s', cache may be corrupted !\n", __LINE__, entry->cache_filename, entry->url)); } } entry->writeFilePtr = NULL; diff --git a/src/utils/color.c b/src/utils/color.c index b7254dc..076fcdc 100644 --- a/src/utils/color.c +++ b/src/utils/color.c @@ -28,6 +28,7 @@ #include #include +#ifndef GPAC_DISABLE_PLAYER /* YUV -> RGB conversion loading two lines at each call */ @@ -1479,7 +1480,7 @@ void gf_cmx_apply_fixed(GF_ColorMatrix *_this, Fixed *a, Fixed *r, Fixed *g, Fix -#ifdef WIN32 +#if defined(WIN32) && !defined(__GNUC__) # include # define GPAC_HAS_SSE2 #else @@ -1616,7 +1617,7 @@ GF_Err gf_color_write_yv12_10_to_yuv(GF_VideoSurface *vs_dst, unsigned char *pY pU = pU + (src_stride * (_src_wnd->y / 2) + _src_wnd->x) / 2; pV = pV + (src_stride * (_src_wnd->y / 2) + _src_wnd->x) / 2; } - + if (swap_uv) { u8 *t = pV; pV = pU; @@ -1661,3 +1662,209 @@ GF_Err gf_color_write_yv12_10_to_yuv(GF_VideoSurface *vs_dst, unsigned char *pY return GF_NOT_SUPPORTED; } +#endif + + +/* Basic SVG datatype parsing functions */ +static const struct predef_col { + const char *name; + u8 r; + u8 g; + u8 b; +} predefined_colors[] = +{ + {"aliceblue",240, 248, 255}, + {"antiquewhite",250, 235, 215}, + {"aquamarine",127, 255, 212}, + {"azure",240, 255, 255}, + {"beige",245, 245, 220}, + {"bisque",255, 228, 196}, + {"black", 0, 0, 0}, + {"blanchedalmond",255, 235, 205}, + {"blue", 0, 0, 255}, + {"blueviolet",138, 43, 226}, + {"brown",165, 42, 42}, + {"burlywood",222, 184, 135}, + {"cadetblue", 95, 158, 160}, + {"chartreuse",127, 255, 0}, + {"chocolate",210, 105, 30}, + {"coral",255, 127, 80}, + {"lightpink",255, 182, 193}, + {"lightsalmon",255, 160, 122}, + {"lightseagreen", 32, 178, 170}, + {"lightskyblue",135, 206, 250}, + {"lightslategray",119, 136, 153}, + {"lightslategrey",119, 136, 153}, + {"lightsteelblue",176, 196, 222}, + {"lightyellow",255, 255, 224}, + {"lime", 0, 255, 0}, + {"limegreen", 50, 205, 50}, + {"linen",250, 240, 230}, + {"magenta",255, 0, 255}, + {"maroon",128, 0, 0}, + {"mediumaquamarine",102, 205, 170}, + {"mediumblue", 0, 0, 205}, + {"mediumorchid",186, 85, 211}, + {"cornflowerblue",100, 149, 237}, + {"cornsilk",255, 248, 220}, + {"crimson",220, 20, 60}, + {"cyan", 0, 255, 255}, + {"darkblue", 0, 0, 139}, + {"darkcyan", 0, 139, 139}, + {"darkgoldenrod",184, 134, 11}, + {"darkgray",169, 169, 169}, + {"darkgreen", 0, 100, 0}, + {"darkgrey",169, 169, 169}, + {"darkkhaki",189, 183, 107}, + {"darkmagenta",139, 0, 139}, + {"darkolivegreen", 85, 107, 47}, + {"darkorange",255, 140, 0}, + {"darkorchid",153, 50, 204}, + {"darkred",139, 0, 0}, + {"darksalmon",233, 150, 122}, + {"darkseagreen",143, 188, 143}, + {"darkslateblue", 72, 61, 139}, + {"darkslategray", 47, 79, 79}, + {"darkslategrey", 47, 79, 79}, + {"darkturquoise", 0, 206, 209}, + {"darkviolet",148, 0, 211}, + {"deeppink",255, 20, 147}, + {"deepskyblue", 0, 191, 255}, + {"dimgray",105, 105, 105}, + {"dimgrey",105, 105, 105}, + {"dodgerblue", 30, 144, 255}, + {"firebrick",178, 34, 34}, + {"floralwhite",255, 250, 240}, + {"forestgreen", 34, 139, 34}, + {"fuchsia",255, 0, 255}, + {"gainsboro",220, 220, 220}, + {"ghostwhite",248, 248, 255}, + {"gold",255, 215, 0}, + {"goldenrod",218, 165, 32}, + {"gray",128, 128, 128}, + {"grey",128, 128, 128}, + {"green", 0, 128, 0}, + {"greenyellow",173, 255, 47}, + {"honeydew",240, 255, 240}, + {"hotpink",255, 105, 180}, + {"indianred",205, 92, 92}, + {"indigo", 75, 0, 130}, + {"ivory",255, 255, 240}, + {"khaki",240, 230, 140}, + {"lavender",230, 230, 25}, + {"lavenderblush",255, 240, 245}, + {"mediumpurple",147, 112, 219}, + {"mediumseagreen", 60, 179, 113}, + {"mediumslateblue",123, 104, 238}, + {"mediumspringgreen", 0, 250, 154}, + {"mediumturquoise", 72, 209, 204}, + {"mediumvioletred",199, 21, 133}, + {"midnightblue", 25, 25, 112}, + {"mintcream",245, 255, 250}, + {"mistyrose",255, 228, 225}, + {"moccasin",255, 228, 181}, + {"navajowhite",255, 222, 173}, + {"navy", 0, 0, 128}, + {"oldlace",253, 245, 230}, + {"olive",128, 128, 0}, + {"olivedrab",107, 142, 35}, + {"orange",255, 165, 0}, + {"orangered",255, 69, 0}, + {"orchid",218, 112, 214}, + {"palegoldenrod",238, 232, 170}, + {"palegreen",152, 251, 152}, + {"paleturquoise",175, 238, 238}, + {"palevioletred",219, 112, 147}, + {"papayawhip",255, 239, 213}, + {"peachpuff",255, 218, 185}, + {"peru",205, 133, 63}, + {"pink",255, 192, 203}, + {"plum",221, 160, 221}, + {"powderblue",176, 224, 230}, + {"purple",128, 0, 128}, + {"red",255, 0, 0}, + {"rosybrown",188, 143, 143}, + {"royalblue", 65, 105, 225}, + {"saddlebrown",139, 69, 19}, + {"salmon",250, 128, 114}, + {"sandybrown",244, 164, 96}, + {"seagreen", 46, 139, 87}, + {"seashell",255, 245, 238}, + {"sienna",160, 82, 45}, + {"silver",192, 192, 192}, + {"skyblue",135, 206, 235}, + {"slateblue",106, 90, 205}, + {"slategray",112, 128, 144}, + {"slategrey",112, 128, 144}, + {"snow",255, 250, 250}, + {"springgreen", 0, 255, 127}, + {"steelblue", 70, 130, 180}, + {"tan",210, 180, 140}, + {"teal", 0, 128, 128}, + {"lawngreen",124, 252, 0}, + {"lemonchiffon",255, 250, 205}, + {"lightblue",173, 216, 230}, + {"lightcoral",240, 128, 128}, + {"lightcyan",224, 255, 255}, + {"lightgoldenrodyellow",250, 250, 210}, + {"lightgray",211, 211, 211}, + {"lightgreen",144, 238, 144}, + {"lightgrey",211, 211, 211}, + {"thistle",216, 191, 216}, + {"tomato",255, 99, 71}, + {"turquoise", 64, 224, 208}, + {"violet",238, 130, 238}, + {"wheat",245, 222, 179}, + {"white",255, 255, 255}, + {"whitesmoke",245, 245, 245}, + {"yellow",255, 255, 0}, + {"yellowgreen",154, 205, 50}, + {"aqua", 0, 255, 255}, + +}; + + +GF_Color gf_color_parse(const char *name) +{ + u32 i, count; + u32 res; + if ((name[0]=='$') || (name[0]=='#')) { + sscanf(name+1, "%x", &res); + return res | 0xFF000000; + } + if (!strnicmp(name, "0x", 2) ) { + sscanf(name+2, "%x", &res); + return res | 0xFF000000; + } + + count = sizeof(predefined_colors) / sizeof(struct predef_col); + for (i=0; ifileName = gf_strdup(fileName); tmp->sections = gf_list_new(); - file = gf_f64_open(fileName, "rt"); + file = gf_fopen(fileName, "rt"); if (!file) return GF_IO_ERR; /* load the file */ @@ -122,14 +121,16 @@ GF_Err gf_cfg_parse_config_file(GF_Config * tmp, const char * filePath, const ch memset(line, 0, sizeof(char)*line_alloc); while (!feof(file)) { - u32 read; + u32 read, nb_pass; ret = fgets(line, line_alloc, file); read = (u32) strlen(line); - while (read + 1 == line_alloc) { + nb_pass = 1; + while (read + nb_pass == line_alloc) { line_alloc += MAX_INI_LINE; line = gf_realloc(line, sizeof(char)*line_alloc); ret = fgets(line+read, MAX_INI_LINE, file); read = (u32) strlen(line); + nb_pass++; } if (!ret) continue; @@ -158,7 +159,7 @@ GF_Err gf_cfg_parse_config_file(GF_Config * tmp, const char * filePath, const ch gf_list_del(tmp->sections); gf_free(tmp->fileName); gf_free(tmp); - fclose(file); + gf_fclose(file); gf_free(line); return GF_IO_ERR; } @@ -184,7 +185,7 @@ GF_Err gf_cfg_parse_config_file(GF_Config * tmp, const char * filePath, const ch } } gf_free(line); - fclose(file); + gf_fclose(file); return GF_OK; } @@ -235,7 +236,7 @@ GF_Err gf_cfg_save(GF_Config *iniFile) if (iniFile->skip_changes) return GF_OK; if (!iniFile->fileName) return GF_OK; - file = gf_f64_open(iniFile->fileName, "wt"); + file = gf_fopen(iniFile->fileName, "wt"); if (!file) return GF_IO_ERR; i=0; @@ -251,7 +252,7 @@ GF_Err gf_cfg_save(GF_Config *iniFile) /* end of section */ fprintf(file, "\n"); } - fclose(file); + gf_fclose(file); return GF_OK; } @@ -429,6 +430,7 @@ void gf_cfg_del_section(GF_Config *iniFile, const char *secName) if (!strcmp(secName, p->section_name)) { DelSection(p); gf_list_rem(iniFile->sections, i-1); + iniFile->hasChanged = GF_TRUE; return; } } diff --git a/src/utils/downloader.c b/src/utils/downloader.c index 0e9bfc8..b819eef 100644 --- a/src/utils/downloader.c +++ b/src/utils/downloader.c @@ -125,7 +125,7 @@ struct __gf_download_session gf_user_credentials_struct * creds; char cookie[GF_MAX_PATH]; DownloadedCacheEntry cache_entry; - Bool reused_cache_entry; + Bool reused_cache_entry, from_cache_only; //mime type, only used when the session is not cached. char *mime_type; @@ -136,7 +136,8 @@ struct __gf_download_session GF_NetIOStatus status; u32 flags; - u32 total_size, bytes_done, start_time, icy_metaint, icy_count, icy_bytes; + u32 total_size, bytes_done, icy_metaint, icy_count, icy_bytes; + u64 start_time; u32 bytes_per_sec; u64 start_time_utc; Bool connection_close; @@ -146,6 +147,8 @@ struct __gf_download_session /* Range information if needed for the download (cf flag) */ Bool needs_range; u64 range_start, range_end; + + u32 connect_time, ssl_setup_time, reply_time, total_time_since_req, req_hdr_size, rsp_hdr_size; /*0: GET 1: HEAD @@ -176,7 +179,7 @@ struct __gf_download_session Bool chunked; u32 nb_left_in_chunk; - u32 request_time; + u64 request_start_time; /*private extension*/ void *ext; }; @@ -193,7 +196,7 @@ struct __gf_download_manager u32 head_timeout, request_timeout; GF_Config *cfg; GF_List *sessions; - Bool disable_cache; + Bool disable_cache, simulate_no_connection, allow_offline_cache; u32 limit_data_rate; GF_List *skip_proxy_servers; @@ -204,7 +207,6 @@ struct __gf_download_manager #ifdef GPAC_HAS_SSL SSL_CTX *ssl_ctx; #endif - }; #ifdef GPAC_HAS_SSL @@ -315,7 +317,7 @@ GF_Err gf_user_credentials_save_digest( GF_DownloadManager * dm, gf_user_credent size = gf_base64_encode(pass_buf, (u32) strlen(pass_buf), range_buf, 1024); range_buf[size] = 0; strcpy(creds->digest, range_buf); - creds->valid = 1; + creds->valid = GF_TRUE; return GF_OK; } @@ -374,28 +376,28 @@ gf_user_credentials_struct * gf_user_credentials_register(GF_DownloadManager * d #ifdef GPAC_HAS_SSL -static Bool _ssl_is_initialized = 0; +static Bool _ssl_is_initialized = GF_FALSE; /*! * initialize the SSL library once for all download managers - * \return 0 if everyhing is OK, 1 otherwise + * \return GF_FALSE if everyhing is OK, GF_TRUE otherwise */ static Bool init_ssl_lib() { if (_ssl_is_initialized) - return 0; + return GF_FALSE; GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTPS] Initializing SSL library...\n")); init_prng(); if (RAND_status() != 1) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[HTTPS] Error while initializing Random Number generator, failed to init SSL !\n")); - return 1; + return GF_TRUE; } SSL_library_init(); SSL_load_error_strings(); SSLeay_add_all_algorithms(); SSLeay_add_ssl_algorithms(); - _ssl_is_initialized = 1; + _ssl_is_initialized = GF_TRUE; GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTPS] Initalization of SSL library complete.\n")); - return 0; + return GF_FALSE; } static int ssl_init(GF_DownloadManager *dm, u32 mode) @@ -464,18 +466,18 @@ error: static Bool gf_dm_is_local(GF_DownloadManager *dm, const char *url) { - if (!strnicmp(url, "file://", 7)) return 1; - if (!strstr(url, "://")) return 1; - return 0; + if (!strnicmp(url, "file://", 7)) return GF_TRUE; + if (!strstr(url, "://")) return GF_TRUE; + return GF_FALSE; } static Bool gf_dm_can_handle_url(GF_DownloadManager *dm, const char *url) { - if (!strnicmp(url, "http://", 7)) return 1; + if (!strnicmp(url, "http://", 7)) return GF_TRUE; #ifdef GPAC_HAS_SSL - if (!strnicmp(url, "https://", 8)) return 1; + if (!strnicmp(url, "https://", 8)) return GF_TRUE; #endif - return 0; + return GF_FALSE; } /*! @@ -578,18 +580,33 @@ void gf_dm_configure_cache(GF_DownloadSession *sess) if (sess->flags & GF_NETIO_SESSION_NOT_CACHED) { sess->cache_entry = NULL; } else { + Bool found = GF_FALSE; + u32 i, count; entry = gf_dm_find_cached_entry_by_url(sess); if (!entry) { entry = gf_cache_create_entry(sess->dm, sess->dm->cache_directory, sess->orig_url, sess->range_start, sess->range_end, (sess->flags&GF_NETIO_SESSION_MEMORY_CACHE) ? 1 : 0); gf_mx_p( sess->dm->cache_mx ); gf_list_add(sess->dm->cache_entries, entry); gf_mx_v( sess->dm->cache_mx ); - sess->is_range_continuation = 0; + sess->is_range_continuation = GF_FALSE; } assert( entry ); sess->cache_entry = entry; sess->reused_cache_entry = gf_cache_is_in_progress(entry); - assert(!sess->reused_cache_entry); + count = gf_list_count(sess->dm->sessions); + for (i=0; idm->sessions, i); + assert(a_sess); + if (a_sess==sess) continue; + if (a_sess->cache_entry==entry) { + found = GF_TRUE; + break; + } + } + if (!found) { + sess->reused_cache_entry = GF_FALSE; + gf_cache_close_write_cache(sess->cache_entry, sess, GF_FALSE); + } gf_cache_add_session_to_cache_entry(sess->cache_entry, sess); GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[CACHE] Cache setup to %p %s\n", sess, gf_cache_get_cache_filename(sess->cache_entry))); } @@ -669,11 +686,15 @@ static void gf_dm_clear_headers(GF_DownloadSession *sess) static void gf_dm_disconnect(GF_DownloadSession *sess, Bool force_close) { assert( sess ); - if (sess->connection_close) force_close=1; - sess->connection_close = 0; + if (sess->connection_close) force_close = GF_TRUE; + sess->connection_close = GF_FALSE; - if (sess->status >= GF_NETIO_DISCONNECTED) + if (sess->status >= GF_NETIO_DISCONNECTED) { + if (force_close && sess->use_cache_file && sess->cache_entry) { + gf_cache_close_write_cache(sess->cache_entry, sess, GF_FALSE); + } return; + } GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Downloader] gf_dm_disconnect(%p)\n", sess )); if (sess->mx) gf_mx_p(sess->mx); @@ -692,6 +713,9 @@ static void gf_dm_disconnect(GF_DownloadSession *sess, Bool force_close) gf_sk_del(sx); } } + if (force_close && sess->use_cache_file) { + gf_cache_close_write_cache(sess->cache_entry, sess, GF_FALSE); + } sess->status = GF_NETIO_DISCONNECTED; if (sess->num_retry) sess->num_retry--; if (sess->mx) @@ -706,10 +730,10 @@ void gf_dm_sess_del(GF_DownloadSession *sess) return; /*self-destruction, let the download manager destroy us*/ if (sess->th && sess->in_callback) { - sess->destroy = 1; + sess->destroy = GF_TRUE; return; } - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); gf_dm_clear_headers(sess); /*if threaded wait for thread exit*/ @@ -751,31 +775,31 @@ static void gf_dm_sess_notify_state(GF_DownloadSession *sess, GF_NetIOStatus dnl { if (sess->user_proc) { GF_NETIO_Parameter par; - sess->in_callback = 1; + sess->in_callback = GF_TRUE; memset(&par, 0, sizeof(GF_NETIO_Parameter)); par.msg_type = dnload_status; par.error = error; par.sess = sess; sess->user_proc(sess->usr_cbk, &par); - sess->in_callback = 0; + sess->in_callback = GF_FALSE; } } static void gf_dm_sess_user_io(GF_DownloadSession *sess, GF_NETIO_Parameter *par) { if (sess->user_proc) { - sess->in_callback = 1; + sess->in_callback = GF_TRUE; par->sess = sess; sess->user_proc(sess->usr_cbk, par); - sess->in_callback = 0; + sess->in_callback = GF_FALSE; } } GF_EXPORT Bool gf_dm_is_thread_dead(GF_DownloadSession *sess) { - if (!sess) return 1; - return (sess->flags & GF_DOWNLOAD_SESSION_THREAD_DEAD) ? 1 : 0; + if (!sess) return GF_TRUE; + return (sess->flags & GF_DOWNLOAD_SESSION_THREAD_DEAD) ? GF_TRUE : GF_FALSE; } GF_EXPORT @@ -844,7 +868,7 @@ static s32 gf_dm_parse_protocol(const char * url, GF_URL_Info * info) { GF_EXPORT GF_Err gf_dm_get_url_info(const char * url, GF_URL_Info * info, const char * baseURL) { - char *tmp, *tmp_url, *current_pos, *urlConcatenateWithBaseURL; + char *tmp, *tmp_url, *current_pos, *urlConcatenateWithBaseURL, *ipv6; char * copyOfUrl; s32 proto_offset; gf_dm_url_info_del(info); @@ -875,13 +899,17 @@ GF_Err gf_dm_get_url_info(const char * url, GF_URL_Info * info, const char * bas info->remotePath = gf_url_percent_encode(tmp); gf_free( urlConcatenateWithBaseURL ); urlConcatenateWithBaseURL = NULL; + + if (!info->remotePath) { + GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[PROTOCOL] : cannot find any protocol in url %s\n", url)); + return GF_BAD_PARAM; + } for (i=0; iremotePath); i++) if (info->remotePath[i]=='\\') info->remotePath[i]='/'; info->canonicalRepresentation = gf_malloc(strlen(info->protocol) + strlen(info->remotePath) + 1); strcpy(info->canonicalRepresentation, info->protocol); strcat(info->canonicalRepresentation, info->remotePath); - if (urlConcatenateWithBaseURL) - gf_free(urlConcatenateWithBaseURL); + return GF_OK; } else { /* We continue the parsing as usual */ @@ -923,7 +951,10 @@ GF_Err gf_dm_get_url_info(const char * url, GF_URL_Info * info, const char * bas info->server_name = gf_strdup(tmp_url); } - tmp = strrchr(current_pos, ':'); + //scan for port number after IPv6 adress ']' end char + ipv6 = strrchr(current_pos, ']'); + tmp = strrchr(ipv6 ? ipv6 : current_pos, ':'); + if (tmp) { info->port = atoi(tmp+1); tmp[0] = 0; @@ -953,7 +984,7 @@ GF_Err gf_dm_get_url_info(const char * url, GF_URL_Info * info, const char * bas GF_EXPORT GF_Err gf_dm_sess_setup_from_url(GF_DownloadSession *sess, const char *url) { - Bool socket_changed = 0; + Bool socket_changed = GF_FALSE; GF_URL_Info info; if (!url) return GF_BAD_PARAM; @@ -962,31 +993,40 @@ GF_Err gf_dm_sess_setup_from_url(GF_DownloadSession *sess, const char *url) gf_dm_url_info_init(&info); - if (!sess->sock) socket_changed = 1; + if (!sess->sock) socket_changed = GF_TRUE; else if (sess->status>GF_NETIO_DISCONNECTED) - socket_changed = 1; + socket_changed = GF_TRUE; sess->last_error = gf_dm_get_url_info(url, &info, sess->remote_path); if (sess->last_error) return sess->last_error; if (sess->port != info.port) { - socket_changed = 1; + socket_changed = GF_TRUE; sess->port = info.port; } + if (sess->from_cache_only) { + socket_changed = GF_TRUE; + sess->from_cache_only = GF_FALSE; + if (sess->cache_entry) { + gf_dm_remove_cache_entry_from_session(sess); + sess->cache_entry = NULL; + } + } + if (!strcmp("http://", info.protocol) || !strcmp("https://", info.protocol)) { if (sess->do_requests != http_do_requests) { sess->do_requests = http_do_requests; - socket_changed = 1; + socket_changed = GF_TRUE; } if (!strcmp("https://", info.protocol)) { if (!(sess->flags & GF_DOWNLOAD_SESSION_USE_SSL)) { sess->flags |= GF_DOWNLOAD_SESSION_USE_SSL; - socket_changed = 1; + socket_changed = GF_TRUE; } } else if (sess->flags & GF_DOWNLOAD_SESSION_USE_SSL) { sess->flags &= ~GF_DOWNLOAD_SESSION_USE_SSL; - socket_changed = 1; + socket_changed = GF_TRUE; } } else { sess->do_requests = NULL; @@ -994,7 +1034,7 @@ GF_Err gf_dm_sess_setup_from_url(GF_DownloadSession *sess, const char *url) if (sess->server_name && info.server_name && !strcmp(sess->server_name, info.server_name)) { } else { - socket_changed = 1; + socket_changed = GF_TRUE; if (sess->server_name) gf_free(sess->server_name); sess->server_name = info.server_name ? gf_strdup(info.server_name) : NULL; } @@ -1078,7 +1118,7 @@ GF_DownloadSession *gf_dm_sess_new_simple(GF_DownloadManager * dm, const char *u } sess->headers = gf_list_new(); sess->flags = dl_flags; - if (dm && !dm->head_timeout) sess->server_only_understand_get = 1; + if (dm && !dm->head_timeout) sess->server_only_understand_get = GF_TRUE; sess->user_proc = user_io; sess->usr_cbk = usr_cbk; sess->creds = NULL; @@ -1125,8 +1165,17 @@ static GF_Err gf_dm_read_data(GF_DownloadSession *sess, char *data, u32 data_siz { GF_Err e; + + if (sess->dm && sess->dm->simulate_no_connection) { + if (sess->sock) { + sess->status = GF_NETIO_DISCONNECTED; + } + return GF_IP_NETWORK_FAILURE; + } + if (!sess) return GF_BAD_PARAM; + #ifdef GPAC_HAS_SSL if (sess->ssl) { s32 size = SSL_read(sess->ssl, data, data_size); @@ -1144,23 +1193,12 @@ static GF_Err gf_dm_read_data(GF_DownloadSession *sess, char *data, u32 data_siz #endif -#if 0 - //reset bandwidth computation at start of each chunk - if (sess->chunked && !sess->nb_left_in_chunk) { - sess->start_time = gf_sys_clock(); - sess->start_time_utc = gf_net_get_utc(); - sess->bytes_done = 0; + if (!sess->sock) { + sess->status = GF_NETIO_DISCONNECTED; + return GF_IP_CONNECTION_CLOSED; } -#endif - - if (!sess->sock) - return GF_NETIO_DISCONNECTED; e = gf_sk_receive(sess->sock, data, data_size, 0, out_read); - if (e==GF_IP_NETWORK_EMPTY) { - gf_sleep(1); - } - return e; } @@ -1189,21 +1227,21 @@ static Bool rfc2818_match(const char *pattern, const char *string) if (d == '\0') break; /*matched c character, check following substrings*/ if ((d == c) && rfc2818_match (&pattern[i], &string[k])) - return 1; + return GF_TRUE; else if (d == '.') - return 0; + return GF_FALSE; k++; } - return (c == '\0') ? 1 : 0; + return (c == '\0') ? GF_TRUE : GF_FALSE; } else { if (c != LWR(string[k])) - return 0; + return GF_FALSE; } i++; k++; } - return (string[k]=='\0') ? 1 : 0; + return (string[k]=='\0') ? GF_TRUE : GF_FALSE; } #undef LWR @@ -1214,7 +1252,7 @@ static void gf_dm_connect(GF_DownloadSession *sess) GF_Err e; u16 proxy_port = 0; const char *proxy, *ip; - GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("gf_dm_connect"":%d\n", __LINE__)); + if (!sess->sock) { sess->num_retry = 40; sess->sock = gf_sk_new(GF_SOCK_TYPE_TCP); @@ -1229,11 +1267,11 @@ static void gf_dm_connect(GF_DownloadSession *sess) proxy = gf_cfg_get_key(sess->dm->cfg, "HTTPProxy", "Enabled"); if (proxy && !strcmp(proxy, "yes")) { u32 i; - Bool use_proxy=1; + Bool use_proxy=GF_TRUE; for (i=0; idm->skip_proxy_servers); i++) { char *skip = gf_list_get(sess->dm->skip_proxy_servers, i); if (!strcmp(skip, sess->server_name)) { - use_proxy=0; + use_proxy=GF_FALSE; break; } } @@ -1272,6 +1310,15 @@ static void gf_dm_connect(GF_DownloadSession *sess) GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] Connecting to %s:%d\n", proxy, proxy_port)); if (sess->status == GF_NETIO_SETUP) { + u64 now; + if (sess->dm && sess->dm->simulate_no_connection) { + sess->status = GF_NETIO_STATE_ERROR; + sess->last_error = GF_IP_NETWORK_FAILURE; + gf_dm_sess_notify_state(sess, sess->status, sess->last_error); + return; + } + + now =gf_sys_clock_high_res(); e = gf_sk_connect(sess->sock, (char *) proxy, proxy_port, (char *)ip); /*retry*/ @@ -1283,20 +1330,34 @@ static void gf_dm_connect(GF_DownloadSession *sess) /*failed*/ if (e) { + if (!sess->cache_entry && sess->dm->allow_offline_cache) { + gf_dm_configure_cache(sess); + if (sess->cache_entry && !gf_cache_check_if_cache_file_is_corrupted(sess->cache_entry)) { + sess->from_cache_only = GF_TRUE; + sess->connect_time = (u32) (gf_sys_clock_high_res() - now); + sess->status = GF_NETIO_CONNECTED; + GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[HTTP] Host %s:%d unreachable, using existing cache\n", proxy, proxy_port)); + gf_dm_sess_notify_state(sess, GF_NETIO_CONNECTED, GF_OK); + return; + } + } sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); return; } + sess->connect_time = (u32) (gf_sys_clock_high_res() - now); sess->status = GF_NETIO_CONNECTED; + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] Connected to %s:%d\n", proxy, proxy_port)); gf_dm_sess_notify_state(sess, GF_NETIO_CONNECTED, GF_OK); - gf_sk_set_buffer_size(sess->sock, 1, GF_DOWNLOAD_BUFFER_SIZE); - gf_sk_set_buffer_size(sess->sock, 0, GF_DOWNLOAD_BUFFER_SIZE); + gf_sk_set_buffer_size(sess->sock, GF_TRUE, GF_DOWNLOAD_BUFFER_SIZE); + gf_sk_set_buffer_size(sess->sock, GF_FALSE, GF_DOWNLOAD_BUFFER_SIZE); } #ifdef GPAC_HAS_SSL if (!sess->ssl && (sess->flags & GF_DOWNLOAD_SESSION_USE_SSL)) { + u64 now = gf_sys_clock_high_res(); if (!sess->dm->ssl_ctx) ssl_init(sess->dm, 0); /*socket is connected, configure SSL layer*/ @@ -1305,7 +1366,7 @@ static void gf_dm_connect(GF_DownloadSession *sess) long vresult; char common_name[256]; X509 *cert; - Bool success = 1; + Bool success = GF_TRUE; sess->ssl = SSL_new(sess->dm->ssl_ctx); SSL_set_fd(sess->ssl, gf_sk_get_handle(sess->sock)); @@ -1329,23 +1390,25 @@ static void gf_dm_connect(GF_DownloadSession *sess) common_name[0] = 0; X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, common_name, sizeof (common_name)); if (!rfc2818_match(common_name, sess->server_name)) { - success = 0; + success = GF_FALSE; GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[SSL] Mismatch in certificate names: got %s expected %s\n", common_name, sess->server_name)); } } else { - success = 0; + success = GF_FALSE; GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[SSL] Error verifying certificate %x\n", vresult)); } X509_free(cert); if (!success) { - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); sess->status = GF_NETIO_STATE_ERROR; sess->last_error = GF_AUTHENTICATION_FAILURE; gf_dm_sess_notify_state(sess, sess->status, sess->last_error); } } + + sess->ssl_setup_time = (u32) (gf_sys_clock_high_res() - now); } } #endif @@ -1360,7 +1423,7 @@ DownloadedCacheEntry gf_dm_refresh_cache_entry(GF_DownloadSession *sess) { u32 timer = 0; u32 flags = sess->flags; sess->flags |= GF_NETIO_SESSION_NOT_CACHED; - go = 1; + go = GF_TRUE; while (go) { switch (sess->status) { /*setup download*/ @@ -1380,9 +1443,9 @@ DownloadedCacheEntry gf_dm_refresh_cache_entry(GF_DownloadSession *sess) { /* Since HEAD is not understood by this server, we use a GET instead */ sess->http_read_type = GET; sess->flags |= GF_NETIO_SESSION_NOT_CACHED; - gf_dm_disconnect(sess, 0); + gf_dm_disconnect(sess, GF_FALSE); sess->status = GF_NETIO_SETUP; - sess->server_only_understand_get = 1; + sess->server_only_understand_get = GF_TRUE; GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("gf_dm_refresh_cache_entry() : Timeout with HEAD, try with GET\n")); e = gf_dm_sess_setup_from_url(sess, sess->orig_url); if (e) { @@ -1402,7 +1465,7 @@ DownloadedCacheEntry gf_dm_refresh_cache_entry(GF_DownloadSession *sess) { case GF_NETIO_DATA_EXCHANGE: case GF_NETIO_DISCONNECTED: case GF_NETIO_STATE_ERROR: - go = 0; + go = GF_FALSE; break; default: break; @@ -1450,17 +1513,17 @@ GF_Err gf_dm_sess_set_range(GF_DownloadSession *sess, u64 start_range, u64 end_r if (!discontinue_cache) { gf_cache_set_end_range(sess->cache_entry, end_range); /*remember this in case we get disconnected*/ - sess->is_range_continuation = 1; + sess->is_range_continuation = GF_TRUE; } else { sess->needs_cache_reconfig = 2; - sess->reused_cache_entry = 0; + sess->reused_cache_entry = GF_FALSE; } } else { if (sess->status != GF_NETIO_SETUP) return GF_BAD_PARAM; } sess->range_start = start_range; sess->range_end = end_range; - sess->needs_range = 1; + sess->needs_range = GF_TRUE; return GF_OK; } @@ -1483,7 +1546,7 @@ GF_Err gf_dm_sess_process(GF_DownloadSession *sess) return GF_OK; } /*otherwise do a synchronous download*/ - go = 1; + go = GF_TRUE; while (go) { switch (sess->status) { /*setup download*/ @@ -1500,9 +1563,20 @@ GF_Err gf_dm_sess_process(GF_DownloadSession *sess) break; case GF_NETIO_DISCONNECTED: case GF_NETIO_STATE_ERROR: - go = 0; + go = GF_FALSE; + break; + + case GF_NETIO_GET_METHOD: + case GF_NETIO_GET_HEADER: + case GF_NETIO_GET_CONTENT: + case GF_NETIO_PARSE_HEADER: + case GF_NETIO_PARSE_REPLY: + case GF_NETIO_DATA_TRANSFERED: break; + default: + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[Downloader] Session in unknown state !! - aborting\n")); + go = GF_FALSE; break; } } @@ -1513,7 +1587,7 @@ GF_EXPORT GF_Err gf_dm_sess_process_headers(GF_DownloadSession *sess) { Bool go; - go = 1; + go = GF_TRUE; while (go) { switch (sess->status) { /*setup download*/ @@ -1527,11 +1601,15 @@ GF_Err gf_dm_sess_process_headers(GF_DownloadSession *sess) gf_sleep(1); case GF_NETIO_CONNECTED: sess->do_requests(sess); + + if (sess->reused_cache_entry && sess->cache_entry && gf_cache_are_headers_processed(sess->cache_entry) ) { + sess->status = GF_NETIO_DATA_EXCHANGE; + } break; case GF_NETIO_DATA_EXCHANGE: case GF_NETIO_DISCONNECTED: case GF_NETIO_STATE_ERROR: - go = 0; + go = GF_FALSE; break; default: break; @@ -1543,7 +1621,7 @@ GF_Err gf_dm_sess_process_headers(GF_DownloadSession *sess) static Bool gf_dm_needs_to_delete_cache(GF_DownloadManager * dm) { const char * opt; if (!dm || !dm->cfg) - return 0; + return GF_FALSE; opt = gf_cfg_get_key(dm->cfg, "Downloader", "CleanCache"); return opt && (!strncmp("yes", opt, 3) || !strncmp("true", opt, 4) || !strncmp("1", opt, 1)); } @@ -1587,6 +1665,8 @@ GF_DownloadManager *gf_dm_new(GF_Config *cfg) opt = gf_cfg_get_key(cfg, "General", "CacheDirectory"); else opt = NULL; + +retry_cache: if (!opt) { default_cache_dir = gf_get_default_cache_directory(); opt = default_cache_dir; @@ -1596,19 +1676,47 @@ GF_DownloadManager *gf_dm_new(GF_Config *cfg) sprintf(dm->cache_directory, "%s%c", opt, GF_PATH_SEPARATOR); } else { dm->cache_directory = gf_strdup(opt); + } + //check cache exists + if (!default_cache_dir) { + FILE *test; + char szTemp[GF_MAX_PATH]; + strcpy(szTemp, dm->cache_directory); + strcat(szTemp, "gpaccache.test"); + test = gf_fopen(szTemp, "wb"); + if (!test) { + gf_mkdir(dm->cache_directory); + test = gf_fopen(szTemp, "wb"); + if (!test) { + GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[Cache] Cannot write to %s directory, using system temp cache\n", dm->cache_directory )); + gf_free(dm->cache_directory); + dm->cache_directory = NULL; + opt = NULL; + goto retry_cache; + } + } + if (test) { + gf_fclose(test); + gf_delete_file(szTemp); + } } opt = cfg ? gf_cfg_get_key(cfg, "Downloader", "MaxRate") : NULL; /*use it in in BYTES per second*/ - if (opt) dm->limit_data_rate = 1000 * atoi(opt) / 8; + if (opt) dm->limit_data_rate = 1024 * atoi(opt) / 8; if (cfg) { opt = gf_cfg_get_key(cfg, "Downloader", "DisableCache"); if (!opt) gf_cfg_set_key(cfg, "Downloader", "DisableCache", "no"); - if (opt && !strcmp(opt, "yes")) dm->disable_cache = 1; + if (opt && !strcmp(opt, "yes")) dm->disable_cache = GF_TRUE; } + dm->allow_offline_cache = GF_FALSE; + opt = gf_cfg_get_key(cfg, "Downloader", "AllowOfflineCache"); + if (opt && !strcmp(opt, "yes") ) + dm->allow_offline_cache = GF_TRUE; + dm->head_timeout = 5000; if (cfg) { opt = gf_cfg_get_key(cfg, "Downloader", "HTTPHeadTimeout"); @@ -1823,13 +1931,25 @@ static char *gf_dm_get_chunk_data(GF_DownloadSession *sess, char *body_start, u3 return te_header+2; } + +static void dm_sess_update_download_rate(GF_DownloadSession * sess, Bool always_check) +{ + u32 runtime; + if (!always_check && (sess->bytes_done==sess->total_size)) return; + + /*update state*/ + runtime = (u32) (gf_sys_clock_high_res() - sess->start_time) / 1000; + if (!runtime) runtime=1; + sess->bytes_per_sec = (u32) (1000 * (u64) sess->bytes_done / runtime); +} + + static GFINLINE void gf_dm_data_received(GF_DownloadSession *sess, u8 *payload, u32 payload_size, Bool store_in_init, u32 *rewrite_size) { u32 nbBytes, hdr_size, remaining; u8 *data; - Bool flush_chunk = 0; + Bool flush_chunk = GF_FALSE; GF_NETIO_Parameter par; - u32 runtime, rcv; nbBytes = payload_size; hdr_size = 0; @@ -1844,7 +1964,7 @@ static GFINLINE void gf_dm_data_received(GF_DownloadSession *sess, u8 *payload, } else { payload_size -= hdr_size + nbBytes + 2; payload += hdr_size + nbBytes + 2; - flush_chunk = 1; + flush_chunk = GF_TRUE; } /*chunk transfer is done*/ if (!nbBytes) { @@ -1863,8 +1983,9 @@ static GFINLINE void gf_dm_data_received(GF_DownloadSession *sess, u8 *payload, if (nbBytes) { - rcv = nbBytes; sess->bytes_done += nbBytes; + dm_sess_update_download_rate(sess, GF_TRUE); + GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] url %s received %d new bytes\n", gf_cache_get_url(sess->cache_entry), nbBytes )); if (sess->total_size && (sess->bytes_done > sess->total_size)) { GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[HTTP] url %s received more bytes than planned!! Got %d bytes vs %d content length\n", gf_cache_get_url(sess->cache_entry), sess->bytes_done , sess->total_size )); @@ -1885,31 +2006,24 @@ static GFINLINE void gf_dm_data_received(GF_DownloadSession *sess, u8 *payload, gf_dm_sess_user_io(sess, &par); } - /*update state if not done*/ - if (rcv) { - runtime = gf_sys_clock() - sess->start_time; - if (!runtime) { - sess->bytes_per_sec = 0; - } else { - u64 nb_bytes = sess->bytes_done; - sess->bytes_per_sec = (u32) (1000*nb_bytes / runtime); - } - } } if (sess->total_size && (sess->bytes_done == sess->total_size)) { - gf_dm_disconnect(sess, 0); + gf_dm_disconnect(sess, GF_FALSE); par.msg_type = GF_NETIO_DATA_TRANSFERED; par.error = GF_OK; gf_dm_sess_user_io(sess, &par); if (sess->use_cache_file) { - gf_cache_close_write_cache(sess->cache_entry, sess, 1); + gf_cache_close_write_cache(sess->cache_entry, sess, GF_TRUE); GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[CACHE] url %s saved as %s\n", gf_cache_get_url(sess->cache_entry), gf_cache_get_cache_filename(sess->cache_entry))); } - GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] url %s downloaded in %d ms (%d kbps)\n", gf_cache_get_url(sess->cache_entry), gf_sys_clock() - sess->start_time, 8*sess->bytes_per_sec/1024 )); + sess->total_time_since_req = (u32) (gf_sys_clock_high_res() - sess->request_start_time); + + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] url %s downloaded in "LLU" us (%d kbps) (%d us since request - got response in %d us)\n", gf_cache_get_url(sess->cache_entry), + gf_sys_clock_high_res() - sess->start_time, 8*sess->bytes_per_sec/1024, sess->total_time_since_req, sess->reply_time )); } if (rewrite_size && sess->chunked) { @@ -1969,7 +2083,7 @@ GF_Err gf_dm_sess_fetch_data(GF_DownloadSession *sess, char *buffer, u32 buffer_ if (e) return e; size = *read_size; *read_size = 0; - gf_dm_data_received(sess, (u8 *) buffer, size, 0, read_size); + gf_dm_data_received(sess, (u8 *) buffer, size, GF_FALSE, read_size); return GF_OK; } @@ -2009,7 +2123,7 @@ const char *gf_dm_sess_get_cache_name(GF_DownloadSession * sess) GF_EXPORT Bool gf_dm_sess_can_be_cached_on_disk(const GF_DownloadSession *sess) { - if (!sess) return 0; + if (!sess) return GF_FALSE; return gf_cache_get_content_length(sess->cache_entry) != 0; } @@ -2019,11 +2133,11 @@ void gf_dm_sess_abort(GF_DownloadSession * sess) assert(sess); if (sess->mx) { gf_mx_p(sess->mx); - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); sess->status = GF_NETIO_STATE_ERROR; gf_mx_v(sess->mx); } else { - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); } } void *gf_dm_sess_get_private(GF_DownloadSession * sess) @@ -2044,15 +2158,6 @@ static GFINLINE u32 http_skip_space(char *val) return ret; } -static GFINLINE char *http_is_header(char *line, char *header_name) -{ - char *res; - if (strnicmp(line, header_name, strlen(header_name))) return NULL; - res = line + strlen(header_name); - while ((res[0] == ':') || (res[0] == ' ')) res+=1; - return res; -} - /*! * Sends the HTTP headers * \param sess The GF_DownloadSession @@ -2062,6 +2167,7 @@ static GFINLINE char *http_is_header(char *line, char *header_name) static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { GF_Err e; GF_NETIO_Parameter par; + Bool no_cache = GF_FALSE; char range_buf[1024]; char pass_buf[1024]; const char *user_agent; @@ -2077,6 +2183,13 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { gf_dm_configure_cache(sess); sess->needs_cache_reconfig = 0; } + if (sess->from_cache_only) { + sess->request_start_time = gf_sys_clock_high_res(); + sess->req_hdr_size = 0; + sess->status = GF_NETIO_WAIT_FOR_REPLY; + gf_dm_sess_notify_state(sess, GF_NETIO_WAIT_FOR_REPLY, GF_OK); + return GF_OK; + } /*setup authentification*/ strcpy(pass_buf, ""); @@ -2091,7 +2204,7 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { if (!user_agent) user_agent = GF_DOWNLOAD_AGENT_NAME; - par.error = 0; + par.error = GF_OK; par.msg_type = GF_NETIO_GET_METHOD; par.name = NULL; gf_dm_sess_user_io(sess, &par); @@ -2126,7 +2239,7 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { } /*get all headers*/ - has_agent = has_accept = has_connection = has_range = has_language = has_mime = 0; + has_agent = has_accept = has_connection = has_range = has_language = has_mime = GF_FALSE; while (1) { par.msg_type = GF_NETIO_GET_HEADER; par.value = NULL; @@ -2136,12 +2249,12 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { strcat(sHTTP, ": "); strcat(sHTTP, par.value); strcat(sHTTP, "\r\n"); - if (!strcmp(par.name, "Accept")) has_accept = 1; - else if (!strcmp(par.name, "Connection")) has_connection = 1; - else if (!strcmp(par.name, "Range")) has_range = 1; - else if (!strcmp(par.name, "User-Agent")) has_agent = 1; - else if (!strcmp(par.name, "Accept-Language")) has_language = 1; - else if (!strcmp(par.name, "Content-Type")) has_mime = 1; + if (!strcmp(par.name, "Accept")) has_accept = GF_TRUE; + else if (!strcmp(par.name, "Connection")) has_connection = GF_TRUE; + else if (!strcmp(par.name, "Range")) has_range = GF_TRUE; + else if (!strcmp(par.name, "User-Agent")) has_agent = GF_TRUE; + else if (!strcmp(par.name, "Accept-Language")) has_language = GF_TRUE; + else if (!strcmp(par.name, "Content-Type")) has_mime = GF_TRUE; if (!par.msg_type) break; } if (!has_agent) { @@ -2157,8 +2270,9 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { if (!has_range && sess->needs_range) { if (!sess->range_end) sprintf(range_buf, "Range: bytes="LLD"-\r\n", sess->range_start); else sprintf(range_buf, "Range: bytes="LLD"-"LLD"\r\n", sess->range_start, sess->range_end); - /* FIXME : cache should not be used here */ strcat(sHTTP, range_buf); + + no_cache = GF_TRUE; } if (!has_language) { const char *opt; @@ -2185,7 +2299,7 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { par.size = 0; /*check if we have personalization info*/ - send_profile = 0; + send_profile = GF_FALSE; if (sess->dm && sess->dm->cfg) user_profile = gf_cfg_get_key(sess->dm->cfg, "Downloader", "UserProfileID"); else @@ -2200,15 +2314,15 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { else user_profile = NULL; if (user_profile) { - FILE *profile = gf_f64_open(user_profile, "rt"); + FILE *profile = gf_fopen(user_profile, "rt"); if (profile) { - gf_f64_seek(profile, 0, SEEK_END); - par.size = (u32) gf_f64_tell(profile); - fclose(profile); + gf_fseek(profile, 0, SEEK_END); + par.size = (u32) gf_ftell(profile); + gf_fclose(profile); sprintf(range_buf, "Content-Length: %d\r\n", par.size); strcat(sHTTP, range_buf); strcat(sHTTP, "Content-Type: text/xml\r\n"); - send_profile = 1; + send_profile = GF_TRUE; } } } @@ -2229,7 +2343,7 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { strcat(sHTTP, "Icy-Metadata: 1\r\n"); /*cached headers are not appended in POST*/ - if (!sess->disable_cache && (GF_OK < appendHttpCacheHeaders( sess->cache_entry, sHTTP)) ) { + if (!no_cache && !sess->disable_cache && (GF_OK < gf_cache_append_http_headers( sess->cache_entry, sHTTP)) ) { GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("Cache Entry : %p, FAILED to append cache directives.", sess->cache_entry)); } } @@ -2249,7 +2363,7 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { assert( sess->dm->cfg ); user_profile = gf_cfg_get_key(sess->dm->cfg, "Downloader", "UserProfile"); assert (user_profile); - profile = gf_f64_open(user_profile, "rt"); + profile = gf_fopen(user_profile, "rt"); if (profile) { u32 readen = (u32) fread(tmp_buf+len, sizeof(char), par.size, profile); if (readenrequest_start_time = gf_sys_clock_high_res(); + sess->req_hdr_size = len+par.size; + #ifdef GPAC_HAS_SSL if (sess->ssl) { u32 writelen = len+par.size; @@ -2278,16 +2395,19 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] Sending request %s\n\n", tmp_buf)); gf_free(tmp_buf); } else { + u32 len = (u32) strlen(sHTTP); + + sess->request_start_time = gf_sys_clock_high_res(); + sess->req_hdr_size = len; #ifdef GPAC_HAS_SSL if (sess->ssl) { - u32 len = strlen(sHTTP); e = GF_OK; if (len != SSL_write(sess->ssl, sHTTP, len)) e = GF_IP_NETWORK_FAILURE; } else #endif - e = gf_sk_send(sess->sock, sHTTP, (u32) strlen(sHTTP)); + e = gf_sk_send(sess->sock, sHTTP, len); #ifndef GPAC_DISABLE_LOG if (e) { @@ -2297,7 +2417,6 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { } #endif } - sess->request_time = gf_sys_clock(); if (e) { sess->status = GF_NETIO_STATE_ERROR; @@ -2312,46 +2431,71 @@ static GF_Err http_send_headers(GF_DownloadSession *sess, char * sHTTP) { } + +static Bool dm_exceeds_cap_rate(GF_DownloadSession * sess) +{ + u32 cumul_rate = 0; + u32 i, count = gf_list_count(sess->dm->sessions); + + dm_sess_update_download_rate(sess, GF_FALSE); + //we already exceed the max rate + if (sess->bytes_per_sec>sess->dm->limit_data_rate) return GF_TRUE; + + //check if this fits with all other sessions + for (i=0; idm->sessions, i); + if (sess == a_sess) continue; + //session done + if (a_sess->total_size==a_sess->bytes_done) { + continue; + } + dm_sess_update_download_rate(a_sess, 0); + cumul_rate += a_sess->bytes_per_sec; + } + if (sess->bytes_per_sec + cumul_rate >= sess->dm->limit_data_rate) return GF_TRUE; + return GF_FALSE; +} + /*! * Parse the remaining part of body * \param sess The session * \param sHTTP the data buffer * \return The error code if any */ -static GF_Err http_parse_remaining_body(GF_DownloadSession * sess, char * sHTTP) { +static GF_Err http_parse_remaining_body(GF_DownloadSession * sess, char * sHTTP) +{ u32 size; GF_Err e; + u32 buf_size = GF_DOWNLOAD_BUFFER_SIZE; + if (sess->dm && sess->dm->limit_data_rate) + buf_size = 1024; + while (1) { if (sess->status>=GF_NETIO_DISCONNECTED) return GF_REMOTE_SERVICE_ERROR; if (sess->dm && sess->dm->limit_data_rate && sess->bytes_per_sec) { - if (sess->bytes_per_sec > sess->dm->limit_data_rate) { - /*update state*/ - u32 runtime = gf_sys_clock() - sess->start_time; - u64 nb_bytes = sess->bytes_done; - sess->bytes_per_sec = (u32) (1000*nb_bytes / runtime); - if (sess->bytes_per_sec > sess->dm->limit_data_rate) return GF_OK; - } + if (dm_exceeds_cap_rate(sess)) + return GF_OK; } - e = gf_dm_read_data(sess, sHTTP, GF_DOWNLOAD_BUFFER_SIZE, &size); + e = gf_dm_read_data(sess, sHTTP, buf_size, &size); if (e!= GF_IP_CONNECTION_CLOSED && (!size || e == GF_IP_NETWORK_EMPTY)) { - if (e == GF_IP_CONNECTION_CLOSED || (!sess->total_size && !sess->chunked && (gf_sys_clock() - sess->start_time > 5000))) { + if (e == GF_IP_CONNECTION_CLOSED || (!sess->total_size && !sess->chunked && (gf_sys_clock_high_res() - sess->start_time > 5000000))) { sess->total_size = sess->bytes_done; gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); assert(sess->server_name); GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[HTTP] Disconnected from %s: %s\n", sess->server_name, gf_error_to_string(e))); - gf_dm_disconnect(sess, (e == GF_IP_CONNECTION_CLOSED) ? 1 : 0); + gf_dm_disconnect(sess, (e == GF_IP_CONNECTION_CLOSED) ? GF_TRUE : GF_FALSE); } return GF_OK; } if (e) { - if (e == GF_IP_CONNECTION_CLOSED) { + if (sess->sock && (e == GF_IP_CONNECTION_CLOSED)) { u32 len = gf_cache_get_content_length(sess->cache_entry); if (size > 0) - gf_dm_data_received(sess, (u8 *) sHTTP, size, 0, NULL); + gf_dm_data_received(sess, (u8 *) sHTTP, size, GF_FALSE, NULL); if ( ( (len == 0) && sess->use_cache_file) /*ivica patch*/ || (size==0) @@ -2366,12 +2510,12 @@ static GF_Err http_parse_remaining_body(GF_DownloadSession * sess, char * sHTTP) e = GF_OK; } } - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); return e; } - gf_dm_data_received(sess, (u8 *) sHTTP, size, 0, NULL); + gf_dm_data_received(sess, (u8 *) sHTTP, size, GF_FALSE, NULL); /*socket empty*/ if (size < GF_DOWNLOAD_BUFFER_SIZE) { @@ -2394,10 +2538,19 @@ static void notify_headers(GF_DownloadSession *sess, char * sHTTP, s32 bytesRead par.name = hdrp->name; par.value = hdrp->value; - par.error = 0; + par.error = GF_OK; par.msg_type = GF_NETIO_PARSE_HEADER; gf_dm_sess_user_io(sess, &par); } + + if (sHTTP) { + sHTTP[bytesRead]=0; + par.error = GF_OK; + par.data = sHTTP + BodyStart; + par.size = (u32) strlen(par.data); + par.msg_type = GF_NETIO_DATA_EXCHANGE; + gf_dm_sess_user_io(sess, &par); + } } /*! @@ -2409,31 +2562,50 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) { GF_NETIO_Parameter par; s32 bytesRead, BodyStart; - u32 res, i; + u32 res, i, buf_size; s32 LinePos, Pos; u32 rsp_code, ContentLength, first_byte, last_byte, total_size, range, no_range; - Bool connection_closed = 0; + Bool connection_closed = GF_FALSE; char buf[1025]; char comp[400]; GF_Err e; char * new_location; + const char * mime_type; assert( sess->status == GF_NETIO_WAIT_FOR_REPLY ); bytesRead = res = 0; new_location = NULL; if (!(sess->flags & GF_NETIO_SESSION_NOT_CACHED)) { - sess->use_cache_file = 1; + sess->use_cache_file = GF_TRUE; + } + + if (sess->from_cache_only) { + GF_NETIO_Parameter par; + sess->reply_time = (u32) (gf_sys_clock_high_res() - sess->request_start_time); + sess->rsp_hdr_size = 0; + sess->total_size = sess->bytes_done = gf_cache_get_content_length(sess->cache_entry);; + + memset(&par, 0, sizeof(GF_NETIO_Parameter)); + par.msg_type = GF_NETIO_DATA_TRANSFERED; + par.error = GF_OK; + gf_dm_sess_user_io(sess, &par); + gf_dm_disconnect(sess, GF_FALSE); + return GF_OK; } + buf_size = GF_DOWNLOAD_BUFFER_SIZE; + if (sess->dm && sess->dm->limit_data_rate) + buf_size = 1024; + //always set start time to the time at last attempt reply parsing - sess->start_time = gf_sys_clock(); + sess->start_time = gf_sys_clock_high_res(); sess->start_time_utc = gf_net_get_utc(); while (1) { - e = gf_dm_read_data(sess, sHTTP + bytesRead, GF_DOWNLOAD_BUFFER_SIZE - bytesRead, &res); + e = gf_dm_read_data(sess, sHTTP + bytesRead, buf_size - bytesRead, &res); switch (e) { case GF_IP_NETWORK_EMPTY: if (!bytesRead) { - if (gf_sys_clock() - sess->request_time > sess->dm->request_timeout) { + if (gf_sys_clock_high_res() - sess->request_start_time > 1000 * sess->dm->request_timeout) { sess->last_error = GF_IP_NETWORK_EMPTY; sess->status = GF_NETIO_STATE_ERROR; return GF_IP_NETWORK_EMPTY; @@ -2445,10 +2617,10 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) case GF_IP_CONNECTION_CLOSED: if (sess->http_read_type == HEAD) { /* Some servers such as shoutcast directly close connection if HEAD or an unknown method is issued */ - sess->server_only_understand_get = 1; + sess->server_only_understand_get = GF_TRUE; } GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] Connection closed by server when getting %s - retrying\n", sess->remote_path)); - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); if (sess->num_retry) sess->status = GF_NETIO_SETUP; @@ -2488,11 +2660,14 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) sHTTP[BodyStart-1] = 0; GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] %s\n\n", sHTTP)); + sess->reply_time = (u32) (gf_sys_clock_high_res() - sess->request_start_time); + sess->rsp_hdr_size = BodyStart; + LinePos = gf_token_get_line(sHTTP, 0, bytesRead, buf, 1024); Pos = gf_token_get(buf, 0, " \t\r\n", comp, 400); if (!strncmp("ICY", comp, 3)) { - sess->use_cache_file = 0; + sess->use_cache_file = GF_FALSE; /*be prepared not to receive any mime type from ShoutCast servers*/ if (!gf_cache_get_mime_type(sess->cache_entry)) gf_cache_set_mime_type(sess->cache_entry, "audio/mpeg"); @@ -2551,29 +2726,29 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) } else if (!stricmp(hdrp->name, "Content-Type")) { - char * mime_type = gf_strdup(hdrp->value); + char *mime = gf_strdup(hdrp->value); while (1) { - u32 len = (u32) strlen(mime_type); - char c = len ? mime_type[len-1] : 0; + u32 len = (u32) strlen(mime); + char c = len ? mime[len-1] : 0; if ((c=='\r') || (c=='\n')) { - mime_type[len-1] = 0; + mime[len-1] = 0; } else { break; } } - val = strchr(mime_type, ';'); + val = strchr(mime, ';'); if (val) val[0] = 0; - strlwr(mime_type); + strlwr(mime); if (rsp_code<300) { if (sess->cache_entry) { - gf_cache_set_mime_type(sess->cache_entry, mime_type); + gf_cache_set_mime_type(sess->cache_entry, mime); } else { - sess->mime_type = mime_type; - mime_type = NULL; + sess->mime_type = mime; + mime = NULL; } } - if (mime_type) gf_free(mime_type); + if (mime) gf_free(mime); } else if (!stricmp(hdrp->name, "Content-Range")) { range = 1; @@ -2597,7 +2772,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) /* For HTTP icy servers, we disable cache */ if (sess->icy_metaint == 0) sess->icy_metaint = -1; - sess->use_cache_file = 0; + sess->use_cache_file = GF_FALSE; if (!stricmp(hdrp->name, "icy-metaint")) { sess->icy_metaint = atoi(hdrp->value); } @@ -2622,13 +2797,15 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) } else if (!stricmp(hdrp->name, "Connection") ) { if (strstr(hdrp->value, "close")) - connection_closed = 1; + connection_closed = GF_TRUE; } if (sess->status==GF_NETIO_DISCONNECTED) return GF_OK; } if (no_range) first_byte = 0; + gf_cache_set_headers_processed(sess->cache_entry); + par.msg_type = GF_NETIO_PARSE_REPLY; par.error = GF_OK; par.reply = rsp_code; @@ -2637,18 +2814,18 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) * If response is correct, it means our credentials are correct */ if (sess->creds && rsp_code != 304) - sess->creds->valid = 1; + sess->creds->valid = GF_TRUE; /*try to flush body */ if (rsp_code>=300) { u32 start = gf_sys_clock(); while (BodyStart + ContentLength > (u32) bytesRead) { - e = gf_dm_read_data(sess, sHTTP + bytesRead, GF_DOWNLOAD_BUFFER_SIZE - bytesRead, &res); + e = gf_dm_read_data(sess, sHTTP + bytesRead, buf_size - bytesRead, &res); switch (e) { case GF_IP_NETWORK_EMPTY: - gf_sleep(1); - continue; + gf_sleep(0); + break; case GF_OK: bytesRead += res; break; @@ -2667,7 +2844,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) if (BodyStart + ContentLength > (u32) bytesRead) { ContentLength = 0; //cannot flush, discard socket - sess->connection_close = 1; + sess->connection_close = GF_TRUE; } } //remember if we can keep the session alive after the transfer is done @@ -2713,6 +2890,9 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) case 304: { sess->status = GF_NETIO_PARSE_REPLY; + assert(sess->cache_entry); + sess->total_size = gf_cache_get_cache_filesize(sess->cache_entry); + gf_dm_sess_notify_state(sess, GF_NETIO_PARSE_REPLY, GF_OK); gf_dm_disconnect(sess, 0); if (sess->user_proc) { @@ -2721,7 +2901,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) FILE * f; filename = gf_cache_get_cache_filename(sess->cache_entry); GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] Sending data to modules from %s...\n", filename)); - f = gf_f64_open(filename, "rb"); + f = gf_fopen(filename, "rb"); assert(filename); if (!f) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] FAILED to open cache file %s for reading contents !\n", filename)); @@ -2738,7 +2918,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) return e; } - par.error = 0; + par.error = GF_OK; par.msg_type = GF_NETIO_PARSE_HEADER; par.name = "Content-Type"; par.value = (char *) gf_cache_get_mime_type(sess->cache_entry); @@ -2764,7 +2944,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) } } while ( read > 0); } - fclose(f); + gf_fclose(f); GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] all data has been sent to modules from %s.\n", filename)); } /* Cache file is the most recent */ @@ -2829,7 +3009,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) sess->flags |= GF_NETIO_SESSION_NOT_CACHED; gf_dm_disconnect(sess, 0); sess->status = GF_NETIO_SETUP; - sess->server_only_understand_get = 1; + sess->server_only_understand_get = GF_TRUE; GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("Method not supported, try with GET.\n")); e = gf_dm_sess_setup_from_url(sess, sess->orig_url); if (e) { @@ -2849,7 +3029,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) /*retry without proxy*/ if (sess->proxy_enabled==1) { sess->proxy_enabled=2; - gf_dm_disconnect(sess, 1); + gf_dm_disconnect(sess, GF_TRUE); sess->status = GF_NETIO_SETUP; return GF_OK; } @@ -2860,68 +3040,71 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) goto exit; } - notify_headers(sess, sHTTP, bytesRead, BodyStart); + notify_headers(sess, NULL, bytesRead, BodyStart); if (sess->http_read_type != GET) - sess->use_cache_file = 0; + sess->use_cache_file = GF_FALSE; if (sess->http_read_type==HEAD) { - gf_dm_disconnect(sess, 0); + gf_dm_disconnect(sess, GF_FALSE); gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); - sess->http_read_type = 0; + sess->http_read_type = GET; return GF_OK; + + + } + + + mime_type = gf_cache_get_mime_type(sess->cache_entry); + if (!ContentLength && mime_type && ((strstr(mime_type, "ogg") || (!strcmp(mime_type, "audio/mpeg"))))) { + if (0 == sess->icy_metaint) + sess->icy_metaint = -1; + sess->use_cache_file = GF_FALSE; } - { - const char * mime_type = gf_cache_get_mime_type(sess->cache_entry); - if (!ContentLength && mime_type && ((strstr(mime_type, "ogg") || (!strcmp(mime_type, "audio/mpeg"))))) { - if (0 == sess->icy_metaint) - sess->icy_metaint = -1; - sess->use_cache_file = 0; - } #ifndef GPAC_DISABLE_LOGS - if (e) { - GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[HTTP] Error connecting to %s: %s\n", sess->server_name, gf_error_to_string(e) ) ); - } else { - GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] Connected to %s\n", sess->server_name ) ); - } + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[HTTP] Error processing rely from %s: %s\n", sess->server_name, gf_error_to_string(e) ) ); + } else { + GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] Reply processed from %s\n", sess->server_name ) ); + } #endif - /*some servers may reply without content length, but we MUST have it*/ - if (e) goto exit; - if (sess->icy_metaint != 0) { - assert( ! sess->use_cache_file ); - GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] ICY protocol detected\n")); - if (mime_type && !stricmp(mime_type, "video/nsv")) { - gf_cache_set_mime_type(sess->cache_entry, "audio/aac"); - } - sess->icy_bytes = 0; + /*some servers may reply without content length, but we MUST have it*/ + if (e) goto exit; + if (sess->icy_metaint != 0) { + assert( ! sess->use_cache_file ); + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP] ICY protocol detected\n")); + if (mime_type && !stricmp(mime_type, "video/nsv")) { + gf_cache_set_mime_type(sess->cache_entry, "audio/aac"); + } + sess->icy_bytes = 0; + sess->total_size = SIZE_IN_STREAM; + sess->status = GF_NETIO_DATA_EXCHANGE; + } else if (!ContentLength && !sess->chunked) { + if (sess->http_read_type == GET) { sess->total_size = SIZE_IN_STREAM; + sess->use_cache_file = GF_FALSE; sess->status = GF_NETIO_DATA_EXCHANGE; - } else if (!ContentLength && !sess->chunked) { - if (sess->http_read_type == GET) { - sess->total_size = SIZE_IN_STREAM; - sess->use_cache_file = 0; - sess->status = GF_NETIO_DATA_EXCHANGE; - sess->bytes_done = 0; - } else { - gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); - gf_dm_disconnect(sess, 0); - return GF_OK; - } + sess->bytes_done = 0; } else { - sess->total_size = ContentLength; - if (sess->use_cache_file && sess->http_read_type == GET ) { - e = gf_cache_open_write_cache(sess->cache_entry, sess); - if (e) { - GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ( "[CACHE] Failed to open cache, error=%d\n", e)); - goto exit; - } + gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); + gf_dm_disconnect(sess, GF_FALSE); + return GF_OK; + } + } else { + sess->total_size = ContentLength; + if (sess->use_cache_file && sess->http_read_type == GET ) { + e = gf_cache_open_write_cache(sess->cache_entry, sess); + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ( "[CACHE] Failed to open cache, error=%d\n", e)); + goto exit; } - sess->status = GF_NETIO_DATA_EXCHANGE; - sess->bytes_done = 0; } + sess->status = GF_NETIO_DATA_EXCHANGE; + sess->bytes_done = 0; } + /* we may have existing data in this buffer ... */ if (!e && (BodyStart < (s32) bytesRead)) { @@ -2929,7 +3112,7 @@ static GF_Err wait_for_header_and_parse(GF_DownloadSession *sess, char * sHTTP) sess->init_data_size = 0; sess->init_data = NULL; - gf_dm_data_received(sess, (u8 *) sHTTP + BodyStart, bytesRead - BodyStart, 1, NULL); + gf_dm_data_received(sess, (u8 *) sHTTP + BodyStart, bytesRead - BodyStart, GF_TRUE, NULL); } exit: if (e) { @@ -2937,7 +3120,7 @@ exit: gf_cache_entry_set_delete_files_when_deleted(sess->cache_entry); gf_dm_remove_cache_entry_from_session(sess); sess->cache_entry = NULL; - gf_dm_disconnect(sess, 0); + gf_dm_disconnect(sess, GF_FALSE); sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); @@ -2956,9 +3139,15 @@ void http_do_requests(GF_DownloadSession *sess) char sHTTP[GF_DOWNLOAD_BUFFER_SIZE+1]; if (sess->reused_cache_entry) { + //main session is done downloading, notify - to do we should send progress events on this session also ... if (!gf_cache_is_in_progress(sess->cache_entry)) { - gf_dm_disconnect(sess, 0); - sess->reused_cache_entry = 0; + GF_NETIO_Parameter par; + gf_dm_disconnect(sess, GF_FALSE); + sess->reused_cache_entry = GF_FALSE; + memset(&par, 0, sizeof(GF_NETIO_Parameter)); + par.msg_type = GF_NETIO_DATA_TRANSFERED; + par.error = GF_OK; + gf_dm_sess_user_io(sess, &par); } return; } @@ -2984,7 +3173,7 @@ void http_do_requests(GF_DownloadSession *sess) par.size = sess->init_data_size; gf_dm_sess_user_io(sess, &par); } - sess->reassigned = 0; + sess->reassigned = GF_FALSE; } http_parse_remaining_body(sess, sHTTP); break; @@ -3012,27 +3201,26 @@ static void wget_NetIO(void *cbk, GF_NETIO_Parameter *param) GF_EXPORT -GF_Err gf_dm_wget(const char *url, const char *filename, u64 start_range, u64 end_range) +GF_Err gf_dm_wget(const char *url, const char *filename, u64 start_range, u64 end_range, char **redirected_url) { GF_Err e; GF_DownloadManager * dm = NULL; dm = gf_dm_new(NULL); if (!dm) return GF_OUT_OF_MEM; - e = gf_dm_wget_with_cache(dm, url, filename, start_range, end_range); + e = gf_dm_wget_with_cache(dm, url, filename, start_range, end_range, redirected_url); gf_dm_del(dm); return e; } -GF_Err gf_dm_wget_with_cache(GF_DownloadManager * dm, - const char *url, const char *filename, u64 start_range, u64 end_range) +GF_Err gf_dm_wget_with_cache(GF_DownloadManager * dm, const char *url, const char *filename, u64 start_range, u64 end_range, char **redirected_url) { GF_Err e; FILE * f; GF_DownloadSession *dnload; if (!filename || !url || !dm) return GF_BAD_PARAM; - f= fopen(filename, "w"); + f = gf_fopen(filename, "wb"); if (!f) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[WGET] Failed to open file %s for write.\n", filename)); return GF_IO_ERR; @@ -3041,18 +3229,22 @@ GF_Err gf_dm_wget_with_cache(GF_DownloadManager * dm, if (!dnload) { return GF_BAD_PARAM; } - dnload->use_cache_file = 1; - dnload->force_data_write_callback = 1; + dnload->use_cache_file = GF_FALSE; + dnload->force_data_write_callback = GF_TRUE; if (end_range) { dnload->range_start = start_range; dnload->range_end = end_range; - dnload->needs_range = 1; + dnload->needs_range = GF_TRUE; } if (e == GF_OK) { e = gf_dm_sess_process(dnload); } e |= gf_cache_close_write_cache(dnload->cache_entry, dnload, e == GF_OK); - fclose(f); + gf_fclose(f); + + if (redirected_url) { + if (dnload->orig_url_before_redirect) *redirected_url = gf_strdup(dnload->orig_url); + } gf_dm_sess_del(dnload); return e; } @@ -3075,7 +3267,7 @@ GF_Err gf_dm_get_file_memory(const char *url, char **out_data, u32 *out_size, ch dm = gf_dm_new(NULL); if (!dm) { - fclose(f); + gf_fclose(f); return GF_OUT_OF_MEM; } @@ -3084,8 +3276,8 @@ GF_Err gf_dm_get_file_memory(const char *url, char **out_data, u32 *out_size, ch gf_dm_del(dm); return GF_BAD_PARAM; } - dnload->use_cache_file = 0; - dnload->disable_cache = 1; + dnload->use_cache_file = GF_FALSE; + dnload->disable_cache = GF_TRUE; if (!e) e = gf_dm_sess_process(dnload); @@ -3093,7 +3285,7 @@ GF_Err gf_dm_get_file_memory(const char *url, char **out_data, u32 *out_size, ch e = gf_cache_close_write_cache(dnload->cache_entry, dnload, e == GF_OK); if (!e) { - u32 size = ftell(f), read; + u32 size = (u32) ftell(f), read; *out_size = size; *out_data = gf_malloc(sizeof(char)* ( 1 + size)); fseek(f, 0, SEEK_SET); @@ -3109,7 +3301,7 @@ GF_Err gf_dm_get_file_memory(const char *url, char **out_data, u32 *out_size, ch } } } - fclose(f); + gf_fclose(f); gf_dm_sess_del(dnload); gf_dm_del(dm); return e; @@ -3136,7 +3328,7 @@ GF_Err gf_dm_sess_reset(GF_DownloadSession *sess) { if (!sess) return GF_BAD_PARAM; sess->status = GF_NETIO_SETUP; - sess->needs_range = 0; + sess->needs_range = GF_FALSE; sess->range_start = sess->range_end = 0; sess->bytes_done = sess->bytes_per_sec = 0; if (sess->init_data) gf_free(sess->init_data); @@ -3177,28 +3369,28 @@ const char * gf_cache_get_cache_filename_range( const GF_DownloadSession * sess, if (newFilename == NULL) return NULL; snprintf(newFilename, maxLen, "%s " LLU LLU, orig, startOffset, endOffset); - fw = gf_f64_open(newFilename, "wb"); + fw = gf_fopen(newFilename, "wb"); if (!fw) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Cannot open partial cache file %s for write\n", newFilename)); gf_free( newFilename ); return NULL; } - fr = gf_f64_open(orig, "rb"); + fr = gf_fopen(orig, "rb"); if (!fr) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Cannot open full cache file %s\n", orig)); gf_free( newFilename ); - fclose( fw ); + gf_fclose( fw ); } /* Now, we copy ! */ { char copyBuff[GF_DOWNLOAD_BUFFER_SIZE+1]; s64 read, write, total; total = endOffset - startOffset; - read = gf_f64_seek(fr, startOffset, SEEK_SET); + read = gf_fseek(fr, startOffset, SEEK_SET); if (read != startOffset) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[CACHE] Cannot seek at right start offset in %s\n", orig)); - fclose( fr ); - fclose( fw ); + gf_fclose( fr ); + gf_fclose( fw ); gf_free( newFilename ); return NULL; } @@ -3209,22 +3401,22 @@ const char * gf_cache_get_cache_filename_range( const GF_DownloadSession * sess, write = gf_fwrite(copyBuff, sizeof(char), (size_t) read, fw); if (write != read) { /* Something bad happened */ - fclose( fw ); - fclose (fr ); + gf_fclose( fw ); + gf_fclose (fr ); gf_free( newFilename ); return NULL; } } else { if (read < 0) { - fclose( fw ); - fclose( fr ); + gf_fclose( fw ); + gf_fclose( fr ); gf_free( newFilename ); return NULL; } } } while (total > 0); - fclose( fr ); - fclose (fw); + gf_fclose( fr ); + gf_fclose (fw); partial = gf_malloc( sizeof(GF_PartialDownload)); if (partial == NULL) { gf_free(newFilename); @@ -3253,9 +3445,9 @@ GF_Err gf_dm_sess_reassign(GF_DownloadSession *sess, u32 flags, gf_dm_user_io us if (sess->cache_entry) { FILE *fptr = gf_cache_get_file_pointer(sess->cache_entry); if (fptr) { - gf_f64_seek(fptr, 0, SEEK_END); - sess->init_data_size = (u32) gf_f64_tell(fptr); - gf_f64_seek(fptr, 0, SEEK_SET); + gf_fseek(fptr, 0, SEEK_END); + sess->init_data_size = (u32) gf_ftell(fptr); + gf_fseek(fptr, 0, SEEK_SET); if (sess->init_data) gf_free(sess->init_data); sess->init_data = gf_malloc(sess->init_data_size); sess->init_data_size = fread(sess->init_data, 1, sess->init_data_size, fptr); @@ -3301,7 +3493,7 @@ GF_Err gf_dm_sess_reassign(GF_DownloadSession *sess, u32 flags, gf_dm_user_io us sess->flags = flags; sess->user_proc = user_io; sess->usr_cbk = cbk; - sess->reassigned = sess->init_data ? 1 : 0; + sess->reassigned = sess->init_data ? GF_TRUE : GF_FALSE; sess->num_retry = SESSION_RETRY_COUNT; if (sess->status==GF_NETIO_DISCONNECTED) @@ -3314,7 +3506,18 @@ GF_Err gf_dm_sess_reassign(GF_DownloadSession *sess, u32 flags, gf_dm_user_io us GF_EXPORT void gf_dm_set_data_rate(GF_DownloadManager *dm, u32 rate_in_bits_per_sec) { - dm->limit_data_rate = rate_in_bits_per_sec/8; + if (rate_in_bits_per_sec == 0xFFFFFFFF) { + dm->simulate_no_connection=GF_TRUE; + } else { + dm->simulate_no_connection=GF_FALSE; + dm->limit_data_rate = rate_in_bits_per_sec/8; + + if (dm->cfg) { + char opt[100]; + sprintf(opt, "%d", rate_in_bits_per_sec / 1024); + gf_cfg_set_key(dm->cfg, "Downloader", "MaxRate", opt); + } + } } GF_EXPORT @@ -3323,6 +3526,28 @@ u32 gf_dm_get_data_rate(GF_DownloadManager *dm) return dm->limit_data_rate*8; } +GF_EXPORT +u32 gf_dm_get_global_rate(GF_DownloadManager *dm) +{ + u32 ret = 0; + u32 i, count; + if (!dm) return 0; + gf_mx_p(dm->cache_mx); + count = gf_list_count(dm->sessions); + + for (i=0; isessions, i); + if (sess->total_size==sess->bytes_done) { + if (gf_sys_clock_high_res() - sess->start_time>2000000) { + continue; + } + } + dm_sess_update_download_rate(sess, 0); + ret += sess->bytes_per_sec; + } + gf_mx_v(dm->cache_mx); + return 8*ret; +} GF_EXPORT const char *gf_dm_sess_get_header(GF_DownloadSession *sess, const char *name) @@ -3337,4 +3562,18 @@ const char *gf_dm_sess_get_header(GF_DownloadSession *sess, const char *name) return NULL; } +GF_EXPORT +GF_Err gf_dm_sess_get_header_sizes_and_times(GF_DownloadSession *sess, u32 *req_hdr_size, u32 *rsp_hdr_size, u32 *connect_time, u32 *reply_time, u32 *download_time) +{ + if (!sess) return GF_BAD_PARAM; + + if (req_hdr_size) *req_hdr_size = sess->req_hdr_size; + if (rsp_hdr_size) *rsp_hdr_size = sess->rsp_hdr_size; + if (connect_time) *connect_time = sess->connect_time; + if (reply_time) *reply_time = sess->reply_time; + if (download_time) *download_time = sess->total_time_since_req; + return GF_OK; +} + + #endif diff --git a/src/utils/error.c b/src/utils/error.c index e28c224..eed69a7 100644 --- a/src/utils/error.c +++ b/src/utils/error.c @@ -412,6 +412,7 @@ gf_log_cbk gf_log_set_callback(void *usr_cbk, gf_log_cbk cbk) } #endif +static char szErrMsg[20]; GF_EXPORT const char *gf_error_to_string(GF_Err e) @@ -512,7 +513,8 @@ const char *gf_error_to_string(GF_Err e) case GF_WRONG_DATAFORMAT: return "Unexpected data format"; default: - return "Unknown Error"; + sprintf(szErrMsg, "Unknown Error (%d)", e); + return szErrMsg; } } @@ -581,8 +583,8 @@ GF_EXPORT const char *gpac_features() { const char *features = "" -#ifdef GPAC_X64 - "GPAC_X64 " +#ifdef GPAC_64_BITS + "GPAC_64_BITS " #endif #ifdef GPAC_FIXED_POINT @@ -612,8 +614,8 @@ const char *gpac_features() #ifdef GPAC_USE_TINYGL "GPAC_USE_TINYGL " #endif -#ifdef GPAC_USE_OGL_ES - "GPAC_USE_OGL_ES " +#ifdef GPAC_USE_GLES1X + "GPAC_USE_GLES1X " #endif #if defined(_WIN32_WCE) #ifdef GPAC_USE_IGPP @@ -705,3 +707,557 @@ const char *gpac_features() ; return features; } + + +static const struct lang_def { + const char *name; + const char *three_char_code; + const char *two_char_code; +} defined_languages [] = +{ + { "Abkhazian","abk","ab"} , + { "Achinese","ace",""} , + { "Acoli","ach",""} , + { "Adangme","ada",""} , + { "Adyghe; Adygei","ady",""} , + { "Afar","aar","aa"} , + { "Afrihili","afh",""} , + { "Afrikaans","afr","af"} , + { "Afro-Asiatic languages","afa",""} , + { "Ainu","ain",""} , + { "Akan","aka","ak"} , + { "Akkadian","akk",""} , + { "Albanian","sqi","sq"} , + { "Aleut","ale",""} , + { "Algonquian languages","alg",""} , + { "Altaic languages","tut",""} , + { "Amharic","amh","am"} , + { "Angika","anp",""} , + { "Apache languages","apa",""} , + { "Arabic","ara","ar"} , + { "Aragonese","arg","an"} , + { "Arapaho","arp",""} , + { "Arawak","arw",""} , + { "Armenian","hye","hy"} , + { "Aromanian; Arumanian; Macedo-Romanian","rup",""} , + { "Artificial languages","art",""} , + { "Assamese","asm","as"} , + { "Asturian; Bable; Leonese; Asturleonese","ast",""} , + { "Athapascan languages","ath",""} , + { "Australian languages","aus",""} , + { "Austronesian languages","map",""} , + { "Avaric","ava","av"} , + { "Avestan","ave","ae"} , + { "Awadhi","awa",""} , + { "Aymara","aym","ay"} , + { "Azerbaijani","aze","az"} , + { "Balinese","ban",""} , + { "Baltic languages","bat",""} , + { "Baluchi","bal",""} , + { "Bambara","bam","bm"} , + { "Bamileke languages","bai",""} , + { "Banda languages","bad",""} , + { "Bantu languages","bnt",""} , + { "Basa","bas",""} , + { "Bashkir","bak","ba"} , + { "Basque","eus","eu"} , + { "Batak languages","btk",""} , + { "Beja; Bedawiyet","bej",""} , + { "Belarusian","bel","be"} , + { "Bemba","bem",""} , + { "Bengali","ben","bn"} , + { "Berber languages","ber",""} , + { "Bhojpuri","bho",""} , + { "Bihari languages","bih","bh"} , + { "Bikol","bik",""} , + { "Bini; Edo","bin",""} , + { "Bislama","bis","bi"} , + { "Blin; Bilin","byn",""} , + { "Blissymbols; Blissymbolics; Bliss","zbl",""} , + { "Bokmal, Norwegian; Norwegian Bokmal","nob","nb"} , + { "Bosnian","bos","bs"} , + { "Braj","bra",""} , + { "Breton","bre","br"} , + { "Buginese","bug",""} , + { "Bulgarian","bul","bg"} , + { "Buriat","bua",""} , + { "Burmese","mya","my"} , + { "Caddo","cad",""} , + { "Catalan; Valencian","cat","ca"} , + { "Caucasian languages","cau",""} , + { "Cebuano","ceb",""} , + { "Celtic languages","cel",""} , + { "Central American Indian languages","cai",""} , + { "Central Khmer","khm","km"} , + { "Chagatai","chg",""} , + { "Chamic languages","cmc",""} , + { "Chamorro","cha","ch"} , + { "Chechen","che","ce"} , + { "Cherokee","chr",""} , + { "Cheyenne","chy",""} , + { "Chibcha","chb",""} , + { "Chichewa; Chewa; Nyanja","nya","ny"} , + { "Chinese","zho","zh"} , + { "Chinook jargon","chn",""} , + { "Chipewyan; Dene Suline","chp",""} , + { "Choctaw","cho",""} , + { "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church} S{ lavonic","chu","cu"} , + { "Chuukese","chk",""} , + { "Chuvash","chv","cv"} , + { "Classical Newari; Old Newari; Classical Nepal Bhasa","nwc",""} , + { "Classical Syriac","syc",""} , + { "Coptic","cop",""} , + { "Cornish","cor","kw"} , + { "Corsican","cos","co"} , + { "Cree","cre","cr"} , + { "Creek","mus",""} , + { "Creoles and pidgins","crp",""} , + { "Creoles and pidgins, English based","cpe",""} , + { "Creoles and pidgins, French-based","cpf",""} , + { "Creoles and pidgins, Portuguese-based","cpp",""} , + { "Crimean Tatar; Crimean Turkish","crh",""} , + { "Croatian","hrv","hr"} , + { "Cushitic languages","cus",""} , + { "Czech","ces","cs"} , + { "Dakota","dak",""} , + { "Danish","dan","da"} , + { "Dargwa","dar",""} , + { "Delaware","del",""} , + { "Dinka","din",""} , + { "Divehi; Dhivehi; Maldivian","div","dv"} , + { "Dogri","doi",""} , + { "Dogrib","dgr",""} , + { "Dravidian languages","dra",""} , + { "Duala","dua",""} , + { "Dutch, Middle (ca.1050-1350)","dum",""} , + { "Dutch; Flemish","nld","nl"} , + { "Dyula","dyu",""} , + { "Dzongkha","dzo","dz"} , + { "Eastern Frisian","frs",""} , + { "Efik","efi",""} , + { "Egyptian (Ancient)","egy",""} , + { "Ekajuk","eka",""} , + { "Elamite","elx",""} , + { "English","eng","en"} , + { "English, Middle (1100-1500)","enm",""} , + { "English, Old (ca.450-1100)","ang",""} , + { "Erzya","myv",""} , + { "Esperanto","epo","eo"} , + { "Estonian","est","et"} , + { "Ewe","ewe","ee"} , + { "Ewondo","ewo",""} , + { "Fang","fan",""} , + { "Fanti","fat",""} , + { "Faroese","fao","fo"} , + { "Fijian","fij","fj"} , + { "Filipino; Pilipino","fil",""} , + { "Finnish","fin","fi"} , + { "Finno-Ugrian languages","fiu",""} , + { "Fon","fon",""} , + { "French","fra","fr"} , + { "French, Middle (ca.1400-1600)","frm",""} , + { "French, Old (842-ca.1400)","fro",""} , + { "Friulian","fur",""} , + { "Fulah","ful","ff"} , + { "Ga","gaa",""} , + { "Gaelic; Scottish Gaelic","gla","gd"} , + { "Galibi Carib","car",""} , + { "Galician","glg","gl"} , + { "Ganda","lug","lg"} , + { "Gayo","gay",""} , + { "Gbaya","gba",""} , + { "Geez","gez",""} , + { "Georgian","kat","ka"} , + { "German","deu","de"} , + { "German, Middle High (ca.1050-1500)","gmh",""} , + { "German, Old High (ca.750-1050)","goh",""} , + { "Germanic languages","gem",""} , + { "Gilbertese","gil",""} , + { "Gondi","gon",""} , + { "Gorontalo","gor",""} , + { "Gothic","got",""} , + { "Grebo","grb",""} , + { "Greek, Ancient (to 1453)","grc",""} , + { "Greek, Modern (1453-)","ell","el"} , + { "Guarani","grn","gn"} , + { "Gujarati","guj","gu"} , + { "Gwich'in","gwi",""} , + { "Haida","hai",""} , + { "Haitian; Haitian Creole","hat","ht"} , + { "Hausa","hau","ha"} , + { "Hawaiian","haw",""} , + { "Hebrew","heb","he"} , + { "Herero","her","hz"} , + { "Hiligaynon","hil",""} , + { "Himachali languages; Western Pahari languages","him",""} , + { "Hindi","hin","hi"} , + { "Hiri Motu","hmo","ho"} , + { "Hittite","hit",""} , + { "Hmong; Mong","hmn",""} , + { "Hungarian","hun","hu"} , + { "Hupa","hup",""} , + { "Iban","iba",""} , + { "Icelandic","isl","is"} , + { "Ido","ido","io"} , + { "Igbo","ibo","ig"} , + { "Ijo languages","ijo",""} , + { "Iloko","ilo",""} , + { "Inari Sami","smn",""} , + { "Indic languages","inc",""} , + { "Indo-European languages","ine",""} , + { "Indonesian","ind","id"} , + { "Ingush","inh",""} , + { "Interlingua (International Auxiliary Language Association)","ina","ia"} , + { "Interlingue; Occidental","ile","ie"} , + { "Inuktitut","iku","iu"} , + { "Inupiaq","ipk","ik"} , + { "Iranian languages","ira",""} , + { "Irish","gle","ga"} , + { "Irish, Middle (900-1200)","mga",""} , + { "Irish, Old (to 900)","sga",""} , + { "Iroquoian languages","iro",""} , + { "Italian","ita","it"} , + { "Japanese","jpn","ja"} , + { "Javanese","jav","jv"} , + { "Judeo-Arabic","jrb",""} , + { "Judeo-Persian","jpr",""} , + { "Kabardian","kbd",""} , + { "Kabyle","kab",""} , + { "Kachin; Jingpho","kac",""} , + { "Kalaallisut; Greenlandic","kal","kl"} , + { "Kalmyk; Oirat","xal",""} , + { "Kamba","kam",""} , + { "Kannada","kan","kn"} , + { "Kanuri","kau","kr"} , + { "Kara-Kalpak","kaa",""} , + { "Karachay-Balkar","krc",""} , + { "Karelian","krl",""} , + { "Karen languages","kar",""} , + { "Kashmiri","kas","ks"} , + { "Kashubian","csb",""} , + { "Kawi","kaw",""} , + { "Kazakh","kaz","kk"} , + { "Khasi","kha",""} , + { "Khoisan languages","khi",""} , + { "Khotanese; Sakan","kho",""} , + { "Kikuyu; Gikuyu","kik","ki"} , + { "Kimbundu","kmb",""} , + { "Kinyarwanda","kin","rw"} , + { "Kirghiz; Kyrgyz","kir","ky"} , + { "Klingon; tlhIngan-Hol","tlh",""} , + { "Komi","kom","kv"} , + { "Kongo","kon","kg"} , + { "Konkani","kok",""} , + { "Korean","kor","ko"} , + { "Kosraean","kos",""} , + { "Kpelle","kpe",""} , + { "Kru languages","kro",""} , + { "Kuanyama; Kwanyama","kua","kj"} , + { "Kumyk","kum",""} , + { "Kurdish","kur","ku"} , + { "Kurukh","kru",""} , + { "Kutenai","kut",""} , + { "Ladino","lad",""} , + { "Lahnda","lah",""} , + { "Lamba","lam",""} , + { "Land Dayak languages","day",""} , + { "Lao","lao","lo"} , + { "Latin","lat","la"} , + { "Latvian","lav","lv"} , + { "Lezghian","lez",""} , + { "Limburgan; Limburger; Limburgish","lim","li"} , + { "Lingala","lin","ln"} , + { "Lithuanian","lit","lt"} , + { "Lojban","jbo",""} , + { "Low German; Low Saxon; German, Low; Saxon, Low","nds",""} , + { "Lower Sorbian","dsb",""} , + { "Lozi","loz",""} , + { "Luba-Katanga","lub","lu"} , + { "Luba-Lulua","lua",""} , + { "Luiseno","lui",""} , + { "Lule Sami","smj",""} , + { "Lunda","lun",""} , + { "Luo (Kenya and Tanzania)","luo",""} , + { "Lushai","lus",""} , + { "Luxembourgish; Letzeburgesch","ltz","lb"} , + { "Macedonian","mkd","mk"} , + { "Madurese","mad",""} , + { "Magahi","mag",""} , + { "Maithili","mai",""} , + { "Makasar","mak",""} , + { "Malagasy","mlg","mg"} , + { "Malay","msa","ms"} , + { "Malayalam","mal","ml"} , + { "Maltese","mlt","mt"} , + { "Manchu","mnc",""} , + { "Mandar","mdr",""} , + { "Mandingo","man",""} , + { "Manipuri","mni",""} , + { "Manobo languages","mno",""} , + { "Manx","glv","gv"} , + { "Maori","mri","mi"} , + { "Mapudungun; Mapuche","arn",""} , + { "Marathi","mar","mr"} , + { "Mari","chm",""} , + { "Marshallese","mah","mh"} , + { "Marwari","mwr",""} , + { "Masai","mas",""} , + { "Mayan languages","myn",""} , + { "Mende","men",""} , + { "Mi'kmaq; Micmac","mic",""} , + { "Minangkabau","min",""} , + { "Mirandese","mwl",""} , + { "Mohawk","moh",""} , + { "Moksha","mdf",""} , + { "Mon-Khmer languages","mkh",""} , + { "Mongo","lol",""} , + { "Mongolian","mon","mn"} , + { "Mossi","mos",""} , + { "Multiple languages","mul",""} , + { "Munda languages","mun",""} , + { "N'Ko","nqo",""} , + { "Nahuatl languages","nah",""} , + { "Nauru","nau","na"} , + { "Navajo; Navaho","nav","nv"} , + { "Ndebele, North; North Ndebele","nde","nd"} , + { "Ndebele, South; South Ndebele","nbl","nr"} , + { "Ndonga","ndo","ng"} , + { "Neapolitan","nap",""} , + { "Nepal Bhasa; Newari","new",""} , + { "Nepali","nep","ne"} , + { "Nias","nia",""} , + { "Niger-Kordofanian languages","nic",""} , + { "Nilo-Saharan languages","ssa",""} , + { "Niuean","niu",""} , + { "No linguistic content; Not applicable","zxx",""} , + { "Nogai","nog",""} , + { "Norse, Old","non",""} , + { "North American Indian languages","nai",""} , + { "Northern Frisian","frr",""} , + { "Northern Sami","sme","se"} , + { "Norwegian","nor","no"} , + { "Norwegian Nynorsk; Nynorsk, Norwegian","nno","nn"} , + { "Nubian languages","nub",""} , + { "Nyamwezi","nym",""} , + { "Nyankole","nyn",""} , + { "Nyoro","nyo",""} , + { "Nzima","nzi",""} , + { "Occitan (post 1500)","oci","oc"} , + { "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)","arc",""} , + { "Ojibwa","oji","oj"} , + { "Oriya","ori","or"} , + { "Oromo","orm","om"} , + { "Osage","osa",""} , + { "Ossetian; Ossetic","oss","os"} , + { "Otomian languages","oto",""} , + { "Pahlavi","pal",""} , + { "Palauan","pau",""} , + { "Pali","pli","pi"} , + { "Pampanga; Kapampangan","pam",""} , + { "Pangasinan","pag",""} , + { "Panjabi; Punjabi","pan","pa"} , + { "Papiamento","pap",""} , + { "Papuan languages","paa",""} , + { "Pedi; Sepedi; Northern Sotho","nso",""} , + { "Persian","fas","fa"} , + { "Persian, Old (ca.600-400 B.C.)","peo",""} , + { "Philippine languages","phi",""} , + { "Phoenician","phn",""} , + { "Pohnpeian","pon",""} , + { "Polish","pol","pl"} , + { "Portuguese","por","pt"} , + { "Prakrit languages","pra",""} , + //{ "Provençal, Old (to 1500);Occitan, Old (to 1500)","pro",""} , + { "Pushto; Pashto","pus","ps"} , + { "Quechua","que","qu"} , + { "Rajasthani","raj",""} , + { "Rapanui","rap",""} , + { "Rarotongan; Cook Islands Maori","rar",""} , + { "Reserved for local use","qaa-qtz",""} , + { "Romance languages","roa",""} , + { "Romanian; Moldavian; Moldovan","ron","ro"} , + { "Romansh","roh","rm"} , + { "Romany","rom",""} , + { "Rundi","run","rn"} , + { "Russian","rus","ru"} , + { "Salishan languages","sal",""} , + { "Samaritan Aramaic","sam",""} , + { "Sami languages","smi",""} , + { "Samoan","smo","sm"} , + { "Sandawe","sad",""} , + { "Sango","sag","sg"} , + { "Sanskrit","san","sa"} , + { "Santali","sat",""} , + { "Sardinian","srd","sc"} , + { "Sasak","sas",""} , + { "Scots","sco",""} , + { "Selkup","sel",""} , + { "Semitic languages","sem",""} , + { "Serbian","srp","sr"} , + { "Serer","srr",""} , + { "Shan","shn",""} , + { "Shona","sna","sn"} , + { "Sichuan Yi; Nuosu","iii","ii"} , + { "Sicilian","scn",""} , + { "Sidamo","sid",""} , + { "Sign Languages","sgn",""} , + { "Siksika","bla",""} , + { "Sindhi","snd","sd"} , + { "Sinhala; Sinhalese","sin","si"} , + { "Sino-Tibetan languages","sit",""} , + { "Siouan languages","sio",""} , + { "Skolt Sami","sms",""} , + { "Slave (Athapascan)","den",""} , + { "Slavic languages","sla",""} , + { "Slovak","slk","sk"} , + { "Slovenian","slv","sl"} , + { "Sogdian","sog",""} , + { "Somali","som","so"} , + { "Songhai languages","son",""} , + { "Soninke","snk",""} , + { "Sorbian languages","wen",""} , + { "Sotho, Southern","sot","st"} , + { "South American Indian languages","sai",""} , + { "Southern Altai","alt",""} , + { "Southern Sami","sma",""} , + { "Spanish; Castilian","spa","es"} , + { "Sranan Tongo","srn",""} , + { "Sukuma","suk",""} , + { "Sumerian","sux",""} , + { "Sundanese","sun","su"} , + { "Susu","sus",""} , + { "Swahili","swa","sw"} , + { "Swati","ssw","ss"} , + { "Swedish","swe","sv"} , + { "Swiss German; Alemannic; Alsatian","gsw",""} , + { "Syriac","syr",""} , + { "Tagalog","tgl","tl"} , + { "Tahitian","tah","ty"} , + { "Tai languages","tai",""} , + { "Tajik","tgk","tg"} , + { "Tamashek","tmh",""} , + { "Tamil","tam","ta"} , + { "Tatar","tat","tt"} , + { "Telugu","tel","te"} , + { "Tereno","ter",""} , + { "Tetum","tet",""} , + { "Thai","tha","th"} , + { "Tibetan","bod","bo"} , + { "Tigre","tig",""} , + { "Tigrinya","tir","ti"} , + { "Timne","tem",""} , + { "Tiv","tiv",""} , + { "Tlingit","tli",""} , + { "Tok Pisin","tpi",""} , + { "Tokelau","tkl",""} , + { "Tonga (Nyasa)","tog",""} , + { "Tonga (Tonga Islands)","ton","to"} , + { "Tsimshian","tsi",""} , + { "Tsonga","tso","ts"} , + { "Tswana","tsn","tn"} , + { "Tumbuka","tum",""} , + { "Tupi languages","tup",""} , + { "Turkish","tur","tr"} , + { "Turkish, Ottoman (1500-1928)","ota",""} , + { "Turkmen","tuk","tk"} , + { "Tuvalu","tvl",""} , + { "Tuvinian","tyv",""} , + { "Twi","twi","tw"} , + { "Udmurt","udm",""} , + { "Ugaritic","uga",""} , + { "Uighur; Uyghur","uig","ug"} , + { "Ukrainian","ukr","uk"} , + { "Umbundu","umb",""} , + { "Uncoded languages","mis",""} , + { "Undetermined","und",""} , + { "Upper Sorbian","hsb",""} , + { "Urdu","urd","ur"} , + { "Uzbek","uzb","uz"} , + { "Vai","vai",""} , + { "Venda","ven","ve"} , + { "Vietnamese","vie","vi"} , + //{ "Volapük","vol","vo"} , + { "Votic","vot",""} , + { "Wakashan languages","wak",""} , + { "Walloon","wln","wa"} , + { "Waray","war",""} , + { "Washo","was",""} , + { "Welsh","cym","cy"} , + { "Western Frisian","fry","fy"} , + { "Wolaitta; Wolaytta","wal",""} , + { "Wolof","wol","wo"} , + { "Xhosa","xho","xh"} , + { "Yakut","sah",""} , + { "Yao","yao",""} , + { "Yapese","yap",""} , + { "Yiddish","yid","yi"} , + { "Yoruba","yor","yo"} , + { "Yupik languages","ypk",""} , + { "Zande languages","znd",""} , + { "Zapotec","zap",""} , + { "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki","zza",""} , + { "Zenaga","zen",""} , + { "Zhuang; Chuang","zha","za"} , + { "Zulu","zul","zu"} , + { "Zuni","zun",""} , +}; + + +GF_EXPORT +u32 gf_lang_get_count() +{ + return sizeof(defined_languages) / sizeof(struct lang_def); +} + +GF_EXPORT +s32 gf_lang_find(const char *lang_or_rfc_5646_code) +{ + //find the language ISO639 entry for the given code + u32 i=0; + u32 len=0; + char *sep; + u32 count = sizeof(defined_languages) / sizeof(struct lang_def); + + + len = 0; + sep = (char *) strchr(lang_or_rfc_5646_code, '-'); + if (sep) { + sep[0] = 0; + len = (u32) strlen(lang_or_rfc_5646_code); + sep[0] = '-'; + } + + for (i=0; i=sizeof(defined_languages) / sizeof(struct lang_def)) return NULL; + return defined_languages[idx].name; +} + +GF_EXPORT +const char *gf_lang_get_2cc(u32 idx) +{ + if (idx>=sizeof(defined_languages) / sizeof(struct lang_def)) return NULL; + return defined_languages[idx].two_char_code; +} + +GF_EXPORT +const char *gf_lang_get_3cc(u32 idx) +{ + if (idx>=sizeof(defined_languages) / sizeof(struct lang_def)) return NULL; + return defined_languages[idx].three_char_code; +} diff --git a/src/utils/gzio.cpp b/src/utils/gzio.cpp index b5bd2e1..1881b44 100644 --- a/src/utils/gzio.cpp +++ b/src/utils/gzio.cpp @@ -389,9 +389,9 @@ local int destroy (gz_stream *s) err = inflateEnd(&(s->stream)); } } - if (s->file != NULL && fclose(s->file)) { + if (s->file != NULL && gf_fclose(s->file)) { #ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ + if (errno != ESPIPE) /* gf_fclose is broken for pipes in HP/UX */ #endif err = Z_ERRNO; } diff --git a/src/utils/math.c b/src/utils/math.c index fac3c18..6a1c596 100644 --- a/src/utils/math.c +++ b/src/utils/math.c @@ -29,7 +29,7 @@ * */ -#include +#include u32 gf_get_bit_size(u32 MaxVal) { diff --git a/src/utils/module.c b/src/utils/module.c index 71ec817..9492d3c 100644 --- a/src/utils/module.c +++ b/src/utils/module.c @@ -28,7 +28,7 @@ #include #include - +#ifndef GPAC_MODULE_CUSTOM_LOAD static void load_all_modules(GF_ModuleManager *mgr) { #define LOAD_PLUGIN( __name ) { \ @@ -148,6 +148,7 @@ static void load_all_modules(GF_ModuleManager *mgr) //todo fix project for iOS #ifdef GPAC_IPHONE + //these do not compile with xcode 4.2 // LOAD_PLUGIN(ios_cam); // LOAD_PLUGIN(ios_mpegv); #endif @@ -158,7 +159,26 @@ static void load_all_modules(GF_ModuleManager *mgr) #undef LOAD_PLUGIN } +#endif //GPAC_MODULE_CUSTOM_LOAD + +GF_EXPORT +GF_Err gf_module_load_static(GF_ModuleManager *pm, GF_InterfaceRegister *(*register_module)()) +{ + GF_InterfaceRegister *pr = register_module(); + GF_Err rc; + if (!pr) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to statically load module\n")); + return GF_NOT_SUPPORTED; + } + + rc = gf_list_add(pm->plugin_registry, pr); + if (rc != GF_OK) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to statically load module\n")); + return rc; + } + return GF_OK; +} GF_EXPORT GF_ModuleManager *gf_modules_new(const char *directory, GF_Config *config) @@ -196,8 +216,9 @@ GF_ModuleManager *gf_modules_new(const char *directory, GF_Config *config) if (opt && !strcmp(opt, "no")) { tmp->no_unload = GF_TRUE; } +#ifndef GPAC_MODULE_CUSTOM_LOAD load_all_modules(tmp); - +#endif loadedModules = gf_modules_refresh(tmp); GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Loaded %d modules from directory %s.\n", loadedModules, directory)); @@ -216,13 +237,19 @@ void gf_modules_del(GF_ModuleManager *pm) gf_modules_free_module(inst); gf_list_rem(pm->plug_list, 0); } + gf_list_del(pm->plug_list); /* Delete module directories*/ for (i = 0; i < pm->num_dirs; i++) { gf_free((void*)pm->dirs[i]); } - gf_list_del(pm->plug_list); + /*remove all static modules registry*/ + while (gf_list_count(pm->plugin_registry)) { + GF_InterfaceRegister *reg = (GF_InterfaceRegister *) gf_list_get(pm->plugin_registry, 0); + gf_free(reg); + gf_list_rem(pm->plugin_registry, 0); + } if (pm->plugin_registry) gf_list_del(pm->plugin_registry); gf_mx_del(pm->mutex); @@ -265,7 +292,8 @@ const char **gf_modules_get_module_directories(GF_ModuleManager *pm, u32* num_di return NULL; } - tmp_dirs = gf_strdup(directories); +// tmp_dirs = gf_strdup(directories); + tmp_dirs = directories; pch = strtok (tmp_dirs,";"); while (pch != NULL) @@ -279,7 +307,7 @@ const char **gf_modules_get_module_directories(GF_ModuleManager *pm, u32* num_di pm->num_dirs++; pch = strtok (NULL, ";"); } - gf_free(tmp_dirs); +// gf_free(tmp_dirs); *num_dirs = pm->num_dirs; return pm->dirs; } diff --git a/src/utils/os_config_init.c b/src/utils/os_config_init.c index 517b6c2..807e4ac 100644 --- a/src/utils/os_config_init.c +++ b/src/utils/os_config_init.c @@ -52,13 +52,13 @@ #else #define TEST_MODULE "gm_dummy_in.dylib" #endif -#define CFG_FILE_NAME ".gpacrc" +#define CFG_FILE_NAME "GPAC.cfg" #else #ifdef GPAC_CONFIG_LINUX #include #endif -#define CFG_FILE_NAME ".gpacrc" +#define CFG_FILE_NAME "GPAC.cfg" #define TEST_MODULE "gm_dummy_in.so" #endif @@ -89,11 +89,12 @@ static Bool check_file_exists(char *name, char *path, char *outPath) } #endif sprintf(szPath, "%s%c%s", path, GF_PATH_SEPARATOR, name); + //do not use gf_fopen here, we don't want to throw en error if failure f = fopen(szPath, "rb"); - if (!f) return 0; + if (!f) return GF_FALSE; fclose(f); if (outPath != path) strcpy(outPath, path); - return 1; + return GF_TRUE; } enum @@ -162,33 +163,34 @@ static Bool get_default_install_path(char *file_path, u32 path_type) } - if (path_type==GF_PATH_APP) return 1; + if (path_type==GF_PATH_APP) return GF_TRUE; if (path_type==GF_PATH_GUI) { char *sep; strcat(file_path, "\\gui"); - if (check_file_exists("gui.bt", file_path, file_path)) return 1; + if (check_file_exists("gui.bt", file_path, file_path)) return GF_TRUE; sep = strstr(file_path, "\\bin\\"); if (sep) { sep[0] = 0; strcat(file_path, "\\gui"); - if (check_file_exists("gui.bt", file_path, file_path)) return 1; + if (check_file_exists("gui.bt", file_path, file_path)) return GF_TRUE; } - return 0; + return GF_FALSE; } /*modules are stored in the GPAC directory (should be changed to GPAC/modules)*/ - if (path_type==GF_PATH_MODULES) return 1; + if (path_type==GF_PATH_MODULES) return GF_TRUE; /*we are looking for the config file path - make sure it is writable*/ assert(path_type == GF_PATH_CFG); strcpy(szPath, file_path); strcat(szPath, "\\gpaccfgtest.txt"); - f = gf_f64_open(szPath, "wb"); + //do not use gf_fopen here, we don't want to through any error if failure + f = fopen(szPath, "wb"); if (f != NULL) { fclose(f); gf_delete_file(szPath); - return 1; + return GF_TRUE; } #ifdef _WIN32_WCE return 0; @@ -201,13 +203,13 @@ static Bool get_default_install_path(char *file_path, u32 path_type) _mkdir(file_path); strcpy(szPath, file_path); strcat(szPath, "\\gpaccfgtest.txt"); - f = gf_f64_open(szPath, "wb"); + f = fopen(szPath, "wb"); /*COMPLETE FAILURE*/ - if (!f) return 0; + if (!f) return GF_FALSE; fclose(f); gf_delete_file(szPath); - return 1; + return GF_TRUE; #endif } @@ -265,11 +267,25 @@ static Bool get_default_install_path(char *file_path, u32 path_type) #ifdef GPAC_IPHONE res = realpath(user_home, buf); if (res) { - strcpy(file_path, buf); + strcpy(file_path, buf); + strcat(file_path, "/Documents"); } else #endif strcpy(file_path, user_home); + if (file_path[strlen(file_path)-1] == '/') file_path[strlen(file_path)-1] = 0; + + //cleanup of old install in .gpacrc + if (check_file_exists(".gpacrc", file_path, file_path)) { + strcpy(app_path, file_path); + strcat(app_path, "/.gpacrc"); + gf_delete_file(app_path); + } + + strcat(file_path, "/.gpac"); + if (!gf_dir_exists(file_path)) { + gf_mkdir(file_path); + } return 1; } @@ -311,6 +327,8 @@ static Bool get_default_install_path(char *file_path, u32 path_type) if (check_file_exists(TEST_MODULE, "/usr/local/lib/gpac", file_path)) return 1; if (check_file_exists(TEST_MODULE, "/opt/lib/gpac", file_path)) return 1; if (check_file_exists(TEST_MODULE, "/opt/local/lib/gpac", file_path)) return 1; + if (check_file_exists(TEST_MODULE, "/usr/lib/x86_64-linux-gnu/gpac", file_path)) return 1; + if (check_file_exists(TEST_MODULE, "/usr/lib/i386-linux-gnu/gpac", file_path)) return 1; } } @@ -364,7 +382,7 @@ static Bool get_default_install_path(char *file_path, u32 path_type) /*iOS app is distributed with embedded GUI*/ get_default_install_path(app_path, GF_PATH_APP); strcat(app_path, "/gui"); - if (check_file_exists("gui_old.bt", app_path, file_path)) return 1; + if (check_file_exists("gui.bt", app_path, file_path)) return 1; #endif } else { // (path_type==GF_PATH_MODULES) @@ -392,28 +410,65 @@ static GF_Config *create_default_config(char *file_path) } /*Create the config file*/ sprintf(szPath, "%s%c%s", file_path, GF_PATH_SEPARATOR, CFG_FILE_NAME); - fprintf(stderr, "Trying to create config file: %s", szPath); - f = gf_f64_open(szPath, "wt"); + GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Trying to create config file: %s\n", szPath )); + f = fopen(szPath, "wt"); if (!f) return NULL; fclose(f); +#ifndef GPAC_IPHONE if (! get_default_install_path(szPath, GF_PATH_MODULES)) { gf_delete_file(szPath); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] default modules not found\n")); return NULL; } +#else + get_default_install_path(szPath, GF_PATH_APP); +#endif cfg = gf_cfg_new(file_path, CFG_FILE_NAME); if (!cfg) return NULL; gf_cfg_set_key(cfg, "General", "ModulesDirectory", szPath); - /*get default temporary directoy */ - cache_dir = gf_get_default_cache_directory(); + /*get default temporary directoy */ + cache_dir = gf_get_default_cache_directory(); + + //get real path where the .gpac dir has been created, and use this as the default path + //for cache (tmp/ dir of ios app) and last working fir +#ifdef GPAC_IPHONE + char buf[GF_MAX_PATH], *res; + res = realpath(file_path, buf); + if (res) { + char *sep = strstr(res, ".gpac"); + assert(sep); + sep[0] = 0; + gf_cfg_set_key(cfg, "General", "LastWorkingDir", res); + gf_cfg_set_key(cfg, "General", "iOSDocumentsDir", res); + + sep = strstr(res, "Documents"); + assert(sep); + sep[0]=0; + strcat(res, "tmp/"); + cache_dir = res; + if (!gf_dir_exists(cache_dir)) gf_mkdir(cache_dir); + gf_cfg_set_key(cfg, "General", "CacheDirectory", cache_dir); + cache_dir=NULL; + } +#endif + if (cache_dir) { gf_cfg_set_key(cfg, "General", "CacheDirectory", cache_dir); gf_free(cache_dir); } + +#if defined(GPAC_IPHONE) + gf_cfg_set_key(cfg, "General", "DeviceType", "iOS"); +#elif defined(GPAC_ANDROID) + gf_cfg_set_key(cfg, "General", "DeviceType", "Android"); +#else + gf_cfg_set_key(cfg, "General", "DeviceType", "Desktop"); +#endif + gf_cfg_set_key(cfg, "Compositor", "Raster2D", "GPAC 2D Raster"); gf_cfg_set_key(cfg, "Audio", "ForceConfig", "yes"); gf_cfg_set_key(cfg, "Audio", "NumBuffers", "2"); @@ -435,7 +490,7 @@ static GF_Config *create_default_config(char *file_path) #elif defined(__APPLE__) #ifdef GPAC_IPHONE - strcpy(szPath, "/System/Library/Fonts/Cache"); + strcpy(szPath, "/System/Library/Fonts/Cache,/System/Library/Fonts/AppFonts,/System/Library/Fonts/Core,/System/Library/Fonts/Extra"); #else strcpy(szPath, "/Library/Fonts"); #endif @@ -476,9 +531,9 @@ static GF_Config *create_default_config(char *file_path) /*locate GUI*/ if ( get_default_install_path(szPath, GF_PATH_GUI) ) { sprintf(gui_path, "%s%cgui.bt", szPath, GF_PATH_SEPARATOR); - f = fopen(gui_path, "rt"); + f = gf_fopen(gui_path, "rt"); if (f) { - fclose(f); + gf_fclose(f); gf_cfg_set_key(cfg, "General", "StartupFile", gui_path); } } @@ -489,7 +544,6 @@ static GF_Config *create_default_config(char *file_path) } /*check if modules directory has changed in the config file -this is mainly intended for OSX where we can have an install in /usr/... and an install in /Applications/Osmo4.app */ static void check_modules_dir(GF_Config *cfg) { @@ -497,24 +551,56 @@ static void check_modules_dir(GF_Config *cfg) const char *opt; if ( get_default_install_path(path, GF_PATH_MODULES) ) { -#if defined(__DARWIN__) || defined(__APPLE__) opt = gf_cfg_get_key(cfg, "General", "ModulesDirectory"); - if (!opt || strcmp(opt, path)) gf_cfg_set_key(cfg, "General", "ModulesDirectory", path); + //for OSX, we can have an install in /usr/... and an install in /Applications/Osmo4.app - always change +#if defined(__DARWIN__) || defined(__APPLE__) + if (!opt || strcmp(opt, path)) + gf_cfg_set_key(cfg, "General", "ModulesDirectory", path); +#else + + //otherwise only check we didn't switch between a 64 bit version and a 32 bit version + if (!opt) { + gf_cfg_set_key(cfg, "General", "ModulesDirectory", path); + } else { + Bool erase_modules_dir = GF_FALSE; + const char *opt64 = gf_cfg_get_key(cfg, "Systems", "64bits"); + if (!opt64) { + //first run or old versions, erase + erase_modules_dir = GF_TRUE; + } else if (!strcmp(opt64, "yes") ) { +#ifndef GPAC_64_BITS + erase_modules_dir = GF_TRUE; +#endif + } else { +#ifdef GPAC_64_BITS + erase_modules_dir = GF_TRUE; +#endif + } + +#ifdef GPAC_64_BITS + opt64 = "yes"; +#else + opt64 = "no"; +#endif + gf_cfg_set_key(cfg, "Systems", "64bits", opt64); + + if (erase_modules_dir) { + gf_cfg_set_key(cfg, "General", "ModulesDirectory", path); + } + } #endif } /*if startup file was disabled, do not attempt to correct it*/ if (gf_cfg_get_key(cfg, "General", "StartupFile")==NULL) return; - + if ( get_default_install_path(path, GF_PATH_GUI) ) { opt = gf_cfg_get_key(cfg, "General", "StartupFile"); - if (strstr(opt, "gui.bt") && strcmp(opt, path)) { -#if defined(_WIN32_WCE) || defined(WIN32) - strcat(path, "\\gui.bt"); -#else + if (strstr(opt, "gui.bt") && strcmp(opt, path) && strstr(path, ".app") ) { +#if defined(__DARWIN__) || defined(__APPLE__) strcat(path, "/gui.bt"); -#endif gf_cfg_set_key(cfg, "General", "StartupFile", path); +#endif } } } @@ -525,17 +611,17 @@ GF_Config *gf_cfg_init(const char *file, Bool *new_cfg) GF_Config *cfg; char szPath[GF_MAX_PATH]; - if (new_cfg) *new_cfg = 0; + if (new_cfg) *new_cfg = GF_FALSE; if (file) { cfg = gf_cfg_new(NULL, file); /*force creation of a new config*/ if (!cfg) { - FILE *fcfg = fopen(file, "wt"); + FILE *fcfg = gf_fopen(file, "wt"); if (fcfg) { - fclose(fcfg); + gf_fclose(fcfg); cfg = gf_cfg_new(NULL, file); - if (new_cfg) *new_cfg = 1; + if (new_cfg) *new_cfg = GF_TRUE; } } if (cfg) { @@ -548,22 +634,31 @@ GF_Config *gf_cfg_init(const char *file, Bool *new_cfg) fprintf(stderr, "Fatal error: Cannot create a configuration file in application or user home directory - no write access\n"); return NULL; } + cfg = gf_cfg_new(szPath, CFG_FILE_NAME); if (!cfg) { fprintf(stderr, "GPAC config file %s not found in %s - creating new file\n", CFG_FILE_NAME, szPath); cfg = create_default_config(szPath); } - if (!cfg) { - fprintf(stderr, "Cannot create config file %s in %s directory\n", CFG_FILE_NAME, szPath); + fprintf(stderr, "\nCannot create config file %s in %s directory\n", CFG_FILE_NAME, szPath); return NULL; } +#ifndef GPAC_IPHONE fprintf(stderr, "Using config file in %s directory\n", szPath); +#endif check_modules_dir(cfg); - if (new_cfg) *new_cfg = 1; + if (!gf_cfg_get_key(cfg, "General", "StorageDirectory")) { + get_default_install_path(szPath, GF_PATH_CFG); + strcat(szPath, "/Storage"); + if (!gf_dir_exists(szPath)) gf_mkdir(szPath); + gf_cfg_set_key(cfg, "General", "StorageDirectory", szPath); + } + + if (new_cfg) *new_cfg = GF_TRUE; return cfg; } diff --git a/src/utils/os_divers.c b/src/utils/os_divers.c index 09d01c5..122aeda 100644 --- a/src/utils/os_divers.c +++ b/src/utils/os_divers.c @@ -84,7 +84,7 @@ u32 gf_sys_clock() { struct timeval now; gettimeofday(&now, NULL); - return ( (now.tv_sec)*1000 + (now.tv_usec) / 1000) - sys_start_time; + return (u32) ( ( (now.tv_sec)*1000 + (now.tv_usec) / 1000) - sys_start_time ); } GF_EXPORT @@ -139,93 +139,6 @@ void gf_sleep(u32 ms) #endif } - -GF_Err gf_rmdir(char *DirPathName) -{ -#if defined (_WIN32_WCE) - TCHAR swzName[MAX_PATH]; - BOOL res; - CE_CharToWide(DirPathName, swzName); - res = RemoveDirectory(swzName); - if (! res) { - int err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete director %s: last error %d\n", DirPathName, err )); - } -#elif defined (WIN32) - int res = rmdir(DirPathName); - if (res==-1) { - int err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete director %s: last error %d\n", DirPathName, err )); - return GF_IO_ERR; - } -#else - int res = rmdir(DirPathName); - if (res==-1) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete director %s: last error %d\n", DirPathName, errno )); - return GF_IO_ERR; - } -#endif - return GF_OK; -} - -GF_EXPORT -GF_Err gf_mkdir(char* DirPathName) -{ -#if defined (_WIN32_WCE) - TCHAR swzName[MAX_PATH]; - BOOL res; - CE_CharToWide(DirPathName, swzName); - res = CreateDirectory(swzName, NULL); - if (! res) { - int err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err )); - } -#elif defined (WIN32) - int res = mkdir(DirPathName); - if (res==-1) { - int err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err )); - } -#else - int res = mkdir(DirPathName, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if (res==-1) { - if(errno == 17) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s, it already exists: last error %d \n", DirPathName, errno )); - return GF_BAD_PARAM; - } else { - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, errno )); - return GF_IO_ERR; - } - } -#endif - return GF_OK; -} - -static Bool delete_dir(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) -{ - Bool directory_clean_mode = *(Bool*)cbck; - - if(directory_clean_mode) { - gf_cleanup_dir(item_path); - gf_rmdir(item_path); - } else { - gf_delete_file(item_path); - } - return 0; -} - -GF_Err gf_cleanup_dir(char* DirPathName) -{ - Bool directory_clean_mode; - - directory_clean_mode = 1; - gf_enum_directory(DirPathName, 1, delete_dir, &directory_clean_mode, NULL); - directory_clean_mode = 0; - gf_enum_directory(DirPathName, 0, delete_dir, &directory_clean_mode, NULL); - - return GF_OK; -} - #ifndef gettimeofday #ifdef _WIN32_WCE @@ -388,70 +301,6 @@ void CE_CharToWide(char *str, unsigned short *w_str) #endif -GF_EXPORT -GF_Err gf_delete_file(const char *fileName) -{ -#if defined(_WIN32_WCE) - TCHAR swzName[MAX_PATH]; - CE_CharToWide((char*)fileName, swzName); - return (DeleteFile(swzName)==0) ? GF_IO_ERR : GF_OK; -#elif defined(WIN32) - /* success if != 0 */ - return (DeleteFile(fileName)==0) ? GF_IO_ERR : GF_OK; -#else - /* success is == 0 */ - return ( remove(fileName) == 0) ? GF_OK : GF_IO_ERR; -#endif -} - -/** - * Remove existing single-quote from a single-quoted string. - * The caller is responsible for deallocating the returns string with gf_free() - */ -static char* gf_sanetize_single_quoted_string(const char *src) { - int i, j; - char *out = gf_malloc(4*strlen(src)+3); - out[0] = '\''; - for (i=0, j=1; (out[j]=src[i]); ++i, ++j) { - if (src[i]=='\'') { - out[++j]='\\'; - out[++j]='\''; - out[++j]='\''; - } - } - out[j++] = '\''; - out[j++] = 0; - return out; -} - -GF_EXPORT -GF_Err gf_move_file(const char *fileName, const char *newFileName) -{ -#if defined(_WIN32_WCE) - TCHAR swzName[MAX_PATH]; - TCHAR swzNewName[MAX_PATH]; - CE_CharToWide((char*)fileName, swzName); - CE_CharToWide((char*)newFileName, swzNewName); - return (MoveFile(swzName, swzNewName) == 0 ) ? GF_IO_ERR : GF_OK; -#elif defined(WIN32) - /* success if != 0 */ - return (MoveFile(fileName, newFileName) == 0 ) ? GF_IO_ERR : GF_OK; -#else - GF_Err e = GF_IO_ERR; - char cmd[1024], *arg1, *arg2; - if (!fileName || !newFileName) - return GF_IO_ERR; - arg1 = gf_sanetize_single_quoted_string(fileName); - arg2 = gf_sanetize_single_quoted_string(newFileName); - if (snprintf(cmd, sizeof cmd, "mv %s %s", arg1, arg2) >= sizeof cmd) goto error; - e = (system(cmd) == 0) ? GF_OK : GF_IO_ERR; -error: - gf_free(arg1); - gf_free(arg2); - return e; -#endif -} - GF_EXPORT void gf_rand_init(Bool Reset) { @@ -476,73 +325,6 @@ u32 gf_rand() #include #endif -GF_EXPORT -u64 gf_file_modification_time(const char *filename) -{ -#if defined(_WIN32_WCE) - WCHAR _file[GF_MAX_PATH]; - WIN32_FIND_DATA FindData; - HANDLE fh; - ULARGE_INTEGER uli; - ULONGLONG time_ms; - BOOL ret; - CE_CharToWide((char *) filename, _file); - fh = FindFirstFile(_file, &FindData); - if (fh == INVALID_HANDLE_VALUE) return 0; - uli.LowPart = FindData.ftLastWriteTime.dwLowDateTime; - uli.HighPart = FindData.ftLastWriteTime.dwHighDateTime; - ret = FindClose(fh); - if (!ret) { - DWORD err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_file_modification_time() returned the following error code: %d\n", err)); - } - time_ms = uli.QuadPart/10000; - return time_ms; -#elif defined(WIN32) && !defined(__GNUC__) - struct _stat64 sb; - if (_stat64(filename, &sb) != 0) return 0; - return sb.st_mtime; -#else - struct stat sb; - if (stat(filename, &sb) != 0) return 0; - return sb.st_mtime; -#endif - return 0; -} - -GF_EXPORT -FILE *gf_temp_file_new() -{ -#if defined(_WIN32_WCE) - TCHAR pPath[MAX_PATH+1]; - TCHAR pTemp[MAX_PATH+1]; - if (!GetTempPath(MAX_PATH, pPath)) { - pPath[0] = '.'; - pPath[1] = '.'; - } - if (GetTempFileName(pPath, TEXT("git"), 0, pTemp)) - return _wfopen(pTemp, TEXT("w+b")); - - return NULL; -#elif defined(WIN32) - char tmp[MAX_PATH], t_file[100]; - FILE *res = tmpfile(); - if (res) return res; - { - u32 err = GetLastError(); - GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Win32] system failure for tmpfile(): 0x%08x\n", err)); - } - /*tmpfile() may fail under vista ...*/ - if (!GetEnvironmentVariable("TEMP",tmp,MAX_PATH)) - return NULL; - sprintf(t_file, "\\gpac_%08x.tmp", (u32) tmp); - strcat(tmp, t_file); - return gf_f64_open(tmp, "w+b"); -#else - return tmpfile(); -#endif -} - GF_EXPORT void gf_utc_time_since_1970(u32 *sec, u32 *msec) { @@ -554,7 +336,7 @@ void gf_utc_time_since_1970(u32 *sec, u32 *msec) #else struct timeval tv; gettimeofday(&tv, NULL); - *sec = tv.tv_sec; + *sec = (u32) tv.tv_sec; *msec = tv.tv_usec/1000; #endif } @@ -583,259 +365,6 @@ void gf_get_user_name(char *buf, u32 buf_size) } -/*enumerate directories*/ -GF_EXPORT -GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter) -{ - char item_path[GF_MAX_PATH]; - GF_FileEnumInfo file_info; - -#if defined(_WIN32_WCE) - char _path[GF_MAX_PATH]; - unsigned short path[GF_MAX_PATH]; - unsigned short w_filter[GF_MAX_PATH]; - char file[GF_MAX_PATH]; -#else - char path[GF_MAX_PATH], *file; -#endif - -#ifdef WIN32 - WIN32_FIND_DATA FindData; - HANDLE SearchH; -#else - DIR *the_dir; - struct dirent* the_file; - struct stat st; -#endif - - if (!dir || !enum_dir_fct) return GF_BAD_PARAM; - - if (filter && (!strcmp(filter, "*") || !filter[0])) filter=NULL; - - memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); - - if (!strcmp(dir, "/")) { -#if defined(WIN32) && !defined(_WIN32_WCE) - u32 len; - char *drives, *volume; - len = GetLogicalDriveStrings(0, NULL); - drives = gf_malloc(sizeof(char)*(len+1)); - drives[0]=0; - GetLogicalDriveStrings(len, drives); - len = (u32) strlen(drives); - volume = drives; - file_info.directory = GF_TRUE; - file_info.drive = GF_TRUE; - while (len) { - enum_dir_fct(cbck, volume, "", &file_info); - volume += len+1; - len = (u32) strlen(volume); - } - gf_free(drives); - return GF_OK; -#elif defined(__SYMBIAN32__) - RFs iFs; - TDriveList aList; - iFs.Connect(); - iFs.DriveList(aList); - for (TInt i=0; id_name, "..")) goto next; - if (the_file->d_name[0] == '.') goto next; -#endif - -#ifdef WIN32 - file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE; - if (!enum_directory && file_info.directory) goto next; - if (enum_directory && !file_info.directory) goto next; -#endif - - if (filter) { -#if defined (_WIN32_WCE) - short ext[30]; - short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.'); - if (!sep) goto next; - wcscpy(ext, sep+1); - wcslwr(ext); - if (!wcsstr(w_filter, ext)) goto next; -#elif defined(WIN32) - char ext[30]; - char *sep = strrchr(FindData.cFileName, '.'); - if (!sep) goto next; - strcpy(ext, sep+1); - strlwr(ext); - if (!strstr(filter, ext)) goto next; -#else - char ext[30]; - char *sep = strrchr(the_file->d_name, '.'); - if (!sep) goto next; - strcpy(ext, sep+1); - strlwr(ext); - if (!strstr(filter, sep+1)) goto next; -#endif - } - -#if defined(WIN32) - file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? 1 : 0; - file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? 1 : 0; - file_info.size = MAXDWORD; - file_info.size += 1; - file_info.size *= FindData.nFileSizeHigh; - file_info.size += FindData.nFileSizeLow; - file_info.last_modified = (u64) ((*(LONGLONG *) &FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); -#endif - -#if defined (_WIN32_WCE) - CE_WideToChar(FindData.cFileName, file); - strcpy(item_path, _path); - strcat(item_path, file); -#elif defined(WIN32) - strcpy(item_path, path); - strcat(item_path, FindData.cFileName); - file = FindData.cFileName; -#else - strcpy(item_path, path); - strcat(item_path, the_file->d_name); - GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file %s for enum\n", item_path)); - - if (stat( item_path, &st ) != 0) goto next; - - file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE; - if (enum_directory && !file_info.directory) goto next; - if (!enum_directory && file_info.directory) goto next; - - file_info.size = st.st_size; - - { - struct tm _t = * gmtime(& st.st_mtime); - file_info.last_modified = mktime(&_t); - } - file = the_file->d_name; - if (file && file[0]=='.') file_info.hidden = 1; - - if (file_info.directory) { - char * parent_name = strrchr(item_path, '/'); - if (!parent_name) { - file_info.drive = GF_TRUE; - } else { - struct stat st_parent; - parent_name[0] = 0; - if (stat(item_path, &st_parent) == 0) { - if ((st.st_dev != st_parent.st_dev) || ((st.st_dev == st_parent.st_dev) && (st.st_ino == st_parent.st_ino))) { - file_info.drive = GF_TRUE; - } - } - parent_name[0] = '/'; - } - } -#endif - if (enum_dir_fct(cbck, file, item_path, &file_info)) { -#ifdef WIN32 - BOOL ret = FindClose(SearchH); - if (!ret) { - DWORD err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err)); - } -#endif - break; - } - -next: -#ifdef WIN32 - if (!FindNextFile(SearchH, &FindData)) { - BOOL ret = FindClose(SearchH); - if (!ret) { - DWORD err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err)); - } - break; - } -#else - the_file = readdir(the_dir); -#endif - } -#ifndef WIN32 - closedir(the_dir); -#endif - return GF_OK; -} - - #ifndef WIN32 GF_EXPORT char * my_str_upr(char *str) @@ -858,109 +387,6 @@ char * my_str_lwr(char *str) } #endif -GF_EXPORT -u64 gf_f64_tell(FILE *fp) -{ -#if defined(_WIN32_WCE) - return (u64) ftell(fp); -#elif defined(GPAC_CONFIG_WIN32) /* mingw or cygwin */ -#if (_FILE_OFFSET_BITS >= 64) - return (u64) ftello64(fp); -#else - return (u64) ftell(fp); -#endif -#elif defined(WIN32) - return (u64) _ftelli64(fp); -#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) - return (u64) ftello64(fp); -#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) - return (u64) ftello(fp); -#else - return (u64) ftell(fp); -#endif -} - -GF_EXPORT -u64 gf_f64_seek(FILE *fp, s64 offset, s32 whence) -{ -#if defined(_WIN32_WCE) - return (u64) fseek(fp, (s32) offset, whence); -#elif defined(GPAC_CONFIG_WIN32) /* mingw or cygwin */ -#if (_FILE_OFFSET_BITS >= 64) - return (u64) fseeko64(fp, offset, whence); -#else - return (u64) fseek(fp, (s32) offset, whence); -#endif -#elif defined(WIN32) - return (u64) _fseeki64(fp, offset, whence); -#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) - return fseeko64(fp, (off64_t) offset, whence); -#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) - return fseeko(fp, (off_t) offset, whence); -#else - return fseek(fp, (s32) offset, whence); -#endif -} - -GF_EXPORT -FILE *gf_f64_open(const char *file_name, const char *mode) -{ -#if defined(WIN32) - FILE *res = fopen(file_name, mode); - if (res) return res; - if (strchr(mode, 'w') || strchr(mode, 'a')) { - u32 err = GetLastError(); - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Win32] system failure for file opening of %s in mode %s: 0x%08x\n", file_name, mode, err)); - } - return NULL; -#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) - return fopen64(file_name, mode); -#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) - return fopen(file_name, mode); -#else - return fopen(file_name, mode); -#endif -} - -#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE) -#define HAVE_STRERROR_R 1 -#endif - -GF_EXPORT -size_t gf_fwrite(const void *ptr, size_t size, size_t nmemb, - FILE *stream) -{ - size_t result = fwrite(ptr, size, nmemb, stream); - if (result != nmemb) { -#ifdef _WIN32_WCE - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data: %d blocks to write but %d blocks written\n", nmemb, result)); -#else -#if defined WIN32 && !defined(GPAC_CONFIG_WIN32) - errno_t errno_save; - _get_errno(&errno_save); -#else - int errno_save = errno; -#endif - //if (errno_save!=0) - { -#ifdef HAVE_STRERROR_R -#define ERRSTR_BUF_SIZE 256 - char errstr[ERRSTR_BUF_SIZE]; - if(strerror_r(errno_save, errstr, ERRSTR_BUF_SIZE) != 0) - { - strerror_r(0, errstr, ERRSTR_BUF_SIZE); - } -#else - char *errstr = (char*)strerror(errno_save); -#endif - GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, nmemb, result)); - } -#endif - } - return result; -} - - /*seems OK under mingw also*/ #ifdef WIN32 #ifdef _WIN32_WCE @@ -1047,7 +473,7 @@ Bool gf_prompt_has_input() if (ch_peek != -1) return 1; t_new.c_cc[VMIN]=0; tcsetattr(0, TCSANOW, &t_new); - nread = read(0, &ch, 1); + nread = (s32) read(0, &ch, 1); t_new.c_cc[VMIN]=1; tcsetattr(0, TCSANOW, &t_new); if(nread == 1) { @@ -1077,8 +503,6 @@ char gf_prompt_get_char() #endif - - static u32 sys_init = 0; static u32 last_update_time = 0; static u64 last_process_k_u_time = 0; @@ -1249,6 +673,36 @@ void gf_mem_enable_tracker(); static u64 memory_at_gpac_startup = 0; +static u32 gpac_argc = 0; +const char **gpac_argv = NULL; + +GF_EXPORT +void gf_sys_set_args(s32 argc, const char **argv) +{ + //for OSX we allow overwrite of argc/argv due to different behavior between console-mode apps and GUI +#if !defined(__DARWIN__) && !defined(__APPLE__) + if (!gpac_argc && (argc>=0) ) +#endif + { + gpac_argc = (u32) argc; + gpac_argv = argv; + } +} +GF_EXPORT +u32 gf_sys_get_argc() +{ + return gpac_argc; +} + +GF_EXPORT +const char *gf_sys_get_arg(u32 arg) +{ + if (!gpac_argc || !gpac_argv) return NULL; + if (arg>=gpac_argc) return NULL; + return gpac_argv[arg]; +} + + GF_EXPORT void gf_sys_init(Bool enable_memory_tracker) { @@ -1351,7 +805,7 @@ void gf_sys_init(Bool enable_memory_tracker) } } #else - the_rti.nb_cores = sysconf( _SC_NPROCESSORS_ONLN ); + the_rti.nb_cores = (u32) sysconf( _SC_NPROCESSORS_ONLN ); #endif sys_start_time = gf_sys_clock(); @@ -1393,10 +847,6 @@ void gf_sys_close() if (psapi_hinst) FreeLibrary(psapi_hinst); psapi_hinst = NULL; #endif - -#ifdef GPAC_MEMORY_TRACKING - gf_memory_print(); -#endif } } @@ -1417,7 +867,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) #endif MEMORYSTATUS ms; u64 creation, exit, kernel, user, process_k_u_time, proc_idle_time, proc_k_u_time; - u32 nb_threads, entry_time; + u32 entry_time; HANDLE hSnapShot; assert(sys_init); @@ -1425,8 +875,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) if (!rti) return 0; proc_idle_time = proc_k_u_time = process_k_u_time = 0; - nb_threads = 0; - + entry_time = gf_sys_clock(); if (last_update_time && (entry_time - last_update_time < refresh_time_ms)) { memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo)); @@ -1531,7 +980,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) proc_k_u_time += user; if (pentry.th32ProcessID==the_rti.pid) { process_k_u_time = user; - nb_threads = pentry.cntThreads; + //nb_threads = pentry.cntThreads; } } if (procH) CloseHandle(procH); @@ -1819,7 +1268,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) } u_k_time = idle_time = 0; - f = gf_f64_open("/proc/stat", "r"); + f = gf_fopen("/proc/stat", "r"); if (f) { u32 k_time, nice_time, u_time; if (fgets(line, 128, f) != NULL) { @@ -1827,7 +1276,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) u_k_time = u_time + k_time + nice_time; } } - fclose(f); + gf_fclose(f); } process_u_k_time = 0; @@ -1837,7 +1286,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) the complete CPU usage of all therads of the process...*/ #if 0 sprintf(szProc, "/proc/%d/stat", the_rti.pid); - f = gf_f64_open(szProc, "r"); + f = gf_fopen(szProc, "r"); if (f) { fflush(f); if (fgets(line, 2048, f) != NULL) { @@ -1869,12 +1318,12 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] error reading pid/stat\n\n", szProc)); } - fclose(f); + gf_fclose(f); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] cannot open %s\n", szProc)); } sprintf(szProc, "/proc/%d/status", the_rti.pid); - f = gf_f64_open(szProc, "r"); + f = gf_fopen(szProc, "r"); if (f) { while (fgets(line, 1024, f) != NULL) { if (!strnicmp(line, "VmSize:", 7)) { @@ -1882,7 +1331,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) the_rti.process_memory *= 1024; } } - fclose(f); + gf_fclose(f); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] cannot open %s\n", szProc)); } @@ -1890,7 +1339,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) the_rti.physical_memory = the_rti.physical_memory_avail = 0; - f = gf_f64_open("/proc/meminfo", "r"); + f = gf_fopen("/proc/meminfo", "r"); if (f) { while (fgets(line, 1024, f) != NULL) { if (!strnicmp(line, "MemTotal:", 9)) { @@ -1902,7 +1351,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) break; } } - fclose(f); + gf_fclose(f); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] cannot open /proc/meminfo\n")); } @@ -1912,12 +1361,12 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) if (last_update_time) { the_rti.sampling_period_duration = (entry_time - last_update_time); - the_rti.process_cpu_time_diff = (process_u_k_time - last_process_k_u_time) * 10; + the_rti.process_cpu_time_diff = (u32) (process_u_k_time - last_process_k_u_time) * 10; /*oops, we have no choice but to assume 100% cpu usage during this period*/ if (!u_k_time) { the_rti.total_cpu_time_diff = the_rti.sampling_period_duration; - u_k_time = last_cpu_u_k_time + the_rti.sampling_period_duration; + u_k_time = (u32) (last_cpu_u_k_time + the_rti.sampling_period_duration); the_rti.cpu_idle_time = 0; the_rti.total_cpu_usage = 100; if (!the_rti.process_cpu_time_diff) the_rti.process_cpu_time_diff = the_rti.total_cpu_time_diff; @@ -1925,7 +1374,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) } else { u64 samp_sys_time; /*move to ms (/proc/stat gives times in 100 ms unit*/ - the_rti.total_cpu_time_diff = (u_k_time - last_cpu_u_k_time)*10; + the_rti.total_cpu_time_diff = (u32) (u_k_time - last_cpu_u_k_time)*10; /*we're not that accurate....*/ if (the_rti.total_cpu_time_diff > the_rti.sampling_period_duration) @@ -1934,7 +1383,7 @@ Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags) if (!idle_time) idle_time = (the_rti.sampling_period_duration - the_rti.total_cpu_time_diff)/10; samp_sys_time = u_k_time - last_cpu_u_k_time; - the_rti.cpu_idle_time = idle_time - last_cpu_idle_time; + the_rti.cpu_idle_time = (u32) (idle_time - last_cpu_idle_time); the_rti.total_cpu_usage = (u32) ( 100 * samp_sys_time / (the_rti.cpu_idle_time + samp_sys_time ) ); /*move to ms (/proc/stat gives times in 100 ms unit*/ the_rti.cpu_idle_time *= 10; @@ -2225,40 +1674,137 @@ void gf_net_get_ntp(u32 *sec, u32 *frac) struct timeval now; gettimeofday(&now, NULL); *sec = (u32) (now.tv_sec) + GF_NTP_SEC_1900_TO_1970; -// *frac = (u32) ( (now.tv_usec << 12) + (now.tv_usec << 8) - ((now.tv_usec * 3650) >> 6) ); frac_part = now.tv_usec * 0xFFFFFFFFULL; frac_part /= 1000000; *frac = (u32) ( frac_part ); } +GF_EXPORT +u64 gf_net_get_ntp_ts() +{ + u64 res; + u32 sec, frac; + gf_net_get_ntp(&sec, &frac); + res = sec; + res<<= 32; + res |= frac; + return res; +} + +GF_EXPORT +s32 gf_net_get_ntp_diff_ms(u64 ntp) +{ + u32 remote_s, remote_f, local_s, local_f; + s64 diff_s, diff_f; + + remote_s = (ntp >> 32); + remote_f = (u32) (ntp & 0xFFFFFFFFULL); + gf_net_get_ntp(&local_s, &local_f); + diff_s = local_s; + diff_s -= remote_s; + diff_s *= 1000; + diff_f = local_f; + diff_f -= remote_f; + diff_f *= 1000; + diff_f /= 0xFFFFFFFFULL; + diff_s += diff_f; + return (s32) diff_s; +} + + GF_EXPORT s32 gf_net_get_timezone() { -#ifdef GPAC_ANDROID - { - /*FIXME - finad a safe way to estimate timezone this does not work !!*/ - s32 t_timezone; - struct tm t_gmt, t_local; - time_t t_time; - t_time = time(NULL); - t_gmt = *gmtime(&t_time); - t_local = *localtime(&t_time); - - t_timezone = (t_gmt.tm_hour - t_local.tm_hour) * 3600; - return t_timezone; - } -#elif defined(_WIN32_WCE) +#if defined(_WIN32_WCE) return 0; #else - { - s32 val = timezone; - return val; + //this has been commented due to some reports of broken implementation on some systems ... + // s32 val = timezone; + // return val; + + + /*FIXME - avoid errors at midnight when estimating timezone this does not work !!*/ + s32 t_timezone; + struct tm t_gmt, t_local; + time_t t_time; + t_time = time(NULL); + t_gmt = *gmtime(&t_time); + t_local = *localtime(&t_time); + + t_timezone = (t_gmt.tm_hour - t_local.tm_hour) * 3600 + (t_gmt.tm_min - t_local.tm_min) * 60; + return t_timezone; +#endif + +} + +//no mkgmtime on mingw..., use our own +#if (defined(WIN32) && defined(__GNUC__)) + +static Bool leap_year(u32 year) { + year += 1900; + return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) ? GF_TRUE : GF_FALSE; +} +static time_t gf_mktime_utc(struct tm *tm) +{ + static const u32 days_per_month[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + }; + time_t time=0; + int i; + + for (i=70; itm_year; i++) { + time += leap_year(i) ? 366 : 365; } + + for (i=0; itm_mon; ++i) { + time += days_per_month[leap_year(tm->tm_year)][i]; + } + time += tm->tm_mday - 1; + time *= 24; + time += tm->tm_hour; + time *= 60; + time += tm->tm_min; + time *= 60; + time += tm->tm_sec; + return time; +} + +#elif defined(WIN32) +static time_t gf_mktime_utc(struct tm *tm) +{ + return _mkgmtime(tm); +} + +#elif defined(GPAC_ANDROID) +#include +#if defined(__LP64__) +static time_t gf_mktime_utc(struct tm *tm) +{ + return timegm64(tm); +} +#else +static time_t gf_mktime_utc(struct tm *tm) +{ + static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1)); + static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1)); + time64_t result = timegm64(tm); + if (result < kTimeMin || result > kTimeMax) + return -1; + return result; +} #endif +#else + +static time_t gf_mktime_utc(struct tm *tm) +{ + return timegm(tm); } +#endif + GF_EXPORT u64 gf_net_parse_date(const char *val) { @@ -2350,12 +1896,16 @@ u64 gf_net_parse_date(const char *val) else if (!strcmp(szDay, "Sun") || !strcmp(szDay, "Sunday")) t.tm_wday = 6; } -#ifdef GPAC_ANDROID - /* strange issue in Android, we have to indicate DST is not applied in our time struct*/ - t.tm_isdst = -1; -#endif + current_time = gf_mktime_utc(&t); - current_time = mktime(&t) - gf_net_get_timezone(); + if ((s64) current_time == -1) { + //use 1 ms + return 1; + } + if (current_time == 0) { + //use 1 ms + return 1; + } #endif @@ -2369,8 +1919,6 @@ u64 gf_net_parse_date(const char *val) return current_time + ms; } - - GF_EXPORT u64 gf_net_get_utc() { @@ -2378,32 +1926,8 @@ u64 gf_net_get_utc() Double msec; u32 sec, frac; -#ifdef _WIN32_WCE - SYSTEMTIME syst; - FILETIME filet; -#else - time_t gtime; - struct tm _t; -#endif - gf_net_get_ntp(&sec, &frac); - -#ifndef _WIN32_WCE - gtime = sec - GF_NTP_SEC_1900_TO_1970; - _t = * gmtime(>ime); - -#ifdef GPAC_ANDROID - /* strange issue in Android, we have to indicate DST is not applied in our time struct*/ - _t.tm_isdst = -1; -#endif - - current_time = mktime(&_t) - gf_net_get_timezone(); -#else - GetSystemTime(&syst); - SystemTimeToFileTime(&syst, &filet); - current_time = (u64) ((*(LONGLONG *) &filet - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); -#endif - + current_time = sec - GF_NTP_SEC_1900_TO_1970; current_time *= 1000; msec = frac*1000.0; msec /= 0xFFFFFFFF; diff --git a/src/utils/os_file.c b/src/utils/os_file.c new file mode 100644 index 0000000..0be9c1c --- /dev/null +++ b/src/utils/os_file.c @@ -0,0 +1,681 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre - Copyright (c) Telecom ParisTech 2000-2012 + * Romain Bouqueau - Copyright (c) Romain Bouqueau 2015 + * All rights reserved + * + * This file is part of GPAC / common tools sub-project + * + * 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 + +#if defined(_WIN32_WCE) + +#include +#include + +#elif defined(WIN32) + +#include +#include +#include + +#else + +#include +#include +#include +#include +#include + +#ifndef __BEOS__ +#include +#endif + +#endif + + +GF_Err gf_rmdir(char *DirPathName) +{ +#if defined (_WIN32_WCE) + TCHAR swzName[MAX_PATH]; + BOOL res; + CE_CharToWide(DirPathName, swzName); + res = RemoveDirectory(swzName); + if (! res) { + int err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete director %s: last error %d\n", DirPathName, err )); + } +#elif defined (WIN32) + int res = rmdir(DirPathName); + if (res==-1) { + int err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete director %s: last error %d\n", DirPathName, err )); + return GF_IO_ERR; + } +#else + int res = rmdir(DirPathName); + if (res==-1) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete director %s: last error %d\n", DirPathName, errno )); + return GF_IO_ERR; + } +#endif + return GF_OK; +} + +GF_EXPORT +GF_Err gf_mkdir(char* DirPathName) +{ +#if defined (_WIN32_WCE) + TCHAR swzName[MAX_PATH]; + BOOL res; + CE_CharToWide(DirPathName, swzName); + res = CreateDirectory(swzName, NULL); + if (! res) { + int err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err )); + } +#elif defined (WIN32) + int res = mkdir(DirPathName); + if (res==-1) { + int err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err )); + } +#else + int res = mkdir(DirPathName, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (res==-1) { + if(errno == 17) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s, it already exists: last error %d \n", DirPathName, errno )); + return GF_BAD_PARAM; + } else { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, errno )); + return GF_IO_ERR; + } + } +#endif + return GF_OK; +} + + +GF_EXPORT +Bool gf_dir_exists(char* DirPathName) +{ +#if defined (_WIN32_WCE) + TCHAR swzName[MAX_PATH]; + BOOL res; + DWORD att; + CE_CharToWide(DirPathName, swzName); + att = GetFileAttributes(swzName); + return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE; +#elif defined (WIN32) + DWORD att = GetFileAttributes(DirPathName); + return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE; +#else + DIR* dir = opendir(DirPathName); + if (!dir) return GF_FALSE; + closedir(dir); + return GF_TRUE; +#endif + return GF_FALSE; +} +static Bool delete_dir(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) +{ + Bool directory_clean_mode = *(Bool*)cbck; + + if(directory_clean_mode) { + gf_cleanup_dir(item_path); + gf_rmdir(item_path); + } else { + gf_delete_file(item_path); + } + return 0; +} + +GF_Err gf_cleanup_dir(char* DirPathName) +{ + Bool directory_clean_mode; + + directory_clean_mode = 1; + gf_enum_directory(DirPathName, 1, delete_dir, &directory_clean_mode, NULL); + directory_clean_mode = 0; + gf_enum_directory(DirPathName, 0, delete_dir, &directory_clean_mode, NULL); + + return GF_OK; +} + +GF_EXPORT +GF_Err gf_delete_file(const char *fileName) +{ +#if defined(_WIN32_WCE) + TCHAR swzName[MAX_PATH]; + CE_CharToWide((char*)fileName, swzName); + return (DeleteFile(swzName)==0) ? GF_IO_ERR : GF_OK; +#elif defined(WIN32) + /* success if != 0 */ + return (DeleteFile(fileName)==0) ? GF_IO_ERR : GF_OK; +#else + /* success is == 0 */ + return ( remove(fileName) == 0) ? GF_OK : GF_IO_ERR; +#endif +} + +#ifndef WIN32 +/** + * Remove existing single-quote from a single-quoted string. + * The caller is responsible for deallocating the returns string with gf_free() + */ +static char* gf_sanetize_single_quoted_string(const char *src) { + int i, j; + char *out = gf_malloc(4*strlen(src)+3); + out[0] = '\''; + for (i=0, j=1; (out[j]=src[i]); ++i, ++j) { + if (src[i]=='\'') { + out[++j]='\\'; + out[++j]='\''; + out[++j]='\''; + } + } + out[j++] = '\''; + out[j++] = 0; + return out; +} +#endif + +GF_EXPORT +GF_Err gf_move_file(const char *fileName, const char *newFileName) +{ +#if defined(_WIN32_WCE) + TCHAR swzName[MAX_PATH]; + TCHAR swzNewName[MAX_PATH]; + CE_CharToWide((char*)fileName, swzName); + CE_CharToWide((char*)newFileName, swzNewName); + return (MoveFile(swzName, swzNewName) == 0 ) ? GF_IO_ERR : GF_OK; +#elif defined(WIN32) + /* success if != 0 */ + return (MoveFile(fileName, newFileName) == 0 ) ? GF_IO_ERR : GF_OK; +#else + GF_Err e = GF_IO_ERR; + char cmd[1024], *arg1, *arg2; + if (!fileName || !newFileName) + return GF_IO_ERR; + arg1 = gf_sanetize_single_quoted_string(fileName); + arg2 = gf_sanetize_single_quoted_string(newFileName); + if (snprintf(cmd, sizeof cmd, "mv %s %s", arg1, arg2) >= sizeof cmd) goto error; + e = (system(cmd) == 0) ? GF_OK : GF_IO_ERR; +error: + gf_free(arg1); + gf_free(arg2); + return e; +#endif +} + +GF_EXPORT +u64 gf_file_modification_time(const char *filename) +{ +#if defined(_WIN32_WCE) + WCHAR _file[GF_MAX_PATH]; + WIN32_FIND_DATA FindData; + HANDLE fh; + ULARGE_INTEGER uli; + ULONGLONG time_ms; + BOOL ret; + CE_CharToWide((char *) filename, _file); + fh = FindFirstFile(_file, &FindData); + if (fh == INVALID_HANDLE_VALUE) return 0; + uli.LowPart = FindData.ftLastWriteTime.dwLowDateTime; + uli.HighPart = FindData.ftLastWriteTime.dwHighDateTime; + ret = FindClose(fh); + if (!ret) { + DWORD err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_file_modification_time() returned the following error code: %d\n", err)); + } + time_ms = uli.QuadPart/10000; + return time_ms; +#elif defined(WIN32) && !defined(__GNUC__) + struct _stat64 sb; + if (_stat64(filename, &sb) != 0) return 0; + return sb.st_mtime; +#else + struct stat sb; + if (stat(filename, &sb) != 0) return 0; + return sb.st_mtime; +#endif + return 0; +} + +static u32 gpac_file_handles = 0; +GF_EXPORT +u32 gf_file_handles_count() +{ + return gpac_file_handles; +} + +GF_EXPORT +FILE *gf_temp_file_new() +{ + FILE *res=NULL; +#if defined(_WIN32_WCE) + TCHAR pPath[MAX_PATH+1]; + TCHAR pTemp[MAX_PATH+1]; + if (!GetTempPath(MAX_PATH, pPath)) { + pPath[0] = '.'; + pPath[1] = '.'; + } + if (GetTempFileName(pPath, TEXT("git"), 0, pTemp)) + res = _wfopen(pTemp, TEXT("w+b")); +#elif defined(WIN32) + char tmp[MAX_PATH]; + res = tmpfile(); + if (!res) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Win32] system failure for tmpfile(): 0x%08x\n", GetLastError())); + + /*tmpfile() may fail under vista ...*/ + if (GetEnvironmentVariable("TEMP",tmp,MAX_PATH)) { + char tmp2[MAX_PATH], *t_file; + gf_rand_init(GF_FALSE); + sprintf(tmp2, "gpac_%08x_", gf_rand()); + t_file = tempnam(tmp, tmp2); + res = gf_fopen(t_file, "w+b"); + free(t_file); + } + } +#else + res = tmpfile(); +#endif + + if (res) { + gpac_file_handles++; + } + return res; +} + +/*enumerate directories*/ +GF_EXPORT +GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter) +{ + char item_path[GF_MAX_PATH]; + GF_FileEnumInfo file_info; + +#if defined(_WIN32_WCE) + char _path[GF_MAX_PATH]; + unsigned short path[GF_MAX_PATH]; + unsigned short w_filter[GF_MAX_PATH]; + char file[GF_MAX_PATH]; +#else + char path[GF_MAX_PATH], *file; +#endif + +#ifdef WIN32 + WIN32_FIND_DATA FindData; + HANDLE SearchH; +#else + DIR *the_dir; + struct dirent* the_file; + struct stat st; +#endif + + if (!dir || !enum_dir_fct) return GF_BAD_PARAM; + + if (filter && (!strcmp(filter, "*") || !filter[0])) filter=NULL; + + memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); + + if (!strcmp(dir, "/")) { +#if defined(WIN32) && !defined(_WIN32_WCE) + u32 len; + char *drives, *volume; + len = GetLogicalDriveStrings(0, NULL); + drives = gf_malloc(sizeof(char)*(len+1)); + drives[0]=0; + GetLogicalDriveStrings(len, drives); + len = (u32) strlen(drives); + volume = drives; + file_info.directory = GF_TRUE; + file_info.drive = GF_TRUE; + while (len) { + enum_dir_fct(cbck, volume, "", &file_info); + volume += len+1; + len = (u32) strlen(volume); + } + gf_free(drives); + return GF_OK; +#elif defined(__SYMBIAN32__) + RFs iFs; + TDriveList aList; + iFs.Connect(); + iFs.DriveList(aList); + for (TInt i=0; id_name, "..")) goto next; + if (the_file->d_name[0] == '.') goto next; +#endif + +#ifdef WIN32 + file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE; + if (!enum_directory && file_info.directory) goto next; + if (enum_directory && !file_info.directory) goto next; +#endif + + if (filter) { +#if defined (_WIN32_WCE) + short ext[30]; + short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.'); + if (!sep) goto next; + wcscpy(ext, sep+1); + wcslwr(ext); + if (!wcsstr(w_filter, ext)) goto next; +#elif defined(WIN32) + char ext[30]; + char *sep = strrchr(FindData.cFileName, '.'); + if (!sep) goto next; + strcpy(ext, sep+1); + strlwr(ext); + if (!strstr(filter, ext)) goto next; +#else + char ext[30]; + char *sep = strrchr(the_file->d_name, '.'); + if (!sep) goto next; + strcpy(ext, sep+1); + strlwr(ext); + if (!strstr(filter, sep+1)) goto next; +#endif + } + +#if defined(WIN32) + file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? 1 : 0; + file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? 1 : 0; + file_info.size = MAXDWORD; + file_info.size += 1; + file_info.size *= FindData.nFileSizeHigh; + file_info.size += FindData.nFileSizeLow; + file_info.last_modified = (u64) ((*(LONGLONG *) &FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); +#endif + +#if defined (_WIN32_WCE) + CE_WideToChar(FindData.cFileName, file); + strcpy(item_path, _path); + strcat(item_path, file); +#elif defined(WIN32) + strcpy(item_path, path); + strcat(item_path, FindData.cFileName); + file = FindData.cFileName; +#else + strcpy(item_path, path); + strcat(item_path, the_file->d_name); + GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file %s for enum\n", item_path)); + + if (stat( item_path, &st ) != 0) goto next; + + file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE; + if (enum_directory && !file_info.directory) goto next; + if (!enum_directory && file_info.directory) goto next; + + file_info.size = st.st_size; + + { + struct tm _t = * gmtime(& st.st_mtime); + file_info.last_modified = mktime(&_t); + } + file = the_file->d_name; + if (file && file[0]=='.') file_info.hidden = 1; + + if (file_info.directory) { + char * parent_name = strrchr(item_path, '/'); + if (!parent_name) { + file_info.drive = GF_TRUE; + } else { + struct stat st_parent; + parent_name[0] = 0; + if (stat(item_path, &st_parent) == 0) { + if ((st.st_dev != st_parent.st_dev) || ((st.st_dev == st_parent.st_dev) && (st.st_ino == st_parent.st_ino))) { + file_info.drive = GF_TRUE; + } + } + parent_name[0] = '/'; + } + } +#endif + if (enum_dir_fct(cbck, file, item_path, &file_info)) { +#ifdef WIN32 + BOOL ret = FindClose(SearchH); + if (!ret) { + DWORD err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err)); + } +#endif + break; + } + +next: +#ifdef WIN32 + if (!FindNextFile(SearchH, &FindData)) { + BOOL ret = FindClose(SearchH); + if (!ret) { + DWORD err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err)); + } + break; + } +#else + the_file = readdir(the_dir); +#endif + } +#ifndef WIN32 + closedir(the_dir); +#endif + return GF_OK; +} + +GF_EXPORT +u64 gf_ftell(FILE *fp) +{ +#if defined(_WIN32_WCE) + return (u64) ftell(fp); +#elif defined(GPAC_CONFIG_WIN32) /* mingw or cygwin */ +#if (_FILE_OFFSET_BITS >= 64) + return (u64) ftello64(fp); +#else + return (u64) ftell(fp); +#endif +#elif defined(WIN32) + return (u64) _ftelli64(fp); +#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) + return (u64) ftello64(fp); +#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) + return (u64) ftello(fp); +#else + return (u64) ftell(fp); +#endif +} + +GF_EXPORT +u64 gf_fseek(FILE *fp, s64 offset, s32 whence) +{ +#if defined(_WIN32_WCE) + return (u64) fseek(fp, (s32) offset, whence); +#elif defined(GPAC_CONFIG_WIN32) /* mingw or cygwin */ +#if (_FILE_OFFSET_BITS >= 64) + return (u64) fseeko64(fp, offset, whence); +#else + return (u64) fseek(fp, (s32) offset, whence); +#endif +#elif defined(WIN32) + return (u64) _fseeki64(fp, offset, whence); +#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) + return fseeko64(fp, (off64_t) offset, whence); +#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) + return fseeko(fp, (off_t) offset, whence); +#else + return fseek(fp, (s32) offset, whence); +#endif +} + +GF_EXPORT +FILE *gf_fopen(const char *file_name, const char *mode) +{ + FILE *res; + +#if defined(WIN32) + res = fopen(file_name, mode); +#elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) + res = fopen64(file_name, mode); +#elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) + res = fopen(file_name, mode); +#else + res = fopen(file_name, mode); +#endif + + if (res) { + gpac_file_handles ++; + } else { + if (strchr(mode, 'w') || strchr(mode, 'a')) { +#if defined(WIN32) + u32 err = GetLastError(); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: 0x%08x\n", file_name, mode, err)); +#else + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: %d\n", file_name, mode, errno)); +#endif + } + } + return res; +} + +GF_EXPORT +s32 gf_fclose(FILE *file) +{ + if (file) { + assert(gpac_file_handles); + gpac_file_handles--; + } + return fclose(file); +} + +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE) && !defined(WIN32) +#define HAVE_STRERROR_R 1 +#endif + +GF_EXPORT +size_t gf_fwrite(const void *ptr, size_t size, size_t nmemb, + FILE *stream) +{ + size_t result = fwrite(ptr, size, nmemb, stream); + if (result != nmemb) { +#ifdef _WIN32_WCE + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data: %d blocks to write but %d blocks written\n", nmemb, result)); +#else +#if defined WIN32 && !defined(GPAC_CONFIG_WIN32) + errno_t errno_save; + _get_errno(&errno_save); +#else + int errno_save = errno; +#endif + //if (errno_save!=0) + { +#ifdef HAVE_STRERROR_R +#define ERRSTR_BUF_SIZE 256 + char errstr[ERRSTR_BUF_SIZE]; + if(strerror_r(errno_save, errstr, ERRSTR_BUF_SIZE) != 0) + { + strerror_r(0, errstr, ERRSTR_BUF_SIZE); + } +#else + char *errstr = (char*)strerror(errno_save); +#endif + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, nmemb, result)); + } +#endif + } + return result; +} + diff --git a/src/utils/os_net.c b/src/utils/os_net.c index b9a5b96..ccc951a 100644 --- a/src/utils/os_net.c +++ b/src/utils/os_net.c @@ -240,10 +240,10 @@ GF_EXPORT Bool gf_net_is_ipv6(const char *address) { char *sep; - if (!address) return 0; + if (!address) return GF_FALSE; sep = strchr(address, ':'); if (sep) sep = strchr(address, ':'); - return sep ? 1 : 0; + return sep ? GF_TRUE : GF_FALSE; } #ifdef GPAC_HAS_IPV6 @@ -289,11 +289,11 @@ static struct addrinfo *gf_sk_get_ipv6_addr(const char *PeerName, u16 PortNumber static Bool gf_sk_ipv6_set_remote_address(GF_Socket *sock, const char *address, u16 PortNumber) { struct addrinfo *res = gf_sk_get_ipv6_addr(address, PortNumber, AF_UNSPEC, 0, (sock->flags & GF_SOCK_IS_TCP) ? SOCK_STREAM : SOCK_DGRAM); - if (!res) return 0; + if (!res) return GF_FALSE; memcpy(&sock->dest_addr, res->ai_addr, res->ai_addrlen); sock->dest_addr_len = (u32) res->ai_addrlen; freeaddrinfo(res); - return 1; + return GF_TRUE; } #endif @@ -379,9 +379,9 @@ GF_Err gf_sk_set_buffer_size(GF_Socket *sock, Bool SendBuffer, u32 NewSize) res = setsockopt(sock->socket, SOL_SOCKET, SO_RCVBUF, (char *) &NewSize, sizeof(u32) ); } if (res<0) { - GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[Core] Couldn't set socket %s buffer size: %d\n", SendBuffer ? "send" : "receive", res)); + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[Socket] Couldn't set socket %s buffer size to %d: %d\n", SendBuffer ? "send" : "receive", NewSize, res)); } else { - GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[Core] Set socket %s buffer size\n", SendBuffer ? "send" : "receive")); + GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[Socket] Set socket %s buffer size to %d\n", SendBuffer ? "send" : "receive", NewSize)); } return GF_OK; } @@ -443,7 +443,7 @@ static void gf_sk_free(GF_Socket *sock) /*if MobileIP socket, unregister it*/ if (sock->flags & GF_SOCK_IS_MIP) { sock->flags &= ~GF_SOCK_IS_MIP; - gf_net_mobileip_ctrl(0); + gf_net_mobileip_ctrl(GF_FALSE); } } @@ -483,12 +483,14 @@ GF_Err gf_sk_connect(GF_Socket *sock, const char *PeerName, u16 PortNumber, cons gf_sk_free(sock); + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV6] Solving %s address\n", PeerName)); res = gf_sk_get_ipv6_addr(PeerName, PortNumber, AF_UNSPEC, AI_PASSIVE, type); if (!res) return GF_IP_CONNECTION_FAILURE; + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV6] Host %s found\n", PeerName)); /*turn on MobileIP*/ if (local_ip && MobileIPAdd && !strcmp(MobileIPAdd, local_ip) ) { - if (gf_net_mobileip_ctrl(1)==GF_OK) { + if (gf_net_mobileip_ctrl(GF_TRUE)==GF_OK) { sock->flags |= GF_SOCK_IS_MIP; } else { local_ip = NULL; @@ -512,7 +514,7 @@ GF_Err gf_sk_connect(GF_Socket *sock, const char *PeerName, u16 PortNumber, cons sock->socket = NULL_SOCKET; continue; } - if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, 1); + if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, GF_TRUE); if (aip->ai_family==PF_INET6) sock->flags |= GF_SOCK_IS_IPV6; else sock->flags &= ~GF_SOCK_IS_IPV6; @@ -525,12 +527,14 @@ GF_Err gf_sk_connect(GF_Socket *sock, const char *PeerName, u16 PortNumber, cons } } + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV6] Connecting to %s:%d\n", PeerName, PortNumber)); ret = connect(sock->socket, aip->ai_addr, (int) aip->ai_addrlen); if (ret == SOCKET_ERROR) { closesocket(sock->socket); sock->socket = NULL_SOCKET; continue; } + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV6] Connected to %s:%d\n", PeerName, PortNumber)); memcpy(&sock->dest_addr, aip->ai_addr, aip->ai_addrlen); sock->dest_addr_len = (u32) aip->ai_addrlen; @@ -562,6 +566,7 @@ GF_Err gf_sk_connect(GF_Socket *sock, const char *PeerName, u16 PortNumber, cons /*get the server IP*/ sock->dest_addr.sin_addr.s_addr = inet_addr(PeerName); if (sock->dest_addr.sin_addr.s_addr==INADDR_NONE) { + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV4] Solving %s address\n", PeerName)); Host = gethostbyname(PeerName); if (Host == NULL) { switch (LASTSOCKERROR) { @@ -574,14 +579,16 @@ GF_Err gf_sk_connect(GF_Socket *sock, const char *PeerName, u16 PortNumber, cons return GF_IP_NETWORK_FAILURE; } } + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV4] Host %s found\n", PeerName)); memcpy((char *) &sock->dest_addr.sin_addr, Host->h_addr_list[0], sizeof(u32)); } if (sock->flags & GF_SOCK_IS_TCP) { + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV4] Connecting to %s:%d\n", PeerName, PortNumber)); ret = connect(sock->socket, (struct sockaddr *) &sock->dest_addr, sizeof(struct sockaddr)); if (ret == SOCKET_ERROR) { u32 res = LASTSOCKERROR; - GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[Core] Couldn't connect socket - last sock error %d\n", res)); + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[Sock_IPV4] Couldn't connect socket - last sock error %d\n", res)); switch (res) { case EAGAIN: return GF_IP_SOCK_WOULD_BLOCK; @@ -606,6 +613,7 @@ GF_Err gf_sk_connect(GF_Socket *sock, const char *PeerName, u16 PortNumber, cons return GF_IP_CONNECTION_FAILURE; } } + GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[Sock_IPV4] Connected to %s:%d\n", PeerName, PortNumber)); } #endif return GF_OK; @@ -667,7 +675,7 @@ GF_Err gf_sk_bind(GF_Socket *sock, const char *local_ip, u16 port, const char *p /*turn on MobileIP*/ if (local_ip && MobileIPAdd && !strcmp(MobileIPAdd, local_ip) ) { - if (gf_net_mobileip_ctrl(1)==GF_OK) { + if (gf_net_mobileip_ctrl(GF_TRUE)==GF_OK) { sock->flags |= GF_SOCK_IS_MIP; } else { res = gf_sk_get_ipv6_addr(NULL, port, af, AI_PASSIVE, type); @@ -706,7 +714,7 @@ GF_Err gf_sk_bind(GF_Socket *sock, const char *local_ip, u16 port, const char *p #endif } - if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, 1); + if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, GF_TRUE); if (peer_name && peer_port) sock->flags |= GF_SOCK_HAS_PEER; @@ -858,9 +866,9 @@ GF_Err gf_sk_send(GF_Socket *sock, const char *buffer, u32 length) count = 0; while (count < length) { if (sock->flags & GF_SOCK_HAS_PEER) { - res = sendto(sock->socket, (char *) buffer+count, length - count, 0, (struct sockaddr *) &sock->dest_addr, sock->dest_addr_len); + res = (s32) sendto(sock->socket, (char *) buffer+count, length - count, 0, (struct sockaddr *) &sock->dest_addr, sock->dest_addr_len); } else { - res = send(sock->socket, (char *) buffer+count, length - count, 0); + res = (s32) send(sock->socket, (char *) buffer+count, length - count, 0); } if (res == SOCKET_ERROR) { switch (res = LASTSOCKERROR) { @@ -920,7 +928,7 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi #ifdef GPAC_HAS_IPV6 struct sockaddr *addr; struct addrinfo *res, *aip; - Bool is_ipv6 = 0; + Bool is_ipv6 = GF_FALSE; u32 type; #endif unsigned long local_add_id; @@ -934,7 +942,7 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi /*turn on MobileIP*/ if (local_interface_ip && MobileIPAdd && !strcmp(MobileIPAdd, local_interface_ip) ) { - if (gf_net_mobileip_ctrl(1)==GF_OK) { + if (gf_net_mobileip_ctrl(GF_TRUE)==GF_OK) { sock->flags |= GF_SOCK_IS_MIP; } else { local_interface_ip = NULL; @@ -943,7 +951,7 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi #ifdef GPAC_HAS_IPV6 - is_ipv6 = gf_net_is_ipv6(multi_IPAdd) || gf_net_is_ipv6(local_interface_ip) ? 1 : 0; + is_ipv6 = gf_net_is_ipv6(multi_IPAdd) || gf_net_is_ipv6(local_interface_ip) ? GF_TRUE : GF_FALSE; type = (sock->flags & GF_SOCK_IS_TCP) ? SOCK_STREAM : SOCK_DGRAM; if (is_ipv6) { @@ -977,7 +985,7 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi #endif /*TODO: copy over other properties (recption buffer size & co)*/ - if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, 1); + if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, GF_TRUE); memcpy(&sock->dest_addr, aip->ai_addr, aip->ai_addrlen); sock->dest_addr_len = (u32) aip->ai_addrlen; @@ -1025,11 +1033,13 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi /*set TTL*/ ret = setsockopt(sock->socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &TTL, sizeof(TTL)); if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; - /*Disable loopback*/ + /*enable loopback*/ flag = 1; ret = setsockopt(sock->socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &flag, sizeof(flag)); - if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; - + if (ret == SOCKET_ERROR) { + GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[Socket] Cannot disale multicast loop: error %d\n", LASTSOCKERROR)); + } + ret = setsockopt(sock->socket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &M_reqV6, sizeof(M_reqV6)); if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; } @@ -1040,7 +1050,7 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi //IPv4 setup sock->socket = socket(AF_INET, (sock->flags & GF_SOCK_IS_TCP) ? SOCK_STREAM : SOCK_DGRAM, 0); - if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, 1); + if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, GF_TRUE); sock->flags &= ~GF_SOCK_IS_IPV6; /*enable address reuse*/ @@ -1050,15 +1060,16 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi optval = 1; setsockopt(sock->socket, SOL_SOCKET, SO_REUSEPORT, SSO_CAST &optval, sizeof(optval)); #endif - + if (local_interface_ip) local_add_id = inet_addr(local_interface_ip); else local_add_id = htonl(INADDR_ANY); - - if (!NoBind) { + + if (!NoBind) { struct sockaddr_in local_address; - + + memset(&local_address, 0, sizeof(struct sockaddr_in )); local_address.sin_family = AF_INET; - local_address.sin_addr.s_addr = local_add_id; + local_address.sin_addr.s_addr = (u32) local_add_id; local_address.sin_port = htons( MultiPortNumber); ret = bind(sock->socket, (struct sockaddr *) &local_address, sizeof(local_address)); @@ -1071,27 +1082,32 @@ GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 Multi } /*setup local interface*/ if (local_interface_ip) { - ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_IF, (char *) &local_add_id, sizeof(local_add_id)); + ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_IF, (char *) &local_add_id, sizeof(local_add_id)); if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; } } /*now join the multicast*/ M_req.imr_multiaddr.s_addr = inet_addr(multi_IPAdd); - M_req.imr_interface.s_addr = local_add_id; - + M_req.imr_interface.s_addr = (u32) local_add_id; + ret = setsockopt(sock->socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &M_req, sizeof(M_req)); if (ret == SOCKET_ERROR) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[core] cannot join multicast: error %d\n", LASTSOCKERROR)); return GF_IP_CONNECTION_FAILURE; } /*set the Time To Live*/ - ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&TTL, sizeof(TTL)); - if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; - /*Disable loopback*/ + if (TTL) { + ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&TTL, sizeof(TTL)); + if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; + } + + /*enable loopback*/ flag = 1; ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &flag, sizeof(flag)); -// if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE; + if (ret == SOCKET_ERROR) { + GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[Socket] Cannot disale multicast loop: error %d\n", LASTSOCKERROR)); + } #ifdef GPAC_HAS_IPV6 ((struct sockaddr_in *) &sock->dest_addr)->sin_family = AF_INET; @@ -1158,28 +1174,34 @@ GF_Err gf_sk_receive(GF_Socket *sock, char *buffer, u32 length, u32 startFrom, u } #endif if (sock->flags & GF_SOCK_HAS_PEER) - res = recvfrom(sock->socket, (char *) buffer + startFrom, length - startFrom, 0, (struct sockaddr *)&sock->dest_addr, &sock->dest_addr_len); + res = (s32) recvfrom(sock->socket, (char *) buffer + startFrom, length - startFrom, 0, (struct sockaddr *)&sock->dest_addr, &sock->dest_addr_len); else { - res = recv(sock->socket, (char *) buffer + startFrom, length - startFrom, 0); + res = (s32) recv(sock->socket, (char *) buffer + startFrom, length - startFrom, 0); if (res == 0) return GF_IP_CONNECTION_CLOSED; } if (res == SOCKET_ERROR) { res = LASTSOCKERROR; - GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[socket] error reading - socket error %d\n", res)); switch (res) { case EAGAIN: return GF_IP_SOCK_WOULD_BLOCK; #ifndef __SYMBIAN32__ case EMSGSIZE: + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[socket] error reading - socket error %d\n", res)); return GF_OUT_OF_MEM; case ENOTCONN: + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[socket] error reading - not connected\n")); + return GF_IP_CONNECTION_CLOSED; case ECONNRESET: + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[socket] error reading - connection reset\n")); + return GF_IP_CONNECTION_CLOSED; case ECONNABORTED: + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[socket] error reading - connection aborted\n")); return GF_IP_CONNECTION_CLOSED; #endif default: + GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[socket] error reading - socket error %d\n", res)); return GF_IP_NETWORK_FAILURE; } } @@ -1416,7 +1438,7 @@ GF_Err gf_sk_send_to(GF_Socket *sock, const char *buffer, u32 length, char *remo #endif count = 0; while (count < length) { - res = sendto(sock->socket, (char *) buffer+count, length - count, 0, (struct sockaddr *) &remote_add, remote_add_len); + res = (s32) sendto(sock->socket, (char *) buffer+count, length - count, 0, (struct sockaddr *) &remote_add, remote_add_len); if (res == SOCKET_ERROR) { switch (LASTSOCKERROR) { case EAGAIN: @@ -1469,7 +1491,7 @@ GF_Err gf_sk_receive_wait(GF_Socket *sock, char *buffer, u32 length, u32 startFr #endif - res = recv(sock->socket, (char *) buffer + startFrom, length - startFrom, 0); + res = (s32) recv(sock->socket, (char *) buffer + startFrom, length - startFrom, 0); if (res == SOCKET_ERROR) { switch (LASTSOCKERROR) { case EAGAIN: @@ -1523,7 +1545,7 @@ GF_Err gf_sk_send_wait(GF_Socket *sock, const char *buffer, u32 length, u32 Seco //direct writing count = 0; while (count < length) { - res = send(sock->socket, (char *) buffer+count, length - count, 0); + res = (s32) send(sock->socket, (char *) buffer+count, length - count, 0); if (res == SOCKET_ERROR) { switch (LASTSOCKERROR) { case EAGAIN: @@ -1541,5 +1563,30 @@ GF_Err gf_sk_send_wait(GF_Socket *sock, const char *buffer, u32 length, u32 Seco return GF_OK; } +GF_EXPORT +u32 gf_htonl(u32 val) +{ + return htonl(val); +} + + +GF_EXPORT +u32 gf_ntohl(u32 val) +{ + return htonl(val); +} + +GF_EXPORT +u16 gf_htons(u16 val) +{ + return htons(val); +} + + +GF_EXPORT +u16 gf_tohs(u16 val) +{ + return htons(val); +} #endif /*GPAC_DISABLE_CORE_TOOLS*/ diff --git a/src/utils/os_thread.c b/src/utils/os_thread.c index 6b054f7..24737d7 100644 --- a/src/utils/os_thread.c +++ b/src/utils/os_thread.c @@ -97,7 +97,7 @@ static const char *log_th_name(u32 id) if (!id) id = gf_th_id(); count = gf_list_count(thread_bank); for (i=0; iid == id) return t->log_name; } return "Main Process"; @@ -109,7 +109,7 @@ static const char *log_th_name(u32 id) GF_EXPORT GF_Thread *gf_th_new(const char *name) { - GF_Thread *tmp = gf_malloc(sizeof(GF_Thread)); + GF_Thread *tmp = (GF_Thread*)gf_malloc(sizeof(GF_Thread)); memset(tmp, 0, sizeof(GF_Thread)); tmp->status = GF_THREAD_STATUS_STOP; @@ -185,7 +185,7 @@ void * RunThread(void *ptr) #endif /* Each thread has its own seed */ - gf_rand_init(0); + gf_rand_init(GF_FALSE); /* Run our thread */ ret = t->Run(t->args); @@ -290,7 +290,7 @@ void Thread_Stop(GF_Thread *t, Bool Destroy) } #else if (Destroy) { -#ifdef GPAC_ANDROID +#if defined(GPAC_ANDROID) || defined(PTHREAD_HAS_NO_CANCEL) if (pthread_kill(t->threadH, SIGQUIT)) #else if (pthread_cancel(t->threadH)) @@ -310,13 +310,13 @@ void Thread_Stop(GF_Thread *t, Bool Destroy) GF_EXPORT void gf_th_stop(GF_Thread *t) { - Thread_Stop(t, 0); + Thread_Stop(t, GF_FALSE); } GF_EXPORT void gf_th_del(GF_Thread *t) { - Thread_Stop(t, 0); + Thread_Stop(t, GF_FALSE); #ifdef WIN32 // if (t->threadH) CloseHandle(t->threadH); #else @@ -436,7 +436,7 @@ GF_Mutex *gf_mx_new(const char *name) #ifndef WIN32 pthread_mutexattr_t attr; #endif - GF_Mutex *tmp = gf_malloc(sizeof(GF_Mutex)); + GF_Mutex *tmp = (GF_Mutex*)gf_malloc(sizeof(GF_Mutex)); if (!tmp) return NULL; memset(tmp, 0, sizeof(GF_Mutex)); @@ -583,11 +583,11 @@ GF_EXPORT Bool gf_mx_try_lock(GF_Mutex *mx) { u32 caller; - if (!mx) return 0; + if (!mx) return GF_FALSE; caller = gf_th_id(); if (caller == mx->Holder) { mx->HolderCount += 1; - return 1; + return GF_TRUE; } #ifdef WIN32 @@ -598,24 +598,24 @@ Bool gf_mx_try_lock(GF_Mutex *mx) case WAIT_ABANDONED: case WAIT_TIMEOUT: GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Couldn't be locked by thread %s (grabbed by thread %s)\n", mx->log_name, gf_sys_clock(), log_th_name(caller), log_th_name(mx->Holder) )); - return 0; + return GF_FALSE; case WAIT_FAILED: GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex %s] At %d WaitForSingleObject failed\n", mx->log_name, gf_sys_clock())); - return 0; + return GF_FALSE; default: assert(0); - return 0; + return GF_FALSE; } #else if (pthread_mutex_trylock(&mx->hMutex) != 0 ) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Couldn't release it for thread %s (grabbed by thread %s)\n", mx->log_name, gf_sys_clock(), log_th_name(caller), log_th_name(mx->Holder) )); - return 0; + return GF_FALSE; } #endif mx->Holder = caller; mx->HolderCount = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Grabbed by thread %s\n", mx->log_name, gf_sys_clock(), log_th_name(mx->Holder) )); - return 1; + return GF_TRUE; } @@ -638,7 +638,7 @@ struct __tag_semaphore GF_EXPORT GF_Semaphore *gf_sema_new(u32 MaxCount, u32 InitCount) { - GF_Semaphore *tmp = gf_malloc(sizeof(GF_Semaphore)); + GF_Semaphore *tmp = (GF_Semaphore*)gf_malloc(sizeof(GF_Semaphore)); if (!tmp) { GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("Couldn't allocate semaphore\n")); return NULL; @@ -691,7 +691,8 @@ void gf_sema_del(GF_Semaphore *sm) #ifdef GPAC_IPHONE sem_close(sm->hSemaphore); #else - sem_destroy(sm->hSemaphore); + sem_close(sm->hSemaphore); +// sem_destroy(sm->hSemaphore); #endif gf_free(sm->SemName); #else @@ -701,14 +702,15 @@ void gf_sema_del(GF_Semaphore *sm) } GF_EXPORT -u32 gf_sema_notify(GF_Semaphore *sm, u32 NbRelease) +Bool gf_sema_notify(GF_Semaphore *sm, u32 NbRelease) { - u32 prevCount; #ifndef WIN32 sem_t *hSem; +#else + u32 prevCount; #endif - if (!sm) return 0; + if (!sm) return GF_FALSE; #if defined(WIN32) ReleaseSemaphore(sm->hSemaphore, NbRelease, (LPLONG) &prevCount); @@ -719,13 +721,13 @@ u32 gf_sema_notify(GF_Semaphore *sm, u32 NbRelease) #else hSem = sm->hSemaphore; #endif - sem_getvalue(hSem, (s32 *) &prevCount); - while (NbRelease) { - if (sem_post(hSem) < 0) return 0; + + while (NbRelease) { + if (sem_post(hSem) < 0) return GF_FALSE; NbRelease -= 1; } #endif - return (u32) prevCount; + return GF_TRUE; } GF_EXPORT @@ -748,8 +750,8 @@ GF_EXPORT Bool gf_sema_wait_for(GF_Semaphore *sm, u32 TimeOut) { #ifdef WIN32 - if (WaitForSingleObject(sm->hSemaphore, TimeOut) == WAIT_TIMEOUT) return 0; - return 1; + if (WaitForSingleObject(sm->hSemaphore, TimeOut) == WAIT_TIMEOUT) return GF_FALSE; + return GF_TRUE; #else sem_t *hSem; #if defined(__DARWIN__) || defined(__APPLE__) @@ -758,15 +760,15 @@ Bool gf_sema_wait_for(GF_Semaphore *sm, u32 TimeOut) hSem = sm->hSemaphore; #endif if (!TimeOut) { - if (!sem_trywait(hSem)) return 1; - return 0; + if (!sem_trywait(hSem)) return GF_TRUE; + return GF_FALSE; } TimeOut += gf_sys_clock(); do { - if (!sem_trywait(hSem)) return 1; + if (!sem_trywait(hSem)) return GF_TRUE; gf_sleep(1); } while (gf_sys_clock() < TimeOut); - return 0; + return GF_FALSE; #endif } diff --git a/src/utils/path2d.c b/src/utils/path2d.c index 928da64..2ff0baa 100644 --- a/src/utils/path2d.c +++ b/src/utils/path2d.c @@ -470,7 +470,7 @@ GF_Err gf_path_add_svg_arc_to(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed r_x, start_x = gp->points[gp->n_points-1].x; start_y = gp->points[gp->n_points-1].y; - phi = gf_mulfix(gf_divfix(x_axis_rotation, 180), GF_PI); + phi = gf_mulfix(x_axis_rotation/180, GF_PI); cos_phi = gf_cos(phi); sin_phi = gf_sin(phi); xmid = (start_x - end_x)/2; @@ -571,7 +571,7 @@ GF_Err gf_path_add_svg_arc_to(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed r_x, for (i=1; i<=num_steps; i++) { Fixed _vx, _vy; Fixed _vxp, _vyp; - Fixed angle = start_angle + sweep_angle*i/num_steps; + Fixed angle = start_angle + sweep_angle*(s32)i/(s32)num_steps; _vx = gf_mulfix(r_x, gf_cos(angle)); _vy = gf_mulfix(r_y, gf_sin(angle)); _vxp = gf_mulfix(cos_phi, _vx) - gf_mulfix(sin_phi, _vy) + c_x; diff --git a/src/utils/sha1.c b/src/utils/sha1.c index 51400cc..920137f 100644 --- a/src/utils/sha1.c +++ b/src/utils/sha1.c @@ -292,7 +292,7 @@ static const u8 sha1_padding[64] = /* * SHA-1 final digest */ -void gf_sha1_finish(GF_SHA1Context *ctx, u8 output[20] ) +void gf_sha1_finish(GF_SHA1Context *ctx, u8 output[GF_SHA1_DIGEST_SIZE] ) { u32 last, padn; u32 high, low; @@ -661,7 +661,7 @@ void gf_sha1_update(GF_SHA1Context *context, u8 *message_array, u32 length ) message_array++; } } -void gf_sha1_finish(GF_SHA1Context *context, u8 output[20] ) +void gf_sha1_finish(GF_SHA1Context *context, u8 output[GF_SHA1_DIGEST_SIZE] ) { if (context->Corrupted) { @@ -688,7 +688,7 @@ void gf_sha1_finish(GF_SHA1Context *context, u8 output[20] ) * Output = SHA-1( file contents ) */ GF_EXPORT -s32 gf_sha1_file( const char *path, u8 output[20] ) +s32 gf_sha1_file( const char *path, u8 output[GF_SHA1_DIGEST_SIZE] ) { FILE *f; size_t n; @@ -705,7 +705,7 @@ s32 gf_sha1_file( const char *path, u8 output[20] ) return 0; } - if( ( f = gf_f64_open( path, "rb" ) ) == NULL ) + if( ( f = gf_fopen( path, "rb" ) ) == NULL ) return( 1 ); ctx = gf_sha1_starts(); @@ -715,7 +715,7 @@ s32 gf_sha1_file( const char *path, u8 output[20] ) gf_sha1_finish(ctx, output ); - fclose( f ); + gf_fclose( f ); return( 0 ); } @@ -723,7 +723,7 @@ s32 gf_sha1_file( const char *path, u8 output[20] ) * Output = SHA-1( input buffer ) */ GF_EXPORT -void gf_sha1_csum( u8 *input, u32 ilen, u8 output[20] ) +void gf_sha1_csum( u8 *input, u32 ilen, u8 output[GF_SHA1_DIGEST_SIZE] ) { GF_SHA1Context *ctx; @@ -733,13 +733,13 @@ void gf_sha1_csum( u8 *input, u32 ilen, u8 output[20] ) } GF_EXPORT -void gf_sha1_csum_hexa(u8 *buf, u32 buflen, u8 digest[41]) { - u8 tmp[20]; +void gf_sha1_csum_hexa(u8 *buf, u32 buflen, u8 digest[GF_SHA1_DIGEST_SIZE_HEXA]) { + u8 tmp[GF_SHA1_DIGEST_SIZE]; gf_sha1_csum (buf, buflen, tmp ); digest[0] = 0; { int i; - for ( i=0; i<20; i++ ) + for ( i=0; ihSemaphore->Signal(NbRelease); -#ifdef __SERIES60_3X__ - prevCount = 0; -#else - prevCount = sm->hSemaphore->Count(); -#endif - return (u32) prevCount; + return GF_TRUE; } GF_EXPORT diff --git a/src/utils/token.c b/src/utils/token.c index f7ae2d9..559f80e 100644 --- a/src/utils/token.c +++ b/src/utils/token.c @@ -133,4 +133,4 @@ s32 gf_token_find(const char *Buffer, u32 Start, u32 Size, const char *Pattern) return -1; } -#endif +#endif diff --git a/src/utils/url.c b/src/utils/url.c index 27e6fd0..d04a378 100644 --- a/src/utils/url.c +++ b/src/utils/url.c @@ -65,7 +65,7 @@ static u32 URL_GetProtocolType(const char *pathName) Bool gf_url_is_local(const char *pathName) { u32 mode = URL_GetProtocolType(pathName); - return (mode==GF_URL_TYPE_ANY) ? 0 : 1; + return (mode==GF_URL_TYPE_ANY) ? GF_FALSE : GF_TRUE; } char *gf_url_get_absolute_path(const char *pathName, const char *parentPath) @@ -216,11 +216,16 @@ char *gf_url_concatenate(const char *parentName, const char *pathName) while (strchr(" \r\n\t", tmp[strlen(tmp)-1])) { tmp[strlen(tmp)-1] = 0; } + //strip query part or fragment part + rad = strchr(tmp, '?'); + if (rad) rad[0] = 0; + rad = strchr(tmp, '#'); + if (rad) rad[0] = 0; /*remove the last /*/ - for (i = (u32) strlen(parentName); i > 0; i--) { + for (i = (u32) strlen(tmp); i > 0; i--) { //break our path at each separator - if ((parentName[i-1] == GF_PATH_SEPARATOR) || (parentName[i-1] == '/')) { + if ((tmp[i-1] == GF_PATH_SEPARATOR) || (tmp[i-1] == '/')) { tmp[i-1] = 0; if (!pathSepCount) break; pathSepCount--; @@ -334,9 +339,9 @@ Bool gf_url_get_resource_path(const char *sURL, char *res_path) if (!sep) sep = strrchr(res_path, '\\'); if (sep) { sep[1] = 0; - return 1; + return GF_TRUE; } - return 0; + return GF_FALSE; } diff --git a/src/utils/xml_parser.c b/src/utils/xml_parser.c index e0ce1a6..1878885 100644 --- a/src/utils/xml_parser.c +++ b/src/utils/xml_parser.c @@ -262,7 +262,7 @@ static void xml_sax_node_end(GF_SAXParser *parser, Bool had_children) static void xml_sax_node_start(GF_SAXParser *parser) { - Bool has_entities = 0; + Bool has_entities = GF_FALSE; u32 i; char *sep, c, *name; @@ -278,8 +278,8 @@ static void xml_sax_node_start(GF_SAXParser *parser) parser->buffer[parser->sax_attrs[i].val_end-1] = 0; if (strchr(parser->attrs[i].value, '&')) { - parser->sax_attrs[i].has_entities = 1; - has_entities = 1; + parser->sax_attrs[i].has_entities = GF_TRUE; + has_entities = GF_TRUE; parser->attrs[i].value = xml_translate_xml_string(parser->attrs[i].value); } /*store first char pos after current attrib for node peeking*/ @@ -302,7 +302,7 @@ static void xml_sax_node_start(GF_SAXParser *parser) if (has_entities) { for (i=0; inb_attrs; i++) { if (parser->sax_attrs[i].has_entities) { - parser->sax_attrs[i].has_entities = 0; + parser->sax_attrs[i].has_entities = GF_FALSE; gf_free(parser->attrs[i].value); } } @@ -336,7 +336,7 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) if (parser->init_state!=1) break; case '/': /*not enough data*/ - if (parser->current_pos+1 == parser->line_size) return 1; + if (parser->current_pos+1 == parser->line_size) return GF_TRUE; if (parser->buffer[parser->current_pos+1]=='>') { parser->current_pos+=2; parser->elt_end_pos = parser->file_pos + parser->current_pos - 1; @@ -345,18 +345,18 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) xml_sax_node_start(parser); /*move to SAX_STATE_TEXT_CONTENT to force text flush*/ parser->sax_state = SAX_STATE_TEXT_CONTENT; - xml_sax_node_end(parser, 0); + xml_sax_node_end(parser, GF_FALSE); } else { parser->nb_attrs = 0; } parser->sax_state = (parser->init_state) ? SAX_STATE_ELEMENT : SAX_STATE_TEXT_CONTENT; parser->text_start = parser->text_end = 0; - return 0; + return GF_FALSE; } if (!parser->in_quote && (c=='/')) { if (!parser->init_state) { format_sax_error(parser, 0, "Markup error"); - return 1; + return GF_TRUE; } } break; @@ -364,7 +364,7 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) if (parser->sax_state==SAX_STATE_ATT_VALUE) break; if (parser->in_quote && (parser->in_quote!=c) ) { format_sax_error(parser, 0, "Markup error"); - return 1; + return GF_TRUE; } if (parser->in_quote) parser->in_quote = 0; else parser->in_quote = c; @@ -375,29 +375,29 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) if (parser->init_state) { if (parser->init_state==1) { format_sax_error(parser, 0, "Invalid DOCTYPE"); - return 1; + return GF_TRUE; } parser->sax_state = SAX_STATE_ELEMENT; - return 0; + return GF_FALSE; } /*done parsing attr*/ parser->sax_state = SAX_STATE_TEXT_CONTENT; xml_sax_node_start(parser); - return 0; + return GF_FALSE; case '[': if (parser->init_state) { parser->current_pos+=1; if (parser->init_state==1) { format_sax_error(parser, 0, "Invalid DOCTYPE"); - return 1; + return GF_TRUE; } parser->sax_state = SAX_STATE_ELEMENT; - return 0; + return GF_FALSE; } break; case '<': format_sax_error(parser, 0, "Invalid character '<'"); - return 0; + return GF_FALSE; /*first char of attr name*/ default: parser->att_name_start = parser->current_pos + 1; @@ -406,20 +406,20 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) parser->current_pos++; if (parser->att_name_start) break; } - if (parser->current_pos == parser->line_size) return 1; + if (parser->current_pos == parser->line_size) return GF_TRUE; } if (parser->init_state==2) { sep = strchr(parser->buffer + parser->att_name_start - 1, parser->in_quote ? parser->in_quote : ' '); /*not enough data*/ - if (!sep) return 1; + if (!sep) return GF_TRUE; parser->current_pos = (u32) (sep - parser->buffer); parser->att_name_start = 0; if (parser->in_quote) { parser->current_pos++; parser->in_quote = 0; } - return 0; + return GF_FALSE; } /*looking for '"'*/ @@ -427,7 +427,7 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) u32 i, first=1; sep = strchr(parser->buffer + parser->att_name_start - 1, '='); /*not enough data*/ - if (!sep) return 1; + if (!sep) return GF_TRUE; parser->current_pos = (u32) (sep - parser->buffer); att = xml_get_sax_attribute(parser); @@ -437,7 +437,7 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) assert(att->name_end); att->name_end --; } - att->has_entities = 0; + att->has_entities = GF_FALSE; for (i=att->name_start; iname_end; i++) { char c = parser->buffer[i-1]; @@ -449,7 +449,7 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) else { format_sax_error(parser, att->name_start-1, "Invalid character \'%c\' for attribute name", c); - return 1; + return GF_TRUE; } first=0; @@ -487,18 +487,18 @@ static Bool xml_sax_parse_attribute(GF_SAXParser *parser) parser->current_pos++; if (parser->att_sep) break; } - if (parser->current_pos == parser->line_size) return 1; + if (parser->current_pos == parser->line_size) return GF_TRUE; } att_retry: assert(parser->att_sep); sep = strchr(parser->buffer + parser->current_pos, parser->att_sep); - if (!sep || !sep[1]) return 1; + if (!sep || !sep[1]) return GF_TRUE; if (sep[1]==parser->att_sep) { format_sax_error(parser, (u32) (sep - parser->buffer), "Invalid character %c after attribute value separator %c ", sep[1], parser->att_sep); - return 1; + return GF_TRUE; } if (!parser->init_state && (strchr(" />\n\t\r", sep[1])==NULL)) { @@ -510,7 +510,7 @@ att_retry: att->val_end = parser->current_pos + 1; parser->current_pos++; - /*"style" always at the begining of the attributes for ease of parsing*/ + /*"style" always at the beginning of the attributes for ease of parsing*/ if (!strncmp(parser->buffer + att->name_start-1, "style", 5)) { GF_XMLSaxAttribute prev = parser->sax_attrs[0]; parser->sax_attrs[0] = *att; @@ -519,9 +519,9 @@ att_retry: parser->att_sep = 0; parser->sax_state = SAX_STATE_ATT_NAME; parser->att_name_start = 0; - return 0; + return GF_FALSE; } - return 1; + return GF_TRUE; } @@ -548,11 +548,11 @@ static void xml_sax_flush_text(GF_SAXParser *parser) if (strchr(text, '&') && strchr(text, ';')) { char *xml_text = xml_translate_xml_string(text); if (xml_text) { - parser->sax_text_content(parser->sax_cbck, xml_text, (parser->sax_state==SAX_STATE_CDATA) ? 1 : 0); + parser->sax_text_content(parser->sax_cbck, xml_text, (parser->sax_state==SAX_STATE_CDATA) ? GF_TRUE : GF_FALSE); gf_free(xml_text); } } else { - parser->sax_text_content(parser->sax_cbck, text, (parser->sax_state==SAX_STATE_CDATA) ? 1 : 0); + parser->sax_text_content(parser->sax_cbck, text, (parser->sax_state==SAX_STATE_CDATA) ? GF_TRUE : GF_FALSE); } parser->buffer[parser->text_end-1] = c; parser->text_start = parser->text_end = 0; @@ -702,7 +702,7 @@ static Bool xml_sax_parse_comments(GF_SAXParser *parser) if (parser->line_size>3) parser->current_pos = parser->line_size-3; xml_sax_swap(parser); - return 0; + return GF_FALSE; } parser->current_pos += 3 + (u32) (end - (parser->buffer + parser->current_pos) ); @@ -710,7 +710,7 @@ static Bool xml_sax_parse_comments(GF_SAXParser *parser) parser->sax_state = SAX_STATE_TEXT_CONTENT; parser->text_start = parser->text_end = 0; xml_sax_swap(parser); - return 1; + return GF_TRUE; } @@ -724,16 +724,16 @@ static GF_Err xml_sax_parse(GF_SAXParser *parser, Bool force_parse) char *elt, sep; u32 cdata_sep; - is_text = 0; + is_text = GF_FALSE; while (parser->current_posline_size) { if (!force_parse && parser->suspended) goto exit; restart: - is_text = 0; + is_text = GF_FALSE; switch (parser->sax_state) { /*load an XML element*/ case SAX_STATE_TEXT_CONTENT: - is_text = 1; + is_text = GF_TRUE; case SAX_STATE_ELEMENT: elt = NULL; i=0; @@ -755,7 +755,7 @@ restart: } if (is_text && i) { xml_sax_store_text(parser, i); - is_text = 0; + is_text = GF_FALSE; parser->sax_state = SAX_STATE_ELEMENT; } else if (i) { parser->current_pos += i; @@ -822,10 +822,10 @@ restart: if (is_end==2) { parser->sax_state = SAX_STATE_ELEMENT; xml_sax_node_start(parser); - xml_sax_node_end(parser, 0); + xml_sax_node_end(parser, GF_FALSE); } else { parser->elt_end_pos += parser->elt_name_end - parser->elt_name_start; - xml_sax_node_end(parser, 1); + xml_sax_node_end(parser, GF_TRUE); } if (parser->sax_state == SAX_STATE_SYNTAX_ERROR) break; parser->current_pos+=2+i; @@ -934,7 +934,7 @@ static GF_Err xml_sax_append_string(GF_SAXParser *parser, char *string) { parser->alloc_size = size+nl_size+1; parser->alloc_size = 3 * parser->alloc_size / 2; - parser->buffer = gf_realloc(parser->buffer, sizeof(char) * parser->alloc_size); + parser->buffer = (char*)gf_realloc(parser->buffer, sizeof(char) * parser->alloc_size); if (!parser->buffer ) return GF_OUT_OF_MEM; } memcpy(parser->buffer+size, string, sizeof(char)*nl_size); @@ -948,13 +948,13 @@ static XML_Entity *gf_xml_locate_entity(GF_SAXParser *parser, char *ent_start, B u32 i, count; u32 len = (u32) strlen(ent_start); - *needs_text = 0; + *needs_text = GF_FALSE; count = gf_list_count(parser->entities); for (i=0; ientities, i); if (len < ent->namelen + 1) { - *needs_text = 1; + *needs_text = GF_TRUE; return NULL; } if (!strncmp(ent->name, ent_start, ent->namelen) && (ent_start[ent->namelen]==';')) { @@ -987,7 +987,7 @@ static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current) entityEnd[0] = 0; len = (u32) strlen(entityStart) + (u32) strlen(current) + 1; - name = gf_malloc(sizeof(char)*len); + name = (char*)gf_malloc(sizeof(char)*len); sprintf(name, "%s%s;", entityStart+1, current); ent = gf_xml_locate_entity(parser, name, &needs_text); @@ -995,7 +995,7 @@ static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current) if (!ent && !needs_text) { xml_sax_append_string(parser, current); - xml_sax_parse(parser, 1); + xml_sax_parse(parser, GF_TRUE); entityEnd[0] = ';'; current = entityEnd; continue; @@ -1005,7 +1005,7 @@ static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current) parser->line_size -= (u32) strlen(entityStart); entityStart[0] = 0; - parser->in_entity = 0; + parser->in_entity = GF_FALSE; entityEnd[0] = ';'; current = entityEnd+1; } else { @@ -1016,7 +1016,7 @@ static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current) /*store current string before entity start*/ entityStart[0] = 0; xml_sax_append_string(parser, current); - xml_sax_parse(parser, 1); + xml_sax_parse(parser, GF_TRUE); entityStart[0] = '&'; /*this is not an entitiy*/ @@ -1027,7 +1027,7 @@ static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current) } if (!ent) { - parser->in_entity = 1; + parser->in_entity = GF_TRUE; /*store entity start*/ return xml_sax_append_string(parser, entityStart); } @@ -1036,12 +1036,12 @@ static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current) /*append entity*/ line_num = parser->line; xml_sax_append_string(parser, ent->value); - xml_sax_parse(parser, 1); + xml_sax_parse(parser, GF_TRUE); parser->line = line_num; } xml_sax_append_string(parser, current); - return xml_sax_parse(parser, 0); + return xml_sax_parse(parser, GF_FALSE); } GF_EXPORT @@ -1165,7 +1165,7 @@ static GF_Err xml_sax_read_file(GF_SAXParser *parser) if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_size, parser->file_size); #ifdef NO_GZIP - fclose(parser->f_in); + gf_fclose(parser->f_in); parser->f_in = NULL; #else gzclose(parser->gz_in); @@ -1204,15 +1204,17 @@ GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_ return GF_URL_ERROR; } parser->file_size = size; - - memcpy(szLine, xml_mem_address, 3); + //copy possible BOM + memcpy(szLine, xml_mem_address, 4); szLine[4] = szLine[5] = 0; - e = gf_xml_sax_init(parser, szLine); - if (e) return e; - parser->file_pos = 4; + + parser->file_pos = 0; parser->elt_start_pos = 0; parser->current_pos = 0; + e = gf_xml_sax_init(parser, szLine); + if (e) return e; + e = gf_xml_sax_parse(parser, xml_mem_address+3); if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_pos, parser->file_size); @@ -1230,16 +1232,19 @@ GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_ } /*check file exists and gets its size (zlib doesn't support SEEK_END)*/ - test = gf_f64_open(fileName, "rb"); + test = gf_fopen(fileName, "rb"); if (!test) return GF_URL_ERROR; - gf_f64_seek(test, 0, SEEK_END); - assert(gf_f64_tell(test) < 1<<31); - parser->file_size = (u32) gf_f64_tell(test); - fclose(test); - + gf_fseek(test, 0, SEEK_END); + assert(gf_ftell(test) < 1<<31); + parser->file_size = (u32) gf_ftell(test); + gf_fclose(test); + parser->file_pos = 0; + parser->elt_start_pos = 0; + parser->current_pos = 0; + //open file and copy possible BOM #ifdef NO_GZIP - parser->f_in = gf_f64_open(fileName, "rt"); + parser->f_in = gf_fopen(fileName, "rt"); fread(szLine, 1, 4, parser->f_in); #else gzInput = gzopen(fileName, "rb"); @@ -1248,25 +1253,23 @@ GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_ /*init SAX parser (unicode setup)*/ gzread(gzInput, szLine, 4); #endif + szLine[4] = szLine[5] = 0; e = gf_xml_sax_init(parser, szLine); if (e) return e; - parser->file_pos = 4; - /* souchay : not sure for next 2 lines, but it works better it seems */ - parser->elt_start_pos = 0; - parser->current_pos = 0; + return xml_sax_read_file(parser); } GF_EXPORT Bool gf_xml_sax_binary_file(GF_SAXParser *parser) { - if (!parser) return 0; + if (!parser) return GF_FALSE; #ifdef NO_GZIP - return 0; + return GF_FALSE; #else - if (!parser->gz_in) return 0; - return (((z_stream*)parser->gz_in)->data_type==Z_BINARY) ? 1 : 0; + if (!parser->gz_in) return GF_FALSE; + return (((z_stream*)parser->gz_in)->data_type==Z_BINARY) ? GF_TRUE : GF_FALSE; #endif } @@ -1294,7 +1297,7 @@ void gf_xml_sax_del(GF_SAXParser *parser) xml_sax_reset(parser); gf_list_del(parser->entities); #ifdef NO_GZIP - if (parser->f_in) fclose(parser->f_in); + if (parser->f_in) gf_fclose(parser->f_in); #else if (parser->gz_in) gzclose(parser->gz_in); #endif @@ -1311,7 +1314,7 @@ GF_Err gf_xml_sax_suspend(GF_SAXParser *parser, Bool do_suspend) #else if (parser->gz_in) return xml_sax_read_file(parser); #endif - return xml_sax_parse(parser, 0); + return xml_sax_parse(parser, GF_FALSE); } return GF_OK; } @@ -1352,7 +1355,7 @@ char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value z_off_t pos; #endif Bool from_buffer; - Bool dobreak=0; + Bool dobreak=GF_FALSE; char szLine1[XML_INPUT_SIZE+2], szLine2[XML_INPUT_SIZE+2], *szLine, *cur_line, *sep, *start, first_c, *result; @@ -1365,11 +1368,11 @@ char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value if (__is_copy) { memcpy(szLine, __str, sizeof(char)*_len); szLine[_len] = 0; }\ else strcat(szLine, __str); \ - from_buffer=0; + from_buffer=GF_FALSE; #ifdef NO_GZIP - if (!parser->f_in) from_buffer=1; + if (!parser->f_in) from_buffer=GF_TRUE; #else - if (!parser->gz_in) from_buffer=1; + if (!parser->gz_in) from_buffer=GF_TRUE; #endif result = NULL; @@ -1378,7 +1381,7 @@ char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value pos=0; if (!from_buffer) { #ifdef NO_GZIP - pos = gf_f64_tell(parser->f_in); + pos = gf_ftell(parser->f_in); #else pos = gztell(parser->gz_in); #endif @@ -1413,7 +1416,7 @@ char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value cur_line = szLine2; } if (from_buffer) { - dobreak=1; + dobreak=GF_TRUE; } else { #ifdef NO_GZIP read = fread(cur_line, 1, XML_INPUT_SIZE, parser->f_in); @@ -1429,7 +1432,7 @@ char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value start = strstr(szLine, end_pattern); if (start) { start[0] = 0; - dobreak = 1; + dobreak = GF_TRUE; } } @@ -1484,7 +1487,7 @@ retry: sep[pos] = 0; state = 2; if (!substitute || !get_attr || strcmp(sep, substitute) ) { - if (is_substitute) *is_substitute = 0; + if (is_substitute) *is_substitute = GF_FALSE; result = gf_strdup(sep); goto exit; } @@ -1502,7 +1505,7 @@ fetch_attr: while (!strchr(" \t\r\n/>", sep[pos])) pos++; sep[pos-1] = 0; result = gf_strdup(sep); - if (is_substitute) *is_substitute = 1; + if (is_substitute) *is_substitute = GF_TRUE; goto exit; } state = 0; @@ -1514,7 +1517,7 @@ exit: if (!from_buffer) { #ifdef NO_GZIP - gf_f64_seek(parser->f_in, pos, SEEK_SET); + gf_fseek(parser->f_in, pos, SEEK_SET); #else gzrewind(parser->gz_in); gzseek(parser->gz_in, pos, SEEK_SET); @@ -1540,7 +1543,7 @@ static void on_peek_node_start(void *cbk, const char *name, const char *ns, cons { struct _peek_type *pt = (struct _peek_type*)cbk; pt->res = gf_strdup(name); - pt->parser->suspended = 1; + pt->parser->suspended = GF_TRUE; } GF_EXPORT @@ -1573,7 +1576,10 @@ struct _tag_dom_parser { GF_SAXParser *parser; GF_List *stack; + //root node being parsed GF_XMLNode *root; + //usually only one :) + GF_List *root_nodes; u32 depth; void (*OnProgress)(void *cbck, u64 done, u64 tot); @@ -1615,7 +1621,7 @@ static void on_dom_node_start(void *cbk, const char *name, const char *ns, const GF_XMLNode *node; if (par->root && !gf_list_count(par->stack)) { - par->parser->suspended = 1; + par->parser->suspended = GF_TRUE; return; } @@ -1632,7 +1638,10 @@ static void on_dom_node_start(void *cbk, const char *name, const char *ns, const node->name = gf_strdup(name); if (ns) node->ns = gf_strdup(ns); gf_list_add(par->stack, node); - if (!par->root) par->root = node; + if (!par->root) { + par->root = node; + gf_list_add(par->root_nodes, node); + } } static void on_dom_node_end(void *cbk, const char *name, const char *ns) @@ -1641,11 +1650,16 @@ static void on_dom_node_end(void *cbk, const char *name, const char *ns) GF_XMLNode *last = (GF_XMLNode *)gf_list_last(par->stack); gf_list_rem_last(par->stack); - if (!last || strcmp(last->name, name) || (!ns && last->ns) || (ns && !last->ns) || (ns && strcmp(last->ns, ns) ) ) { + if (!last || (strlen(last->name)!=strlen(name)) || strcmp(last->name, name) || (!ns && last->ns) || (ns && !last->ns) || (ns && strcmp(last->ns, ns) ) ) { + s32 idx; format_sax_error(par->parser, 0, "Invalid node stack: closing node is %s but %s was expected", name, last->name); - par->parser->suspended = 1; + par->parser->suspended = GF_TRUE; gf_xml_dom_node_del(last); - if (last==par->root) par->root=NULL; + if (last == par->root) + par->root=NULL; + idx = gf_list_find(par->root_nodes, last); + if (idx != -1) + gf_list_rem(par->root_nodes, idx); return; } @@ -1676,6 +1690,7 @@ GF_DOMParser *gf_xml_dom_new() { GF_DOMParser *dom; GF_SAFEALLOC(dom, GF_DOMParser); + dom->root_nodes = gf_list_new(); return dom; } @@ -1690,14 +1705,21 @@ static void gf_xml_dom_reset(GF_DOMParser *dom, Bool full_reset) while (gf_list_count(dom->stack)) { GF_XMLNode *n = (GF_XMLNode *)gf_list_last(dom->stack); gf_list_rem_last(dom->stack); - if (dom->root==n) dom->root = NULL; + if (dom->root==n) { + gf_list_del_item(dom->root_nodes, n); + dom->root = NULL; + } gf_xml_dom_node_del(n); } gf_list_del(dom->stack); dom->stack = NULL; } - if (full_reset && dom->root) { - gf_xml_dom_node_del(dom->root); + if (full_reset && gf_list_count(dom->root_nodes) ) { + while (gf_list_count(dom->root_nodes)) { + GF_XMLNode *n = (GF_XMLNode *)gf_list_last(dom->root_nodes); + gf_list_rem_last(dom->root_nodes); + gf_xml_dom_node_del(n); + } dom->root = NULL; } } @@ -1705,7 +1727,11 @@ static void gf_xml_dom_reset(GF_DOMParser *dom, Bool full_reset) GF_EXPORT void gf_xml_dom_del(GF_DOMParser *parser) { - gf_xml_dom_reset(parser, 1); + if (!parser) + return; + + gf_xml_dom_reset(parser, GF_TRUE); + gf_list_del(parser->root_nodes); gf_free(parser); } @@ -1727,13 +1753,13 @@ GF_EXPORT GF_Err gf_xml_dom_parse(GF_DOMParser *dom, const char *file, gf_xml_sax_progress OnProgress, void *cbk) { GF_Err e; - gf_xml_dom_reset(dom, 1); + gf_xml_dom_reset(dom, GF_TRUE); dom->stack = gf_list_new(); dom->parser = gf_xml_sax_new(on_dom_node_start, on_dom_node_end, on_dom_text_content, dom); dom->OnProgress = OnProgress; dom->cbk = cbk; e = gf_xml_sax_parse_file(dom->parser, file, OnProgress ? dom_on_progress : NULL); - gf_xml_dom_reset(dom, 0); + gf_xml_dom_reset(dom, GF_FALSE); return e<0 ? e : GF_OK; } @@ -1741,11 +1767,11 @@ GF_EXPORT GF_Err gf_xml_dom_parse_string(GF_DOMParser *dom, char *string) { GF_Err e; - gf_xml_dom_reset(dom, 1); + gf_xml_dom_reset(dom, GF_TRUE); dom->stack = gf_list_new(); dom->parser = gf_xml_sax_new(on_dom_node_start, on_dom_node_end, on_dom_text_content, dom); e = gf_xml_sax_init(dom->parser, (unsigned char *) string); - gf_xml_dom_reset(dom, 0); + gf_xml_dom_reset(dom, GF_FALSE); return e<0 ? e : GF_OK; } @@ -1777,6 +1803,19 @@ u32 gf_xml_dom_get_line(GF_DOMParser *parser) return gf_xml_sax_get_line(parser->parser); } +GF_EXPORT +u32 gf_xml_dom_get_root_nodes_count(GF_DOMParser *parser) +{ + return parser? gf_list_count(parser->root_nodes) : 0; +} + +GF_EXPORT +GF_XMLNode *gf_xml_dom_get_root_idx(GF_DOMParser *parser, u32 idx) +{ + return parser ? (GF_XMLNode*)gf_list_get(parser->root_nodes, idx) : NULL; +} + + static void gf_xml_dom_node_serialize(GF_XMLNode *node, Bool content_only, char **str, u32 *alloc_size, u32 *size) { u32 i, count, vlen; @@ -1816,7 +1855,7 @@ static void gf_xml_dom_node_serialize(GF_XMLNode *node, Bool content_only, char SET_STRING(" "); count = gf_list_count(node->attributes); for (i=0; iattributes, i); + GF_XMLAttribute *att = (GF_XMLAttribute*)gf_list_get(node->attributes, i); SET_STRING(att->name); SET_STRING("=\""); SET_STRING(att->value); @@ -1832,8 +1871,8 @@ static void gf_xml_dom_node_serialize(GF_XMLNode *node, Bool content_only, char count = gf_list_count(node->content); for (i=0; icontent, i); - gf_xml_dom_node_serialize(child, 0, str, alloc_size, size); + GF_XMLNode *child = (GF_XMLNode*)gf_list_get(node->content, i); + gf_xml_dom_node_serialize(child, GF_FALSE, str, alloc_size, size); } if (!content_only) { SET_STRING("attributes, &i))) { if (!strcmp(att->name, name)) { @@ -1891,7 +1930,7 @@ GF_XMLAttribute *gf_xml_dom_get_attribute(GF_XMLNode *node, const char* name) { GF_EXPORT GF_Err gf_xml_dom_append_child(GF_XMLNode *node, GF_XMLNode *child) { - if (!node | !child) return GF_BAD_PARAM; + if (!node || !child) return GF_BAD_PARAM; if (!node->content) { node->content = gf_list_new(); if (!node->content) return GF_OUT_OF_MEM; @@ -1899,6 +1938,15 @@ GF_Err gf_xml_dom_append_child(GF_XMLNode *node, GF_XMLNode *child) { return gf_list_add(node->content, child); } +GF_EXPORT +GF_Err gf_xml_dom_rem_child(GF_XMLNode *node, GF_XMLNode *child) { + s32 idx; + if (!node || !child || !node->content) return GF_BAD_PARAM; + idx = gf_list_find(node->content, child); + if (idx == -1) return GF_BAD_PARAM; + return gf_list_rem(node->content, idx); +} + GF_EXPORT GF_XMLNode* gf_xml_dom_node_new(const char* ns, const char* name) { GF_XMLNode* node; @@ -1935,14 +1983,11 @@ GF_XMLNode* gf_xml_dom_node_new(const char* ns, const char* name) { }\ -GF_EXPORT -GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **specInfo, u32 *specInfoSize) +static GF_Err gf_xml_parse_bit_sequence_bs(GF_XMLNode *bsroot, GF_BitStream *bs) { u32 i, j; GF_XMLNode *node; GF_XMLAttribute *att; - GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); - if (!bs) return GF_OUT_OF_MEM; i=0; while ((node = (GF_XMLNode *) gf_list_enum(bsroot->content, &i))) { @@ -1951,15 +1996,23 @@ GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **specInfo, u32 *specI u64 offset = 0; s64 value = 0; bin128 word128; + Float val_float = 0; + Double val_double = 0; Bool use_word128 = GF_FALSE; Bool use_text = GF_FALSE; Bool big_endian = GF_TRUE; + Bool has_float = GF_FALSE; + Bool has_double = GF_FALSE; const char *szFile = NULL; const char *szString = NULL; const char *szBase64 = NULL; const char *szData = NULL; if (node->type) continue; - if (stricmp(node->name, "BS") ) continue; + + if (stricmp(node->name, "BS") ) { + gf_xml_parse_bit_sequence_bs(node, bs); + continue; + } j=0; while ( (att = (GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) { @@ -1967,6 +2020,12 @@ GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **specInfo, u32 *specI XML_SCAN_INT("%d", nb_bits); } else if (!stricmp(att->name, "value")) { XML_SCAN_INT(LLD, value); + } else if (!stricmp(att->name, "float")) { + sscanf(att->value, "%f", &val_float); + has_float = GF_TRUE; + } else if (!stricmp(att->name, "double")) { + sscanf(att->value, "%lf", &val_double); + has_double = GF_TRUE; } else if (!stricmp(att->name, "mediaOffset") || !stricmp(att->name, "dataOffset")) { XML_SCAN_INT(LLU, offset); } else if (!stricmp(att->name, "dataLength")) { @@ -1988,10 +2047,8 @@ GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **specInfo, u32 *specI } else if (!stricmp(att->name, "data")) { szData = att->value; if (!strnicmp(szData, "0x", 2)) szData += 2; - } else if (!stricmp(att->name, "endian")) { - if (!stricmp(att->value, "little")) { - big_endian = GF_FALSE; - } + } else if (!stricmp(att->name, "endian") && !stricmp(att->value, "little")) { + big_endian = GF_FALSE; } } if (szString) { @@ -2003,17 +2060,24 @@ GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **specInfo, u32 *specI } else if (szBase64) { u32 len = (u32) strlen(szBase64); char *data = (char *) gf_malloc(sizeof(char)*len); - u32 ret = (u32) gf_base64_decode((char *)szBase64, len, data, len); + u32 ret; + if (!data ) return GF_OUT_OF_MEM; + + ret = (u32) gf_base64_decode((char *)szBase64, len, data, len); if ((s32) ret >=0) { gf_bs_write_int(bs, ret, nb_bits); gf_bs_write_data(bs, data, ret); } else { - GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[XML/NHML] Error decoding base64 %s\n", att->value)); + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[XML/NHML] Error decoding base64 %s\n", att->value)); + gf_free(data); + return GF_BAD_PARAM; } gf_free(data); } else if (szData) { u32 j, len = (u32) strlen(szData); char *data = (char *) gf_malloc(sizeof(char)*len/2); + if (!data) return GF_OUT_OF_MEM; + for (j=0; j offset) - size -= (u32) offset; - } - remain = size; - gf_f64_seek(_tmp, offset, SEEK_SET); - while (remain) { - read = (u32) fread(block, 1, (remain>1024) ? 1024 : remain, _tmp); - gf_bs_write_data(bs, block, read); - remain -= size; - } - fclose(_tmp); + FILE *_tmp = gf_fopen(szFile, use_text ? "rt" : "rb"); + + if (!_tmp) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[XML/NHML] Error opening file %s\n", szFile)); + return GF_URL_ERROR; + } + + if (!size) { + gf_fseek(_tmp, 0, SEEK_END); + size = (u32) gf_ftell(_tmp); + //if offset only copy from offset until end + if ((u64) size > offset) + size -= (u32) offset; } + remain = size; + gf_fseek(_tmp, offset, SEEK_SET); + while (remain) { + read = (u32) fread(block, 1, (remain>1024) ? 1024 : remain, _tmp); + gf_bs_write_data(bs, block, read); + remain -= size; + } + gf_fclose(_tmp); } else if (use_word128) { gf_bs_write_data(bs, (char *)word128, 16); } } + return GF_OK; +} + +GF_EXPORT +GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, char **data, u32 *data_size) +{ + GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); + if (!bs) return GF_OUT_OF_MEM; + + gf_xml_parse_bit_sequence_bs(bsroot, bs); + gf_bs_align(bs); - gf_bs_get_content(bs, specInfo, specInfoSize); + gf_bs_get_content(bs, data, data_size); gf_bs_del(bs); return GF_OK; - } #endif diff --git a/src/utils/zutil.c b/src/utils/zutil.c index 3e0d894..56a087e 100644 --- a/src/utils/zutil.c +++ b/src/utils/zutil.c @@ -6,6 +6,7 @@ /* @(#) $Id: zutil.c,v 1.2 2010-02-23 16:24:20 jeanlf Exp $ */ #include "zutil.h" +#include #ifndef NO_DUMMY_DECL struct internal_state { diff --git a/version.bat b/version.bat index 6ced6ac..23cc862 100644 --- a/version.bat +++ b/version.bat @@ -1,16 +1,24 @@ -@echo off -set OLDDIR=%CD% -cd /d %~dp0 -for /f "delims=" %%a in ('svnversion') do echo #define GPAC_SVN_REVISION "%%a" > test.h -if not exist include\gpac\revision.h goto create -ECHO n|COMP test.h include\gpac\revision.h > nul -if errorlevel 1 goto create -DEL test.h -goto done - -:create -MOVE /Y test.h include\gpac\revision.h - -:done -cd /d %OLDDIR% -exit/b +@echo off +set OLDDIR=%CD% +cd /d %~dp0 +for /f "delims=" %%a in ('git describe --tags --long') do @set VERSION=%%a +for /f "delims=" %%a in ('git describe --tags --abbrev^=0') do @set TAG=%%a- +for /f "delims=" %%a in ('git rev-parse --abbrev-ref HEAD') do @set BRANCH=%%a +REM remove anotated tag from VERSION +setlocal enabledelayedexpansion +call set VERSION=%%VERSION:!TAG!=%% +setlocal disabledelayedexpansion +echo #define GPAC_GIT_REVISION "%VERSION%-%BRANCH%" > test.h +if not exist include\gpac\revision.h goto create +ECHO n|COMP test.h include\gpac\revision.h > nul +if errorlevel 1 goto create +DEL test.h +goto done + +:create +MOVE /Y test.h include\gpac\revision.h + +:done +cd /d %OLDDIR% +exit/b + -- 2.30.2