From 30f23e2d4aed7c7a734d551255a2091be5790969 Mon Sep 17 00:00:00 2001
From: Reinhard Tartler
Date: Sat, 22 Feb 2014 13:29:38 +0000
Subject: [PATCH] Imported Upstream version 0.5.0+svn5104~dfsg1
---
Makefile | 25 +-
applications/Makefile | 10 +-
applications/dashcast/Makefile | 71 +
applications/dashcast/audio_data.c | 97 +
applications/dashcast/audio_data.h | 134 +
applications/dashcast/audio_decoder.c | 283 +
applications/dashcast/audio_decoder.h | 90 +
applications/dashcast/audio_encoder.c | 290 +
applications/dashcast/audio_encoder.h | 64 +
applications/dashcast/audio_muxer.c | 423 +
applications/dashcast/audio_muxer.h | 131 +
applications/dashcast/circular_buffer.c | 263 +
applications/dashcast/circular_buffer.h | 246 +
applications/dashcast/cmd_data.c | 888 +
applications/dashcast/cmd_data.h | 136 +
applications/dashcast/controler.c | 1564 +
applications/dashcast/controler.h | 100 +
applications/dashcast/dashcast.c | 49 +
applications/dashcast/libav_compat.h | 54 +
applications/dashcast/message_queue.c | 120 +
applications/dashcast/message_queue.h | 58 +
applications/dashcast/register.c | 85 +
applications/dashcast/register.h | 50 +
applications/dashcast/task.c | 69 +
applications/dashcast/task.h | 69 +
applications/dashcast/video_data.c | 92 +
applications/dashcast/video_data.h | 164 +
applications/dashcast/video_decoder.c | 378 +
applications/dashcast/video_decoder.h | 96 +
applications/dashcast/video_encoder.c | 295 +
applications/dashcast/video_encoder.h | 63 +
applications/dashcast/video_muxer.c | 690 +
applications/dashcast/video_muxer.h | 110 +
applications/dashcast/video_scaler.c | 257 +
applications/dashcast/video_scaler.h | 167 +
applications/generators/MPEG4/Makefile | 8 +-
applications/generators/MPEG4/main.c | 4 +-
applications/generators/SVG/Makefile | 8 +-
applications/generators/X3D/Makefile | 8 +-
applications/mp42avi/Makefile | 8 +-
applications/mp42ts/Makefile | 8 +-
applications/mp42ts/main.c | 470 +-
applications/mp4box/Makefile | 18 +-
applications/mp4box/filedump.c | 286 +-
applications/mp4box/fileimport.c | 366 +-
applications/mp4box/live.c | 135 +-
applications/mp4box/main.c | 584 +-
applications/mp4client/Makefile | 8 +-
applications/mp4client/main.c | 415 +-
applications/testapps/bmp4demux/Makefile | 50 +
applications/testapps/bmp4demux/bmp4demux.sln | 20 +
.../testapps/bmp4demux/bmp4demux.vcxproj | 189 +
.../bmp4demux/bmp4demux.vcxproj.filters | 131 +
applications/testapps/bmp4demux/build.sh | 2 +
applications/testapps/bmp4demux/main.c | 93 +
applications/testapps/fmp4demux/Makefile | 50 +
applications/testapps/fmp4demux/build.sh | 2 +
applications/testapps/fmp4demux/fmp4demux.sln | 20 +
.../testapps/fmp4demux/fmp4demux.vcxproj | 188 +
.../fmp4demux/fmp4demux.vcxproj.filters | 134 +
applications/testapps/fmp4demux/main.c | 315 +
applications/testapps/loadcompare/Makefile | 8 +-
applications/testapps/mpedemux/Makefile | 8 +-
applications/testapps/segmp4demux/Makefile | 50 +
applications/testapps/segmp4demux/build.sh | 2 +
applications/testapps/segmp4demux/main.c | 139 +
.../testapps/segmp4demux/segmp4demux.sln | 20 +
.../testapps/segmp4demux/segmp4demux.vcxproj | 189 +
.../segmp4demux/segmp4demux.vcxproj.filters | 131 +
applications/ts2hds/Makefile | 106 +-
applications/ts2hds/f4m.c | 346 +-
applications/ts2hds/f4v.c | 368 +-
applications/ts2hds/main.c | 610 +-
applications/ts2hds/ts2hds.h | 96 +-
applications/udptsseg/Makefile | 8 +-
bin/win32/release/nsis_install/default.out | 7 -
configure | 309 +-
doc/configuration.html | 54 +-
doc/doxyfile | 2236 +-
doc/doxyfile-full | 2321 +
.../include/OpenSVCDecoder/ControlLayer.h | 90 +-
extra_lib/include/OpenSVCDecoder/ParseAU.h | 78 +-
.../OpenSVCDecoder/SVCDecoder_ietr_api.h | 272 +-
.../include/OpenSVCDecoder/SvcInterface.h | 119 +-
extra_lib/include/avcap/avcap-export.h | 86 +-
.../include/avcap/windows/DS_Connector.h | 148 +-
.../avcap/windows/DS_ConnectorManager.h | 182 +-
extra_lib/include/avcap/windows/DS_Control.h | 370 +-
.../include/avcap/windows/DS_ControlManager.h | 160 +-
extra_lib/include/avcap/windows/DS_Device.h | 164 +-
.../avcap/windows/DS_DeviceDescriptor.h | 262 +-
.../include/avcap/windows/DS_FormatManager.h | 202 +-
extra_lib/include/avcap/windows/DS_Tuner.h | 268 +-
.../include/avcap/windows/DS_VidCapManager.h | 196 +-
extra_lib/include/{faad => }/faad.h | 0
extra_lib/include/libavdevice/avdevice.h | 69 +
extra_lib/include/libavdevice/version.h | 50 +
extra_lib/include/{mad => }/mad.h | 0
extra_lib/include/{faad => }/neaacdec.h | 0
extra_lib/include/openHevcWrapper.h | 72 +
extra_lib/include/{openjpeg => }/openjpeg.h | 0
extra_lib/include/platinum/Neptune.h | 2 +
.../include/platinum/NptAutomaticCleaner.h | 90 +
.../include/platinum/NptAutoreleasePool.h | 57 +
extra_lib/include/platinum/NptCommon.h | 10 +-
extra_lib/include/platinum/NptConfig.h | 61 +-
extra_lib/include/platinum/NptCrypto.h | 78 +
extra_lib/include/platinum/NptDigest.h | 78 +
extra_lib/include/platinum/NptFile.h | 50 +-
extra_lib/include/platinum/NptHash.h | 83 +
extra_lib/include/platinum/NptHttp.h | 293 +-
extra_lib/include/platinum/NptJson.h | 42 +
extra_lib/include/platinum/NptList.h | 104 +-
extra_lib/include/platinum/NptLogging.h | 28 +-
extra_lib/include/platinum/NptMap.h | 507 +-
extra_lib/include/platinum/NptMessaging.h | 62 +-
extra_lib/include/platinum/NptNetwork.h | 30 +-
extra_lib/include/platinum/NptQueue.h | 6 +-
extra_lib/include/platinum/NptReferences.h | 61 +-
extra_lib/include/platinum/NptResults.h | 77 +-
extra_lib/include/platinum/NptRingBuffer.h | 2 +-
.../include/platinum/NptSimpleMessageQueue.h | 2 +-
extra_lib/include/platinum/NptSockets.h | 40 +-
extra_lib/include/platinum/NptStack.h | 2 +
extra_lib/include/platinum/NptStreams.h | 3 +-
extra_lib/include/platinum/NptStrings.h | 55 +-
extra_lib/include/platinum/NptSystem.h | 3 +
extra_lib/include/platinum/NptThreads.h | 43 +-
extra_lib/include/platinum/NptTime.h | 132 +-
extra_lib/include/platinum/NptTls.h | 227 +-
.../platinum/NptTlsDefaultTrustAnchorsBase.h | 583 +
.../NptTlsDefaultTrustAnchorsExtended.h | 91 +
extra_lib/include/platinum/NptTypes.h | 10 +-
extra_lib/include/platinum/NptUri.h | 200 +-
extra_lib/include/platinum/NptUtils.h | 11 +-
extra_lib/include/platinum/NptVersion.h | 4 +-
extra_lib/include/platinum/NptXml.h | 25 +-
extra_lib/include/platinum/NptZip.h | 36 +-
extra_lib/include/platinum/Platinum.h | 73 +-
extra_lib/include/platinum/PltAction.h | 205 +-
extra_lib/include/platinum/PltArgument.h | 32 +-
extra_lib/include/platinum/PltConstants.h | 36 +-
extra_lib/include/platinum/PltCtrlPoint.h | 206 +-
extra_lib/include/platinum/PltCtrlPointTask.h | 97 +-
.../include/platinum/PltDatagramStream.h | 24 +-
extra_lib/include/platinum/PltDeviceData.h | 59 +-
extra_lib/include/platinum/PltDeviceHost.h | 285 +-
extra_lib/include/platinum/PltDidl.h | 56 +-
extra_lib/include/platinum/PltDownloader.h | 30 +-
extra_lib/include/platinum/PltEvent.h | 64 +-
.../include/platinum/PltFileMediaServer.h | 132 +-
extra_lib/include/platinum/PltFrameBuffer.h | 76 +
extra_lib/include/platinum/PltFrameServer.h | 103 +
extra_lib/include/platinum/PltFrameStream.h | 79 +
extra_lib/include/platinum/PltHttp.h | 120 +-
.../include/platinum/PltHttpClientTask.h | 83 +-
extra_lib/include/platinum/PltHttpServer.h | 80 +-
.../include/platinum/PltHttpServerTask.h | 108 +-
extra_lib/include/platinum/PltLeaks.h | 5 +-
extra_lib/include/platinum/PltMediaBrowser.h | 34 +-
extra_lib/include/platinum/PltMediaCache.h | 172 +-
extra_lib/include/platinum/PltMediaConnect.h | 96 +-
.../include/platinum/PltMediaController.h | 50 +-
extra_lib/include/platinum/PltMediaItem.h | 172 +-
extra_lib/include/platinum/PltMediaRenderer.h | 23 +-
extra_lib/include/platinum/PltMediaServer.h | 106 +-
.../include/platinum/PltMetadataHandler.h | 13 +-
extra_lib/include/platinum/PltMimeType.h | 75 +
extra_lib/include/platinum/PltProtocolInfo.h | 158 +
.../include/platinum/PltRingBufferStream.h | 40 +-
extra_lib/include/platinum/PltService.h | 391 +-
extra_lib/include/platinum/PltSsdp.h | 125 +-
extra_lib/include/platinum/PltStateVariable.h | 143 +-
extra_lib/include/platinum/PltStreamPump.h | 5 +-
.../include/platinum/PltSyncMediaBrowser.h | 13 +-
extra_lib/include/platinum/PltTaskManager.h | 48 +-
extra_lib/include/platinum/PltThreadTask.h | 98 +-
extra_lib/include/platinum/PltUPnP.h | 69 +-
extra_lib/include/platinum/PltUtilities.h | 724 +
extra_lib/include/platinum/PltVersion.h | 12 +-
extra_lib/include/platinum/PltXbox360.h | 73 +
extra_lib/include/{xvid => }/xvid.h | 0
fixEOL.sh | 12 +
generate_installer.bat | 33 +-
gui/webvtt-renderer.js | 281 +
include/gpac/ait.h | 484 +-
include/gpac/avparse.h | 3 +
include/gpac/bitstream.h | 48 +
include/gpac/cache.h | 4 +-
include/gpac/color.h | 2 +
include/gpac/config_file.h | 16 +-
include/gpac/configuration.h | 28 +-
include/gpac/constants.h | 28 +-
include/gpac/dash.h | 525 +-
include/gpac/download.h | 72 +-
include/gpac/dsmcc.h | 1330 +-
include/gpac/esi.h | 7 +-
include/gpac/events.h | 3 +
include/gpac/events_constants.h | 997 +-
include/gpac/filestreamer.h | 3 +-
include/gpac/html5_media.h | 355 +
include/gpac/html5_mse.h | 215 +
include/gpac/ietf.h | 13 +-
include/gpac/internal/camera.h | 3 +-
include/gpac/internal/compositor_dev.h | 56 +-
include/gpac/internal/crypt_dev.h | 2 +-
include/gpac/internal/ietf_dev.h | 7 +-
include/gpac/internal/isomedia_dev.h | 312 +-
include/gpac/internal/m3u8.h | 25 +-
include/gpac/internal/media_dev.h | 68 +-
include/gpac/internal/mpd.h | 9 +-
include/gpac/internal/scenegraph_dev.h | 32 +-
include/gpac/internal/smjs_api.h | 2 +
include/gpac/internal/swf_dev.h | 31 +-
include/gpac/internal/terminal_dev.h | 73 +-
include/gpac/ismacryp.h | 45 +-
include/gpac/isomedia.h | 223 +-
include/gpac/list.h | 67 +
include/gpac/map.h | 213 +
include/gpac/math.h | 2 +-
include/gpac/media_tools.h | 37 +-
include/gpac/mediaobject.h | 22 +-
include/gpac/module.h | 62 +-
include/gpac/modules/codec.h | 8 +
include/gpac/modules/font.h | 2 +-
include/gpac/modules/hardcoded_proto.h | 3 +-
include/gpac/modules/ipmp.h | 12 +
include/gpac/modules/service.h | 87 +-
include/gpac/mpeg4_odf.h | 27 +-
include/gpac/mpegts.h | 100 +-
include/gpac/network.h | 27 +-
include/gpac/options.h | 5 +
include/gpac/path2d.h | 2 +-
include/gpac/rtp_streamer.h | 53 +-
include/gpac/scene_engine.h | 112 +-
include/gpac/scene_manager.h | 5 +-
include/gpac/scenegraph.h | 3 +
include/gpac/scenegraph_svg.h | 117 +-
include/gpac/scenegraph_vrml.h | 4 +-
include/gpac/setup.h | 17 +-
include/gpac/svg_types.h | 3 +-
include/gpac/sync_layer.h | 7 +
include/gpac/term_info.h | 5 +-
include/gpac/terminal.h | 5 +-
include/gpac/thread.h | 3 +-
include/gpac/token.h | 28 +-
include/gpac/tools.h | 86 +-
include/gpac/version.h | 2 +-
include/gpac/webvtt.h | 83 +
include/gpac/xml.h | 115 +-
mkdmg.sh | 13 +-
modules/Makefile | 90 +-
modules/aac_in/Makefile | 8 +-
modules/aac_in/aac_in.c | 19 +-
modules/aac_in/faad_dec.c | 16 +-
modules/ac3_in/Makefile | 8 +-
modules/ac3_in/ac3_in.c | 12 +-
modules/ac3_in/liba52_dec.c | 7 +
modules/alsa/Makefile | 9 +-
modules/alsa/alsa.c | 8 +-
modules/amr_dec/Makefile | 8 +-
modules/amr_dec/amr_dec.c | 8 +-
modules/amr_dec/amr_in.c | 21 +-
modules/amr_float_dec/Makefile | 8 +-
modules/amr_float_dec/amr_float_dec.c | 7 +-
modules/audio_filter/Makefile | 9 +-
modules/audio_filter/audio_filter.c | 8 +-
modules/avcap/Makefile | 10 +-
modules/avcap/avcap.cpp | 107 +-
modules/bifs_dec/Makefile | 8 +-
modules/bifs_dec/bifs_dec.c | 7 +-
modules/ctx_load/Makefile | 8 +-
modules/ctx_load/ctx_load.c | 10 +-
modules/demo_is/Makefile | 8 +-
modules/demo_is/demo_is.c | 8 +-
modules/directfb_out/Makefile | 8 +-
modules/directfb_out/directfb_out.c | 9 +-
modules/droid_audio/droidaudio.c | 184 +-
modules/droid_cam/droid_cam.c | 1444 +-
modules/droid_mpegv/droid_mpegv.c | 880 +-
modules/droid_out/droid_vout-bitmap.c | 9 +-
modules/droid_out/droid_vout.c | 9 +-
modules/dummy_in/Makefile | 8 +-
modules/dummy_in/dummy_in.c | 12 +-
modules/dx_hw/Makefile | 14 +-
modules/dx_hw/copy_pixels.c | 74 +-
modules/dx_hw/dx_2d.c | 32 +-
modules/dx_hw/dx_hw.h | 15 +-
modules/dx_hw/dx_hw.rc | 2 +-
modules/dx_hw/dx_video.c | 222 +-
modules/dx_hw/dx_window.c | 63 +-
modules/epoc_hw/epoc_vout.cpp | 9 +-
modules/ffmpeg_in/Makefile | 10 +-
modules/ffmpeg_in/ffmpeg_decode.c | 221 +-
modules/ffmpeg_in/ffmpeg_demux.c | 11 +-
modules/ffmpeg_in/ffmpeg_in.h | 25 +-
modules/ffmpeg_in/ffmpeg_load.c | 9 +-
modules/freenect/Makefile | 10 +-
modules/freenect/freenect.c | 9 +-
modules/ft_font/Makefile | 8 +-
modules/ft_font/ft_font.c | 31 +-
modules/gapi/gapi.cpp | 80 +-
modules/gdip_raster/gdip_font.cpp | 22 +-
modules/gdip_raster/gdip_grad.cpp | 12 +-
modules/gdip_raster/gdip_priv.h | 11 -
modules/gdip_raster/gdip_rend.cpp | 16 +-
modules/gdip_raster/gdip_texture.cpp | 42 +-
modules/gpac_js/Makefile | 8 +-
modules/gpac_js/gpac_js.c | 90 +-
modules/hyb_in/Makefile | 8 +-
modules/hyb_in/fm_fake_pull.c | 440 +-
modules/hyb_in/fm_fake_push.c | 658 +-
modules/hyb_in/fm_mmbtools.c | 58 +-
modules/hyb_in/hyb_in.c | 623 +-
modules/hyb_in/hyb_in.h | 192 +-
modules/img_in/Makefile | 8 +-
modules/img_in/bmp_dec.c | 3 +
modules/img_in/img_dec.c | 8 +-
modules/img_in/img_in.c | 4 +-
modules/img_in/jp2_dec.c | 11 +
modules/img_in/jpeg_dec.c | 3 +
modules/img_in/png_dec.c | 3 +
modules/ios_cam/CameraObject.h | 64 +
modules/ios_cam/CameraObject.m | 170 +
modules/ios_cam/cam_wrap.h | 55 +
modules/ios_cam/cam_wrap.m | 82 +
modules/ios_cam/ios_cam.c | 431 +
modules/ios_mpegv/SensorAcces.m | 209 +
modules/ios_mpegv/SensorAccess.h | 34 +
modules/ios_mpegv/ios_mpegv-Prefix.pch | 7 +
modules/ios_mpegv/ios_mpegv.c | 309 +
modules/ios_mpegv/sensor_wrap.h | 43 +
modules/ismacryp/Makefile | 10 +-
modules/ismacryp/isma_ea.c | 646 +
modules/ismacryp/ismacryp.c | 363 -
modules/isom_in/Makefile | 10 +-
modules/isom_in/{cache.c => isom_cache.c} | 1 -
modules/isom_in/isom_in.h | 24 +-
modules/isom_in/load.c | 129 +-
modules/isom_in/read.c | 389 +-
modules/isom_in/read_ch.c | 484 +-
modules/jack/Makefile | 9 +-
modules/jack/jack.c | 8 +-
modules/laser_dec/Makefile | 8 +-
modules/laser_dec/laser_dec.c | 8 +-
modules/libplayer/Makefile | 8 +-
modules/libplayer/libplayer.c | 8 +-
modules/modules_export.cpp | 2 +-
modules/mp3_in/Makefile | 8 +-
modules/mp3_in/mad_dec.c | 15 +-
modules/mp3_in/mp3_in.c | 10 +-
modules/mpd_in/Makefile | 8 +-
modules/mpd_in/mpd_in.c | 313 +-
modules/mpegts_in/Makefile | 8 +-
modules/mpegts_in/mpegts_in.c | 399 +-
modules/mse_in/Makefile | 59 +
modules/mse_in/mse_in.c | 364 +
modules/odf_dec/Makefile | 8 +-
modules/odf_dec/odf_dec.c | 8 +-
modules/ogg/Makefile | 8 +-
modules/ogg/ogg_in.c | 5 +-
modules/ogg/ogg_load.c | 19 +-
modules/opencv_is/Makefile | 8 +-
modules/opencv_is/opencv_is.c | 8 +-
modules/openhevc_dec/Makefile | 49 +
modules/openhevc_dec/openhevc_dec.c | 461 +
modules/opensvc_dec/Makefile | 8 +-
modules/opensvc_dec/opensvc_dec.c | 183 +-
modules/osd/Makefile | 100 +-
modules/osd/osd.c | 604 +-
modules/oss_audio/Makefile | 9 +-
modules/oss_audio/oss.c | 8 +-
modules/platinum/GPACFileMediaServer.cpp | 55 +-
modules/platinum/GPACFileMediaServer.h | 10 +-
modules/platinum/GPACMediaController.cpp | 8 +-
modules/platinum/GPACMediaController.h | 8 +-
modules/platinum/GPACMediaRenderer.cpp | 61 +-
modules/platinum/GPACMediaRenderer.h | 7 +-
modules/platinum/GPACPlatinum.cpp | 187 +-
modules/platinum/GenericDevice.cpp | 42 +-
modules/platinum/GenericDevice.h | 4 +-
modules/platinum/Makefile | 16 +-
modules/pulseaudio/Makefile | 9 +-
modules/pulseaudio/pulseaudio.c | 7 +-
modules/raw_out/Makefile | 8 +-
modules/raw_out/raw_video.c | 131 +-
modules/redirect_av/Makefile | 13 +-
modules/redirect_av/ffmpeg_ts_muxer.c | 14 +-
modules/redirect_av/gpac_ts_muxer.c | 3 +-
modules/redirect_av/redirect_av.c | 45 +-
modules/rtp_in/Makefile | 8 +-
modules/rtp_in/rtp_in.c | 124 +-
modules/rtp_in/rtp_in.h | 16 +-
modules/rtp_in/rtp_session.c | 16 +-
modules/rtp_in/rtp_signaling.c | 18 +-
modules/rtp_in/rtp_stream.c | 100 +-
modules/rtp_in/sdp_fetch.c | 6 +-
modules/rtp_in/sdp_load.c | 53 +-
modules/rvc_dec/Makefile | 8 +-
modules/rvc_dec/rvc_dec.c | 903 +-
modules/saf_in/Makefile | 8 +-
modules/saf_in/saf_in.c | 10 +-
modules/sdl_out/Makefile | 12 +-
modules/sdl_out/audio.c | 34 +-
modules/sdl_out/cursors.c | 2 +
modules/sdl_out/sdl_out.c | 26 +-
modules/sdl_out/sdl_out.h | 24 +-
modules/sdl_out/video.c | 683 +-
modules/soft_raster/Makefile | 8 +-
modules/soft_raster/rast_soft.h | 1 +
modules/soft_raster/raster_565.c | 8 +-
modules/soft_raster/raster_argb.c | 151 +-
modules/soft_raster/raster_load.c | 8 +-
modules/soft_raster/stencil.c | 10 +-
modules/soft_raster/surface.c | 5 +-
modules/svg_in/Makefile | 15 +-
modules/svg_in/svg_in.c | 17 +-
modules/timedtext/Makefile | 8 +-
modules/timedtext/timedtext_dec.c | 16 +-
modules/ui_rec/Makefile | 8 +-
modules/ui_rec/ui_rec.c | 8 +-
modules/validator/validator.c | 2033 +-
modules/vtt_in/Makefile | 51 +
modules/vtt_in/vtt_dec.c | 396 +
modules/vtt_in/vtt_in.c | 441 +
modules/wav_out/Makefile | 8 +-
modules/wav_out/wav_out.c | 8 +-
modules/widgetman/Makefile | 8 +-
modules/widgetman/unzip.c | 2 +-
modules/widgetman/widget.c | 4 +-
modules/widgetman/widgetman.c | 78 +-
modules/wiiis/Makefile | 8 +-
modules/wiiis/wiiis.c | 8 +-
modules/x11_out/Makefile | 8 +-
modules/x11_out/x11_out.c | 138 +-
modules/x11_out/x11_out.h | 1 +
modules/xvid_dec/Makefile | 8 +-
modules/xvid_dec/xvid_dec.c | 19 +-
modules/xvid_dec/xvid_dec_wce.cpp | 8 +-
packagers/win32_64/nsis/default.out | 0
.../win32_64/nsis}/gpac_installer.nsi | 192 +-
.../win32_64/nsis}/readme.txt | 0
regression_tests/auxiliary_files/logo.bt | 126 +
...exturing-compositetexture2D-transparent.bt | 4 +-
regression_tests/dom/gpac-dom-portability.js | 144 +
regression_tests/dom/gpac-html-portability.js | 96 +
.../html5_video/basic_arraybuffer.js | 21 +
regression_tests/html5_video/basic_audio.svg | 12 +
.../html5_video/basic_mediasource.js | 25 +
.../html5_video/basic_sourcebuffer.js | 53 +
regression_tests/html5_video/basic_url.js | 26 +
regression_tests/html5_video/basic_video.js | 81 +
regression_tests/html5_video/basic_video.svg | 7 +
regression_tests/html5_video/bind.js | 26 +
.../counter-mp4-audio-segments-http.js | 20 +
.../counter-mp4-av-segments-http.js | 20 +
.../counter-mp4-video-segments-http.js | 36 +
...unter-mp4-video-segments-live-nobs-http.js | 36 +
.../counter-mp4-video-segments-local.js | 28 +
regression_tests/html5_video/file.json | 1 +
regression_tests/html5_video/file.txt | 1 +
regression_tests/html5_video/file.xml | 4 +
.../html5_video/gpac-mse-spatial.js | 55 +
regression_tests/html5_video/gpac-mse.js | 358 +
.../html5_video/implementation_notes.txt | 36 +
regression_tests/html5_video/mediaevents.js | 348 +
regression_tests/html5_video/mediaevents.svg | 29 +
regression_tests/html5_video/mse-overlap.js | 71 +
regression_tests/html5_video/mse.svg | 58 +
regression_tests/html5_video/myanmar-tiles.js | 135 +
.../html5_video/nodejs-byte-server.js | 71 +
.../redbull-mp4-audio-segments-http.js | 36 +
.../redbull-mp4-video-segments-http.js | 140 +
regression_tests/html5_video/spatial-mse.svg | 28 +
regression_tests/html5_video/two-videos.svg | 33 +
regression_tests/html5_video/video.svg | 30 +
regression_tests/html5_video/xhr.js | 147 +
regression_tests/html5_video/xhr.svg | 4 +
regression_tests/webvtt/comments.vtt | 45 +
regression_tests/webvtt/concatenation.vtt | 51 +
regression_tests/webvtt/counter.srt | 2400 +
regression_tests/webvtt/counter.vtt | 4502 ++
.../webvtt/elephants-dream-chapters-en.vtt | 29 +
.../webvtt/elephants-dream-subtitles-de.vtt | 309 +
.../webvtt/elephants-dream-subtitles-en.vtt | 357 +
regression_tests/webvtt/empty.vtt | 1 +
regression_tests/webvtt/empty2.vtt | 1 +
regression_tests/webvtt/empty3.vtt | 2 +
regression_tests/webvtt/empty4.vtt | 3 +
regression_tests/webvtt/header.vtt | 42 +
regression_tests/webvtt/invalid1.vtt | 3 +
regression_tests/webvtt/invalid2.vtt | 3 +
regression_tests/webvtt/invalid3.vtt | 5 +
regression_tests/webvtt/invalid4.vtt | 8 +
regression_tests/webvtt/invalid5.vtt | 12 +
regression_tests/webvtt/long-duration.vtt | 43814 ++++++++++++++++
.../webvtt/multiline-header-additional.vtt | 23 +
.../webvtt/multiline-header-id-invalid.vtt | 23 +
.../webvtt/multiline-header-id.vtt | 22 +
regression_tests/webvtt/multiline-header.vtt | 25 +
regression_tests/webvtt/overlapping-end.vtt | 17 +
.../webvtt/overlapping-middle.vtt | 17 +
.../webvtt/overlapping-rewritten.vtt | 81 +
regression_tests/webvtt/overlapping-start.vtt | 17 +
regression_tests/webvtt/overlapping.vtt | 26 +
regression_tests/webvtt/simple.vtt | 32 +
regression_tests/webvtt/spaces.vtt | 36 +
.../webvtt/spec-example-basic.vtt | 40 +
.../webvtt/spec-example-comment.vtt | 10 +
.../webvtt/spec-example-comment2.vtt | 21 +
.../webvtt/spec-example-identifier.vtt | 8 +
.../webvtt/spec-example-multiple-lines.vtt | 11 +
.../webvtt/spec-example-nested.vtt | 19 +
.../webvtt/spec-example-voice.vtt | 13 +
regression_tests/webvtt/svg.vtt | 4502 ++
.../webvtt/timestamps-invalid.vtt | 10 +
regression_tests/webvtt/timestamps.vtt | 19 +
src/Makefile | 320 +-
src/bifs/com_dec.c | 7 +-
src/bifs/field_decode.c | 2 +-
src/bifs/field_encode.c | 14 +-
src/bifs/quantize.c | 1 +
src/bifs/script_dec.c | 2 +-
src/bifs/script_enc.c | 5 +-
src/compositor/audio_input.c | 6 +-
src/compositor/audio_mixer.c | 79 +-
src/compositor/audio_render.c | 2 +-
src/compositor/camera.c | 17 +-
src/compositor/compositor.c | 547 +-
src/compositor/compositor_2d.c | 503 +-
src/compositor/compositor_3d.c | 2 +-
src/compositor/compositor_node_init.c | 15 +-
src/compositor/drawable.c | 40 +-
src/compositor/drawable.h | 4 +
src/compositor/events.c | 28 +-
src/compositor/font_engine.c | 2 +-
src/compositor/gl_inc.h | 10 +-
src/compositor/hardcoded_protos.c | 2 +-
src/compositor/mesh_collide.c | 2 +-
src/compositor/mesh_tesselate.c | 4 +
src/compositor/mpeg4_audio.c | 2 +-
src/compositor/mpeg4_background2d.c | 65 +-
src/compositor/mpeg4_bitmap.c | 6 +-
src/compositor/mpeg4_composite.c | 1 +
src/compositor/mpeg4_geometry_2d.c | 6 +-
src/compositor/mpeg4_layer_2d.c | 6 +-
src/compositor/mpeg4_layout.c | 6 +-
src/compositor/mpeg4_sensors.c | 11 +-
src/compositor/mpeg4_textures.c | 14 +-
src/compositor/offscreen_cache.c | 2 +-
src/compositor/svg_filters.c | 4 +-
src/compositor/svg_font.c | 22 +-
src/compositor/svg_geometry.c | 3 +-
src/compositor/svg_grouping.c | 2 +-
src/compositor/svg_media.c | 116 +-
src/compositor/svg_text.c | 8 +-
src/compositor/texturing.c | 51 +-
src/compositor/texturing.h | 2 +
src/compositor/texturing_gl.c | 388 +-
src/compositor/visual_manager.c | 7 +-
src/compositor/visual_manager.h | 16 +-
src/compositor/visual_manager_2d.c | 142 +-
src/compositor/visual_manager_2d.h | 40 +-
src/compositor/visual_manager_2d_draw.c | 155 +-
src/compositor/visual_manager_3d.c | 32 +-
src/compositor/visual_manager_3d.h | 2 +
src/compositor/visual_manager_3d_gl.c | 276 +-
src/export.cpp | 258 +-
src/ietf/rtcp.c | 52 +-
src/ietf/rtp.c | 40 +-
src/ietf/rtp_depacketizer.c | 223 +-
src/ietf/rtp_packetizer.c | 9 +-
src/ietf/rtp_pck_mpeg4.c | 157 +-
src/ietf/rtp_streamer.c | 48 +-
src/ietf/rtsp_command.c | 2 +-
src/ietf/rtsp_common.c | 48 +-
src/ietf/rtsp_response.c | 24 +-
src/ietf/rtsp_session.c | 10 +-
src/ietf/sdp.c | 2 +-
src/isomedia/avc_ext.c | 839 +-
src/isomedia/box_code_3gpp.c | 30 +-
src/isomedia/box_code_adobe.c | 1382 +-
src/isomedia/box_code_base.c | 594 +-
src/isomedia/box_code_drm.c | 265 +-
src/isomedia/box_code_meta.c | 6 +-
src/isomedia/box_dump.c | 296 +-
src/isomedia/box_funcs.c | 190 +-
src/isomedia/data_map.c | 118 +-
src/isomedia/drm_sample.c | 833 +-
src/isomedia/generic_subtitle.c | 322 -
src/isomedia/hint_track.c | 4 +-
src/isomedia/isom_intern.c | 126 +-
src/isomedia/isom_read.c | 604 +-
src/isomedia/isom_store.c | 13 +-
src/isomedia/isom_write.c | 224 +-
src/isomedia/media.c | 60 +-
src/isomedia/meta.c | 35 +-
src/isomedia/movie_fragments.c | 353 +-
src/isomedia/sample_descs.c | 27 +-
src/isomedia/stbl_read.c | 10 +-
src/isomedia/stbl_write.c | 18 +-
src/isomedia/track.c | 159 +-
src/isomedia/ttml.c | 372 +
src/isomedia/tx3g.c | 10 +-
src/laser/lsr_dec.c | 9 +-
src/laser/lsr_enc.c | 16 +-
src/mcrypt/cbc.c | 4 +-
src/mcrypt/g_crypt.c | 3 +-
src/media_tools/ait.c | 1584 +-
src/media_tools/av_parsers.c | 778 +-
src/media_tools/avilib.c | 6 +-
src/media_tools/dash_client.c | 8624 +--
src/media_tools/dash_segmenter.c | 8570 +--
src/media_tools/dsmcc.c | 3879 +-
src/media_tools/filestreamer.c | 60 +-
src/media_tools/gpac_ogg.c | 4 +-
src/media_tools/html5_media.c | 229 +
src/media_tools/html5_mse.c | 889 +
src/media_tools/img.c | 48 +-
src/media_tools/ismacryp.c | 1269 +-
src/media_tools/isom_hinter.c | 40 +-
src/media_tools/isom_tools.c | 781 +-
src/media_tools/m2ts_mux.c | 408 +-
src/media_tools/m3u8.c | 8 +-
src/media_tools/media_export.c | 576 +-
src/media_tools/media_import.c | 1031 +-
src/media_tools/mpd.c | 84 +-
src/media_tools/mpeg2_ps.c | 2 +-
src/media_tools/mpegts.c | 801 +-
src/media_tools/saf.c | 4 +-
src/media_tools/text_import.c | 679 +-
src/media_tools/webvtt.c | 1495 +
src/odf/descriptors.c | 78 +-
src/odf/ipmpx_code.c | 4 +-
src/odf/ipmpx_parse.c | 12 +-
src/odf/odf_code.c | 42 +-
src/odf/odf_dump.c | 15 +-
src/odf/odf_parse.c | 13 +-
src/scene_manager/loader_bt.c | 39 +-
src/scene_manager/loader_svg.c | 203 +-
src/scene_manager/loader_xmt.c | 45 +-
src/scene_manager/scene_dump.c | 90 +-
src/scene_manager/scene_engine.c | 2 +-
src/scene_manager/scene_manager.c | 6 +-
src/scene_manager/swf_bifs.c | 10 +-
src/scene_manager/swf_parse.c | 116 +-
src/scene_manager/swf_svg.c | 1717 +-
src/scene_manager/text_to_bifs.c | 4 +-
src/scenegraph/base_scenegraph.c | 31 +-
src/scenegraph/dom_events.c | 445 +-
src/scenegraph/dom_smjs.c | 2095 +-
src/scenegraph/html5_media_smjs.c | 1631 +
src/scenegraph/html5_mse_smjs.c | 860 +
src/scenegraph/mpeg4_nodes.c | 724 +-
src/scenegraph/smil_timing.c | 4 +-
src/scenegraph/svg_attributes.c | 83 +-
src/scenegraph/svg_smjs.c | 304 +-
src/scenegraph/svg_types.c | 13 +-
src/scenegraph/vrml_proto.c | 12 +-
src/scenegraph/vrml_route.c | 55 +-
src/scenegraph/vrml_smjs.c | 143 +-
src/scenegraph/vrml_tools.c | 12 +-
src/scenegraph/webvtt_smjs.c | 127 +
src/scenegraph/xml_ns.c | 14 +-
src/terminal/channel.c | 466 +-
src/terminal/clock.c | 54 +-
src/terminal/decoder.c | 403 +-
src/terminal/input_sensor.c | 16 +-
src/terminal/media_control.h | 2 +-
src/terminal/media_manager.c | 74 +-
src/terminal/media_memory.c | 54 +-
src/terminal/media_memory.h | 2 +
src/terminal/media_object.c | 422 +-
src/terminal/media_sensor.c | 3 +
src/terminal/mpeg4_inline.c | 110 +-
src/terminal/network_service.c | 179 +-
src/terminal/object_browser.c | 43 +-
src/terminal/object_manager.c | 150 +-
src/terminal/scene.c | 212 +-
src/terminal/term_node_init.c | 4 +-
src/terminal/terminal.c | 173 +-
src/utils/alloc.c | 13 +-
src/utils/bitstream.c | 113 +-
src/utils/cache.c | 57 +-
src/utils/color.c | 119 +-
src/utils/configfile.c | 20 +-
src/utils/dlmalloc.c | 29 +-
src/utils/downloader.c | 700 +-
src/utils/error.c | 29 +-
src/utils/list.c | 81 +-
src/utils/map.c | 337 +
src/utils/math.c | 17 +-
src/utils/module.c | 244 +-
src/utils/module_wrap.h | 16 +-
src/utils/os_config_init.c | 1095 +-
src/utils/os_divers.c | 298 +-
src/utils/os_module.c | 244 +-
src/utils/os_net.c | 227 +-
src/utils/os_thread.c | 40 +-
src/utils/ringbuffer.c | 9 +-
src/utils/sha1.c | 18 +-
src/utils/token.c | 8 +-
src/utils/url.c | 31 +-
src/utils/utf.c | 4 +-
src/utils/xml_parser.c | 284 +-
705 files changed, 139228 insertions(+), 31713 deletions(-)
create mode 100644 applications/dashcast/Makefile
create mode 100644 applications/dashcast/audio_data.c
create mode 100644 applications/dashcast/audio_data.h
create mode 100644 applications/dashcast/audio_decoder.c
create mode 100644 applications/dashcast/audio_decoder.h
create mode 100644 applications/dashcast/audio_encoder.c
create mode 100644 applications/dashcast/audio_encoder.h
create mode 100644 applications/dashcast/audio_muxer.c
create mode 100644 applications/dashcast/audio_muxer.h
create mode 100644 applications/dashcast/circular_buffer.c
create mode 100644 applications/dashcast/circular_buffer.h
create mode 100644 applications/dashcast/cmd_data.c
create mode 100644 applications/dashcast/cmd_data.h
create mode 100644 applications/dashcast/controler.c
create mode 100644 applications/dashcast/controler.h
create mode 100644 applications/dashcast/dashcast.c
create mode 100644 applications/dashcast/libav_compat.h
create mode 100644 applications/dashcast/message_queue.c
create mode 100644 applications/dashcast/message_queue.h
create mode 100644 applications/dashcast/register.c
create mode 100644 applications/dashcast/register.h
create mode 100644 applications/dashcast/task.c
create mode 100644 applications/dashcast/task.h
create mode 100644 applications/dashcast/video_data.c
create mode 100644 applications/dashcast/video_data.h
create mode 100644 applications/dashcast/video_decoder.c
create mode 100644 applications/dashcast/video_decoder.h
create mode 100644 applications/dashcast/video_encoder.c
create mode 100644 applications/dashcast/video_encoder.h
create mode 100644 applications/dashcast/video_muxer.c
create mode 100644 applications/dashcast/video_muxer.h
create mode 100644 applications/dashcast/video_scaler.c
create mode 100644 applications/dashcast/video_scaler.h
create mode 100644 applications/testapps/bmp4demux/Makefile
create mode 100644 applications/testapps/bmp4demux/bmp4demux.sln
create mode 100644 applications/testapps/bmp4demux/bmp4demux.vcxproj
create mode 100644 applications/testapps/bmp4demux/bmp4demux.vcxproj.filters
create mode 100644 applications/testapps/bmp4demux/build.sh
create mode 100644 applications/testapps/bmp4demux/main.c
create mode 100644 applications/testapps/fmp4demux/Makefile
create mode 100755 applications/testapps/fmp4demux/build.sh
create mode 100644 applications/testapps/fmp4demux/fmp4demux.sln
create mode 100644 applications/testapps/fmp4demux/fmp4demux.vcxproj
create mode 100644 applications/testapps/fmp4demux/fmp4demux.vcxproj.filters
create mode 100644 applications/testapps/fmp4demux/main.c
create mode 100644 applications/testapps/segmp4demux/Makefile
create mode 100644 applications/testapps/segmp4demux/build.sh
create mode 100644 applications/testapps/segmp4demux/main.c
create mode 100644 applications/testapps/segmp4demux/segmp4demux.sln
create mode 100644 applications/testapps/segmp4demux/segmp4demux.vcxproj
create mode 100644 applications/testapps/segmp4demux/segmp4demux.vcxproj.filters
delete mode 100644 bin/win32/release/nsis_install/default.out
create mode 100644 doc/doxyfile-full
rename extra_lib/include/{faad => }/faad.h (100%)
create mode 100644 extra_lib/include/libavdevice/avdevice.h
create mode 100644 extra_lib/include/libavdevice/version.h
rename extra_lib/include/{mad => }/mad.h (100%)
rename extra_lib/include/{faad => }/neaacdec.h (100%)
create mode 100644 extra_lib/include/openHevcWrapper.h
rename extra_lib/include/{openjpeg => }/openjpeg.h (100%)
create mode 100644 extra_lib/include/platinum/NptAutomaticCleaner.h
create mode 100644 extra_lib/include/platinum/NptAutoreleasePool.h
create mode 100644 extra_lib/include/platinum/NptCrypto.h
create mode 100644 extra_lib/include/platinum/NptDigest.h
create mode 100644 extra_lib/include/platinum/NptHash.h
create mode 100644 extra_lib/include/platinum/NptJson.h
create mode 100644 extra_lib/include/platinum/NptTlsDefaultTrustAnchorsBase.h
create mode 100644 extra_lib/include/platinum/NptTlsDefaultTrustAnchorsExtended.h
create mode 100644 extra_lib/include/platinum/PltFrameBuffer.h
create mode 100644 extra_lib/include/platinum/PltFrameServer.h
create mode 100644 extra_lib/include/platinum/PltFrameStream.h
create mode 100644 extra_lib/include/platinum/PltMimeType.h
create mode 100644 extra_lib/include/platinum/PltProtocolInfo.h
create mode 100644 extra_lib/include/platinum/PltUtilities.h
create mode 100644 extra_lib/include/platinum/PltXbox360.h
rename extra_lib/include/{xvid => }/xvid.h (100%)
create mode 100644 fixEOL.sh
create mode 100644 gui/webvtt-renderer.js
create mode 100644 include/gpac/html5_media.h
create mode 100644 include/gpac/html5_mse.h
create mode 100644 include/gpac/map.h
create mode 100644 include/gpac/webvtt.h
create mode 100644 modules/ios_cam/CameraObject.h
create mode 100644 modules/ios_cam/CameraObject.m
create mode 100644 modules/ios_cam/cam_wrap.h
create mode 100644 modules/ios_cam/cam_wrap.m
create mode 100644 modules/ios_cam/ios_cam.c
create mode 100644 modules/ios_mpegv/SensorAcces.m
create mode 100644 modules/ios_mpegv/SensorAccess.h
create mode 100644 modules/ios_mpegv/ios_mpegv-Prefix.pch
create mode 100644 modules/ios_mpegv/ios_mpegv.c
create mode 100644 modules/ios_mpegv/sensor_wrap.h
create mode 100644 modules/ismacryp/isma_ea.c
delete mode 100644 modules/ismacryp/ismacryp.c
rename modules/isom_in/{cache.c => isom_cache.c} (99%)
create mode 100644 modules/mse_in/Makefile
create mode 100644 modules/mse_in/mse_in.c
create mode 100644 modules/openhevc_dec/Makefile
create mode 100644 modules/openhevc_dec/openhevc_dec.c
create mode 100644 modules/vtt_in/Makefile
create mode 100644 modules/vtt_in/vtt_dec.c
create mode 100644 modules/vtt_in/vtt_in.c
create mode 100644 packagers/win32_64/nsis/default.out
rename {bin/win32/release/nsis_install => packagers/win32_64/nsis}/gpac_installer.nsi (81%)
rename {bin/win32/release/nsis_install => packagers/win32_64/nsis}/readme.txt (100%)
create mode 100644 regression_tests/auxiliary_files/logo.bt
create mode 100644 regression_tests/dom/gpac-dom-portability.js
create mode 100644 regression_tests/dom/gpac-html-portability.js
create mode 100644 regression_tests/html5_video/basic_arraybuffer.js
create mode 100644 regression_tests/html5_video/basic_audio.svg
create mode 100644 regression_tests/html5_video/basic_mediasource.js
create mode 100644 regression_tests/html5_video/basic_sourcebuffer.js
create mode 100644 regression_tests/html5_video/basic_url.js
create mode 100644 regression_tests/html5_video/basic_video.js
create mode 100644 regression_tests/html5_video/basic_video.svg
create mode 100644 regression_tests/html5_video/bind.js
create mode 100644 regression_tests/html5_video/counter-mp4-audio-segments-http.js
create mode 100644 regression_tests/html5_video/counter-mp4-av-segments-http.js
create mode 100644 regression_tests/html5_video/counter-mp4-video-segments-http.js
create mode 100644 regression_tests/html5_video/counter-mp4-video-segments-live-nobs-http.js
create mode 100644 regression_tests/html5_video/counter-mp4-video-segments-local.js
create mode 100644 regression_tests/html5_video/file.json
create mode 100644 regression_tests/html5_video/file.txt
create mode 100644 regression_tests/html5_video/file.xml
create mode 100644 regression_tests/html5_video/gpac-mse-spatial.js
create mode 100644 regression_tests/html5_video/gpac-mse.js
create mode 100644 regression_tests/html5_video/implementation_notes.txt
create mode 100644 regression_tests/html5_video/mediaevents.js
create mode 100644 regression_tests/html5_video/mediaevents.svg
create mode 100644 regression_tests/html5_video/mse-overlap.js
create mode 100644 regression_tests/html5_video/mse.svg
create mode 100644 regression_tests/html5_video/myanmar-tiles.js
create mode 100644 regression_tests/html5_video/nodejs-byte-server.js
create mode 100644 regression_tests/html5_video/redbull-mp4-audio-segments-http.js
create mode 100644 regression_tests/html5_video/redbull-mp4-video-segments-http.js
create mode 100644 regression_tests/html5_video/spatial-mse.svg
create mode 100644 regression_tests/html5_video/two-videos.svg
create mode 100644 regression_tests/html5_video/video.svg
create mode 100644 regression_tests/html5_video/xhr.js
create mode 100644 regression_tests/html5_video/xhr.svg
create mode 100644 regression_tests/webvtt/comments.vtt
create mode 100644 regression_tests/webvtt/concatenation.vtt
create mode 100644 regression_tests/webvtt/counter.srt
create mode 100644 regression_tests/webvtt/counter.vtt
create mode 100644 regression_tests/webvtt/elephants-dream-chapters-en.vtt
create mode 100644 regression_tests/webvtt/elephants-dream-subtitles-de.vtt
create mode 100644 regression_tests/webvtt/elephants-dream-subtitles-en.vtt
create mode 100644 regression_tests/webvtt/empty.vtt
create mode 100644 regression_tests/webvtt/empty2.vtt
create mode 100644 regression_tests/webvtt/empty3.vtt
create mode 100644 regression_tests/webvtt/empty4.vtt
create mode 100644 regression_tests/webvtt/header.vtt
create mode 100644 regression_tests/webvtt/invalid1.vtt
create mode 100644 regression_tests/webvtt/invalid2.vtt
create mode 100644 regression_tests/webvtt/invalid3.vtt
create mode 100644 regression_tests/webvtt/invalid4.vtt
create mode 100644 regression_tests/webvtt/invalid5.vtt
create mode 100644 regression_tests/webvtt/long-duration.vtt
create mode 100644 regression_tests/webvtt/multiline-header-additional.vtt
create mode 100644 regression_tests/webvtt/multiline-header-id-invalid.vtt
create mode 100644 regression_tests/webvtt/multiline-header-id.vtt
create mode 100644 regression_tests/webvtt/multiline-header.vtt
create mode 100644 regression_tests/webvtt/overlapping-end.vtt
create mode 100644 regression_tests/webvtt/overlapping-middle.vtt
create mode 100644 regression_tests/webvtt/overlapping-rewritten.vtt
create mode 100644 regression_tests/webvtt/overlapping-start.vtt
create mode 100644 regression_tests/webvtt/overlapping.vtt
create mode 100644 regression_tests/webvtt/simple.vtt
create mode 100644 regression_tests/webvtt/spaces.vtt
create mode 100644 regression_tests/webvtt/spec-example-basic.vtt
create mode 100644 regression_tests/webvtt/spec-example-comment.vtt
create mode 100644 regression_tests/webvtt/spec-example-comment2.vtt
create mode 100644 regression_tests/webvtt/spec-example-identifier.vtt
create mode 100644 regression_tests/webvtt/spec-example-multiple-lines.vtt
create mode 100644 regression_tests/webvtt/spec-example-nested.vtt
create mode 100644 regression_tests/webvtt/spec-example-voice.vtt
create mode 100644 regression_tests/webvtt/svg.vtt
create mode 100644 regression_tests/webvtt/timestamps-invalid.vtt
create mode 100644 regression_tests/webvtt/timestamps.vtt
delete mode 100644 src/isomedia/generic_subtitle.c
create mode 100644 src/isomedia/ttml.c
create mode 100644 src/media_tools/html5_media.c
create mode 100644 src/media_tools/html5_mse.c
create mode 100644 src/media_tools/webvtt.c
create mode 100644 src/scenegraph/html5_media_smjs.c
create mode 100644 src/scenegraph/html5_mse_smjs.c
create mode 100644 src/scenegraph/webvtt_smjs.c
create mode 100644 src/utils/map.c
diff --git a/Makefile b/Makefile
index a3bd4b4..77f440e 100644
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,19 @@ all: version
$(MAKE) -C applications all
$(MAKE) -C modules all
+SVNREV_PATH:=$(SRC_PATH)/include/gpac/revision.h
+
version:
- @if [ -d ".svn" ]; then if which svnversion >/dev/null; then echo "#define GPAC_SVN_REVISION \"$(shell svnversion $(SRC_PATH) )\"" > $(SRC_PATH)/include/gpac/revision.h ; else echo "No SVN Version found"; fi; fi
+ @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 \
+ else \
+ echo "No SVN Version found" ; \
+ fi \
lib: version
$(MAKE) -C src all
@@ -57,6 +68,13 @@ install:
$(INSTALL) -d "$(DESTDIR)$(prefix)"
$(INSTALL) -d "$(DESTDIR)$(prefix)/$(libdir)"
$(INSTALL) -d "$(DESTDIR)$(prefix)/bin"
+ifeq ($(DISABLE_ISOFF), no)
+ifeq ($(CONFIG_LINUX), yes)
+ifneq ($(CONFIG_FFMPEG), no)
+ $(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/DashCast "$(DESTDIR)$(prefix)/bin"
+endif
+endif
+endif
ifeq ($(DISABLE_ISOFF), no)
$(INSTALL) $(INSTFLAGS) -m 755 bin/gcc/MP4Box "$(DESTDIR)$(prefix)/bin"
endif
@@ -99,6 +117,7 @@ uninstall:
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/DashCast
rm -rf $(DESTDIR)$(mandir)/man1/mp4box.1
rm -rf $(DESTDIR)$(mandir)/man1/mp4client.1
rm -rf $(DESTDIR)$(mandir)/man1/gpac.1
@@ -193,6 +212,4 @@ endif
@echo
@echo "to build libgpac documentation, go to gpac/doc and type 'doxygen'"
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/Makefile b/applications/Makefile
index b2511e9..da358cb 100644
--- a/applications/Makefile
+++ b/applications/Makefile
@@ -6,8 +6,16 @@ ifeq ($(DISABLE_PLAYER), no)
APPDIRS+=mp4client
endif
+
ifeq ($(DISABLE_ISOFF), no)
-APPDIRS+=mp4box
+APPDIRS+=mp4box
+ifneq ($(CONFIG_FFMPEG), no)
+ifneq ($(DISABLE_CORE_TOOLS), yes)
+ifneq ($(DISABLE_AV_PARSERS), yes)
+APPDIRS+=dashcast
+endif
+endif
+endif
ifeq ($(DISABLE_M2TS_MUX), no)
APPDIRS+=mp42ts
endif
diff --git a/applications/dashcast/Makefile b/applications/dashcast/Makefile
new file mode 100644
index 0000000..a68e927
--- /dev/null
+++ b/applications/dashcast/Makefile
@@ -0,0 +1,71 @@
+include ../../config.mak
+
+vpath %.c $(SRC_PATH)/applications/dashcast
+
+CFLAGS= $(OPTFLAGS) -D_GNU_SOURCE -I"$(SRC_PATH)/include" -I../../ $(ffmpeg_cflags)
+
+LINKLIBS=$(GPAC_SH_FLAGS)
+
+ifeq ($(DEBUGBUILD), yes)
+CFLAGS+=-g
+LDFLAGS+=-g
+endif
+
+ifeq ($(GPROFBUILD), yes)
+CFLAGS+=-pg
+LDFLAGS+=-pg
+endif
+
+ifeq ($(GPACREADONLY), yes)
+CFLAGS+=-DGPAC_READ_ONLY
+endif
+
+ifeq ($(CONFIG_LIBAV),yes)
+CFLAGS+=-DGPAC_USE_LIBAV
+endif
+
+#common obj
+OBJS= dashcast.o audio_data.o audio_decoder.o audio_encoder.o audio_muxer.o circular_buffer.o cmd_data.o controler.o message_queue.o register.o video_data.o video_decoder.o video_encoder.o video_muxer.o video_scaler.o task.o
+
+ifeq ($(CONFIG_WIN32),yes)
+EXE=.exe
+PROG=DashCast$(EXE)
+else
+EXT=
+PROG=DashCast
+endif
+
+LINKLIBS+= $(ffmpeg_lflags)
+
+ifeq ($(CONFIG_DARWIN), yes)
+#fixme - use proper detection of libavdevice dependencies
+LINKLIBS+=-lavfilter -lswresample -lbz2
+endif
+
+
+SRCS := $(OBJS:.o=.c)
+
+all: $(PROG)
+
+DashCast$(EXE): $(OBJS)
+ $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) -L../../bin/gcc -lgpac $(LINKLIBS)
+
+clean:
+ rm -f $(OBJS) ../../bin/gcc/$(PROG)
+
+install: clean
+ install -m 755 $(INSTFLAGS) ../../bin/gcc/DashCast "$(DESTDIR)$(prefix)/bin"
+
+uninstall:
+ rm -rf $(DESTDIR)$(prefix)/bin/DashCast
+
+dep: depend
+
+depend:
+ rm -f .depend
+ $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
+
+distclean: clean
+ rm -f Makefile.bak .depend
+
+-include .depend
diff --git a/applications/dashcast/audio_data.c b/applications/dashcast/audio_data.c
new file mode 100644
index 0000000..5512d0f
--- /dev/null
+++ b/applications/dashcast/audio_data.c
@@ -0,0 +1,97 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "audio_data.h"
+
+
+void dc_audio_data_set_default(AudioDataConf *audio_data_conf)
+{
+ strcpy(audio_data_conf->filename, "");
+ strcpy(audio_data_conf->format, "");
+ strcpy(audio_data_conf->codec, "");
+ audio_data_conf->bitrate = -1;
+ audio_data_conf->channels= -1;
+ audio_data_conf->samplerate = -1;
+}
+
+void dc_audio_data_init(AudioDataConf *audio_data_conf, char *filename, char *format)
+{
+ if (filename != NULL && strlen(filename) > 0)
+ strcpy(audio_data_conf->filename, filename);
+ else
+ strcpy(audio_data_conf->filename, "");
+
+ if (format != NULL && strlen(format) > 0)
+ strcpy(audio_data_conf->format, format);
+ else
+ strcpy(audio_data_conf->format, "");
+}
+
+int dc_audio_input_data_init(AudioInputData *audio_input_data, int channels, int samplerate, int num_consumers, int mode)
+{
+ int i;
+
+ dc_producer_init(&audio_input_data->producer, AUDIO_CB_SIZE, "audio decoder");
+ dc_circular_buffer_create(&audio_input_data->circular_buf, AUDIO_CB_SIZE, mode, num_consumers);
+
+ for (i = 0; i < AUDIO_CB_SIZE; i++) {
+ AudioDataNode *audio_data_node = gf_malloc(sizeof(AudioDataNode));
+ audio_input_data->circular_buf.list[i].data = (void *) audio_data_node;
+
+ audio_data_node->abuf_size = MAX_AUDIO_PACKET_SIZE;
+ audio_data_node->abuf = gf_malloc(audio_data_node->abuf_size * sizeof(uint8_t));
+ }
+
+ audio_input_data->aframe = FF_ALLOC_FRAME();
+ if (audio_input_data->aframe == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize AudioInputData"));
+ return -1;
+ }
+
+ audio_input_data->channels = channels;
+ audio_input_data->samplerate = samplerate;
+
+ return 0;
+}
+
+void dc_audio_input_data_destroy(AudioInputData *audio_input_data)
+{
+ int i;
+ if (audio_input_data->circular_buf.list) {
+ for (i = 0; i < AUDIO_CB_SIZE; i++) {
+ AudioDataNode *audio_data_node = audio_input_data->circular_buf.list[i].data;
+ gf_free(audio_data_node->abuf);
+ gf_free(audio_data_node);
+ }
+ }
+
+ dc_circular_buffer_destroy(&audio_input_data->circular_buf);
+}
+
+void dc_audio_inout_data_end_signal(AudioInputData *audio_input_data)
+{
+ dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf);
+ dc_producer_end_signal_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
+}
diff --git a/applications/dashcast/audio_data.h b/applications/dashcast/audio_data.h
new file mode 100644
index 0000000..d322e5a
--- /dev/null
+++ b/applications/dashcast/audio_data.h
@@ -0,0 +1,134 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AUDIO_DATA_H_
+#define AUDIO_DATA_H_
+
+#define AUDIO_CB_SIZE 3
+
+#define LIVE_FRAME_SIZE 1024
+#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
+
+
+#include "../../modules/ffmpeg_in/ffmpeg_in.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/mem.h"
+#include "libav_compat.h"
+#include "circular_buffer.h"
+
+#include
+
+
+/*
+ * AudioInputData is designed to keep the data of input audio in a circular buffer.
+ * The circular buffer has its own mechanism for synchronization.
+ */
+typedef struct {
+ /* The circular buffer of input audio. Input audio is the audio frames after decoding. */
+ CircularBuffer circular_buf;
+
+ /* The user of circular buffer has an index to it, which is in this variable. */
+ Producer producer;
+
+ AVFrame *aframe;
+
+ int64_t next_pts;
+
+ int channels;
+ int samplerate;
+} AudioInputData;
+
+/*
+ * This structure corresponds to an entry of audio configuration in the configuration file
+ */
+typedef struct {
+ /* audio file name */
+ char filename[GF_MAX_PATH];
+ /* audio format */
+ char format[GF_MAX_PATH];
+ /* audio bitrate */
+ int bitrate;
+ /* audio samplerate */
+ int samplerate;
+ /* audio channel number */
+ int channels;
+ /* audio codec */
+ char codec[GF_MAX_PATH];
+ /* custom parameter to be passed directly to the encoder - free it once you're done */
+ char *custom;
+
+ /* used for source switching */
+ char source_id[GF_MAX_PATH];
+ time_t start_time;
+ time_t end_time;
+} AudioDataConf;
+
+/*
+ * Each node in a circular buffer is a pointer.
+ * To use the circular buffer for audio frame we must
+ * define the node. AudioDataNode simply contains
+ * an AVFrame.
+ */
+typedef struct {
+ uint8_t *abuf;
+ int abuf_size;
+ uint64_t channel_layout;
+ int sample_rate;
+ int format;
+ int channels;
+} AudioDataNode;
+
+void dc_audio_data_set_default(AudioDataConf *audio_data_conf);
+
+/*
+ * Initialize an AudioInputData.
+ *
+ * @param audio_input_data [out] is the structure to be initialize.
+ * @param num_consumers [in] contains information on the number of users of circular buffer;
+ * which means the number of audio encoders.
+ * @param live [in] indicates the system is live
+ *
+ * @return 0 on success, -1 on failure.
+ *
+ * @note Must use dc_audio_data_destroy to free memory.
+ */
+int dc_audio_input_data_init(AudioInputData *audio_input_data, int channels, int samplerate, int num_consumers, int mode);
+
+/*
+ * Destroy an AudioInputData
+ *
+ * @param audio_input_data [in] the structure to be destroyed.
+ */
+void dc_audio_input_data_destroy(AudioInputData *audio_input_data);
+
+/*
+ * Signal to all the users of the circular buffer in the AudioInputData
+ * which the current node is the last node to consume.
+ *
+ * @param audio_input_data [in] the structure to be signaled on.
+ */
+void dc_audio_inout_data_end_signal(AudioInputData *audio_input_data);
+
+#endif /* AUDIO_DATA_H_ */
diff --git a/applications/dashcast/audio_decoder.c b/applications/dashcast/audio_decoder.c
new file mode 100644
index 0000000..ee18bbf
--- /dev/null
+++ b/applications/dashcast/audio_decoder.c
@@ -0,0 +1,283 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "audio_decoder.h"
+
+int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop)
+{
+ u32 i;
+ AVCodecContext *codec_ctx;
+ AVCodec *codec;
+ AVInputFormat *in_fmt = NULL;
+
+ if (audio_data_conf->format && strcmp(audio_data_conf->format,"") != 0) {
+ in_fmt = av_find_input_format(audio_data_conf->format);
+ if (in_fmt == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", audio_data_conf->format));
+ return -1;
+ }
+ }
+
+ /*
+ * Open audio (may already be opened when shared with the video input).
+ */
+ if (!audio_input_file->av_fmt_ctx) {
+ if (avformat_open_input(&audio_input_file->av_fmt_ctx, audio_data_conf->filename, in_fmt, NULL) != 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file: %s\n", audio_data_conf->filename));
+ return -1;
+ }
+
+ /*
+ * Retrieve stream information
+ */
+ if (avformat_find_stream_info(audio_input_file->av_fmt_ctx, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find stream information\n"));
+ return -1;
+ }
+
+ av_dump_format(audio_input_file->av_fmt_ctx, 0, audio_data_conf->filename, 0);
+ }
+
+ /*
+ * Find the first audio stream
+ */
+ audio_input_file->astream_idx = -1;
+ for (i=0; iav_fmt_ctx->nb_streams; i++) {
+ if (audio_input_file->av_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ audio_input_file->astream_idx = i;
+ break;
+ }
+ }
+ if (audio_input_file->astream_idx == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find a audio stream\n"));
+ return -1;
+ }
+
+ /*
+ * Get a pointer to the codec context for the audio stream
+ */
+ codec_ctx = audio_input_file->av_fmt_ctx->streams[audio_input_file->astream_idx]->codec;
+
+ /*
+ * Find the decoder for the audio stream
+ */
+ codec = avcodec_find_decoder(codec_ctx->codec_id);
+ if (codec == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Input audio codec is not supported.\n"));
+ avformat_close_input(&audio_input_file->av_fmt_ctx);
+ return -1;
+ }
+
+ /*
+ * Open codec
+ */
+ if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio codec.\n"));
+ avformat_close_input(&audio_input_file->av_fmt_ctx);
+ return -1;
+ }
+
+ audio_input_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE);
+
+ audio_data_conf->channels = codec_ctx->channels;
+ audio_data_conf->samplerate = codec_ctx->sample_rate;
+
+ audio_input_file->mode = mode;
+ audio_input_file->no_loop = no_loop;
+
+ return 0;
+}
+
+int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audio_input_data)
+{
+ int ret;
+ AVPacket packet;
+ int got_frame = 0;
+ //int locked_already = 0;
+ AVCodecContext *codec_ctx;
+ AudioDataNode *audio_data_node;
+
+ /* Get a pointer to the codec context for the audio stream */
+ codec_ctx = audio_input_file->av_fmt_ctx->streams[audio_input_file->astream_idx]->codec;
+
+ /* Read frames */
+ while (1) {
+ if (audio_input_file->av_pkt_list) {
+ if (gf_list_count(audio_input_file->av_pkt_list)) {
+ AVPacket *packet_copy;
+ assert(audio_input_file->av_pkt_list);
+ gf_mx_p(audio_input_file->av_pkt_list_mutex);
+ packet_copy = gf_list_pop_front(audio_input_file->av_pkt_list);
+ gf_mx_v(audio_input_file->av_pkt_list_mutex);
+
+ if (packet_copy == NULL) {
+ ret = AVERROR_EOF;
+ } else {
+ memcpy(&packet, packet_copy, sizeof(AVPacket));
+ gf_free(packet_copy);
+ ret = 0;
+ }
+ } else {
+ gf_sleep(1);
+ continue;
+ }
+ } else {
+ ret = av_read_frame(audio_input_file->av_fmt_ctx, &packet);
+ }
+ if (ret == AVERROR_EOF) {
+ if (audio_input_file->mode == LIVE_MEDIA && audio_input_file->no_loop == 0) {
+ av_seek_frame(audio_input_file->av_fmt_ctx, audio_input_file->astream_idx, 0, 0);
+ continue;
+ }
+
+ /* Flush decoder */
+ packet.data = NULL;
+ packet.size = 0;
+ avcodec_get_frame_defaults(audio_input_data->aframe);
+ avcodec_decode_audio4(codec_ctx, audio_input_data->aframe, &got_frame, &packet);
+
+ if (got_frame) {
+ dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf);
+ dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
+ audio_data_node = (AudioDataNode*)dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf);
+
+ audio_data_node->abuf_size = audio_input_data->aframe->linesize[0];
+ memcpy(audio_data_node->abuf, audio_input_data->aframe->data[0], audio_data_node->abuf_size);
+
+ dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf);
+ return 0;
+ }
+
+ dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf);
+ dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
+
+ return -2;
+ }
+ else if (ret < 0)
+ {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot read audio frame.\n"));
+ continue;
+ }
+
+ /* Is this a packet from the audio stream? */
+ if (packet.stream_index == audio_input_file->astream_idx) {
+ /* Set audio frame to default */
+ avcodec_get_frame_defaults(audio_input_data->aframe);
+
+ /* Decode audio frame */
+ if (avcodec_decode_audio4(codec_ctx, audio_input_data->aframe, &got_frame, &packet) < 0) {
+ av_free_packet(&packet);
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while decoding audio.\n"));
+ dc_producer_end_signal(&audio_input_data->producer, &audio_input_data->circular_buf);
+ dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
+ return -1;
+ }
+
+ if (audio_input_data->aframe->pts != AV_NOPTS_VALUE)
+ audio_input_data->next_pts = audio_input_data->aframe->pts;
+
+ audio_input_data->next_pts += ((int64_t)AV_TIME_BASE * audio_input_data->aframe->nb_samples) / codec_ctx->sample_rate;
+
+ /* Did we get a video frame? */
+ if (got_frame) {
+ av_fifo_generic_write(audio_input_file->fifo, audio_input_data->aframe->data[0], audio_input_data->aframe->linesize[0], NULL);
+
+ if (/*audio_input_file->circular_buf.mode == OFFLINE*/audio_input_file->mode == ON_DEMAND || audio_input_file->mode == LIVE_MEDIA) {
+ dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf);
+
+ /* Unlock the previous node in the circular buffer. */
+ dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
+
+ /* Get the pointer of the current node in circular buffer. */
+ audio_data_node = (AudioDataNode *) dc_producer_produce(&audio_input_data->producer, &audio_input_data->circular_buf);
+#ifdef GPAC_USE_LIBAV
+ audio_data_node->channels = codec_ctx->channels;
+ audio_data_node->channel_layout = codec_ctx->request_channel_layout;
+ audio_data_node->sample_rate = codec_ctx->sample_rate;
+#else
+ audio_data_node->channels = audio_input_data->aframe->channels;
+ audio_data_node->channel_layout = audio_input_data->aframe->channel_layout;
+ audio_data_node->sample_rate = audio_input_data->aframe->sample_rate;
+#endif
+ audio_data_node->format = audio_input_data->aframe->format;
+ audio_data_node->abuf_size = audio_input_data->aframe->linesize[0];
+ av_fifo_generic_read(audio_input_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size , NULL);
+
+ dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf);
+ } else {
+ while (av_fifo_size(audio_input_file->fifo) >= LIVE_FRAME_SIZE) {
+ /* Lock the current node in the circular buffer. */
+ if (dc_producer_lock(&audio_input_data->producer, &audio_input_data->circular_buf) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped an audio frame\n"));
+ continue;
+ }
+
+ /* Unlock the previous node in the circular buffer. */
+ dc_producer_unlock_previous(&audio_input_data->producer, &audio_input_data->circular_buf);
+
+ /* Get the pointer of the current node in circular buffer. */
+ audio_data_node = (AudioDataNode *) dc_producer_produce( &audio_input_data->producer, &audio_input_data->circular_buf);
+
+ audio_data_node->abuf_size = LIVE_FRAME_SIZE;
+ av_fifo_generic_read(audio_input_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL);
+
+ dc_producer_advance(&audio_input_data->producer, &audio_input_data->circular_buf);
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ /*
+ * Free the packet that was allocated by av_read_frame
+ */
+ av_free_packet(&packet);
+ }
+
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown error while reading audio frame.\n"));
+ return -1;
+}
+
+void dc_audio_decoder_close(AudioInputFile *audio_input_file)
+{
+ /*
+ * Close the audio format context
+ */
+ avformat_close_input(&audio_input_file->av_fmt_ctx);
+
+ if (audio_input_file->av_pkt_list_mutex) {
+ gf_mx_p(audio_input_file->av_pkt_list_mutex);
+ while (gf_list_count(audio_input_file->av_pkt_list)) {
+ AVPacket *pkt = gf_list_last(audio_input_file->av_pkt_list);
+ av_free_packet(pkt);
+ gf_list_rem_last(audio_input_file->av_pkt_list);
+ }
+ gf_mx_v(audio_input_file->av_pkt_list_mutex);
+ gf_mx_del(audio_input_file->av_pkt_list_mutex);
+ }
+
+ av_fifo_free(audio_input_file->fifo);
+}
diff --git a/applications/dashcast/audio_decoder.h b/applications/dashcast/audio_decoder.h
new file mode 100644
index 0000000..a6fc08d
--- /dev/null
+++ b/applications/dashcast/audio_decoder.h
@@ -0,0 +1,90 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AUDIO_DECODER_H_
+#define AUDIO_DECODER_H_
+
+#include "audio_data.h"
+
+#include "libavformat/avformat.h"
+#include "libavutil/fifo.h"
+
+
+/*
+ * The structure which keeps the data of
+ * input audio file.
+ */
+typedef struct {
+ /* Format context structure provided by avlib to open and read from a media file. */
+ AVFormatContext *av_fmt_ctx;
+
+ /* A list of AVPackets and return value to be processed: when this parameter is non-null,
+ * the video thread makes the demux and pushes the packets. */
+ GF_List *av_pkt_list;
+ GF_Mutex *av_pkt_list_mutex;
+
+ /* The index of the audio stream in the file. */
+ int astream_idx;
+
+ AVFifoBuffer *fifo;
+
+ int mode;
+ int no_loop;
+} AudioInputFile;
+
+/*
+ * Open the input audio
+ *
+ * @param cmd_data [in] contains information about the file name
+ * and the audio format.
+ *
+ * @param audio_input_file [out] pointer to the structure which we want to
+ * open the file
+ *
+ * @return 0 on success -1 on failure.
+ */
+int dc_audio_decoder_open(AudioInputFile *audio_input_file, AudioDataConf *audio_data_conf, int mode, int no_loop);
+
+/*
+ * Read and decode audio and put samples on circular buffer
+ *
+ * @param audio_input_file [in] contains info on input audio. This parameter
+ * must have been opened with open_audio_input
+ *
+ * @param audio_input_data [out] the samples will be saved on the circular buffer
+ * of this parameter.
+ *
+ * @return 0 on success, -1 on failure, -2 on EOF (end of the file)
+ */
+int dc_audio_decoder_read(AudioInputFile *audio_input_file, AudioInputData *audio_input_data);
+
+/*
+ * Close the input audio
+ *
+ * @param audio_input_file [in] the audio file to be closed
+ */
+void dc_audio_decoder_close(AudioInputFile *audio_input_file);
+
+#endif /* AUDIO_DECODER_H_ */
diff --git a/applications/dashcast/audio_encoder.c b/applications/dashcast/audio_encoder.c
new file mode 100644
index 0000000..3cd7b11
--- /dev/null
+++ b/applications/dashcast/audio_encoder.c
@@ -0,0 +1,290 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "audio_encoder.h"
+
+
+extern void build_dict(void *priv_data, const char *options);
+
+
+int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf)
+{
+ int osize;
+
+ audio_output_file->fifo = av_fifo_alloc(2 * MAX_AUDIO_PACKET_SIZE);
+ audio_output_file->aframe = FF_ALLOC_FRAME();
+ audio_output_file->adata_buf = (uint8_t*) av_malloc(2 * MAX_AUDIO_PACKET_SIZE);
+#ifndef GPAC_USE_LIBAV
+ audio_output_file->aframe->channel_layout = 0;
+ audio_output_file->aframe->sample_rate = -1;
+ audio_output_file->aframe->channels = -1;
+#endif
+ audio_output_file->aframe->format = -1;
+ audio_output_file->codec = avcodec_find_encoder_by_name(audio_data_conf->codec);
+ if (audio_output_file->codec == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output audio codec not found\n"));
+ return -1;
+ }
+
+ audio_output_file->codec_ctx = avcodec_alloc_context3(audio_output_file->codec);
+ 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;
+ {
+ AVRational time_base;
+ time_base.num = 1;
+ time_base.den = audio_data_conf->samplerate;
+ audio_output_file->codec_ctx->time_base = time_base;
+ }
+ audio_output_file->codec_ctx->channels = audio_data_conf->channels;
+ audio_output_file->codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; /*FIXME: depends on channels -> http://ffmpeg.org/doxygen/trunk/channel__layout_8c_source.html#l00074*/
+ audio_output_file->codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
+#ifdef DC_AUDIO_RESAMPLER
+ audio_output_file->aresampler = NULL;
+#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;
+
+ /* open the audio codec */
+ if (avcodec_open2(audio_output_file->codec_ctx, audio_output_file->codec, NULL) < 0) {
+ /*FIXME: if we enter here (set "mp2" as a codec and "200000" as a bitrate -> deadlock*/
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio codec\n"));
+ return -1;
+ }
+
+ osize = av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt);
+ audio_output_file->frame_bytes = audio_output_file->codec_ctx->frame_size * osize * audio_output_file->codec_ctx->channels;
+ avcodec_get_frame_defaults(audio_output_file->aframe);
+ audio_output_file->aframe->nb_samples = audio_output_file->frame_bytes
+ / (audio_output_file->codec_ctx->channels * av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt));
+
+ 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->frame_bytes, 1) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Fill audio frame failed\n"));
+ return -1;
+ }
+
+ //audio_output_file->acc_samples = 0;
+ audio_output_file->frame_size = audio_output_file->codec_ctx->frame_size;
+
+ return 0;
+}
+
+int dc_audio_encoder_read(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data)
+{
+ int ret;
+ AudioDataNode *audio_data_node;
+
+ ret = dc_consumer_lock(&audio_output_file->consumer, &audio_input_data->circular_buf);
+ if (ret < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio encoder got an end of buffer!\n"));
+ return -2;
+ }
+
+ dc_consumer_unlock_previous(&audio_output_file->consumer, &audio_input_data->circular_buf);
+
+ audio_data_node = (AudioDataNode *) dc_consumer_consume(&audio_output_file->consumer, &audio_input_data->circular_buf);
+#ifndef GPAC_USE_LIBAV
+ audio_output_file->aframe->channels = audio_data_node->channels;
+ audio_output_file->aframe->channel_layout = audio_data_node->channel_layout;
+ audio_output_file->aframe->sample_rate = audio_data_node->sample_rate;
+#endif
+ audio_output_file->aframe->format = audio_data_node->format;
+
+ /* Write audio sample on fifo */
+// av_fifo_generic_write(audio_output_file->fifo, audio_data_node->aframe->data[0],
+// audio_data_node->aframe->linesize[0], NULL);
+ av_fifo_generic_write(audio_output_file->fifo, audio_data_node->abuf, audio_data_node->abuf_size, NULL);
+
+ dc_consumer_advance(&audio_output_file->consumer);
+
+ return 0;
+}
+
+#if 0
+int dc_audio_encoder_flush(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data)
+{
+ int got_pkt;
+ //AVStream *audio_stream = audio_output_file->av_fmt_ctx->streams[audio_output_file->astream_idx];
+ //AVCodecContext *audio_codec_ctx = audio_stream->codec;
+ AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
+
+ av_init_packet(&audio_output_file->packet);
+ audio_output_file->packet.data = NULL;
+ audio_output_file->packet.size = 0;
+
+ /* Set PTS (method 1) */
+ audio_output_file->aframe->pts = audio_input_data->next_pts;
+ /* Encode audio */
+#ifdef DC_AUDIO_RESAMPLER
+#error resampling is not done here
+#endif
+ if (avcodec_encode_audio2(audio_codec_ctx, &audio_output_file->packet, NULL, &got_pkt) != 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while encoding audio.\n"));
+ return -1;
+ }
+ if (got_pkt) {
+ //audio_output_file->acc_samples += audio_output_file->aframe->nb_samples;
+ return 0;
+ }
+ av_free_packet(&audio_output_file->packet);
+ return 1;
+}
+#endif
+
+int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data)
+{
+ int got_pkt;
+#ifdef DC_AUDIO_RESAMPLER
+ int i;
+#endif
+ //AVStream *audio_stream = audio_output_file->av_fmt_ctx->streams[audio_output_file->astream_idx];
+ //AVCodecContext *audio_codec_ctx = audio_stream->codec;
+ AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
+
+ while (av_fifo_size(audio_output_file->fifo) >= audio_output_file->frame_bytes) {
+ av_fifo_generic_read(audio_output_file->fifo, audio_output_file->adata_buf, audio_output_file->frame_bytes, NULL);
+
+ audio_output_file->aframe->data[0] = audio_output_file->adata_buf;
+ audio_output_file->aframe->linesize[0] = audio_output_file->frame_bytes;
+
+ av_init_packet(&audio_output_file->packet);
+ audio_output_file->packet.data = NULL;
+ audio_output_file->packet.size = 0;
+
+ /*
+ * Set PTS (method 1)
+ */
+ //audio_output_file->aframe->pts = audio_input_data->next_pts;
+
+ /*
+ * Set PTS (method 2)
+ */
+ //{
+ // int64_t now = av_gettime();
+ // AVRational avr;
+ // avr.num = 1;
+ // avr.den = AV_TIME_BASE;
+ // audio_output_file->aframe->pts = av_rescale_q(now, avr, audio_codec_ctx->time_base);
+ //}
+
+ /* Resample if needed */
+ if ( audio_output_file->aframe->format != audio_codec_ctx->sample_fmt
+#ifndef GPAC_USE_LIBAV
+ || audio_output_file->aframe->sample_rate != audio_codec_ctx->sample_rate
+ || audio_output_file->aframe->channel_layout != audio_codec_ctx->channel_layout
+#endif
+ ) {
+#ifndef DC_AUDIO_RESAMPLER
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Audio resampling is needed, but not supported by your version of DashCast. Aborting.\n"));
+ exit(1);
+#else
+ if (!audio_output_file->aresampler) {
+ audio_output_file->aresampler = avresample_alloc_context();
+ if (!audio_output_file->aresampler) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate the audio resampler. Aborting.\n"));
+ return -1;
+ }
+ av_opt_set_int(audio_output_file->aresampler, "in_channel_layout", audio_output_file->aframe->channel_layout, 0);
+ av_opt_set_int(audio_output_file->aresampler, "out_channel_layout", audio_codec_ctx->channel_layout, 0);
+ av_opt_set_int(audio_output_file->aresampler, "in_sample_fmt", audio_output_file->aframe->format, 0);
+ av_opt_set_int(audio_output_file->aresampler, "out_sample_fmt", audio_codec_ctx->sample_fmt, 0);
+ av_opt_set_int(audio_output_file->aresampler, "in_sample_rate", audio_output_file->aframe->sample_rate, 0);
+ av_opt_set_int(audio_output_file->aresampler, "out_sample_rate", audio_codec_ctx->sample_rate, 0);
+ av_opt_set_int(audio_output_file->aresampler, "in_channels", audio_output_file->aframe->channels, 0);
+ av_opt_set_int(audio_output_file->aresampler, "out_channels", audio_codec_ctx->channels, 0);
+
+ if (avresample_open(audio_output_file->aresampler)) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not open the audio resampler. Aborting.\n"));
+ return -1;
+ }
+ }
+
+ //resample - see http://ffmpeg.org/pipermail/libav-user/2012-June/002164.html
+ {
+ int num_planes = av_sample_fmt_is_planar(audio_codec_ctx->sample_fmt) ? 1 : audio_codec_ctx->channels;
+ uint8_t **output = (uint8_t**)av_malloc(num_planes*sizeof(uint8_t*));
+ for (i=0; iaresampler, output, 192000, audio_output_file->aframe->nb_samples, audio_output_file->aframe->extended_data, audio_output_file->aframe->linesize[0], audio_output_file->aframe->nb_samples) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not resample audio frame. Aborting.\n"));
+ return -1;
+ }
+ num_planes = av_sample_fmt_is_planar(audio_codec_ctx->sample_fmt) ? audio_codec_ctx->channels : 1;
+ for (i=0; iaframe->extended_data[i]);
+ }
+ av_free(audio_output_file->aframe->extended_data);
+ audio_output_file->aframe->extended_data = output;
+ audio_codec_ctx->channel_layout = audio_output_file->aframe->channel_layout;
+ audio_codec_ctx->sample_fmt = audio_output_file->aframe->format;
+ audio_codec_ctx->sample_rate = audio_output_file->aframe->sample_rate;
+ audio_codec_ctx->channels = audio_output_file->aframe->channels;
+ }
+#endif
+ }
+
+ /* Encode audio */
+ if (avcodec_encode_audio2(audio_codec_ctx, &audio_output_file->packet, audio_output_file->aframe, &got_pkt) != 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while encoding audio.\n"));
+ return -1;
+ }
+
+ if (got_pkt) {
+ //audio_output_file->acc_samples += audio_output_file->aframe->nb_samples;
+ return 0;
+ }
+
+ av_free_packet(&audio_output_file->packet);
+ }
+
+ return 1;
+}
+
+void dc_audio_encoder_close(AudioOutputFile *audio_output_file)
+{
+// int i;
+//
+// /* free the streams */
+// for (i = 0; i < audio_output_file->av_fmt_ctx->nb_streams; i++) {
+// avcodec_close(audio_output_file->av_fmt_ctx->streams[i]->codec);
+// av_freep(&audio_output_file->av_fmt_ctx->streams[i]->info);
+// }
+
+ av_fifo_free(audio_output_file->fifo);
+
+ av_free(audio_output_file->adata_buf);
+ av_free(audio_output_file->aframe);
+
+ avcodec_close(audio_output_file->codec_ctx);
+ av_free(audio_output_file->codec_ctx);
+}
diff --git a/applications/dashcast/audio_encoder.h b/applications/dashcast/audio_encoder.h
new file mode 100644
index 0000000..c30499a
--- /dev/null
+++ b/applications/dashcast/audio_encoder.h
@@ -0,0 +1,64 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AUDIO_ENCODER_H_
+#define AUDIO_ENCODER_H_
+
+#include "audio_muxer.h"
+
+/*
+ * Open an audio stream
+ *
+ * @param audio_output_file [in] add an audio stream to the file
+ * with the parameters already passed to open_audio_output
+ *
+ * @return 0 on success, -1 on failure
+ */
+int dc_audio_encoder_open(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf);
+
+int dc_audio_encoder_read(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data);
+
+//int dc_audio_encoder_flush(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data);
+
+/*
+ * Read the decoded audio sample from circular buffer (which is in audio_input_data)
+ * and encode and write them on the output file
+ *
+ * @param audio_output_file [in] audio output file
+ * @param audio_input_data [in] audio input data structure which contains a circular buffer with audio samples
+ *
+ * @return 0 on success, -1 on failure, -2 on finishing;
+ * when there is no more data on circular buffer to encode
+ */
+int dc_audio_encoder_encode(AudioOutputFile *audio_output_file, AudioInputData *audio_input_data);
+
+/*
+ * Close the output audio file
+ *
+ * @param audio_output_file [in] audio output file
+ */
+void dc_audio_encoder_close(AudioOutputFile *audio_output_file);
+
+#endif /* AUDIO_ENCODER_H_ */
diff --git a/applications/dashcast/audio_muxer.c b/applications/dashcast/audio_muxer.c
new file mode 100644
index 0000000..0e41e34
--- /dev/null
+++ b/applications/dashcast/audio_muxer.c
@@ -0,0 +1,423 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "audio_muxer.h"
+#include "libavformat/avio.h"
+
+
+int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename)
+{
+ GF_Err ret;
+ u32 di, track;
+ u8 bpsample;
+ GF_ESD *esd;
+#ifndef GPAC_DISABLE_AV_PARSERS
+ GF_M4ADecSpecInfo acfg;
+#endif
+ AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
+
+ audio_output_file->isof = gf_isom_open(filename, GF_ISOM_OPEN_WRITE, NULL);
+ if (!audio_output_file->isof) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open iso file %s\n", filename));
+ return -1;
+ }
+
+ esd = gf_odf_desc_esd_new(2);
+ if (!esd) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create GF_ESD\n"));
+ return -1;
+ }
+
+ esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
+ esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
+ esd->decoderConfig->streamType = GF_STREAM_AUDIO;
+ esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1;
+ esd->decoderConfig->bufferSizeDB = 20;
+ esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate;
+ esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
+ esd->ESID = 1;
+
+#ifndef GPAC_DISABLE_AV_PARSERS
+ memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo));
+ acfg.base_object_type = GF_M4A_LAYER2;
+ acfg.base_sr = audio_codec_ctx->sample_rate;
+ acfg.nb_chan = audio_codec_ctx->channels;
+ acfg.sbr_object_type = 0;
+ acfg.audioPL = gf_m4a_get_profile(&acfg);
+
+ ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
+ assert(ret == GF_OK);
+#endif
+ //gf_isom_store_movie_config(video_output_file->isof, 0);
+ track = gf_isom_new_track(audio_output_file->isof, esd->ESID, GF_ISOM_MEDIA_AUDIO, audio_codec_ctx->sample_rate);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("TimeScale: %d \n", audio_codec_ctx->time_base.den));
+ if (!track) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create new track\n"));
+ return -1;
+ }
+
+ ret = gf_isom_set_track_enabled(audio_output_file->isof, track, 1);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+// if (!esd->ESID) esd->ESID = gf_isom_get_track_id(audio_output_file->isof, track);
+
+ ret = gf_isom_new_mpeg4_description(audio_output_file->isof, track, esd, NULL, NULL, &di);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_new_mpeg4_description\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ gf_odf_desc_del((GF_Descriptor *) esd);
+ esd = NULL;
+
+ 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);
+ 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;
+ }
+
+#ifndef GPAC_DISABLE_AV_PARSERS
+ ret = gf_isom_set_pl_indication(audio_output_file->isof, GF_ISOM_PL_AUDIO, acfg.audioPL);
+#endif
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_pl_indication\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("time scale: %d sample dur: %d \n", audio_codec_ctx->time_base.den, audio_output_file->codec_ctx->frame_size));
+
+ 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)));
+ return -1;
+ }
+
+ //gf_isom_add_track_to_root_od(video_output_file->isof,1);
+
+ ret = gf_isom_finalize_for_fragment(audio_output_file->isof, 1);
+ 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;
+ }
+
+ return 0;
+}
+
+int dc_gpac_audio_isom_open_seg(AudioOutputFile *audio_output_file, char *filename)
+{
+ GF_Err ret;
+ ret = gf_isom_start_segment(audio_output_file->isof, filename, GF_TRUE);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_start_segment\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ audio_output_file->dts = 0;
+
+ return 0;
+}
+
+int dc_gpac_audio_isom_write(AudioOutputFile *audio_output_file)
+{
+ GF_Err ret;
+ //AVStream *video_stream = video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx];
+ //AVCodecContext *video_codec_ctx = video_stream->codec;
+ //AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
+
+ audio_output_file->sample->data = (char *) audio_output_file->packet.data;
+ 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;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("RAP %d , DTS %ld \n", audio_output_file->sample->IsRAP, audio_output_file->sample->DTS));
+
+ ret = gf_isom_fragment_add_sample(audio_output_file->isof, 1, audio_output_file->sample, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0);
+ audio_output_file->dts += audio_output_file->codec_ctx->frame_size;
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_fragment_add_sample\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+// ret = gf_isom_flush_fragments(video_output_file->isof, 1);
+// if (ret != GF_OK) {
+// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_flush_fragments\n", gf_error_to_string(ret)));
+// return -1;
+// }
+
+ return 0;
+}
+
+int dc_gpac_audio_isom_close_seg(AudioOutputFile *audio_output_file)
+{
+ GF_Err ret;
+ ret = gf_isom_close_segment(audio_output_file->isof, 0, 0,0, 0, 0, 0, 1, audio_output_file->seg_marker, NULL, NULL);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close_segment\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ //audio_output_file->acc_samples = 0;
+
+ return 0;
+}
+
+int dc_gpac_audio_isom_close(AudioOutputFile *audio_output_file)
+{
+ GF_Err ret;
+ ret = gf_isom_close(audio_output_file->isof);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ //audio_output_file->acc_samples = 0;
+
+ return 0;
+}
+
+int dc_ffmpeg_audio_muxer_open(AudioOutputFile *audio_output_file, char *filename)
+{
+ AVStream *audio_stream;
+ AVOutputFormat *output_fmt;
+
+ AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
+ audio_output_file->av_fmt_ctx = NULL;
+
+// strcpy(audio_output_file->filename, audio_data_conf->filename);
+// audio_output_file->abr = audio_data_conf->bitrate;
+// audio_output_file->asr = audio_data_conf->samplerate;
+// audio_output_file->ach = audio_data_conf->channels;
+// strcpy(audio_output_file->codec, audio_data_conf->codec);
+
+ /* Find output format */
+ output_fmt = av_guess_format(NULL, filename, NULL);
+ if (!output_fmt) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find suitable output format\n"));
+ return -1;
+ }
+
+ audio_output_file->av_fmt_ctx = avformat_alloc_context();
+ if (!audio_output_file->av_fmt_ctx) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate memory for pOutVideoFormatCtx\n"));
+ return -1;
+ }
+
+ audio_output_file->av_fmt_ctx->oformat = output_fmt;
+ strcpy(audio_output_file->av_fmt_ctx->filename, filename);
+
+ /* Open the output file */
+ if (!(output_fmt->flags & AVFMT_NOFILE)) {
+ if (avio_open(&audio_output_file->av_fmt_ctx->pb, filename, URL_WRONLY) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot not open '%s'\n", filename));
+ return -1;
+ }
+ }
+
+ audio_stream = avformat_new_stream(audio_output_file->av_fmt_ctx, audio_output_file->codec);
+ if (!audio_stream) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create output video stream\n"));
+ return -1;
+ }
+
+ audio_stream->codec->codec_id = audio_output_file->codec->id;
+ audio_stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ 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;
+ audio_stream->codec->sample_fmt = AV_SAMPLE_FMT_S16;
+
+// if (audio_output_file->av_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+// audio_output_file->codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ //video_stream->codec = video_output_file->codec_ctx;
+
+ /* open the video codec */
+ if (avcodec_open2(audio_stream->codec, audio_output_file->codec, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n"));
+ return -1;
+ }
+
+ avformat_write_header(audio_output_file->av_fmt_ctx, NULL);
+
+ return 0;
+}
+
+int dc_ffmpeg_audio_muxer_write(AudioOutputFile *audio_output_file)
+{
+ AVStream *audio_stream = audio_output_file->av_fmt_ctx->streams[audio_output_file->astream_idx];
+ AVCodecContext *audio_codec_ctx = audio_stream->codec;
+
+ audio_output_file->packet.stream_index = audio_stream->index;
+
+ if (audio_output_file->packet.pts != AV_NOPTS_VALUE)
+ audio_output_file->packet.pts = av_rescale_q(audio_output_file->packet.pts, audio_codec_ctx->time_base, audio_stream->time_base);
+
+ if (audio_output_file->packet.duration > 0)
+ audio_output_file->packet.duration = (int)av_rescale_q(audio_output_file->packet.duration, audio_codec_ctx->time_base, audio_stream->time_base);
+ /*
+ * if (pkt.pts != AV_NOPTS_VALUE)
+ * pkt.pts = av_rescale_q(pkt.pts, audioEncCtx->time_base, audioStream->time_base);
+ */
+
+ audio_output_file->packet.flags |= AV_PKT_FLAG_KEY;
+
+ if (av_interleaved_write_frame(audio_output_file->av_fmt_ctx, &audio_output_file->packet) != 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n"));
+ av_free_packet(&audio_output_file->packet);
+ return -1;
+ }
+
+ av_free_packet(&audio_output_file->packet);
+
+ return 0;
+}
+
+int dc_ffmpeg_audio_muxer_close(AudioOutputFile *audio_output_file)
+{
+ u32 i;
+
+ av_write_trailer(audio_output_file->av_fmt_ctx);
+ avio_close(audio_output_file->av_fmt_ctx->pb);
+
+ // free the streams
+ for (i = 0; i < audio_output_file->av_fmt_ctx->nb_streams; i++) {
+ avcodec_close(audio_output_file->av_fmt_ctx->streams[i]->codec);
+ av_freep(&audio_output_file->av_fmt_ctx->streams[i]->info);
+ }
+
+ //video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx]->codec = NULL;
+ avformat_free_context(audio_output_file->av_fmt_ctx);
+
+ //audio_output_file->acc_samples = 0;
+
+ return 0;
+
+}
+
+int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag, u32 seg_marker)
+{
+ char name[GF_MAX_PATH];
+ snprintf(name, sizeof(name), "audio encoder %s", audio_data_conf->filename);
+ dc_consumer_init(&audio_output_file->consumer, AUDIO_CB_SIZE, name);
+
+ audio_output_file->sample = gf_isom_sample_new();
+ audio_output_file->isof = NULL;
+ 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)
+{
+ if (audio_output_file->isof != NULL) {
+ gf_isom_close(audio_output_file->isof);
+ }
+
+ //gf_isom_sample_del(&audio_output_file->sample);
+}
+
+GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg)
+{
+ GF_Err ret;
+ 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);
+ 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) {
+ 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;
+ }
+ 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;
+ default:
+ return GF_BAD_PARAM;
+ }
+
+ return GF_BAD_PARAM;
+}
+
+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);
+ case GPAC_AUDIO_MUXER:
+ case GPAC_INIT_AUDIO_MUXER:
+ if (frame_nb % audio_output_file->frame_per_frag == 0) {
+ gf_isom_start_fragment(audio_output_file->isof, 1);
+ gf_isom_set_traf_base_media_decode_time(audio_output_file->isof, 1, audio_output_file->first_dts * audio_output_file->frame_size);
+ audio_output_file->first_dts += audio_output_file->frame_per_frag;
+ }
+ dc_gpac_audio_isom_write(audio_output_file);
+ if (frame_nb % audio_output_file->frame_per_frag == audio_output_file->frame_per_frag - 1) {
+ gf_isom_flush_fragments(audio_output_file->isof, 1);
+ }
+ if (frame_nb + 1 == audio_output_file->frame_per_seg) {
+ return 1;
+ }
+ return 0;
+ default:
+ return GF_BAD_PARAM;
+ }
+
+ return GF_BAD_PARAM;
+}
+
+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);
+ 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);
+ default:
+ return GF_BAD_PARAM;
+ }
+
+ return GF_BAD_PARAM;
+}
diff --git a/applications/dashcast/audio_muxer.h b/applications/dashcast/audio_muxer.h
new file mode 100644
index 0000000..67c4adb
--- /dev/null
+++ b/applications/dashcast/audio_muxer.h
@@ -0,0 +1,131 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AUDIO_MUXER_H_
+#define AUDIO_MUXER_H_
+
+#include
+#include "../../modules/ffmpeg_in/ffmpeg_in.h"
+#include "libavutil/fifo.h"
+#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
+#ifdef DC_AUDIO_RESAMPLER
+#include "libavresample/avresample.h"
+#endif
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include
+#include
+#include
+#include "audio_data.h"
+
+
+typedef enum {
+ FFMPEG_AUDIO_MUXER,
+ GPAC_AUDIO_MUXER,
+ GPAC_INIT_AUDIO_MUXER
+} AudioMuxerType;
+
+/*
+ * AudioOutputFile structure has the data needed
+ * to encode audio samples and write them on the file.
+ * It reads the data from a circular buffer so it needs
+ * to keep the index to that circular buffer. This index is
+ * available in Consumer data structure.
+ *
+ */
+typedef struct {
+ //AudioDataConf *audio_data_conf;
+
+ /* File format context structure */
+ AVFormatContext *av_fmt_ctx;
+ AVCodec *codec;
+ AVCodecContext *codec_ctx;
+
+ GF_ISOFile *isof;
+ GF_ISOSample *sample;
+ int dts;
+
+ /* The index to the audio stream in the file */
+ int astream_idx;
+
+ /* It keeps the index with which encoder access to the circular buffer (as a consumer) */
+ Consumer consumer;
+
+#ifdef DC_AUDIO_RESAMPLER
+ /* Optional audio resampling between the decoder and the encoder */
+ AVAudioResampleContext *aresampler;
+#endif
+
+ /* Variables that encoder needs to encode data */
+ AVFrame *aframe;
+ uint8_t *adata_buf;
+ int frame_bytes;
+ AVPacket packet;
+
+ /*
+ * Audio samples stored in the AVFrame are not always
+ * complete. Which means more than 1 AVFrame is needed
+ * to complete an access unit. This fifo is provided
+ * to store audio samples in the fifo and once an access unit
+ * is complete we can encode it.
+ */
+ AVFifoBuffer *fifo;
+
+ AudioMuxerType muxer_type;
+
+ /* Accumulated sample */
+ //int acc_samples;
+
+ int frame_per_seg;
+ int frame_per_frag;
+ int first_dts;
+
+ u32 seg_marker;
+
+ int frame_size;
+
+} AudioOutputFile;
+
+int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag, u32 seg_marker);
+void dc_audio_muxer_free(AudioOutputFile *audio_output_file);
+
+/*
+ * Open the output audio
+ *
+ * @param audio_output_file [out] open the audio output on this file
+ *
+ * @param audio_data_conf [in] the structure containing the
+ * configuration of the output file (bitrate, samplerate, name, channels)
+ *
+ * @return 0 on success, -1 on failure
+ */
+GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg);
+
+GF_Err dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb);
+
+GF_Err dc_audio_muxer_close(AudioOutputFile *audio_output_file);
+
+#endif /* AUDIO_MUXER_H_ */
diff --git a/applications/dashcast/circular_buffer.c b/applications/dashcast/circular_buffer.c
new file mode 100644
index 0000000..6fae808
--- /dev/null
+++ b/applications/dashcast/circular_buffer.c
@@ -0,0 +1,263 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "circular_buffer.h"
+
+
+//#define DEBUG
+
+
+void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int max_num_consumers)
+{
+ u32 i;
+ circular_buf->size = size;
+ circular_buf->list = gf_malloc(size * sizeof(Node));
+ circular_buf->mode = mode;
+ circular_buf->max_num_consumers = max_num_consumers;
+
+ for (i=0; ilist[i].num_producers = 0;
+ circular_buf->list[i].num_consumers = 0;
+ circular_buf->list[i].num_consumers_accessed = 0;
+ circular_buf->list[i].marked = 0;
+ circular_buf->list[i].num_consumers_waiting = 0;
+ circular_buf->list[i].consumers_semaphore = gf_sema_new(1000, 0);
+ circular_buf->list[i].producers_semaphore = gf_sema_new(1000, 0);
+ circular_buf->list[i].mutex = gf_mx_new("Circular Buffer Mutex");
+ }
+}
+
+void dc_circular_buffer_destroy(CircularBuffer *circular_buf)
+{
+ u32 i;
+ for (i = 0; i < circular_buf->size; i++) {
+ gf_sema_del(circular_buf->list[i].consumers_semaphore);
+ gf_sema_del(circular_buf->list[i].producers_semaphore);
+ gf_mx_del(circular_buf->list[i].mutex);
+ }
+
+ gf_free(circular_buf->list);
+}
+
+void dc_consumer_init(Consumer *consumer, int max_idx, char *name)
+{
+ consumer->idx = 0;
+ consumer->max_idx = max_idx;
+ strcpy(consumer->name, name);
+}
+
+void * dc_consumer_consume(Consumer *consumer, CircularBuffer *circular_buf)
+{
+ return circular_buf->list[consumer->idx].data;
+}
+
+int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf)
+{
+ Node *node = &circular_buf->list[consumer->idx];
+
+ gf_mx_p(node->mutex);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s enters lock %d\n", consumer->name, consumer->idx));
+ if (node->marked == 2) {
+ gf_mx_v(node->mutex);
+ return -1;
+ }
+
+ node->num_consumers_waiting++;
+ while (node->num_producers || !node->marked) {
+ gf_mx_v(node->mutex);
+ gf_sema_wait(node->consumers_semaphore);
+ gf_mx_p(node->mutex);
+
+ if (node->marked == 2) {
+ gf_mx_v(node->mutex);
+ return -1;
+ }
+ }
+ node->num_consumers_waiting--;
+
+ if (node->marked == 2) {
+ gf_mx_v(node->mutex);
+ return -1;
+ }
+ node->num_consumers++;
+ node->num_consumers_accessed++;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s exits lock %d \n", consumer->name, consumer->idx));
+ gf_mx_v(node->mutex);
+
+ return 0;
+}
+
+int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf)
+{
+ int last_consumer = 0;
+ Node *node = &circular_buf->list[consumer->idx];
+
+ gf_mx_p(node->mutex);
+ node->num_consumers--;
+
+ if (node->num_consumers_accessed == circular_buf->max_num_consumers) {
+ node->marked = 0;
+ node->num_consumers_accessed = 0;
+ last_consumer = 1;
+ }
+
+ gf_sema_notify(node->producers_semaphore, 1);
+
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s unlock %d \n", consumer->name, consumer->idx));
+ gf_mx_v(node->mutex);
+
+ return last_consumer;
+}
+
+int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf)
+{
+ int node_idx = (consumer->idx - 1 + consumer->max_idx) % consumer->max_idx;
+ int last_consumer = 0;
+ Node *node = &circular_buf->list[node_idx];
+
+ gf_mx_p(node->mutex);
+
+ node->num_consumers--;
+ if (node->num_consumers < 0)
+ node->num_consumers = 0;
+
+ if (node->num_consumers_accessed == circular_buf->max_num_consumers) {
+ if (node->marked != 2)
+ node->marked = 0;
+ node->num_consumers_accessed = 0;
+ last_consumer = 1;
+ }
+
+ gf_sema_notify(node->producers_semaphore, 1);
+
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("consumer %s unlock %d \n", consumer->name, node_idx));
+ gf_mx_v(node->mutex);
+
+ return last_consumer;
+}
+
+void dc_consumer_advance(Consumer *consumer)
+{
+ consumer->idx = (consumer->idx + 1) % consumer->max_idx;
+}
+
+void dc_producer_init(Producer *producer, int max_idx, char *name)
+{
+ producer->idx = 0;
+ producer->max_idx = max_idx;
+ strcpy(producer->name, name);
+}
+
+void * dc_producer_produce(Producer *producer, CircularBuffer *circular_buf)
+{
+ return circular_buf->list[producer->idx].data;
+}
+
+int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf)
+{
+ Node *node = &circular_buf->list[producer->idx];
+
+ gf_mx_p(node->mutex);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s enters lock %d \n", producer->name, producer->idx));
+
+ if ( (circular_buf->mode == LIVE_CAMERA || circular_buf->mode == LIVE_MEDIA) && (node->num_consumers || node->marked)) {
+ gf_mx_v(node->mutex);
+ return -1;
+ }
+
+ while (node->num_consumers || node->marked) {
+ gf_mx_v(node->mutex);
+ gf_sema_wait(node->producers_semaphore);
+ gf_mx_p(node->mutex);
+ }
+
+ node->num_producers++;
+ if (circular_buf->size>1) {
+ node->marked = 1;
+ }
+
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s exits lock %d \n", producer->name, producer->idx));
+ gf_mx_v(node->mutex);
+
+ return 0;
+}
+
+void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf)
+{
+ Node *node = &circular_buf->list[producer->idx];
+
+ gf_mx_p(node->mutex);
+ node->num_producers--;
+ gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s unlock %d \n", producer->name, producer->idx));
+ gf_mx_v(node->mutex);
+}
+
+void dc_producer_unlock_previous(Producer *producer, CircularBuffer *circular_buf)
+{
+ int node_idx = (producer->idx - 1 + producer->max_idx) % producer->max_idx;
+ Node *node = &circular_buf->list[node_idx];
+
+ gf_mx_p(node->mutex);
+ node->num_producers = 0;
+ gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s unlock %d \n", producer->name, node_idx));
+ gf_mx_v(node->mutex);
+}
+
+void dc_producer_advance(Producer *producer, CircularBuffer *circular_buf)
+{
+ if (circular_buf->size == 1) {
+ Node *node = &circular_buf->list[producer->idx];
+ gf_mx_p(node->mutex);
+ node->marked = 1;
+ gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting);
+ gf_mx_v(node->mutex);
+ }
+ producer->idx = (producer->idx + 1) % producer->max_idx;
+}
+
+void dc_producer_end_signal(Producer *producer, CircularBuffer *circular_buf)
+{
+ Node *node = &circular_buf->list[producer->idx];
+
+ gf_mx_p(node->mutex);
+ node->marked = 2;
+ gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s sends end signal %d \n", producer->name, producer->idx));
+ gf_mx_v(node->mutex);
+}
+
+void dc_producer_end_signal_previous(Producer *producer, CircularBuffer *circular_buf)
+{
+ int i_node = (producer->max_idx + producer->idx - 1) % producer->max_idx;
+ Node *node = &circular_buf->list[i_node];
+
+ gf_mx_p(node->mutex);
+ node->marked = 2;
+ gf_sema_notify(node->consumers_semaphore, node->num_consumers_waiting);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("producer %s sends end signal %d \n", producer->name, node));
+ gf_mx_v(node->mutex);
+}
diff --git a/applications/dashcast/circular_buffer.h b/applications/dashcast/circular_buffer.h
new file mode 100644
index 0000000..4e90a5e
--- /dev/null
+++ b/applications/dashcast/circular_buffer.h
@@ -0,0 +1,246 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef CIRCULAR_BUFFER_H_
+#define CIRCULAR_BUFFER_H_
+
+#include
+#include
+#include
+
+
+/*
+ * The method (mode) of multithread management.
+ * It can be LIVE or OFFLINE.
+ * LIVE means that the system is real time. The producer does not wait
+ * for anyone and it always produces and finds a place on the circular buffer.
+ * OFFLINE means that the system is working offline, so the producer can
+ * wait for the consumers to finish their job.
+ */
+typedef enum {
+ LIVE_CAMERA,
+ LIVE_MEDIA,
+ ON_DEMAND
+} LockMode;
+
+/*
+ * Every node of the circular buffer has a data, plus
+ * all the variables needed for multithread management.
+ */
+typedef struct {
+ /* Pointer to the data on the node */
+ void *data;
+ /* The number of the producer currently using this node */
+ int num_producers;
+ /* The number of consumer currently using this node */
+ int num_consumers;
+ /* The number of consumer currently waiting for this node */
+ int num_consumers_waiting;
+ /* Mutex used for synchronizing the users of this node. */
+ GF_Mutex *mutex;
+ /* Semaphore for producer */
+ GF_Semaphore *producers_semaphore;
+ /* Semaphore for consumers */
+ GF_Semaphore *consumers_semaphore;
+ /* If marked is 0 it means the data on this node is not valid.
+ * If marked is 1 it means that the data on this node is valid.
+ * If marked is 2 it means this node is the last node. */
+ int marked;
+ /* Indicates the number of consumers which already accessed this node.
+ * It is used for the case where the last consumer has to do something. */
+ int num_consumers_accessed;
+} Node;
+
+/*
+ * The circular buffer has a size, a list of nodes and it
+ * has the number of consumers using it. Also it needs to know which
+ * locking mechanism it needs to use. (LIVE or OFFLINE)
+ */
+typedef struct {
+ /* The size of circular buffer */
+ u32 size;
+ /* A list of all the nodes */
+ Node *list;
+ /* The mode for multithread management. */
+ LockMode mode;
+ /* The maximum number of the consumers using the circular buffer */
+ u32 max_num_consumers;
+} CircularBuffer;
+
+/*
+ * Producer has an index to the circular buffer.
+ */
+typedef struct {
+ /* The index where the producer is using */
+ int idx;
+ /* The maximum of the index. (Which means the size of circular buffer) */
+ int max_idx;
+
+ char name[GF_MAX_PATH];
+} Producer;
+
+/*
+ * Consumer has an index to the circular buffer.
+ */
+typedef struct {
+ /* The index where the consumer is using */
+ int idx;
+ /* The maximum of the index. (Which means the size of circular buffer) */
+ int max_idx;
+
+ char name[GF_MAX_PATH];
+} Consumer;
+
+/*
+ * Create a circular buffer
+ *
+ * @param circular_buf [out] circular buffer to be created
+ * @param size [in] size of circular buffer
+ * @param mode [in] mode of multithread management (LIVE or OFFLINE)
+ * @param num_consumers [in] maximum number of the consumers of the circular buffer
+ */
+void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int num_consumers);
+
+/*
+ * Destroy the circular buffer
+ *
+ * @param circular_buf [in] circular buffer to be destroyed
+ */
+void dc_circular_buffer_destroy(CircularBuffer *circular_buf);
+
+/*
+ * Initialize a consumer
+ *
+ * @param consumer [out] the consumer to be initialize
+ * @param num_consumers [in] maximum number of the consumers
+ */
+void dc_consumer_init(Consumer *consumer, int num_consumers, char *name);
+
+/*
+ * Return the data in the node in question. (circular_buf[consumer index])
+ *
+ * @param consumer [in] consumer
+ * @param circular_buf [in] circular buffer
+ */
+void * dc_consumer_consume(Consumer *consumer, CircularBuffer *circular_buf);
+
+/*
+ * Consumer lock on circular buffer
+ *
+ * @param consumer [in] consumer
+ * @param circular_buf [in] circular buffer
+ *
+ * @return 0 on success, -1 if the node in question is the last node and not usable.
+ */
+int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf);
+
+/*
+ * Consumer unlock on circular buffer
+ *
+ * @param consumer [in] consumer
+ * @param circular_buf [in] circular buffer
+ *
+ * @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer.
+ */
+int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf);
+
+/*
+ * Consumer unlock on previous node of the circular buffer
+ *
+ * @param consumer [in] consumer
+ * @param circular_buf [in] circular buffer
+ *
+ * @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer.
+ */
+int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf);
+
+/*
+ * Consumer leads its index
+ *
+ * @param consumer [in] consumer
+ */
+void dc_consumer_advance(Consumer *consumer);
+
+/*
+ * Initialize a producer
+ *
+ * @param producer [out] the producer to be initialize
+ * @param maxpro [in] maximum number of the producers
+ */
+void dc_producer_init(Producer *producer, int maxpro, char *name);
+
+/*
+ * Return the data in the node in question. (circular_buf[consumer index])
+ *
+ * @param producer [in] producer
+ * @param circular_buf [in] circular buffer
+ */
+void * dc_producer_produce(Producer *producer, CircularBuffer *circular_buf);
+
+/*
+ * Producer lock on circular buffer
+ *
+ * @param producer [in] producer
+ * @param circular_buf [in] circular buffer
+ *
+ * @return 0 on success, -1 if the mode is live and cannot wait.
+ */
+int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf);
+
+/*
+ * Producer unlock on circular buffer
+ *
+ * @param producer [in] producer
+ * @param circular_buf [in] circular buffer
+ */
+void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf);
+
+/*
+ * Producer unlock on the previous node of the circular buffer
+ *
+ * @param producer [in] producer
+ * @param circular_buf [in] circular buffer
+ */
+void dc_producer_unlock_previous(Producer *, CircularBuffer *);
+
+/*
+ * Producer leads its index
+ *
+ * @param producer [in] producer
+ * @param circular_buf [in] circular buffer
+ */
+void dc_producer_advance(Producer *producer, CircularBuffer *);
+
+/*
+ * Producer signal that the current node is the last node
+ *
+ * @param producer [in] producer
+ * @param circular_buf [in] circular buffer
+ */
+void dc_producer_end_signal(Producer *producer, CircularBuffer *circular_buf);
+
+void dc_producer_end_signal_previous(Producer *producer, CircularBuffer *circular_buf);
+
+#endif /* CIRCULAR_BUFFER_H_ */
diff --git a/applications/dashcast/cmd_data.c b/applications/dashcast/cmd_data.c
new file mode 100644
index 0000000..9f64326
--- /dev/null
+++ b/applications/dashcast/cmd_data.c
@@ -0,0 +1,888 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "cmd_data.h"
+
+
+#define DASHCAST_CHECK_NEXT_ARG \
+ i++; \
+ if (i >= argc) { \
+ fprintf(stderr, "%s: %s", command_error, argv[i]); \
+ fprintf(stderr, "%s", command_usage); \
+ return -1; \
+ }
+
+
+int dc_str_to_resolution(char *str, int *width, int *height)
+{
+ char *token = strtok(str, "x");
+ if (!token) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse resolution string.\n"));
+ return -1;
+ }
+ *width = atoi(token);
+
+ token = strtok(NULL, " ");
+ if (!token) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse resolution string.\n"));
+ return -1;
+ }
+ *height = atoi(token);
+
+ return 0;
+}
+
+
+#define DEFAULT_VIDEO_BITRATE 400000
+#define DEFAULT_VIDEO_FRAMERATE 25
+#define DEFAULT_VIDEO_WIDTH 640
+#define DEFAULT_VIDEO_HEIGHT 480
+#define DEFAULT_VIDEO_CODEC "libx264"
+#define DEFAULT_AUDIO_BITRATE 192000
+#define DEFAULT_AUDIO_SAMPLERATE 48000
+#define DEFAULT_AUDIO_CHANNELS 2
+#define DEFAULT_AUDIO_CODEC "mp2"
+
+
+static void dc_create_configuration(CmdData *cmd_data)
+{
+ u32 i;
+ GF_Config *conf = cmd_data->conf;
+ u32 sec_count = gf_cfg_get_section_count(conf);
+ if (!sec_count) {
+ gf_cfg_set_key(conf, "v1", "type", "video");
+ gf_cfg_set_key(conf, "a1", "type", "audio");
+ sec_count = gf_cfg_get_section_count(conf);
+ }
+ for (i=0; ivideo_data_conf.bitrate == -1)
+ cmd_data->video_data_conf.bitrate = DEFAULT_VIDEO_BITRATE;
+ snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.bitrate);
+ gf_cfg_set_key(conf, section_name, "bitrate", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "framerate")) {
+ if (cmd_data->video_data_conf.framerate == -1)
+ cmd_data->video_data_conf.framerate = DEFAULT_VIDEO_FRAMERATE;
+ snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.framerate);
+ gf_cfg_set_key(conf, section_name, "framerate", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "width")) {
+ if (cmd_data->video_data_conf.width == -1)
+ cmd_data->video_data_conf.width = DEFAULT_VIDEO_WIDTH;
+ snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.width);
+ gf_cfg_set_key(conf, section_name, "width", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "height")) {
+ if (cmd_data->video_data_conf.height == -1)
+ cmd_data->video_data_conf.height = DEFAULT_VIDEO_HEIGHT;
+ snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.height);
+ gf_cfg_set_key(conf, section_name, "height", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "crop_x")) {
+ if (cmd_data->video_data_conf.crop_x == -1)
+ cmd_data->video_data_conf.crop_x = 0;
+ 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, "crop_y")) {
+ if (cmd_data->video_data_conf.crop_y == -1)
+ cmd_data->video_data_conf.crop_y = 0;
+ snprintf(value, sizeof(value), "%d", cmd_data->video_data_conf.crop_y);
+ gf_cfg_set_key(conf, section_name, "crop_y", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "codec"))
+ gf_cfg_set_key(conf, section_name, "codec", DEFAULT_VIDEO_CODEC);
+ }
+
+ if (strcmp(section_type, "audio") == 0) {
+ if (!gf_cfg_get_key(conf, section_name, "bitrate")) {
+ if (cmd_data->audio_data_conf.bitrate == -1)
+ cmd_data->audio_data_conf.bitrate = DEFAULT_AUDIO_BITRATE;
+ snprintf(value, sizeof(value), "%d", cmd_data->audio_data_conf.bitrate);
+ gf_cfg_set_key(conf, section_name, "bitrate", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "samplerate")) {
+ if (cmd_data->audio_data_conf.samplerate == -1)
+ cmd_data->audio_data_conf.samplerate = DEFAULT_AUDIO_SAMPLERATE;
+ snprintf(value, sizeof(value), "%d", cmd_data->audio_data_conf.samplerate);
+ gf_cfg_set_key(conf, section_name, "samplerate", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "channels")) {
+ if (cmd_data->audio_data_conf.channels == -1)
+ cmd_data->audio_data_conf.channels = DEFAULT_AUDIO_CHANNELS;
+ snprintf(value, sizeof(value), "%d", cmd_data->audio_data_conf.channels);
+ gf_cfg_set_key(conf, section_name, "channels", value);
+ }
+
+ if (!gf_cfg_get_key(conf, section_name, "codec"))
+ gf_cfg_set_key(conf, section_name, "codec", DEFAULT_AUDIO_CODEC);
+ }
+ }
+}
+
+int dc_read_configuration(CmdData *cmd_data)
+{
+ const char *opt;
+ u32 i;
+ GF_Config *conf = cmd_data->conf;
+
+ u32 sec_count = gf_cfg_get_section_count(conf);
+ for (i=0; ifilename, section_name);
+ opt = gf_cfg_get_key(conf, section_name, "codec");
+ if (!opt) opt = DEFAULT_VIDEO_CODEC;
+ strcpy(video_data_conf->codec, opt);
+ opt = gf_cfg_get_key(conf, section_name, "bitrate");
+ video_data_conf->bitrate = opt ? atoi(opt) : DEFAULT_VIDEO_BITRATE;
+ opt = gf_cfg_get_key(conf, section_name, "framerate");
+ video_data_conf->framerate = opt ? atoi(opt) : DEFAULT_VIDEO_FRAMERATE;
+ opt = gf_cfg_get_key(conf, section_name, "height");
+ video_data_conf->height = opt ? atoi(opt) : DEFAULT_VIDEO_HEIGHT;
+ opt = gf_cfg_get_key(conf, section_name, "width");
+ video_data_conf->width = opt ? atoi(opt) : DEFAULT_VIDEO_WIDTH;
+ opt = gf_cfg_get_key(conf, section_name, "crop_x");
+ 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, "custom");
+ video_data_conf->custom = opt ? gf_strdup(opt) : NULL;
+ gf_list_add(cmd_data->video_lst, (void *) video_data_conf);
+ }
+ else if (strcmp(section_type, "audio") == 0)
+ {
+ AudioDataConf *audio_data_conf;
+ GF_SAFEALLOC(audio_data_conf, AudioDataConf);
+ strcpy(audio_data_conf->filename, section_name);
+ opt = gf_cfg_get_key(conf, section_name, "codec");
+ if (!opt) opt = DEFAULT_AUDIO_CODEC;
+ strcpy(audio_data_conf->codec, opt);
+ opt = gf_cfg_get_key(conf, section_name, "bitrate");
+ audio_data_conf->bitrate = opt ? atoi(opt) : DEFAULT_AUDIO_BITRATE;
+ opt = gf_cfg_get_key(conf, section_name, "samplerate");
+ audio_data_conf->samplerate = opt ? atoi(opt) : DEFAULT_AUDIO_SAMPLERATE;
+ 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;
+ gf_list_add(cmd_data->audio_lst, (void *) audio_data_conf);
+ } else {
+ fprintf(stderr, "Configuration file: type %s is not supported.\n", section_type);
+ }
+ }
+
+ fprintf(stdout, "\33[34m\33[1m");
+ fprintf(stdout, "Configurations:\n");
+ for (i=0; ivideo_lst); i++) {
+ VideoDataConf *video_data_conf = gf_list_get(cmd_data->video_lst, i);
+ fprintf(stdout, " id:%s\tres:%dx%d\tvbr:%d\n", video_data_conf->filename,
+ video_data_conf->width, video_data_conf->height,
+ video_data_conf->bitrate/*, video_data_conf->framerate, video_data_conf->codec*/); }
+
+ for (i=0; iaudio_lst); i++) {
+ AudioDataConf *audio_data_conf = gf_list_get(cmd_data->audio_lst, i);
+ fprintf(stdout, " id:%s\tabr:%d\n", audio_data_conf->filename, audio_data_conf->bitrate/*, audio_data_conf->samplerate, audio_data_conf->channels,audio_data_conf->codec*/);
+ }
+ fprintf(stdout, "\33[0m");
+ fflush(stdout);
+
+ return 0;
+}
+
+/**
+ * Parse time from a string to a struct tm.
+ */
+static Bool parse_time(const char* str_time, struct tm *tm_time)
+{
+ if (!tm_time)
+ return GF_FALSE;
+
+#if defined(__GNUC__)
+ strptime(str_time, "%Y-%m-%d %H:%M:%S", tm_time);
+#elif defined(WIN32)
+ assert(0); //TODO
+#else
+#error
+#endif
+
+ return GF_TRUE;
+}
+
+int dc_read_switch_config(CmdData *cmd_data)
+{
+ u32 i;
+ int src_number;
+ char start_time[4096], end_time[4096];
+
+ time_t now_t = time(NULL);
+ struct tm start_tm = *localtime(&now_t);
+ struct tm end_tm = *localtime(&now_t);
+
+ GF_Config *conf = cmd_data->switch_conf;
+ u32 sec_count = gf_cfg_get_section_count(conf);
+
+ dc_task_init(&cmd_data->task_list);
+
+ if (sec_count == 0) {
+ return 0;
+ }
+
+ for (i = 0; i < sec_count; i++) {
+ const char *section_name = gf_cfg_get_section_name(conf, i);
+ const char *section_type = gf_cfg_get_key(conf, section_name, "type");
+
+ if (strcmp(section_type, "video") == 0) {
+ VideoDataConf *video_data_conf = gf_malloc(sizeof(VideoDataConf));
+
+ strcpy(video_data_conf->source_id, section_name);
+ strcpy(video_data_conf->filename, gf_cfg_get_key(conf, section_name, "source"));
+
+ strcpy(start_time, gf_cfg_get_key(conf, section_name, "start"));
+ parse_time(start_time, &start_tm);
+ video_data_conf->start_time = mktime(&start_tm);
+ strcpy(end_time, gf_cfg_get_key(conf, section_name, "end"));
+ parse_time(end_time, &end_tm);
+ video_data_conf->end_time = mktime(&end_tm);
+
+ gf_list_add(cmd_data->vsrc, (void *) video_data_conf);
+
+ src_number = gf_list_count(cmd_data->vsrc);
+
+ dc_task_add(&cmd_data->task_list, src_number, video_data_conf->source_id, video_data_conf->start_time, video_data_conf->end_time);
+ }
+ else if (strcmp(section_type, "audio") == 0)
+ {
+ AudioDataConf *audio_data_conf = gf_malloc(sizeof(AudioDataConf));
+ strcpy(audio_data_conf->source_id, section_name);
+ strcpy(audio_data_conf->filename, gf_cfg_get_key(conf, section_name, "source"));
+
+ strcpy(start_time, gf_cfg_get_key(conf, section_name, "start"));
+ parse_time(start_time, &start_tm);
+ audio_data_conf->start_time = mktime(&start_tm);
+
+ strcpy(end_time, gf_cfg_get_key(conf, section_name, "end"));
+ parse_time(end_time, &end_tm);
+ audio_data_conf->end_time = mktime(&end_tm);
+
+ gf_list_add(cmd_data->asrc, (void *) audio_data_conf);
+ } else {
+ fprintf(stdout, "Switch source configuration file: type %s is not supported.\n", section_type);
+ }
+ }
+
+ fprintf(stdout, "\33[34m\33[1m");
+ fprintf(stdout, "Sources:\n");
+ for (i=0; ivsrc); i++) {
+ VideoDataConf *video_data_conf = gf_list_get(cmd_data->vsrc, i);
+ strftime(start_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&video_data_conf->start_time));
+ strftime(end_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&video_data_conf->end_time));
+ fprintf(stdout, " id:%s\tsource:%s\tstart:%s\tend:%s\n", video_data_conf->source_id, video_data_conf->filename, start_time, end_time);
+ }
+
+ for (i=0; iasrc); i++) {
+ AudioDataConf *audio_data_conf = gf_list_get(cmd_data->asrc, i);
+ strftime(start_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&audio_data_conf->start_time));
+ strftime(end_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&audio_data_conf->end_time));
+ fprintf(stdout, " id:%s\tsource:%s\tstart:%s\tend:%s\n", audio_data_conf->source_id, audio_data_conf->filename, start_time, end_time);
+ }
+ fprintf(stdout, "\33[0m");
+ fflush(stdout);
+
+ return 0;
+}
+
+void dc_cmd_data_init(CmdData *cmd_data)
+{
+ memset(cmd_data, 0, sizeof(CmdData));
+ dc_audio_data_set_default(&cmd_data->audio_data_conf);
+ dc_video_data_set_default(&cmd_data->video_data_conf);
+
+ cmd_data->mode = ON_DEMAND;
+ cmd_data->ast_offset = -1;
+ cmd_data->min_buffer_time = -1;
+ cmd_data->minimum_update_period = -1;
+ cmd_data->use_source_timing = 1;
+
+ cmd_data->audio_lst = gf_list_new();
+ cmd_data->video_lst = gf_list_new();
+ cmd_data->asrc = gf_list_new();
+ cmd_data->vsrc = gf_list_new();
+}
+
+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);
+ }
+ gf_list_del(cmd_data->audio_lst);
+
+ while (gf_list_count(cmd_data->video_lst)) {
+ VideoDataConf *video_data_conf = gf_list_last(cmd_data->video_lst);
+ gf_free(video_data_conf->custom);
+ gf_list_rem_last(cmd_data->video_lst);
+ gf_free(video_data_conf);
+ }
+ gf_list_del(cmd_data->video_lst);
+
+ gf_list_del(cmd_data->asrc);
+ gf_list_del(cmd_data->vsrc);
+ gf_cfg_del(cmd_data->conf);
+ gf_cfg_del(cmd_data->switch_conf);
+ if (cmd_data->logfile)
+ fclose(cmd_data->logfile);
+
+ dc_task_destroy(&cmd_data->task_list);
+
+ gf_sys_close();
+}
+
+static void on_dc_log(void *cbk, u32 ll, u32 lm, const char *av_fmt_ctx, va_list list)
+{
+ FILE *logs = cbk;
+ vfprintf(logs, av_fmt_ctx, list);
+ fflush(logs);
+}
+
+int dc_parse_command(int argc, char **argv, CmdData *cmd_data)
+{
+ Bool use_mem_track = GF_FALSE;
+ int i;
+
+ const char *command_usage =
+ "Usage: DashCast [options]\n"
+ "\n"
+ "General options:\n"
+ " -log-file filename set output log file. Also works with -lf\n"
+ " -logs LOGS set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n"
+#ifdef GPAC_MEMORY_TRACKING
+ " -mem-track enable the memory tracker\n"
+#endif
+ " -conf filename set the configuration file name (default: dashcast.conf)\n"
+ " -switch-source filename set the configuration file name for source switching\n"
+ "\n"
+ "Live options:\n"
+ " -live system is live and input is a camera\n"
+ " -live-media system is live and input is a media file\n"
+ " -no-loop system does not loop on the input media file when live\n"
+ " -dynamic-ast changes segment availability start time at each MPD generation (old behaviour but not allowed in most profiles)\n"
+ " -insert-utc inserts UTC clock at the start of each segment\n"
+ "\n"
+ "Source options:\n"
+ " -npts use frame counting for timestamps (not error-free) instead of source timing (default)\n"
+ " -av string set the source name for a multiplexed audio and video input\n"
+ " - if this option is present, neither '-a' nor '-v' shall be present\n"
+ "* Video options:\n"
+ " -v string set the source name for a video input\n"
+ " - if input is from a webcam, use \"/dev/video[x]\" \n"
+ " where x is the video device number\n"
+ " - if input is the screen video, use \":0.0+[x],[y]\" \n"
+ " which captures from upper-left at x,y\n"
+ " - if input is from stdin, use \"pipe:\"\n"
+ " -vf string set the input video format\n"
+#ifdef WIN32
+ " - to capture from a VfW webcam, set vfwcap\n"
+ " - to capture from a directshow device, set dshow\n"
+#else
+ " - to capture from a webcam, set video4linux2\n"
+ " - to capture the screen, set x11grab\n"
+ " -v4l2f inv4l2f inv4l2f is the input format for webcam acquisition\n"
+ " - it can be mjpeg, yuyv422, etc.\n"
+#endif
+ " -pixf FMT set the input pixel format\n"
+ " -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"
+ " where x is the card number and y is the device number\n"
+ " -af string set the input audio format\n"
+ "\n"
+ "Output options:\n"
+ "* Video encoding options:\n"
+ " -vcodec string set the output video codec (default: h264)\n"
+#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"
+ "* Audio encoding options:\n"
+ " -acodec string set the output audio codec (default: mp2)\n"
+#if 0 //TODO: bind to option and params - test first how it binds to current input parameters
+ " -ab int set the output audio bitrate in bits (default: 192000)\n"
+ " -as int set the sample rate (default: 48000)\n"
+ " -ach int set the number of output audio channels (default: 2)\n"
+#endif
+ " -acustom string send custom parameters directly to the audio encoder\n"
+ "\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"
+ " -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"
+ " -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"
+ " -min-buffer dur:float dur is the MPD minBufferTime in seconds (default value: 1.0)\n"
+ " -base-url baseurl:str baseurl is the MPD BaseURL\n"
+ "\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ " DashCast -av test.avi -live-media\n"
+ " DashCast -a test_audio.mp3 -v test_audio.mp4 -live-media\n"
+#ifdef WIN32
+ " DashCast -vf vfwcap -vres 1280x720 -vfr 24 -v 0 -live\n"
+ " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"screen-capture-recorder\" -live (please install http://screencapturer.sf.net/)\n"
+ " DashCast -vf dshow -vres 1280x720 -vfr 24 -v video=\"YOUR-WEBCAM\" -pixf yuv420p -live\n"
+#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"
+#endif
+ "\n";
+
+ const char *command_error = "\33[31mUnknown option or missing mandatory argument.\33[0m\n";
+
+ if (argc == 1) {
+ fprintf(stderr, "%s", command_usage);
+ return -2;
+ }
+
+#ifdef GPAC_MEMORY_TRACKING
+ i = 1;
+ while (i < argc) {
+ if (strcmp(argv[i], "-mem-track") == 0) {
+ use_mem_track = GF_TRUE;
+ break;
+ }
+ i++;
+ }
+#endif
+
+ gf_sys_init(use_mem_track);
+
+ if (use_mem_track) {
+ gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO);
+ }
+
+ /* Initialize command data */
+ dc_cmd_data_init(cmd_data);
+
+ i = 1;
+ while (i < argc) {
+ if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "-av") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(argv[i - 1], "-a") == 0 || strcmp(argv[i - 1], "-av") == 0) {
+ if (strcmp(cmd_data->audio_data_conf.filename, "") != 0) {
+ fprintf(stderr, "Audio source has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strcpy(cmd_data->audio_data_conf.filename, argv[i]);
+ }
+
+ if (strcmp(argv[i - 1], "-v") == 0 || strcmp(argv[i - 1], "-av") == 0) {
+ if (strcmp(cmd_data->video_data_conf.filename, "") != 0) {
+ fprintf(stderr, "Video source has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strcpy(cmd_data->video_data_conf.filename, argv[i]);
+ }
+
+ i++;
+ } else if (strcmp(argv[i], "-af") == 0 || strcmp(argv[i], "-vf") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(argv[i - 1], "-af") == 0) {
+ if (strcmp(cmd_data->audio_data_conf.format, "") != 0) {
+ fprintf(stderr, "Audio format has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strcpy(cmd_data->audio_data_conf.format, argv[i]);
+ }
+ if (strcmp(argv[i - 1], "-vf") == 0) {
+ if (strcmp(cmd_data->video_data_conf.format, "") != 0) {
+ fprintf(stderr, "Video format has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strcpy(cmd_data->video_data_conf.format, argv[i]);
+ }
+ i++;
+ } else if (strcmp(argv[i], "-pixf") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->video_data_conf.pixel_format, "") != 0) {
+ fprintf(stderr, "Input pixel format has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strcpy(cmd_data->video_data_conf.pixel_format, argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-vfr") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->video_data_conf.framerate != -1) {
+ fprintf(stderr, "Video framerate has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->video_data_conf.framerate = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-vres") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->video_data_conf.height != -1 && cmd_data->video_data_conf.width != -1) {
+ fprintf(stderr, "Video resolution has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ dc_str_to_resolution(argv[i], &cmd_data->video_data_conf.width, &cmd_data->video_data_conf.height);
+ i++;
+ } else if (strcmp(argv[i], "-vcrop") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->video_data_conf.crop_x && cmd_data->video_data_conf.crop_y) {
+ fprintf(stderr, "Video crop has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ dc_str_to_resolution(argv[i], &cmd_data->video_data_conf.crop_x, &cmd_data->video_data_conf.crop_y);
+ i++;
+ } else if (strcmp(argv[i], "-vcodec") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->video_data_conf.codec, "") != 0) {
+ fprintf(stderr, "Video codec has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strncpy(cmd_data->video_data_conf.codec, argv[i], GF_MAX_PATH);
+ i++;
+ } else if (strcmp(argv[i], "-vcustom") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->video_data_conf.custom, "") != 0) {
+ 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);
+ i++;
+ } else if (strcmp(argv[i], "-acodec") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->audio_data_conf.codec, "") != 0) {
+ fprintf(stderr, "Audio codec has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strncpy(cmd_data->audio_data_conf.codec, argv[i], GF_MAX_PATH);
+ i++;
+ } else if (strcmp(argv[i], "-acustom") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->audio_data_conf.custom, "") != 0) {
+ 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);
+ i++;
+ } else if (strcmp(argv[i], "-conf") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ cmd_data->conf = gf_cfg_force_new(NULL, argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-switch-source") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ cmd_data->switch_conf = gf_cfg_force_new(NULL, argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-out") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ strcpy(cmd_data->out_dir, argv[i]);
+ i++;
+#ifndef WIN32
+ } else if (strcmp(argv[i], "-v4l2f") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ strcpy(cmd_data->video_data_conf.v4l2f, argv[i]);
+ i++;
+#endif
+ } else if (strcmp(argv[i], "-seg-marker") == 0) {
+ char *m;
+ DASHCAST_CHECK_NEXT_ARG
+ m = argv[i];
+ if (strlen(m) == 4) {
+ cmd_data->seg_marker = GF_4CC(m[0], m[1], m[2], m[3]);
+ } else {
+ fprintf(stderr, "Invalid marker box name specified: %s\n", m);
+ return -1;
+ }
+ i++;
+ } else if (strcmp(argv[i], "-mpd") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->mpd_filename, "") != 0) {
+ fprintf(stderr, "MPD file has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strncpy(cmd_data->mpd_filename, argv[i], GF_MAX_PATH);
+ i++;
+ } else if (strcmp(argv[i], "-seg-dur") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->seg_dur != 0) {
+ fprintf(stderr, "Segment duration has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->seg_dur = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-frag-dur") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->frag_dur != 0) {
+ fprintf(stderr, "Fragment duration has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->frag_dur = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-ast-offset") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->ast_offset != -1) {
+ fprintf(stderr, "AvailabilityStartTime offset has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->ast_offset = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-mpd-refresh") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->minimum_update_period != -1) {
+ fprintf(stderr, "minimumUpdatePeriod (mpd-refresh) has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->minimum_update_period = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-time-shift") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->time_shift != 0) {
+ fprintf(stderr, "TimeShiftBufferDepth has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->time_shift = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-gop") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->gop_size != 0) {
+ fprintf(stderr, "GOP size has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->gop_size = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-min-buffer") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (cmd_data->min_buffer_time != -1) {
+ fprintf(stderr, "Min Buffer Time has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ cmd_data->min_buffer_time = (float)atof(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-base-url") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (strcmp(cmd_data->base_url, "") != 0) {
+ fprintf(stderr, "BaseURL has already been specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ strncpy(cmd_data->base_url, argv[i], GF_MAX_PATH);
+ i++;
+ } else if (strcmp(argv[i], "-live") == 0) {
+ cmd_data->mode = LIVE_CAMERA;
+ i++;
+ } else if (strcmp(argv[i], "-npts") == 0) {
+ cmd_data->use_source_timing = 0;
+ i++;
+ } else if (strcmp(argv[i], "-live-media") == 0) {
+ cmd_data->mode = LIVE_MEDIA;
+ i++;
+ } else if (strcmp(argv[i], "-no-loop") == 0) {
+ cmd_data->no_loop = 1;
+ i++;
+ } else if (strcmp(argv[i], "-insert-utc") == 0) {
+ cmd_data->insert_utc = 1;
+ i++;
+ } else if (strcmp(argv[i], "-dynamic-ast") == 0) {
+ cmd_data->use_dynamic_ast = 1;
+ i++;
+ } else if (strcmp(argv[i], "-send-message") == 0) {
+ //FIXME: unreferenced option. Seems related to a separate fragment thread.
+ cmd_data->send_message = 1;
+ i++;
+ } else if (strcmp(argv[i], "-logs") == 0) {
+ DASHCAST_CHECK_NEXT_ARG
+ if (gf_log_set_tools_levels(argv[i]) != GF_OK) {
+ fprintf(stderr, "Invalid log format %s", argv[i]);
+ return 1;
+ }
+ i++;
+ } else if (strcmp(argv[i], "-mem-track") == 0) {
+ i++;
+#ifndef GPAC_MEMORY_TRACKING
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n"));
+#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");
+ gf_log_set_callback(cmd_data->logfile, on_dc_log);
+ i++;
+ } else if (strcmp(argv[i], "-gdr") == 0) {
+ if ( (i+1 <= argc) && (argv[i+1][0] != '-')) {
+ DASHCAST_CHECK_NEXT_ARG
+ cmd_data->gdr = atoi(argv[i]);
+ } else {
+ //for historical reasons in dashcast
+ cmd_data->gdr = 8;
+ }
+ i++;
+ } else {
+ fprintf(stderr, "%s: %s", command_error, argv[i]);
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ }
+
+ if (strcmp(cmd_data->mpd_filename, "") == 0) {
+ strcpy(cmd_data->mpd_filename, "dashcast.mpd");
+ }
+
+ if (strcmp(cmd_data->out_dir, "") == 0) {
+ struct stat status;
+ strcpy(cmd_data->out_dir, "output");
+ if (stat(cmd_data->out_dir, &status) != 0) {
+ gf_mkdir(cmd_data->out_dir);
+ }
+ }
+
+ if (strcmp(cmd_data->video_data_conf.filename, "") == 0 && strcmp(cmd_data->audio_data_conf.filename, "") == 0) {
+ fprintf(stderr, "Audio/Video source must be specified.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+
+ if (cmd_data->seg_dur == 0) {
+ cmd_data->seg_dur = 1000;
+ }
+
+ if (cmd_data->frag_dur == 0) {
+ cmd_data->frag_dur = cmd_data->seg_dur;
+ }
+
+ if (cmd_data->ast_offset == -1) {
+ //generate MPD as soon as possible (no offset)
+ cmd_data->ast_offset = 0;
+ }
+
+ if (cmd_data->mode == ON_DEMAND)
+ cmd_data->time_shift = -1;
+ else {
+ if (cmd_data->time_shift == 0) {
+ cmd_data->time_shift = 10;
+ }
+ }
+
+ if (cmd_data->min_buffer_time == -1) {
+ cmd_data->min_buffer_time = 1.0;
+ }
+
+ //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) {
+ fprintf(stderr, "You cannot use '-vcrop' without '-vres'. Please check usage.\n");
+ fprintf(stderr, "%s", command_usage);
+ return -1;
+ }
+ }
+
+ fprintf(stdout, "\33[34m\33[1m");
+ fprintf(stdout, "Options:\n");
+ fprintf(stdout, " video source: %s\n", cmd_data->video_data_conf.filename);
+ if (strcmp(cmd_data->video_data_conf.format, "") != 0) {
+ fprintf(stdout, " video format: %s\n", cmd_data->video_data_conf.format);
+ }
+#ifndef WIN32
+ if (strcmp(cmd_data->video_data_conf.v4l2f, "") != 0) {
+ fprintf(stdout, " v4l2 format: %s\n", cmd_data->video_data_conf.v4l2f);
+ }
+#endif
+ if (cmd_data->video_data_conf.framerate != -1) {
+ fprintf(stdout, " video framerate: %d\n", cmd_data->video_data_conf.framerate);
+ }
+ if (cmd_data->video_data_conf.height != -1 && cmd_data->video_data_conf.width != -1) {
+ fprintf(stdout, " video resolution: %dx%d\n", cmd_data->video_data_conf.width, cmd_data->video_data_conf.height);
+ }
+ if (cmd_data->video_data_conf.crop_x != -1 && cmd_data->video_data_conf.crop_y != -1) {
+ fprintf(stdout, " video crop: %dx%d\n", cmd_data->video_data_conf.crop_x, cmd_data->video_data_conf.crop_y);
+ }
+
+ fprintf(stdout, " audio source: %s\n", cmd_data->audio_data_conf.filename);
+ if (strcmp(cmd_data->audio_data_conf.format, "") != 0) {
+ fprintf(stdout, " audio format: %s\n", cmd_data->audio_data_conf.format);
+ }
+ fprintf(stdout, "\33[0m");
+// fflush(stdout);
+
+ if (!cmd_data->conf) {
+ cmd_data->conf = gf_cfg_force_new(NULL, "dashcast.conf");
+ dc_create_configuration(cmd_data);
+ }
+ dc_read_configuration(cmd_data);
+
+ if (!cmd_data->switch_conf) {
+ cmd_data->switch_conf = gf_cfg_force_new(NULL, "switch.conf");
+ }
+ dc_read_switch_config(cmd_data);
+
+ return 0;
+}
diff --git a/applications/dashcast/cmd_data.h b/applications/dashcast/cmd_data.h
new file mode 100644
index 0000000..e572c63
--- /dev/null
+++ b/applications/dashcast/cmd_data.h
@@ -0,0 +1,136 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef CMD_DATA_H_
+#define CMD_DATA_H_
+
+#define MAX_SOURCE_NUMBER 20
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "audio_data.h"
+#include "video_data.h"
+#include "task.h"
+
+
+/*
+ * This structure corresponds to
+ * the data in command line
+ */
+typedef struct {
+ /* input video */
+ VideoDataConf video_data_conf;
+ /* audio input data */
+ AudioDataConf audio_data_conf;
+ /* Configuration file */
+ GF_Config *conf;
+ /* Switch source configuration file */
+ GF_Config *switch_conf;
+ /* MPD file */
+ char mpd_filename[GF_MAX_PATH];
+ /* segment duration */
+ int seg_dur;
+ /* fragment duration */
+ int frag_dur;
+ /* Exit signal emitting from user to end the program */
+ volatile int exit_signal;
+ /* List of entries for video in configuration file */
+ GF_List *video_lst;
+ /* List of entries for audio in configuration file */
+ GF_List *audio_lst;
+ /* Indicates that the system is live */
+ /* List of video input sources */
+ GF_List *vsrc;
+ /* List of audio input sources */
+ GF_List *asrc;
+ //int live;
+ /* Indicates that the system is live from a media input */
+ //int live_media;
+ /* The mode of the system: ON_DEMAND, LIVE_CAMERA, LIVE_MEDIA */
+ int mode;
+ /* Does not loop on input */
+ int no_loop;
+ /* MPD AvailabilityStartTime offset in milliseconds. Default is 1000 milliseconds delay */
+ int ast_offset;
+ /* MPD time shift buffer depth in seconds */
+ int time_shift;
+ /* MPD minimumUpdatePeriod in seconds */
+ int minimum_update_period;
+ /* Send message on port 1234 once fragment is ready */
+ int send_message;
+ /* End of Segment Box name */
+ u32 seg_marker;
+ /* GDR */
+ int gdr;
+ /* GOP size in frames - 0 means framerate (1 sec)*/
+ int gop_size;
+ /* MPD min buffer time */
+ float min_buffer_time;
+ /* MPD BaseURL*/
+ char base_url[GF_MAX_PATH];
+ /* output directory name */
+ char out_dir[GF_MAX_PATH];
+ /* switch source configuration file */
+ //char switch_cfg_filename[GF_MAX_PATH];
+ FILE *logfile;
+ TaskList task_list;
+ /*dynamic ast*/
+ int use_dynamic_ast;
+ /*insert UTC */
+ int insert_utc;
+
+ Bool use_source_timing;
+} CmdData;
+
+/*
+ * Initilize the command data structure
+ *
+ * @param cmd_data [out] structure to be initialize
+ */
+void dc_cmd_data_init(CmdData *cmd_data);
+
+/*
+ * Destroy the command data structure
+ *
+ * @param cmd_data [out] structure to be destroyed
+ */
+void dc_cmd_data_destroy(CmdData *cmd_data);
+
+/*
+ * Parse command line
+ *
+ * @param argc [in] number of arguments
+ * @param argv [in] a list of strings each containing one argument
+ * @param cmd_data [out] the data structure to fill
+ */
+int dc_parse_command(int argc, char **argv, CmdData *cmd_data);
+
+#endif /* CMD_DATA_H_ */
diff --git a/applications/dashcast/controler.c b/applications/dashcast/controler.c
new file mode 100644
index 0000000..189dc62
--- /dev/null
+++ b/applications/dashcast/controler.c
@@ -0,0 +1,1564 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "controler.h"
+
+
+#if (!defined(__DARWIN__) && !defined(__APPLE__))
+#include
+#endif
+
+#include
+//FIXME: use GPAC utility functions
+#if defined(__GNUC__)
+#include
+#include
+#elif defined(WIN32)
+#include
+#include
+#define suseconds_t long
+
+s32 gettimeofday(struct timeval *tp, void *tz)
+{
+ struct _timeb timebuffer;
+
+ _ftime( &timebuffer );
+ tp->tv_sec = (long) (timebuffer.time);
+ tp->tv_usec = timebuffer.millitm * 1000;
+ return 0;
+}
+#else
+#error
+#endif
+
+
+typedef struct {
+ int segnum;
+ u64 time;
+} segtime;
+
+
+//#define MAX_SOURCE_NUMBER 20
+#define DASHER 0
+#define FRAGMENTER 0
+//#define DEBUG 1
+
+//#define VIDEO_MUXER FFMPEG_VIDEO_MUXER
+//#define VIDEO_MUXER RAW_VIDEO_H264
+//#define VIDEO_MUXER GPAC_VIDEO_MUXER
+#define VIDEO_MUXER GPAC_INIT_VIDEO_MUXER_AVC1
+//#define VIDEO_MUXER GPAC_INIT_VIDEO_MUXER_AVC3
+
+//#define AUDIO_MUXER FFMPEG_AUDIO_MUXER
+//#define AUDIO_MUXER GPAC_AUDIO_MUXER
+#define AUDIO_MUXER GPAC_INIT_AUDIO_MUXER
+
+#define DASHCAST_PRINT
+
+#define AUDIO_FRAME_SIZE 1024
+
+
+void optimize_seg_frag_dur(int *seg, int *frag)
+{
+ int seg_nb = *seg;
+ int frag_nb = *frag;
+
+ int min_rem = seg_nb % frag_nb;
+ if (seg_nb % (frag_nb + 1) < min_rem) {
+ min_rem = seg_nb % (frag_nb + 1);
+ *seg = seg_nb;
+ *frag = frag_nb + 1;
+ }
+
+ if ((seg_nb + 1) % frag_nb < min_rem) {
+ min_rem = (seg_nb + 1) % frag_nb;
+ *seg = seg_nb + 1;
+ *frag = frag_nb;
+ }
+
+ if ((seg_nb + 1) % (frag_nb + 1) < min_rem) {
+ min_rem = (seg_nb + 1) % (frag_nb + 1);
+ *seg = seg_nb + 1;
+ *frag = frag_nb + 1;
+ }
+
+ *seg -= min_rem;
+}
+
+Bool change_source_thread(void *params)
+{
+ int ret = 0;
+ return ret;
+}
+
+u32 send_frag_event(void *params)
+{
+ int ret;
+ //int status;
+ char buff[GF_MAX_PATH];
+ ThreadParam *th_param = (ThreadParam*)params;
+ CmdData *cmd_data = th_param->in_data;
+ MessageQueue *mq = th_param->mq;
+
+ while (1) {
+ if (cmd_data->exit_signal) {
+ break;
+ }
+
+ ret = dc_message_queue_get(mq, (void*) buff);
+ if (ret > 0) {
+ fprintf(stdout, "Message received: %s\n", buff);
+ }
+ }
+
+ return 0;
+}
+
+static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, const VideoDataConf *video_data_conf, const char *presentation_duration, const char *availability_start_time, const char *time_shift, const int segnum, const int ast_offset)
+{
+ u32 i = 0;
+ int audio_seg_dur = 0, video_seg_dur = 0, audio_frag_dur = 0, video_frag_dur = 0;
+ int audio_frame_size = AUDIO_FRAME_SIZE;
+ FILE *f;
+
+ char name[GF_MAX_PATH];
+ snprintf(name, sizeof(name), "%s/%s", cmddata->out_dir, cmddata->mpd_filename);
+
+ if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
+ audio_data_conf = gf_list_get(cmddata->audio_lst, 0);
+ audio_seg_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->seg_dur / 1000.0));
+ audio_frag_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->frag_dur / 1000.0));
+ optimize_seg_frag_dur(&audio_seg_dur, &audio_frag_dur);
+ }
+
+ if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
+ video_data_conf = gf_list_get(cmddata->video_lst, 0);
+ video_seg_dur = (int)(video_data_conf->framerate * (cmddata->seg_dur / 1000.0));
+ video_frag_dur = (int)(video_data_conf->framerate * (cmddata->frag_dur / 1000.0));
+ optimize_seg_frag_dur(&video_seg_dur, &video_frag_dur);
+ }
+
+ f = fopen(name, "w");
+ //TODO: if (!f) ...
+
+ // time_t t = time(NULL);
+ // time_t t2 = t + 2;
+ // t += (2 * (cmddata->seg_dur / 1000.0));
+ // tm = *gmtime(&t2);
+ // snprintf(availability_start_time, "%d-%d-%dT%d:%d:%dZ", tm.tm_year + 1900,
+ // tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ // fprintf(stdout, "%s \n", availability_start_time);
+
+ fprintf(f, "\n");
+ fprintf(f, "mode == ON_DEMAND) ? "mediaPresentationDuration" : "availabilityStartTime",
+ (cmddata->mode == ON_DEMAND) ? presentation_duration : availability_start_time,
+ cmddata->min_buffer_time, time_shift,
+ (cmddata->mode == ON_DEMAND) ? "static" : "dynamic");
+ if (cmddata->minimum_update_period > 0 ) {
+ fprintf(f, " minimumUpdatePeriod=\"PT%dS\"", cmddata->minimum_update_period);
+ }
+ fprintf(f, ">\n");
+ fprintf(f,
+ " \n"
+ " %s\n"
+ " \n", cmddata->mpd_filename);
+
+ if (strcmp(cmddata->base_url, "") != 0) {
+ fprintf(f, " %s\n", cmddata->base_url);
+ }
+
+ fprintf(f, " \n");
+
+ if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
+ fprintf(f, " \n");
+
+ fprintf(f,
+ " \n");
+
+ fprintf(f,
+ " samplerate, audio_seg_dur * audio_frame_size, segnum);
+
+ if (ast_offset<0) {
+ fprintf(f, " availabilityTimeOffset=\"%g\"", -ast_offset/1000.0);
+ }
+ fprintf(f, "/>\n");
+
+
+
+ for (i = 0; i < gf_list_count(cmddata->audio_lst); i++) {
+ audio_data_conf = gf_list_get(cmddata->audio_lst, i);
+ fprintf(f,
+ " \n"
+ " \n", audio_data_conf->filename, audio_data_conf->samplerate, audio_data_conf->bitrate);
+ }
+
+ fprintf(f, " \n");
+ }
+
+ if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
+ fprintf(f, " \n");
+
+ fprintf(f,
+ " framerate, video_seg_dur, segnum);
+
+
+ if (ast_offset<0) {
+ fprintf(f, " availabilityTimeOffset=\"%g\"", -ast_offset/1000.0);
+ }
+ fprintf(f, "/>\n");
+
+ for (i = 0; i < gf_list_count(cmddata->video_lst); i++) {
+ video_data_conf = gf_list_get(cmddata->video_lst, i);
+ fprintf(f, " \n"
+ " \n", video_data_conf->filename,
+ VIDEO_MUXER == GPAC_INIT_VIDEO_MUXER_AVC1 ? "avc1.42e01e" : "avc3", //FIXME: hardcoded. We would need acces to the ISOFile to call gf_media_get_rfc_6381_codec_name()
+ video_data_conf->width, video_data_conf->height, video_data_conf->framerate,
+ video_data_conf->bitrate);
+ }
+
+ fprintf(f, " \n");
+ }
+
+ fprintf(f, " \n");
+
+ 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");
+}
+
+static u32 mpd_thread(void *params)
+{
+ ThreadParam *th_param = (ThreadParam*)params;
+ CmdData *cmddata = th_param->in_data;
+ MessageQueue *mq = th_param->mq;
+ char availability_start_time[GF_MAX_PATH];
+ char presentation_duration[GF_MAX_PATH];
+ char time_shift[GF_MAX_PATH] = "";
+ AudioDataConf *audio_data_conf = NULL;
+ VideoDataConf *video_data_conf = NULL;
+ struct tm ast_time;
+
+ segtime main_seg_time;
+ Bool first = GF_TRUE;
+ main_seg_time.segnum = 0;
+ main_seg_time.time = 0;
+
+ if (cmddata->mode == LIVE_CAMERA || cmddata->mode == LIVE_MEDIA) {
+ while (1) {
+ u32 msecs;
+ time_t t;
+ segtime seg_time;
+ seg_time.segnum = 0;
+ seg_time.time = 0;
+
+ if (cmddata->exit_signal) {
+ break;
+ }
+
+ if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
+ dc_message_queue_get(mq, &seg_time);
+ }
+
+ if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
+ if (dc_message_queue_get(mq, &seg_time)<0) {
+ continue;
+ }
+
+ if (cmddata->ast_offset>0) {
+ seg_time.time += cmddata->ast_offset;
+ }
+
+ if (cmddata->use_dynamic_ast) {
+ main_seg_time = seg_time;
+ } else {
+ //get the last notification of AST
+ if (first) {
+ if (seg_time.segnum) {
+ first = GF_FALSE;
+ } else {
+ main_seg_time = seg_time;
+ }
+ } else {
+ assert(seg_time.segnum);
+ }
+ }
+ }
+
+ //printf time at which we generate MPD
+ t = seg_time.time / 1000;
+ msecs = (u32) ( (seg_time.time - t*1000) );
+ 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);
+
+ t = main_seg_time.time / 1000;
+ msecs = (u32) ( (main_seg_time.time - t*1000) );
+ 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);
+
+ if (cmddata->time_shift != -1) {
+ int ts, h, m, s;
+ ts = cmddata->time_shift;
+ h = ts / 3600;
+ ts = ts % 3600;
+ m = ts / 60;
+ s = ts % 60;
+ 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);
+ }
+ } else {
+
+ int a_dur = 0;
+ int v_dur = 0;
+
+ if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
+ dc_message_queue_get(mq, &a_dur);
+ }
+
+ if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
+ dc_message_queue_get(mq, &v_dur);
+ }
+
+ {
+ int dur, h, m, s, ms;
+ dur = v_dur > a_dur ? v_dur : a_dur;
+ h = dur / 3600000;
+ dur = dur % 3600000;
+ m = dur / 60000;
+ dur = dur % 60000;
+ s = dur / 1000;
+ ms = dur % 1000;
+ snprintf(presentation_duration, sizeof(presentation_duration), "PT%02dH%02dM%02d.%03dS", h, m, s, ms);
+ fprintf(stdout, "Duration: %s\n", presentation_duration);
+ }
+
+ dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, time_shift, 0, cmddata->ast_offset);
+ }
+
+ return 0;
+}
+
+u32 delete_seg_thread(void *params)
+{
+ int ret;
+ ThreadParam *th_param = (ThreadParam*)params;CmdData *cmd_data = th_param->in_data;
+ MessageQueue *mq = th_param->mq;
+
+ char buff[GF_MAX_PATH];
+
+ while (1) {
+ ret = dc_message_queue_get(mq, (void*) buff);
+ if (ret > 0) {
+ int status;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Message received: %s\n", buff));
+ status = unlink(buff);
+ if (status != 0) {
+ GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unable to delete the file %s\n", buff));
+ }
+ }
+
+ if (cmd_data->exit_signal) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+Bool fragmenter_thread(void *params)
+{
+ int ret;
+ ThreadParam *th_param = (ThreadParam*)params;
+ CmdData *cmd_data = th_param->in_data;
+ MessageQueue *mq = th_param->mq;
+
+ char buff[GF_MAX_PATH];
+
+ while (1) {
+ ret = dc_message_queue_get(mq, (void*) buff);
+ if (ret > 0) {
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Message received: %s\n", buff));
+ }
+
+ if (cmd_data->exit_signal) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+Bool dasher_thread(void *params)
+{
+// int i;
+// ThreadParam *th_param = (ThreadParam *) params;
+// CmdData *cmd_data = th_param->in_data;
+//
+// char sz_mpd[GF_MAX_PATH];
+// GF_DashSegmenterInput *dash_inputs;
+// u32 nb_dash_inputs = 0;
+// Bool use_url_template = 0;
+// GF_Err e;
+// s32 subsegs_per_sidx = 0;
+// Bool daisy_chain_sidx = 0;
+// char *seg_ext = NULL;
+// const char *dash_title = NULL;
+// const char *dash_source = NULL;
+// const char *dash_more_info = NULL;
+// char *tmpdir = NULL, *cprt = NULL, *seg_name = NULL;
+// char **mpd_base_urls = NULL;
+// u32 nb_mpd_base_urls = 0;
+// Bool single_segment = 0;
+//
+// Bool single_file = 0;
+// GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_INBAND;
+// Bool seg_at_rap = 0;
+// Bool frag_at_rap = 0;
+//
+// Double interleaving_time = 0.0;
+// u32 time_shift_depth = 0;
+// Double dash_duration = 0.0, dash_subduration = 0.0;
+// u32 mpd_update_time = 0;
+//
+//
+// GF_DashProfile dash_profile = GF_DASH_PROFILE_UNKNOWN;
+// u32 dash_dynamic = 0;
+// GF_Config *dash_ctx = NULL;
+//
+// int video_list_size = gf_list_count(cmd_data->video_lst);
+// int audio_list_size = gf_list_count(cmd_data->audio_lst);
+// nb_dash_inputs = video_list_size + audio_list_size;
+//
+// dash_inputs = gf_malloc(nb_dash_inputs * sizeof(GF_DashSegmenterInput));
+//
+// for (i = 0; i < video_list_size; i++) {
+//
+// VideoDataConf *video_data_conf = gf_list_get(cmd_data->video_lst, i);
+// dash_inputs[i].file_name = video_data_conf->filename;
+// snprintf(dash_inputs[i].representationID, "%d", i);
+// strcpy(dash_inputs[i].periodID, "");
+// strcpy(dash_inputs[i].role, "");
+//
+// }
+//
+// for (i = 0; i < audio_list_size; i++) {
+//
+// AudioDataConf *audio_data_conf = gf_list_get(cmd_data->audio_lst, i);
+// dash_inputs[i + video_list_size].file_name = audio_data_conf->filename;
+// snprintf(dash_inputs[i + video_list_size].representationID, "%d",
+// i + video_list_size);
+// strcpy(dash_inputs[i + video_list_size].periodID, "");
+// strcpy(dash_inputs[i + video_list_size].role, "");
+//
+// }
+//
+// dash_profile = cmd_data->live ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_MAIN;
+// strncpy(sz_mpd, cmd_data->mpd_filename, GF_MAX_PATH);
+//
+// dash_duration = cmd_data->dash_dur ? cmd_data->dash_dur / 1000 : 1;
+//
+// if (cmd_data->live) {
+// dash_ctx = gf_cfg_new(NULL, NULL);
+// }
+//
+// if (!dash_dynamic) {
+// time_shift_depth = 0;
+// mpd_update_time = 0;
+// } else if ((dash_profile >= GF_DASH_PROFILE_MAIN) && !use_url_template
+// && !mpd_update_time) {
+// /*use a default MPD update of dash_duration sec*/
+// mpd_update_time = (u32) (
+// dash_subduration ? dash_subduration : dash_duration);
+// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Using default MPD refresh of %d seconds\n",
+// mpd_update_time);
+// }
+//
+// if (cmd_data->live)
+// gf_sleep(dash_duration * 1000);
+//
+// while (1) {
+//
+// //TODO Signiture of this API has changed!
+// /*
+// e = gf_dasher_segment_files(sz_mpd, dash_inputs, nb_dash_inputs,
+// dash_profile, dash_title, dash_source, cprt, dash_more_info,
+// (const char **) mpd_base_urls, nb_mpd_base_urls,
+// use_url_template, single_segment, single_file,
+// bitstream_switching_mode, seg_at_rap, dash_duration, seg_name,
+// seg_ext, interleaving_time, subsegs_per_sidx, daisy_chain_sidx,
+// frag_at_rap, tmpdir, dash_ctx, dash_dynamic, mpd_update_time,
+// time_shift_depth, dash_subduration);
+//
+// if (e) {
+// fprintf(stdout, "Error while segmenting.\n");
+// break;
+// }
+// */
+//
+// if (!cmd_data->live)
+// break;
+//
+// u32 sleefor = gf_dasher_next_update_time(dash_ctx, mpd_update_time);
+//
+// if (cmd_data->exit_signal) {
+// break;
+// }
+//
+// if (sleefor) {
+// if (dash_dynamic != 2) {
+// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("sleep for %d ms\n", sleefor);
+// gf_sleep(sleefor);
+// }
+// }
+//
+// }
+
+ return 0;
+}
+
+static u32 keyboard_thread(void *params)
+{
+
+ ThreadParam *th_param = (ThreadParam*)params;
+ CmdData *in_data = th_param->in_data;
+ char c;
+
+ while (1) {
+ if (gf_prompt_has_input()) {
+ c = gf_prompt_get_char();
+ if (c == 'q' || c == 'Q') {
+ in_data->exit_signal = 1;
+ break;
+ }
+ }
+
+ if (in_data->exit_signal) {
+ break;
+ }
+
+ gf_sleep(100);
+ }
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Keyboard thread exit\n"));
+ return 0;
+}
+
+u32 video_decoder_thread(void *params)
+{
+#ifdef DASHCAST_PRINT
+ int i = 0;
+#endif
+ int ret;
+ int source_number = 0;
+
+ //int first_time = 1;
+ struct timeval time_start, time_end, time_wait;
+ VideoThreadParam *thread_params = (VideoThreadParam *) params;
+
+ CmdData *in_data = thread_params->in_data;
+ VideoInputData *video_input_data = thread_params->video_input_data;
+ VideoInputFile **video_input_file = thread_params->video_input_file;
+
+ suseconds_t total_wait_time = 1000000 / in_data->video_data_conf.framerate;
+ suseconds_t pick_packet_delay, select_delay = 0, real_wait, other_delays = 2;
+
+ Task t;
+ //fprintf(stdout, "wait time : %f\n", total_wait_time);
+
+ if (!gf_list_count(in_data->video_lst))
+ return 0;
+
+ while (1) {
+ dc_task_get_current(&in_data->task_list, &t);
+ source_number = t.source_number;
+
+ //fprintf(stdout, "sourcenumber: %d\n", source_number);
+
+ if (video_input_file[source_number]->mode == LIVE_MEDIA) {
+ gettimeofday(&time_start, NULL);
+ }
+
+ ret = dc_video_decoder_read(video_input_file[source_number], video_input_data, source_number, in_data->use_source_timing, (in_data->mode == LIVE_CAMERA) ? 1 : 0, (const int *) &in_data->exit_signal);
+#ifdef DASHCAST_PRINT
+ fprintf(stdout, "Read video frame %d\r", i++);
+ fflush(stdout);
+#endif
+ if (ret == -2) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video reader has no more frame to read.\n"));
+ break;
+ }
+ if (ret == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occurred while reading video frame.\n"));
+ break;
+ }
+
+ if (in_data->exit_signal) {
+ dc_video_input_data_end_signal(video_input_data);
+ break;
+ }
+
+ if (video_input_file[source_number]->mode == LIVE_MEDIA) {
+ gettimeofday(&time_end, NULL);
+ pick_packet_delay = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec;
+ time_wait.tv_sec = 0;
+ real_wait = total_wait_time - pick_packet_delay - select_delay - other_delays;
+ time_wait.tv_usec = real_wait;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("delay: %ld = %ld - %ld\n", time_wait.tv_usec, total_wait_time, pick_packet_delay));
+
+ gettimeofday(&time_start, NULL);
+ select(0, NULL, NULL, NULL, &time_wait);
+ gettimeofday(&time_end, NULL);
+
+ select_delay = (((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec) - real_wait;
+ }
+ }
+
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Video decoder is exiting...\n"));
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video decoder thread exit\n"));
+ return 0;
+}
+
+u32 audio_decoder_thread(void *params)
+{
+#ifdef DASHCAST_PRINT
+ int i = 0;
+#endif
+ int ret;
+ struct timeval time_start, time_end, time_wait;
+ AudioThreadParam *thread_params = (AudioThreadParam*)params;
+
+ CmdData *in_data = thread_params->in_data;
+ AudioInputData *audio_input_data = thread_params->audio_input_data;
+ AudioInputFile *audio_input_file = thread_params->audio_input_file;
+
+ suseconds_t pick_packet_delay, select_delay = 0, real_wait, other_delays = 1;
+ suseconds_t total_wait_time;
+ if (in_data->audio_data_conf.samplerate < 1024) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error: invalid audio sample rate: %d\n", in_data->audio_data_conf.samplerate));
+ dc_audio_inout_data_end_signal(audio_input_data);
+ //FIXME: deadlock on the mpd thread. Reproduce with big_buck_bunny.mp4.
+ return 1;
+ }
+ total_wait_time = 1000000 / (in_data->audio_data_conf.samplerate / 1024);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("wait time : %ld\n", total_wait_time));
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("sample-rate : %ld\n", in_data->audio_data_conf.samplerate));
+
+ if (!gf_list_count(in_data->audio_lst))
+ return 0;
+
+ while (1) {
+ if (audio_input_file->mode == LIVE_MEDIA) {
+ gettimeofday(&time_start, NULL);
+ }
+
+ ret = dc_audio_decoder_read(audio_input_file, audio_input_data);
+#ifdef DASHCAST_PRINT
+ fprintf(stdout, "Read audio frame %d\r", i++);
+ fflush(stdout);
+#endif
+ if (ret == -2) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder has no more frame to read.\n"));
+ break;
+ }
+ if (ret == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occurred while reading video frame.\n"));
+ break;
+ }
+
+ if (in_data->exit_signal) {
+ dc_audio_inout_data_end_signal(audio_input_data);
+ break;
+ }
+
+ if (audio_input_file->mode == LIVE_MEDIA) {
+ gettimeofday(&time_end, NULL);
+ pick_packet_delay = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec;
+ time_wait.tv_sec = 0;
+ real_wait = total_wait_time - pick_packet_delay - select_delay - other_delays;
+ time_wait.tv_usec = real_wait;
+
+ gettimeofday(&time_start, NULL);
+ select(0, NULL, NULL, NULL, &time_wait);
+ gettimeofday(&time_end, NULL);
+
+ select_delay = (((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec) - real_wait;
+ }
+ }
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder is exiting...\n"));
+ return 0;
+}
+
+u32 video_scaler_thread(void *params)
+{
+ int ret;
+ VideoThreadParam *thread_params = (VideoThreadParam *) params;
+ CmdData *in_data = thread_params->in_data;
+ VideoInputData *video_input_data = thread_params->video_input_data;
+ VideoScaledData *video_scaled_data = thread_params->video_scaled_data;
+
+ if (!gf_list_count(in_data->video_lst))
+ return 0;
+
+ while (1) {
+ ret = dc_video_scaler_scale(video_input_data, video_scaled_data);
+ if (ret == -2) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video scaler has no more frame to read.\n"));
+ break;
+ }
+ }
+
+ dc_video_scaler_end_signal(video_scaled_data);
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video scaler thread exit\n"));
+ return 0;
+}
+
+u32 video_encoder_thread(void *params)
+{
+ int ret, shift, frame_nb, seg_frame_max, frag_frame_max, seg_nb = 0, loss_state = 0, quit = 0;
+ char name_to_delete[GF_MAX_PATH], name_to_send[GF_MAX_PATH];
+ u64 start_utc, seg_utc;
+ segtime time_at_segment_start;
+ VideoMuxerType muxer_type = VIDEO_MUXER;
+ VideoThreadParam *thread_params = (VideoThreadParam*)params;
+
+ 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);
+
+ VideoScaledData *video_scaled_data = thread_params->video_scaled_data;
+ int video_cb_size = (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) ? 1 : VIDEO_CB_DEFAULT_SIZE;
+ VideoOutputFile out_file;
+
+ MessageQueue *mq = thread_params->mq;
+ MessageQueue *delete_seg_mq = thread_params->delete_seg_mq;
+ MessageQueue *send_seg_mq = thread_params->send_seg_mq;
+#ifndef FRAGMENTER
+ MessageQueue *mq = thread_params->mq;
+#endif
+
+ if (!gf_list_count(in_data->video_lst))
+ return 0;
+
+ seg_frame_max = (int)(video_data_conf->framerate * (float) (in_data->seg_dur / 1000.0));
+ frag_frame_max = (int)(video_data_conf->framerate * (float) (in_data->frag_dur / 1000.0));
+ optimize_seg_frag_dur(&seg_frame_max, &frag_frame_max);
+
+ if (seg_frame_max <= 0)
+ seg_frame_max = -1;
+
+ shift = 0;
+ if (in_data->use_source_timing) {
+ //ugly patch ...
+ shift = 1000;
+ while (!video_scaled_data->frame_duration && shift) {
+ gf_sleep(1);
+ shift--;
+ }
+ shift = (u32) video_scaled_data->frame_duration;
+ }
+ if (dc_video_muxer_init(&out_file, video_data_conf, muxer_type, seg_frame_max, frag_frame_max, in_data->seg_marker, in_data->gdr, in_data->seg_dur, in_data->frag_dur, shift, in_data->gop_size, video_cb_size) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output video file.\n"));
+ in_data->exit_signal = 1;
+ return -1;
+ }
+
+ if (dc_video_encoder_open(&out_file, video_data_conf, in_data->use_source_timing) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video stream.\n"));
+ in_data->exit_signal = 1;
+ return -1;
+ }
+
+ start_utc = gf_net_get_utc();
+ seg_utc = 0;
+ while (1) {
+ frame_nb = 0;
+ //log time at segment start, because segment availabilityStartTime is computed from AST anchor + segment duration
+ //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();
+
+ if (dc_video_muxer_open(&out_file, in_data->out_dir, video_data_conf->filename, seg_nb) < 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;
+// }
+ //we have the RAP already encoded, skip coder
+ if (loss_state == 2) {
+ ret = 1;
+ loss_state = 0;
+ } else {
+ ret = dc_video_encoder_encode(&out_file, video_scaled_data);
+ }
+
+ if (ret == -2) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder has no more data to encode.\n"));
+ quit = 1;
+ break;
+ }
+ if (ret == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing video frame.\n"));
+ quit = 1;
+ break;
+ }
+
+ 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);
+ if (r < 0) {
+ quit = 1;
+ in_data->exit_signal = 1;
+ break;
+ } else if (r == 1) {
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("fragment is written!\n"));
+ if (in_data->send_message == 1) {
+ snprintf(name_to_send, sizeof(name_to_send), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, seg_nb);
+ dc_message_queue_put(send_seg_mq, name_to_send, sizeof(name_to_send));
+ }
+
+ break;
+ }
+
+ frame_nb++;
+ }
+ }
+
+ dc_video_muxer_close(&out_file);
+
+#ifndef FRAGMENTER
+ dc_message_queue_put(mq, video_data_conf->filename, sizeof(video_data_conf->filename));
+#endif
+
+ // If system is live,
+ // Send the time that a segment is available to MPD generator thread.
+ if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) {
+ //check we don't loose sync
+ int diff;
+ int seg_diff;
+ seg_utc = gf_net_get_utc();
+ diff = (int) (seg_utc - start_utc);
+
+ //if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers
+ if (diff > (seg_nb+2) * in_data->seg_dur) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Rep %s UTC diff %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", out_file.rep_id, diff, seg_nb));
+
+ while (diff > (seg_nb+2) * in_data->seg_dur) {
+ seg_nb++;
+
+ //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;
+ }
+ }
+ //wait for RAP to cut next segment
+ loss_state = 1;
+ } else {
+#define SYNC_SAFE 800
+
+ seg_diff = diff;
+ seg_diff -= (seg_nb+1) * in_data->seg_dur;
+ if (seg_diff > SYNC_SAFE) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Rep %s UTC diff at segment close: %d is higher than cumulated segment duration %d (diff %d) - frame rate is probably not correct !!\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff));
+ }
+ else if (seg_diff < -SYNC_SAFE) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Rep %s UTC diff at segment close: %d is lower than cumulated segment duration %d (diff %d) - frame rate is probably not correct or frames were lost !!\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff));
+ } else {
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Rep %s UTC diff at segment close: %d - cumulated segment duration %d (diff %d)\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff));
+ }
+ }
+
+ //time_t t = time(NULL);
+ dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start));
+ }
+
+ if ((in_data->time_shift != -1)) {
+ shift = 1000 * in_data->time_shift / in_data->seg_dur;
+ if (seg_nb - shift>=0) {
+ snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, (seg_nb - shift));
+ dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete));
+ }
+ }
+
+ seg_nb++;
+
+ if (quit)
+ break;
+ }
+
+ // If system is not live,
+ // Send the duration of the video
+ if (in_data->mode == ON_DEMAND) {
+ if (thread_params->video_conf_idx == 0) {
+ int dur = (seg_nb * seg_frame_max * 1000) / video_data_conf->framerate;
+ int dur_tot = (out_file.codec_ctx->frame_number * 1000)
+ / video_data_conf->framerate;
+ if (dur > dur_tot)
+ dur = dur_tot;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Duration: %d \n", dur));
+ dc_message_queue_put(mq, &dur, sizeof(dur));
+ }
+ }
+
+ /* Close output video file */
+ dc_video_encoder_close(&out_file);
+
+ dc_video_muxer_free(&out_file);
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video encoder thread exit\n"));
+ return 0;
+}
+
+u32 audio_encoder_thread(void *params)
+{
+ int ret, exit_loop = 0, quit = 0, seg_nb = 0, frame_per_seg, frame_per_frag, frame_nb, shift;
+ //int seg_frame_max;
+ //int frag_frame_max;
+ //int audio_frame_size = AUDIO_FRAME_SIZE;
+ char name_to_delete[GF_MAX_PATH];
+ u64 start_utc, seg_utc;
+
+ AudioMuxerType muxer_type = AUDIO_MUXER;
+ AudioThreadParam *thread_params = (AudioThreadParam *) params;
+
+ CmdData *in_data = thread_params->in_data;
+ int audio_conf_idx = thread_params->audio_conf_idx;
+ AudioDataConf *audio_data_conf = gf_list_get(in_data->audio_lst, audio_conf_idx);
+
+ AudioInputData *audio_input_data = thread_params->audio_input_data;
+ AudioOutputFile audio_output_file;
+
+ MessageQueue *mq = thread_params->mq;
+ MessageQueue *delete_seg_mq = thread_params->delete_seg_mq;
+#ifndef FRAGMENTER
+ MessageQueue *mq = thread_params->mq;
+#endif
+
+ if (!gf_list_count(in_data->audio_lst))
+ return 0;
+
+ //seg_frame_max = audio_data_conf->samplerate
+ // * (float) (in_data->seg_dur / 1000.0);
+
+ //frag_frame_max = audio_data_conf->samplerate * (float) (in_data->frag_dur / 1000.0);
+ //if (seg_frame_max <= 0)
+ // seg_frame_max = -1;
+
+ if (dc_audio_encoder_open(&audio_output_file, audio_data_conf) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio stream.\n"));
+ in_data->exit_signal = 1;
+ return -1;
+ }
+
+ frame_per_seg = (int)((audio_data_conf->samplerate / (double) audio_output_file.frame_size) * (in_data->seg_dur / 1000.0));
+ frame_per_frag = (int)((audio_data_conf->samplerate / (double) audio_output_file.frame_size) * (in_data->frag_dur / 1000.0));
+ optimize_seg_frag_dur(&frame_per_seg, &frame_per_frag);
+
+ if (dc_audio_muxer_init(&audio_output_file, audio_data_conf, muxer_type, frame_per_seg, frame_per_frag, in_data->seg_marker) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output audio.\n"));
+ in_data->exit_signal = 1;
+ return -1;
+ }
+
+ start_utc = gf_net_get_utc();
+ seg_utc = 0;
+ 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) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio.\n"));
+ in_data->exit_signal = 1;
+ return -1;
+ }
+
+ while (1) {
+ exit_loop = 0;
+// if (frame_per_seg > 0) {
+// if (frame_nb == frame_per_seg) {
+//
+// //if (dc_audio_encoder_flush(&audio_output_file, audio_input_data) == 0) {
+// // dc_audio_muxer_write(&audio_output_file);
+// // frame_nb++;//= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples;
+// //}
+//
+// exit_loop = 1;
+// break;
+// }
+// }
+
+ ret = dc_audio_encoder_read(&audio_output_file, audio_input_data);
+ if (ret == -2) {
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder has no more data to encode.\n"));
+ //if (dc_audio_encoder_flush(&audio_output_file, audio_input_data) == 0) {
+ // dc_audio_muxer_write(&audio_output_file);
+ // frame_nb++;//= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples;
+ //}
+ quit = 1;
+ break;
+ }
+
+ while (1) {
+ ret = dc_audio_encoder_encode(&audio_output_file, audio_input_data);
+ if (ret == 1) {
+ break;
+ }
+ if (ret == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while encoding audio frame.\n"));
+ quit = 1;
+ break;
+ }
+
+ ret = dc_audio_muxer_write(&audio_output_file, frame_nb);
+ if (ret == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing audio frame.\n"));
+ quit = 1;
+ break;
+ }
+
+ if (ret == 1) {
+ exit_loop = 1;
+ break;
+ }
+
+ frame_nb++; //= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples;
+ }
+
+ if (exit_loop || quit)
+ break;
+ }
+
+ dc_audio_muxer_close(&audio_output_file);
+
+#ifndef FRAGMENTER
+ dc_message_queue_put(mq, audio_data_conf->filename, sizeof(audio_data_conf->filename));
+#endif
+
+ // Send the time that a segment is available to MPD generator thread.
+ if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA) {
+ if (thread_params->audio_conf_idx == 0) {
+ segtime t;
+
+ //check we don't loose sync
+ int diff;
+ seg_utc = gf_net_get_utc();
+ diff = (int) (seg_utc - start_utc);
+ //if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers
+ if (diff > (seg_nb+2) * in_data->seg_dur) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("UTC diff %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", diff, seg_nb));
+ while (diff > (seg_nb+2) * in_data->seg_dur) {
+ seg_nb++;
+ }
+ }
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("UTC diff %d - cumulated segment duration %d\n", diff, (seg_nb+1) * in_data->seg_dur));
+ t.segnum = seg_nb;
+ t.time = gf_net_get_utc();
+ //time_t t = time(NULL);
+ dc_message_queue_put(mq, &t, sizeof(t));
+ }
+ }
+
+ if (in_data->time_shift != -1) {
+ shift = 1000 * in_data->time_shift / in_data->seg_dur;
+ snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, audio_data_conf->filename, (seg_nb - shift));
+ dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete));
+ }
+
+ seg_nb++;
+
+ if (quit)
+ break;
+ }
+
+ // If system is not live,
+ // Send the duration of the video
+ if (in_data->mode == ON_DEMAND) {
+ if (thread_params->audio_conf_idx == 0) {
+ int dur = (seg_nb * audio_output_file.frame_size * frame_per_seg * 1000) / audio_data_conf->samplerate;
+ int dur_tot = (audio_output_file.codec_ctx->frame_number * audio_output_file.frame_size * 1000) / audio_data_conf->samplerate;
+ if (dur > dur_tot)
+ dur = dur_tot;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Duration: %d \n", dur));
+ dc_message_queue_put(mq, &dur, sizeof(dur));
+ }
+ }
+
+ dc_audio_muxer_free(&audio_output_file);
+
+ /* Close output audio file */
+ dc_audio_encoder_close(&audio_output_file);
+
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder is exiting...\n"));
+ return 0;
+}
+
+int dc_run_controler(CmdData *in_data)
+{
+ int ret = 0;
+ u32 video_cb_size = VIDEO_CB_DEFAULT_SIZE;
+ u32 i, j;
+
+ ThreadParam keyboard_th_params;
+ ThreadParam mpd_th_params;
+ ThreadParam delete_seg_th_params;
+ ThreadParam send_frag_th_params;
+
+ //Video parameters
+ VideoThreadParam vdecoder_th_params;
+ VideoThreadParam *vencoder_th_params = alloca(gf_list_count(in_data->video_lst) * sizeof(VideoThreadParam));
+ VideoInputData video_input_data;
+ VideoInputFile *video_input_file[MAX_SOURCE_NUMBER];
+ VideoScaledDataList video_scaled_data_list;
+ VideoThreadParam *vscaler_th_params = NULL;
+
+ //Audio parameters
+ AudioThreadParam adecoder_th_params;
+ AudioThreadParam *aencoder_th_params = alloca(gf_list_count(in_data->audio_lst) * sizeof(AudioThreadParam));
+ AudioInputData audio_input_data;
+ AudioInputFile audio_input_file;
+
+#ifndef DASHER
+ ThreadParam dasher_th_params;
+#endif
+
+#ifndef FRAGMENTER
+ ThreadParam fragmenter_th_params;
+#endif
+
+ MessageQueue mq;
+ MessageQueue delete_seg_mq;
+ MessageQueue send_frag_mq;
+
+ dc_register_libav();
+
+ for (i = 0; i < MAX_SOURCE_NUMBER; i++)
+ video_input_file[i] = gf_malloc(sizeof(VideoInputFile));
+
+ dc_message_queue_init(&mq);
+ dc_message_queue_init(&delete_seg_mq);
+ dc_message_queue_init(&send_frag_mq);
+
+ memset(&audio_input_data, 0, sizeof(AudioInputData));;
+ memset(&audio_input_file, 0, sizeof(AudioInputFile));
+ memset(&video_input_data, 0, sizeof(VideoInputData));
+
+
+ if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA)
+ video_cb_size = 1;
+
+ if (strcmp(in_data->video_data_conf.filename, "") != 0) {
+ dc_video_scaler_list_init(&video_scaled_data_list, in_data->video_lst);
+ vscaler_th_params = gf_malloc(video_scaled_data_list.size * sizeof(VideoThreadParam));
+
+ /* Open input video */
+ if (dc_video_decoder_open(video_input_file[0], &in_data->video_data_conf, in_data->mode, in_data->no_loop, video_scaled_data_list.size) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n"));
+ ret = -1;
+ goto exit;
+ }
+
+ if (dc_video_input_data_init(&video_input_data, /*video_input_file[0]->width, video_input_file[0]->height,
+ video_input_file[0]->pix_fmt,*/video_scaled_data_list.size, in_data->mode, MAX_SOURCE_NUMBER, video_cb_size) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize audio data.\n"));
+ ret = -1;
+ goto exit;
+ }
+
+ /* open other input videos for source switching */
+ for (i = 0; i < gf_list_count(in_data->vsrc); i++) {
+ VideoDataConf *video_data_conf = gf_list_get(in_data->vsrc, i);
+ if (dc_video_decoder_open(video_input_file[i + 1], video_data_conf, LIVE_MEDIA, 1, video_scaled_data_list.size) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n"));
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ 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);
+ }
+
+ for (i=0; ivsrc) + 1; j++) {
+ dc_video_scaler_data_set_prop(&video_input_data, video_scaled_data_list.video_scaled_data[i], j);
+ }
+ }
+
+ /* Initialize video decoder thread */
+ vdecoder_th_params.thread = gf_th_new("video_decoder_thread");
+
+ for (i=0; ivideo_lst); i++)
+ vencoder_th_params[i].thread = gf_th_new("video_encoder_thread");
+ }
+
+ /* When video and audio share the same source, open it once. This allow to read from unicast streams */
+ if (!strcmp(in_data->video_data_conf.filename, in_data->audio_data_conf.filename)) {
+ audio_input_file.av_fmt_ctx = video_input_file[0]->av_fmt_ctx;
+ video_input_file[0]->av_fmt_ctx_ref_cnt++;
+ audio_input_file.av_pkt_list = video_input_file[0]->av_pkt_list = gf_list_new();
+ audio_input_file.av_pkt_list_mutex = video_input_file[0]->av_pkt_list_mutex = gf_mx_new("Demux AVPackets List");
+ }
+
+ if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
+ /* Open input audio */
+ if (dc_audio_decoder_open(&audio_input_file, &in_data->audio_data_conf, in_data->mode, in_data->no_loop) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio.\n"));
+ ret = -1;
+ goto exit;
+ }
+
+ if (dc_audio_input_data_init(&audio_input_data, in_data->audio_data_conf.channels, in_data->audio_data_conf.samplerate, gf_list_count(in_data->audio_lst), in_data->mode) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize audio data.\n"));
+ ret = -1;
+ goto exit;
+ }
+
+ /* Initialize audio decoder thread */
+ adecoder_th_params.thread = gf_th_new("audio_decoder_thread");
+
+ /* Initialize audio encoder threads */
+ for (i = 0; i < gf_list_count(in_data->audio_lst); i++)
+ aencoder_th_params[i].thread = gf_th_new("video_encoder_thread");
+ }
+
+ /******** Keyboard controler Thread ********/
+
+ /* Initialize keyboard controller thread */
+ keyboard_th_params.thread = gf_th_new("keyboard_thread");
+
+ /* Create keyboard controller thread */
+ keyboard_th_params.in_data = in_data;
+ if (gf_th_run(keyboard_th_params.thread, keyboard_thread, (void *)&keyboard_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for keyboard_thread.\n"));
+ }
+
+ /********************************************/
+
+ //Communication between decoder and audio encoder
+ for (i = 0; i < gf_list_count(in_data->audio_lst); i++) {
+ AudioDataConf *tmadata = gf_list_get(in_data->audio_lst, i);
+ tmadata->channels = in_data->audio_data_conf.channels;
+ tmadata->samplerate = in_data->audio_data_conf.samplerate;
+ }
+
+ //Communication between decoder and video encoder
+ for (i = 0; i < gf_list_count(in_data->video_lst); i++) {
+ VideoDataConf *tmvdata = gf_list_get(in_data->video_lst, i);
+ tmvdata->framerate = in_data->video_data_conf.framerate;
+ if (in_data->use_source_timing) {
+ tmvdata->time_base = in_data->video_data_conf.time_base;
+ }
+ }
+
+ /******** MPD Thread ********/
+
+ /* Initialize MPD generator thread */
+ mpd_th_params.thread = gf_th_new("mpd_thread");
+
+ /* Create MPD generator thread */
+ mpd_th_params.in_data = in_data;
+ mpd_th_params.mq = &mq;
+ if (gf_th_run(mpd_th_params.thread, mpd_thread, (void *)&mpd_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for mpd_thread.\n"));
+ }
+
+ /****************************/
+
+ if (strcmp(in_data->video_data_conf.filename, "") != 0) {
+ /* Create video encoder threads */
+ for (i=0; ivideo_lst); i++) {
+ VideoDataConf * video_data_conf = gf_list_get(in_data->video_lst, i);
+
+ vencoder_th_params[i].in_data = in_data;
+ vencoder_th_params[i].video_conf_idx = i;
+ vencoder_th_params[i].video_scaled_data = dc_video_scaler_get_data(&video_scaled_data_list, video_data_conf->width, video_data_conf->height);
+
+ vencoder_th_params[i].mq = &mq;
+ vencoder_th_params[i].delete_seg_mq = &delete_seg_mq;
+ vencoder_th_params[i].send_seg_mq = &send_frag_mq;
+
+ if (gf_th_run(vencoder_th_params[i].thread, video_encoder_thread, (void*)&vencoder_th_params[i]) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_encoder_thread.\n"));
+ }
+ }
+
+ /* Create video scaler threads */
+ for (i=0; iaudio_data_conf.filename, "") != 0) {
+ /* Create audio encoder threads */
+ for (i = 0; i < gf_list_count(in_data->audio_lst); i++) {
+ aencoder_th_params[i].in_data = in_data;
+ aencoder_th_params[i].audio_conf_idx = i;
+ aencoder_th_params[i].audio_input_data = &audio_input_data;
+
+ aencoder_th_params[i].mq = &mq;
+ aencoder_th_params[i].delete_seg_mq = &delete_seg_mq;
+ aencoder_th_params[i].send_seg_mq = &send_frag_mq;
+
+ if (gf_th_run(aencoder_th_params[i].thread, audio_encoder_thread, (void *) &aencoder_th_params[i]) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_encoder_thread.\n"));
+ }
+ }
+ }
+
+ if (strcmp(in_data->video_data_conf.filename, "") != 0) {
+ /* Create video decoder thread */
+ vdecoder_th_params.in_data = in_data;
+ vdecoder_th_params.video_input_data = &video_input_data;
+ vdecoder_th_params.video_input_file = video_input_file;
+ if (gf_th_run(vdecoder_th_params.thread, video_decoder_thread, (void *) &vdecoder_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_decoder_thread.\n"));
+ }
+ }
+
+ if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
+ /* Create audio decoder thread */
+ adecoder_th_params.in_data = in_data;
+ adecoder_th_params.audio_input_data = &audio_input_data;
+ adecoder_th_params.audio_input_file = &audio_input_file;
+ if (gf_th_run(adecoder_th_params.thread, audio_decoder_thread, (void *) &adecoder_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_decoder_thread.\n"));
+ }
+ }
+
+ if (in_data->time_shift != -1) {
+ /* Initialize delete segment thread */
+ delete_seg_th_params.thread = gf_th_new("delete_seg_thread");
+ delete_seg_th_params.in_data = in_data;
+ delete_seg_th_params.mq = &delete_seg_mq;
+ if (gf_th_run(delete_seg_th_params.thread, delete_seg_thread, (void *) &delete_seg_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for delete_seg_thread.\n"));
+ }
+ }
+
+ if (in_data->send_message == 1) {
+ /* Initialize delete segment thread */
+ send_frag_th_params.thread = gf_th_new("send_frag_event_thread");
+ send_frag_th_params.in_data = in_data;
+ send_frag_th_params.mq = &send_frag_mq;
+ if (gf_th_run(send_frag_th_params.thread, send_frag_event, (void *) &send_frag_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for send_frag_event_thread.\n"));
+ }
+ }
+
+#ifndef FRAGMENTER
+ if (strcmp(in_data->mpd_filename, "") != 0) {
+ /* Initialize keyboard controller thread */
+ fragmenter_th_params.thread = gf_th_new("fragmenter_thread");
+ fragmenter_th_params.in_data = in_data;
+ fragmenter_th_params.mq = &mq;
+ if (gf_th_run(fragmenter_th_params.thread, fragmenter_thread, (void *) &fragmenter_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for fragmenter_thread.\n"));
+ }
+ }
+#endif
+
+#ifndef DASHER
+ if (in_data->live && strcmp(in_data->mpd_filename, "") != 0) {
+ /* Initialize keyboard controller thread */
+ dasher_th_params.thread = gf_th_new("dasher_thread");
+ dasher_th_params.in_data = in_data;
+ if (gf_th_run(dasher_th_params.thread, dasher_thread, (void *) &dasher_th_params) != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for dasher_thread.\n"));
+ }
+ }
+#endif
+
+ fprintf(stdout, "Press q or Q to exit...\n");
+
+ if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
+ /* Wait for and destroy audio decoder threads */
+ gf_th_stop(adecoder_th_params.thread);
+ gf_th_del(adecoder_th_params.thread);
+ }
+
+ if (strcmp(in_data->video_data_conf.filename, "") != 0) {
+ /* Wait for and destroy video decoder threads */
+ gf_th_stop(vdecoder_th_params.thread);
+ gf_th_del(vdecoder_th_params.thread);
+ }
+
+ if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
+ /* Wait for and destroy audio encoder threads */
+ for (i = 0; i < gf_list_count(in_data->audio_lst); i++) {
+ gf_th_stop(aencoder_th_params[i].thread);
+ gf_th_del(aencoder_th_params[i].thread);
+ }
+ }
+
+ if (strcmp(in_data->video_data_conf.filename, "") != 0) {
+ /* Wait for and destroy video encoder threads */
+ for (i=0; ivideo_lst); i++) {
+ gf_th_stop(vencoder_th_params[i].thread);
+ gf_th_del(vencoder_th_params[i].thread);
+ }
+
+ /* Wait for and destroy video scaler threads */
+ for (i=0; ilive && strcmp(in_data->mpd_filename, "") != 0) {
+ /* Wait for and destroy dasher thread */
+ gf_th_stop(dasher_th_params.thread);
+ gf_th_del(dasher_th_params.thread);
+ }
+#endif
+
+ keyboard_th_params.in_data->exit_signal = 1;
+
+#ifndef FRAGMENTER
+ dc_message_queue_flush(&mq);
+
+ if (strcmp(in_data->mpd_filename, "") != 0) {
+ /* Wait for and destroy dasher thread */
+ gf_th_stop(fragmenter_th_params.thread);
+ gf_th_del(fragmenter_th_params.thread);
+ }
+#endif
+
+ /********** Keyboard thread ***********/
+
+ /* Wait for and destroy keyboard controler thread */
+ gf_th_stop(keyboard_th_params.thread);
+ gf_th_del(keyboard_th_params.thread);
+
+ /**************************************/
+
+ /********** MPD generator thread ***********/
+
+ /* Wait for and destroy MPD generator thread */
+ gf_th_stop(mpd_th_params.thread);
+ gf_th_del(mpd_th_params.thread);
+
+ /**************************************/
+
+ if (in_data->time_shift != -1) {
+ // dc_message_queue_flush(&delete_seg_mq);
+ /* Wait for and destroy delete segment thread */
+ gf_th_stop(delete_seg_th_params.thread);
+ gf_th_del(delete_seg_th_params.thread);
+ }
+
+ if (in_data->send_message == 1) {
+ /* Wait for and destroy delete segment thread */
+ gf_th_stop(send_frag_th_params.thread);
+ gf_th_del(send_frag_th_params.thread);
+ }
+
+#ifndef DASHER
+ if (!in_data->live && strcmp(in_data->mpd_filename, "") != 0) {
+ dasher_th_params.in_data = in_data;
+ dasher_thread((void*) &dasher_th_params);
+ }
+#endif
+
+exit:
+ if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
+ /* Destroy audio input data */
+ dc_audio_input_data_destroy(&audio_input_data);
+ /* Close input audio */
+ dc_audio_decoder_close(&audio_input_file);
+ }
+
+ if (strcmp(in_data->video_data_conf.filename, "") != 0) {
+ /* Destroy video input data */
+ dc_video_input_data_destroy(&video_input_data);
+
+ for (i = 0; i < gf_list_count(in_data->vsrc); i++) {
+ /* Close input video */
+ dc_video_decoder_close(video_input_file[i]);
+ }
+
+ for (i=0; i
+#include
+#include
+
+#include "register.h"
+#include "video_decoder.h"
+#include "video_encoder.h"
+#include "audio_decoder.h"
+#include "audio_encoder.h"
+#include "cmd_data.h"
+#include "message_queue.h"
+
+
+/* General thread parameters */
+typedef struct {
+ /* command data */
+ CmdData *in_data;
+ /* handle to thread */
+ GF_Thread *thread;
+
+ MessageQueue *mq;
+} ThreadParam;
+
+/* Video thread parameters */
+typedef struct {
+ /* command data */
+ CmdData *in_data;
+ /* The index in the configuration file to a video entry corresponding to the thread. */
+ int video_conf_idx;
+ /* Video input data structure corresponding to the thread. (This data is shared between video decoder and video scaler) */
+ VideoInputData *video_input_data;
+ /* Video scaled data structure corresponding to the thread. (This data is shared between video scaler and video encoder) */
+ VideoScaledData *video_scaled_data;
+ /* Video input file structure corresponding to the thread */
+ VideoInputFile **video_input_file;
+ /* handle to the thread */
+ GF_Thread *thread;
+
+ MessageQueue *mq;
+ MessageQueue *delete_seg_mq;
+ MessageQueue *send_seg_mq;
+} VideoThreadParam;
+
+/* Audio thread parameters */
+typedef struct {
+ /* command data */
+ CmdData *in_data;
+ /* The index in the configuration file to an audio entry corresponding to the thread */
+ int audio_conf_idx;
+ /* Audio input data (This data is shared between audio decoder and audio encoder */
+ AudioInputData *audio_input_data;
+ /* Audio input file structure */
+ AudioInputFile *audio_input_file;
+ /* handle to the thread */
+ GF_Thread *thread;
+
+ MessageQueue *mq;
+ MessageQueue *delete_seg_mq;
+ MessageQueue *send_seg_mq;
+} AudioThreadParam;
+
+/*
+ * Run controler runs all decoder, scalers, and encoders
+ * of audio and video
+ *
+ * @param cmd_data [in] command data
+ *
+ * @return 0 on success, -1 on failure
+ */
+int dc_run_controler(CmdData *);
+
+#endif /* CONTROLER_H_ */
diff --git a/applications/dashcast/dashcast.c b/applications/dashcast/dashcast.c
new file mode 100644
index 0000000..ef6c2ab
--- /dev/null
+++ b/applications/dashcast/dashcast.c
@@ -0,0 +1,49 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "cmd_data.h"
+#include "controler.h"
+
+
+int main(int argc, char **argv)
+{
+ s32 res;
+ CmdData cmd_data;
+
+ /* Read command line (performs init) and parse input */
+ res = dc_parse_command(argc, argv, &cmd_data);
+ if (res < 0) {
+ if (res==-1) dc_cmd_data_destroy(&cmd_data);
+ return -1;
+ }
+
+ res = dc_run_controler(&cmd_data);
+
+ /* Destroy command data */
+ dc_cmd_data_destroy(&cmd_data);
+
+ return res;
+}
+
diff --git a/applications/dashcast/libav_compat.h b/applications/dashcast/libav_compat.h
new file mode 100644
index 0000000..ef691c9
--- /dev/null
+++ b/applications/dashcast/libav_compat.h
@@ -0,0 +1,54 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Romain Bouqueau
+ * Copyright (c) Telecom ParisTech 2000-2013 - Romain Bouqueau 2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef LIBAV_COMPAT_H_
+#define LIBAV_COMPAT_H_
+
+#ifndef URL_WRONLY
+#define URL_WRONLY AVIO_FLAG_WRITE
+#endif
+
+#ifndef CODEC_ID_RAWVIDEO
+
+#if (LIBAVCODEC_VERSION_MAJOR <= 53) && (LIBAVCODEC_VERSION_MINOR < 30)
+#define CODEC_ID_RAWVIDEO AV_CODEC_ID_RAWVIDEO
+#define CODEC_ID_H264 AV_CODEC_ID_H264
+#endif
+#endif
+
+#ifndef AV_CH_LAYOUT_STEREO
+#define AV_CH_FRONT_LEFT 0x00000001
+#define AV_CH_FRONT_RIGHT 0x00000002
+#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
+#endif
+
+#if (LIBAVCODEC_VERSION_MAJOR<=55) && (LIBAVCODEC_VERSION_MINOR<=40)
+#define FF_ALLOC_FRAME avcodec_alloc_frame
+#else
+#define FF_ALLOC_FRAME av_frame_alloc
+#endif
+
+#endif
+
diff --git a/applications/dashcast/message_queue.c b/applications/dashcast/message_queue.c
new file mode 100644
index 0000000..6f6cb68
--- /dev/null
+++ b/applications/dashcast/message_queue.c
@@ -0,0 +1,120 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "message_queue.h"
+
+
+void dc_message_queue_init(MessageQueue *mq)
+{
+ memset(mq, 0, sizeof(MessageQueue));
+ mq->first_node = NULL;
+ mq->last_node = NULL;
+ mq->nb_nodes = 0;
+ mq->mutex = gf_mx_new("MessageQueue Mutex");
+ mq->sem = gf_sema_new(1000, 0); //TODO: why 1000 (at other places too)
+}
+
+void dc_message_queue_put(MessageQueue *mq, void *data, u32 size)
+{
+ MessageQueueNode *mqn = gf_malloc(sizeof(MessageQueueNode));
+ mqn->data = gf_malloc(size);
+ memcpy(mqn->data, data, size);
+ mqn->size = size;
+ mqn->next = NULL;
+
+ gf_mx_p(mq->mutex);
+
+ if (!mq->last_node)
+ mq->first_node = mqn;
+ else
+ mq->last_node->next = mqn;
+
+ mq->last_node = mqn;
+ mq->nb_nodes++;
+
+ gf_sema_notify(mq->sem, 1);
+ gf_mx_v(mq->mutex);
+}
+
+int dc_message_queue_get(MessageQueue *mq, void * data)
+{
+ int ret = 0;
+ MessageQueueNode *mqn;
+
+ gf_mx_p(mq->mutex);
+
+ mqn = mq->first_node;
+ if (!mqn) {
+ gf_mx_v(mq->mutex);
+ ret = gf_sema_wait_for(mq->sem, 10000);
+ gf_mx_p(mq->mutex);
+
+ mqn = mq->first_node;
+
+ if (!ret || !mqn) {
+ gf_mx_v(mq->mutex);
+ return -1;
+ }
+ }
+ if (mqn) {
+ mq->first_node = mqn->next;
+ if (!mq->first_node)
+ mq->last_node = NULL;
+ mq->nb_nodes--;
+ memcpy(data, mqn->data, mqn->size);
+ ret = (int)mqn->size;
+ gf_free(mqn->data);
+ gf_free(mqn);
+ }
+
+ gf_mx_v(mq->mutex);
+
+ return ret;
+}
+
+void dc_message_queue_flush(MessageQueue *mq)
+{
+ MessageQueueNode *mqn, *mqn1;
+
+ gf_mx_p(mq->mutex);
+
+ for (mqn = mq->first_node; mqn != NULL; mqn = mqn1) {
+ mqn1 = mqn->next;
+ gf_free(mqn);
+ }
+ mq->last_node = NULL;
+ mq->first_node = NULL;
+ mq->nb_nodes = 0;
+
+ gf_sema_notify(mq->sem, 1);
+ gf_mx_v(mq->mutex);
+}
+
+void dc_message_queue_free(MessageQueue *mq)
+{
+ dc_message_queue_flush(mq);
+ gf_mx_del(mq->mutex);
+ gf_sema_del(mq->sem);
+}
diff --git a/applications/dashcast/message_queue.h b/applications/dashcast/message_queue.h
new file mode 100644
index 0000000..7e402c1
--- /dev/null
+++ b/applications/dashcast/message_queue.h
@@ -0,0 +1,58 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef MESSAGE_QUEUE_H_
+#define MESSAGE_QUEUE_H_
+
+#include
+#include
+#include
+
+
+typedef struct MessageQueueNode {
+ void *data;
+ u32 size;
+ struct MessageQueueNode *next;
+} MessageQueueNode;
+
+typedef struct MessageQueue {
+ MessageQueueNode *last_node;
+ MessageQueueNode *first_node;
+ int nb_nodes;
+ GF_Semaphore *sem;
+ GF_Mutex *mutex;
+} MessageQueue;
+
+void dc_message_queue_init(MessageQueue *mq);
+
+void dc_message_queue_put(MessageQueue *mq, void *data, u32 size);
+
+int dc_message_queue_get(MessageQueue *mq, void *data);
+
+void dc_message_queue_flush(MessageQueue *mq);
+
+void dc_message_queue_free(MessageQueue *mq);
+
+#endif /* MESSAGE_QUEUE_H_ */
diff --git a/applications/dashcast/register.c b/applications/dashcast/register.c
new file mode 100644
index 0000000..c8ad3d9
--- /dev/null
+++ b/applications/dashcast/register.c
@@ -0,0 +1,85 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "register.h"
+
+
+static GF_List *av_mutex = NULL;
+
+int lock_call_back(void ** mutex, enum AVLockOp op)
+{
+ switch (op) {
+ case AV_LOCK_CREATE:
+ {
+ static int i = 0;
+ char mxName[64];
+ snprintf(mxName, 64, "AVLIB callback mutex %d", i++);
+ *mutex = gf_mx_new(mxName);
+ gf_list_add(av_mutex, *mutex);
+ break;
+ }
+ case AV_LOCK_OBTAIN:
+ gf_mx_p(*mutex);
+ break;
+ case AV_LOCK_RELEASE:
+ gf_mx_v(*mutex);
+ break;
+ case AV_LOCK_DESTROY:
+ gf_list_del_item(av_mutex, *mutex);
+ gf_mx_del(*mutex);
+ *mutex = NULL;
+ break;
+ }
+
+ return 0;
+}
+
+void dc_register_libav()
+{
+ av_mutex = gf_list_new();
+
+ av_register_all();
+ avcodec_register_all();
+ avdevice_register_all();
+ avformat_network_init();
+
+ av_lockmgr_register(&lock_call_back);
+}
+
+void dc_unregister_libav()
+{
+ av_lockmgr_register(NULL);
+
+ if (av_mutex) {
+ while (gf_list_count(av_mutex)) {
+ GF_Mutex *mx = gf_list_last(av_mutex);
+ gf_list_rem_last(av_mutex);
+ gf_mx_del(mx);
+ }
+ gf_list_del(av_mutex);
+ av_mutex = NULL;
+ }
+}
+
diff --git a/applications/dashcast/register.h b/applications/dashcast/register.h
new file mode 100644
index 0000000..a885a65
--- /dev/null
+++ b/applications/dashcast/register.h
@@ -0,0 +1,50 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef REGISTER_H_
+#define REGISTER_H_
+
+//#include
+#include "../../modules/ffmpeg_in/ffmpeg_in.h"
+#include "libavcodec/avcodec.h"
+#include "libavdevice/avdevice.h"
+#include "libavformat/avformat.h"
+
+#include
+
+
+/*
+ * Register all codecs and define
+ * the lock manager on top of avlib
+ */
+void dc_register_libav();
+void dc_unregister_libav();
+
+/*
+ * performs libav* cleanup
+ */
+void dc_unregister_libav();
+
+#endif /* REGISTER_H_ */
diff --git a/applications/dashcast/task.c b/applications/dashcast/task.c
new file mode 100644
index 0000000..ff2499c
--- /dev/null
+++ b/applications/dashcast/task.c
@@ -0,0 +1,69 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "task.h"
+
+
+void dc_task_init(TaskList *list)
+{
+ list->tasks = gf_list_new();
+ list->size = 0;
+}
+
+void dc_task_destroy(TaskList *list)
+{
+ gf_list_del(list->tasks);
+}
+
+void dc_task_add(TaskList *list, int source_number, char *id_name, time_t start, time_t end)
+{
+ Task *task = gf_malloc(sizeof(Task));
+ task->source_number = source_number;
+ strncpy(task->id, id_name, MAX_ID_SIZE);
+ task->start_time_t = start;
+ task->end_time_t = end;
+ gf_list_add(list->tasks, task);
+ list->size++;
+}
+
+int dc_task_get_current(TaskList *list, Task *task)
+{
+ u32 i;
+ time_t now_time = time(NULL);
+ for (i = 0; isize; i++) {
+ Task *cur_task = gf_list_get(list->tasks, i);
+ if (now_time > cur_task->start_time_t && now_time < cur_task->end_time_t) {
+ //strncpy(task->id, cur_task->id, MAX_ID_SIZE);
+ //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;
+ return 0;
+ }
+ }
+
+ task->source_number = 0;
+ return -1;
+}
+
diff --git a/applications/dashcast/task.h b/applications/dashcast/task.h
new file mode 100644
index 0000000..8e4ed30
--- /dev/null
+++ b/applications/dashcast/task.h
@@ -0,0 +1,69 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef TASK_H_
+#define TASK_H_
+
+#define MAX_ID_SIZE 512
+
+#include
+#include
+#include
+
+
+typedef struct {
+ char id[MAX_ID_SIZE];
+ int source_number;
+ time_t start_time_t;
+ time_t end_time_t;
+} Task;
+
+typedef struct {
+ GF_List *tasks;
+ u32 size;
+} TaskList;
+
+/**
+ * initialize a list of task
+ */
+void dc_task_init(TaskList *list);
+
+/**
+ * destroy the list of task
+ */
+void dc_task_destroy(TaskList *list);
+
+/**
+ * audio_input_data a task to the list
+ */
+void dc_task_add(TaskList *list, int source_number, char *id_name, time_t start, time_t end);
+
+/**
+ * give the task which corresponds to the time=NOW
+ * note: in the case of infering tasks, the first one is picked
+ */
+int dc_task_get_current(TaskList *list, Task *task);
+
+#endif /* TASK_H_ */
diff --git a/applications/dashcast/video_data.c b/applications/dashcast/video_data.c
new file mode 100644
index 0000000..97b37df
--- /dev/null
+++ b/applications/dashcast/video_data.c
@@ -0,0 +1,92 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "video_data.h"
+
+
+void dc_video_data_set_default(VideoDataConf *video_data_conf)
+{
+ memset(video_data_conf, 0, sizeof(VideoDataConf));
+ video_data_conf->bitrate = -1;
+ video_data_conf->framerate = -1;
+ video_data_conf->crop_x = 0;
+ video_data_conf->crop_y = 0;
+ video_data_conf->height = -1;
+ video_data_conf->width = -1;
+}
+
+void dc_video_input_data_end_signal(VideoInputData *video_input_data)
+{
+ dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf);
+ dc_producer_end_signal_previous(&video_input_data->producer, &video_input_data->circular_buf);
+}
+
+int dc_video_input_data_init(VideoInputData *video_input_data, /*int width, int height, int pix_fmt*/ int num_consumers, int mode, int max_source, int video_cb_size)
+{
+ int i;
+
+ dc_producer_init(&video_input_data->producer, video_cb_size, "video decoder");
+
+ //video_input_data->width = width;
+ //video_input_data->height = height;
+ //video_input_data->pix_fmt = pix_fmt;
+
+ video_input_data->vprop = gf_malloc(max_source * sizeof(VideoInputProp));
+
+ dc_circular_buffer_create(&video_input_data->circular_buf, video_cb_size, mode, num_consumers);
+
+ for (i=0; icircular_buf.list[i].data = (void *) video_data_node;
+ video_data_node->vframe = FF_ALLOC_FRAME();
+ }
+
+ 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)
+{
+ 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;
+}
+
+void dc_video_input_data_destroy(VideoInputData *video_input_data)
+{
+ int i;
+ for (i=0; i<(int) video_input_data->circular_buf.size; i++) {
+ if (video_input_data->circular_buf.list) {
+ VideoDataNode *video_data_node = video_input_data->circular_buf.list[i].data;
+ av_free(video_data_node->vframe);
+ gf_free(video_data_node);
+ }
+ }
+
+ dc_circular_buffer_destroy(&video_input_data->circular_buf);
+ gf_free(video_input_data->vprop);
+}
diff --git a/applications/dashcast/video_data.h b/applications/dashcast/video_data.h
new file mode 100644
index 0000000..a4a28de
--- /dev/null
+++ b/applications/dashcast/video_data.h
@@ -0,0 +1,164 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef VIDEO_DATA_H_
+#define VIDEO_DATA_H_
+
+#include "../../modules/ffmpeg_in/ffmpeg_in.h"
+#include "libavcodec/avcodec.h"
+#include "libswscale/swscale.h"
+#include "libav_compat.h"
+
+#include "circular_buffer.h"
+
+#include
+
+//anything different is broken in dash cast (random frame inversions at encoding time ...)
+#define VIDEO_CB_DEFAULT_SIZE 1
+
+
+/*
+ * This structure corresponds to an
+ * entry of video configuration in the
+ * configuration file.
+ */
+typedef struct {
+ /* video file name */
+ char filename[GF_MAX_PATH];
+ /* video format */
+ char format[GF_MAX_PATH];
+ /* video format */
+ char pixel_format[GF_MAX_PATH];
+ /* v4l2 format */
+ char v4l2f[GF_MAX_PATH];
+ /* left crop */
+ int crop_x;
+ /* top crop */
+ int crop_y;
+ /* video final width */
+ int width;
+ /* video final height */
+ int height;
+ /* video bitrate */
+ int bitrate;
+ /* video frame rate */
+ int framerate;
+ /* video codec */
+ char codec[GF_MAX_PATH];
+ /* custom parameter to be passed directly to the encoder - free it once you're done */
+ char *custom;
+
+ /* used for source switching */
+ char source_id[GF_MAX_PATH];
+ time_t start_time;
+ time_t end_time;
+
+ //copy over from source file
+ AVRational time_base;
+ u64 frame_duration;
+} VideoDataConf;
+
+typedef struct {
+ /* Width, height and pixel format of the input video. */
+ int width;
+ int height;
+ int crop_x, crop_y;
+ int pix_fmt;
+} VideoInputProp;
+
+/*
+ * VideoInputData is designed to keep the data
+ * of input video in a circular buffer.
+ * The circular buffer has its own mechanism for synchronization.
+ */
+typedef struct {
+ /* The circular buffer of the video frames after decoding. */
+ CircularBuffer circular_buf;
+ /* The user of circular buffer has an index to it, which is in this variable. */
+ Producer producer;
+
+ VideoInputProp *vprop;
+
+ /* Width, height and pixel format of the input video */
+ //int width;
+ //int height;
+ //int pix_fmt;
+ u64 frame_duration;
+} VideoInputData;
+
+
+/*
+ * Each node in a circular buffer is a pointer.
+ * To use the circular buffer for video frame we must
+ * define the node. VideoDataNode simply contains
+ * an AVFrame.
+ */
+typedef struct {
+ AVFrame * vframe;
+ int source_number;
+ uint8_t nb_raw_frames_ref;
+ AVPacket raw_packet;
+} VideoDataNode;
+
+void dc_video_data_set_default(VideoDataConf *video_data_conf);
+
+/*
+ * Initialize a VideoInputData.
+ *
+ * @param video_input_data [out] is the structure to be initialize.
+ * @param width [in] input video width
+ * @param height [in] input video height
+ * @param pixfmt [in] input video pixel format
+ * @param num_consumers [in] contains information on the number of users of circular buffer;
+ * which means the number of video encoders.
+ * @param live [in] indicates the system is live
+ *
+ * @return 0 on success, -1 on failure.
+ *
+ * @note Must use dc_video_data_destroy to free memory.
+ */
+int dc_video_input_data_init(VideoInputData *video_input_data,/* int width, int height, int pix_fmt,*/ int num_consumers, int mode, int num_producers, int video_cb_size);
+
+/*
+ * 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);
+
+/*
+ * Destroy a VideoInputData.
+ *
+ * @param video_input_data [in] the structure to be destroyed.
+ */
+void dc_video_input_data_destroy(VideoInputData *video_input_data);
+
+/*
+ * Signal to all the users of the circular buffer in the VideoInputData
+ * which the current node is the last node to consume.
+ *
+ * @param video_input_data [in] the structure to be signaled on.
+ */
+void dc_video_input_data_end_signal(VideoInputData *video_input_data);
+
+#endif /* VIDEO_DATA_H_ */
diff --git a/applications/dashcast/video_decoder.c b/applications/dashcast/video_decoder.c
new file mode 100644
index 0000000..d2f878b
--- /dev/null
+++ b/applications/dashcast/video_decoder.c
@@ -0,0 +1,378 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "video_decoder.h"
+#include
+#include
+
+
+//#define DASHCAST_DEBUG_TIME_
+
+
+int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video_data_conf, int mode, int no_loop, int nb_consumers)
+{
+ s32 ret;
+ u32 i;
+ s32 open_res;
+ AVInputFormat *in_fmt = NULL;
+ AVDictionary *options = NULL;
+ AVCodecContext *codec_ctx;
+ AVCodec *codec;
+
+ memset(video_input_file, 0, sizeof(VideoInputFile));
+
+ if (video_data_conf->width > 0 && video_data_conf->height > 0) {
+ char vres[16];
+ snprintf(vres, sizeof(vres), "%dx%d", video_data_conf->width, video_data_conf->height);
+ ret = av_dict_set(&options, "video_size", vres, 0);
+ if (ret < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video size %s.\n", vres));
+ return -1;
+ }
+ }
+
+ if (video_data_conf->framerate > 0) {
+ char vfr[16];
+ snprintf(vfr, sizeof(vfr), "%d", video_data_conf->framerate);
+ ret = av_dict_set(&options, "framerate", vfr, 0);
+ if (ret < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video framerate %s.\n", vfr));
+ return -1;
+ }
+ }
+
+ if (strlen(video_data_conf->pixel_format)) {
+ ret = av_dict_set(&options, "pixel_format", video_data_conf->pixel_format, 0);
+ if (ret < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set pixel format %s.\n", video_data_conf->pixel_format));
+ return -1;
+ }
+ }
+
+#ifndef WIN32
+ if (strcmp(video_data_conf->v4l2f, "") != 0) {
+ ret = av_dict_set(&options, "input_format", video_data_conf->v4l2f, 0);
+ if (ret < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set input format %s.\n", video_data_conf->v4l2f));
+ return -1;
+ }
+ }
+#endif
+
+ if (video_data_conf->format && strcmp(video_data_conf->format, "") != 0) {
+ in_fmt = av_find_input_format(video_data_conf->format);
+ if (in_fmt == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", video_data_conf->format));
+ return -1;
+ }
+ }
+
+ video_input_file->av_fmt_ctx = NULL;
+
+ /* Open video */
+ open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL);
+ if ( (open_res < 0) && !stricmp(video_data_conf->filename, "screen-capture-recorder") ) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Buggy screen capture input (open failed with code %d), retrying without specifying resolution\n", open_res));
+ av_dict_set(&options, "video_size", NULL, 0);
+ open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL);
+ }
+
+ if ( (open_res < 0) && options) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error %d opening input - retrying without options\n", open_res));
+ av_dict_free(&options);
+ open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, NULL);
+ }
+
+ if (open_res < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file %s\n", video_data_conf->filename));
+ return -1;
+ }
+
+ /* Retrieve stream information */
+ if (avformat_find_stream_info(video_input_file->av_fmt_ctx, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find stream information\n"));
+ return -1;
+ }
+
+ av_dump_format(video_input_file->av_fmt_ctx, 0, video_data_conf->filename, 0);
+
+ /* Find the first video stream */
+ video_input_file->vstream_idx = -1;
+ for (i = 0; i < video_input_file->av_fmt_ctx->nb_streams; i++) {
+ if (video_input_file->av_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ video_input_file->vstream_idx = i;
+ break;
+ }
+ }
+ if (video_input_file->vstream_idx == -1) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find a video stream\n"));
+ return -1;
+ }
+
+ /* Get a pointer to the codec context for the video stream */
+ codec_ctx = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->codec;
+
+ /* Find the decoder for the video stream */
+ codec = avcodec_find_decoder(codec_ctx->codec_id);
+ if (codec == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Codec is not supported.\n"));
+ if (!video_input_file->av_fmt_ctx_ref_cnt)
+ avformat_close_input(&video_input_file->av_fmt_ctx);
+ return -1;
+ }
+
+ /* Open codec */
+ if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open codec.\n"));
+ if (!video_input_file->av_fmt_ctx_ref_cnt)
+ avformat_close_input(&video_input_file->av_fmt_ctx);
+ return -1;
+ }
+
+ video_input_file->width = codec_ctx->width;
+ video_input_file->height = codec_ctx->height;
+ video_input_file->pix_fmt = codec_ctx->pix_fmt;
+ if (video_data_conf->framerate >= 0) {
+ 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) {
+ const int num = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.num;
+ const int den = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.den == 0 ? 1 : video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.den;
+ video_data_conf->framerate = num / den;
+ if (video_data_conf->framerate / 1000 != 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Framerate %d was divided by 1000: %d\n", video_data_conf->framerate, video_data_conf->framerate/1000));
+ video_data_conf->framerate = video_data_conf->framerate / 1000;
+ }
+
+ if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) {
+ video_data_conf->framerate = num / den;
+ if (video_data_conf->framerate / 1000 != 0) {
+ video_data_conf->framerate = video_data_conf->framerate / 1000;
+ }
+ }
+ }
+
+ if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Invalid input framerate.\n"));
+ return -1;
+ }
+
+ video_data_conf->time_base = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->time_base;
+ video_input_file->mode = mode;
+ video_input_file->no_loop = no_loop;
+ video_input_file->nb_consumers = nb_consumers;
+ return 0;
+}
+
+int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *video_input_data, int source_number, int use_source_timing, int is_live_capture, const int *exit_signal_addr)
+{
+#ifdef DASHCAST_DEBUG_TIME_
+ struct timeval start, end;
+ long elapsed_time;
+#endif
+ AVPacket packet;
+ int ret, got_frame, already_locked = 0;
+ AVCodecContext *codec_ctx;
+ VideoDataNode *video_data_node;
+
+ /* Get a pointer to the codec context for the video stream */
+ codec_ctx = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->codec;
+
+ /* Read frames */
+ while (1) {
+#ifdef DASHCAST_DEBUG_TIME_
+ gettimeofday(&start, NULL);
+#endif
+ memset(&packet, 0, sizeof(AVPacket));
+ ret = av_read_frame(video_input_file->av_fmt_ctx, &packet);
+#ifdef DASHCAST_DEBUG_TIME_
+ gettimeofday(&end, NULL);
+ elapsed_time = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
+ fprintf(stdout, "fps: %f\n", 1000000.0/elapsed_time);
+#endif
+
+ /* If we demux for the audio thread, send the packet to the audio */
+ if (video_input_file->av_fmt_ctx_ref_cnt && ((packet.stream_index != video_input_file->vstream_idx) || (ret == AVERROR_EOF))) {
+ AVPacket *packet_copy = NULL;
+ if (ret != AVERROR_EOF) {
+ GF_SAFEALLOC(packet_copy, AVPacket);
+ memcpy(packet_copy, &packet, sizeof(AVPacket));
+ }
+
+ assert(video_input_file->av_pkt_list);
+ gf_mx_p(video_input_file->av_pkt_list_mutex);
+ gf_list_add(video_input_file->av_pkt_list, packet_copy);
+ gf_mx_v(video_input_file->av_pkt_list_mutex);
+
+ if (ret != AVERROR_EOF) {
+ continue;
+ }
+ }
+
+ if (ret == AVERROR_EOF) {
+ if (video_input_file->mode == LIVE_MEDIA && video_input_file->no_loop == 0) {
+ av_seek_frame(video_input_file->av_fmt_ctx, video_input_file->vstream_idx, 0, 0);
+ av_free_packet(&packet);
+ continue;
+ }
+
+ dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf);
+ dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf);
+ video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf);
+ video_data_node->source_number = source_number;
+ /* Flush decoder */
+ memset(&packet, 0, sizeof(AVPacket));
+ avcodec_get_frame_defaults(video_data_node->vframe);
+ avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet);
+ if (got_frame) {
+ dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf);
+ return 0;
+ }
+
+ dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf);
+ dc_producer_unlock(&video_input_data->producer, &video_input_data->circular_buf);
+ return -2;
+ }
+ else if (ret < 0)
+ {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot read video frame.\n"));
+ continue;
+ }
+
+ /* Is this a packet from the video stream? */
+ if (packet.stream_index == video_input_file->vstream_idx) {
+ if (!already_locked) {
+ if (dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped a video frame\n"));
+ continue;
+ }
+
+ dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf);
+
+ already_locked = 1;
+ }
+
+ video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf);
+ video_data_node->source_number = source_number;
+
+ /* Set video frame to default */
+ avcodec_get_frame_defaults(video_data_node->vframe);
+
+ /* Decode video frame */
+ if (avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet) < 0) {
+ av_free_packet(&packet);
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while decoding video.\n"));
+ dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf);
+ dc_producer_unlock(&video_input_data->producer, &video_input_data->circular_buf);
+ return -1;
+ }
+
+ /* Did we get a video frame? */
+ if (got_frame) {
+ if (use_source_timing && is_live_capture) {
+ u64 pts;
+ if (video_input_file->pts_init == 0) {
+ 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_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
+ 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));
+ }
+ }
+
+// 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);
+
+ 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;
+ }
+
+ if (video_data_node->vframe->pts==AV_NOPTS_VALUE) {
+ if (!use_source_timing ) {
+ video_data_node->vframe->pts = video_input_file->frame_decoded;
+ } else {
+ video_data_node->vframe->pts = video_data_node->vframe->pkt_pts;
+ }
+ }
+ 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() ));
+
+ // For a decode/encode process we must free this memory.
+ //But if the input is raw and there is no need to decode then
+ // the packet is directly passed for decoded frame. We must wait until rescale is done before freeing it
+
+ if (codec_ctx->codec->id == CODEC_ID_RAWVIDEO) {
+ video_data_node->nb_raw_frames_ref = video_input_file->nb_consumers;
+
+ video_data_node->raw_packet = packet;
+#ifndef GPAC_USE_LIBAV
+ video_data_node->vframe = av_frame_clone(video_data_node->vframe);
+#endif
+
+ dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf);
+ while (video_data_node->nb_raw_frames_ref && ! *exit_signal_addr) {
+ gf_sleep(0);
+ }
+ } else {
+ dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf);
+ av_free_packet(&packet);
+ }
+ return 0;
+
+ }
+ }
+
+ /* Free the packet that was allocated by av_read_frame */
+ av_free_packet(&packet);
+ }
+
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown error while reading video frame.\n"));
+ return -1;
+}
+
+void dc_video_decoder_close(VideoInputFile *video_input_file)
+{
+ /* Close the video format context */
+ if (!video_input_file->av_fmt_ctx_ref_cnt)
+ avformat_close_input(&video_input_file->av_fmt_ctx);
+
+ video_input_file->av_pkt_list = NULL;
+ video_input_file->av_pkt_list_mutex = NULL;
+}
diff --git a/applications/dashcast/video_decoder.h b/applications/dashcast/video_decoder.h
new file mode 100644
index 0000000..305d95f
--- /dev/null
+++ b/applications/dashcast/video_decoder.h
@@ -0,0 +1,96 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef VIDEO_DECODER_H_
+#define VIDEO_DECODER_H_
+
+#include "video_data.h"
+
+#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
+
+
+/*
+ * The structure which keeps the data of
+ * input video file.
+ */
+typedef struct {
+ /* Format context structure provided by avlib to open and read from a media file. */
+ AVFormatContext *av_fmt_ctx;
+ /* A reference counter on the format context (may be shared with other sources). Currently redundant with av_pkt_list non-NULLness. */
+ int av_fmt_ctx_ref_cnt;
+ /* A list of AVPackets and return value to be processed: when this parameter is non-null,
+ * the video thread makes the demux and pushes the packets. Packets must be freed when retrieved.*/
+ GF_List *av_pkt_list;
+ GF_Mutex *av_pkt_list_mutex;
+ /* The index of the video stream in the file. */
+ int vstream_idx;
+ /* video width, height, and pixel format. */
+ int width;
+ int height;
+ int pix_fmt;
+
+ int mode;
+ int no_loop, nb_consumers;
+
+ u32 frame_decoded;
+ Bool pts_init;
+ u64 first_pts, prev_pts, computed_pts, sync_tolerance;
+ u64 utc_at_init;
+} VideoInputFile;
+
+/*
+ * Open the input video
+ *
+ * @param cmd_data [in] contains information about the file name
+ * and the video format.
+ *
+ * @param video_input_file [out] pointer to the structure which we want to
+ * open the file
+ *
+ * @return 0 on success -1 on failure.
+ */
+int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video_data_conf, int mode, int no_loop, int nb_consumers);
+
+/*
+ * Read and decode video and put decoded frames on circular buffer
+ *
+ * @param video_input_file [in] contains info on input video.
+ * @param video_input_data [out] the decoded samples will be put
+ * on the circular buffer of this parameter.
+ *
+ * @return 0 on success, -1 on failure, -2 on EOF (end of the file)
+ */
+int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *video_input_data, int source_number, int use_source_timing, int is_live_capture, const int *exit_signal_addr);
+
+/*
+ * Close the input video
+ *
+ * @param video_input_file [in] the video file to be closed
+ *
+ */
+void dc_video_decoder_close(VideoInputFile *);
+
+#endif /* VIDEO_DECODER_H_ */
diff --git a/applications/dashcast/video_encoder.c b/applications/dashcast/video_encoder.c
new file mode 100644
index 0000000..1f3a41a
--- /dev/null
+++ b/applications/dashcast/video_encoder.c
@@ -0,0 +1,295 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "video_encoder.h"
+#include "libavutil/opt.h"
+#include "libavdevice/avdevice.h"
+
+
+#if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
+
+#define _TOSTR(_val) #_val
+#define TOSTR(_val) _TOSTR(_val)
+
+#pragma comment(lib, "avcodec-"TOSTR(LIBAVCODEC_VERSION_MAJOR) )
+#pragma comment(lib, "avdevice-"TOSTR(LIBAVDEVICE_VERSION_MAJOR) )
+#pragma comment(lib, "avformat-"TOSTR(LIBAVFORMAT_VERSION_MAJOR) )
+#pragma comment(lib, "avutil-"TOSTR(LIBAVUTIL_VERSION_MAJOR) )
+#pragma comment(lib, "swscale-"TOSTR(LIBSWSCALE_VERSION_MAJOR) )
+
+#endif
+
+
+//#define DEBUG 1
+
+
+/**
+ * A function which pushes argument to a libav codec using its private data.
+ * param priv_data
+ * param options a list of space separated and ':' affected options (e.g. "a:b c:d e:f"). @options be non NULL.
+ */
+void build_dict(void *priv_data, const char *options) {
+ char *opt = gf_strdup(options);
+ char *tok = strtok(opt, "=");
+ char *tokval = NULL;
+ while (tok && (tokval=strtok(NULL, " "))) {
+ if (av_opt_set(priv_data, tok, tokval, 0) < 0)
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown custom option \"%s\" with value \"%s\" in %s\n", tok, tokval, options));
+ tok = strtok(NULL, "=");
+ }
+ free(opt);
+}
+
+int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing)
+{
+ 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);
+
+// video_output_file->codec = avcodec_find_encoder_by_name("libx264"/*video_data_conf->codec*/);
+ video_output_file->codec = avcodec_find_encoder(CODEC_ID_H264);
+ if (video_output_file->codec == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Output video codec %d not found\n", CODEC_ID_H264));
+ return -1;
+ }
+
+ video_output_file->codec_ctx = avcodec_alloc_context3(video_output_file->codec);
+
+ //Create new video stream
+// video_stream = avformat_new_stream(video_output_file->av_fmt_ctx, video_codec);
+// if (!video_stream) {
+// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create output video stream\n"));
+// return -1;
+// }
+
+ video_output_file->codec_ctx->codec_id = video_output_file->codec->id;
+ video_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
+ 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->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;
+
+ video_output_file->use_source_timing = use_source_timing;
+ if (use_source_timing) {
+ //for avcodec to do rate allcoation, we need to have ctx->timebase == 1/framerate
+ video_output_file->codec_ctx->time_base.den = video_data_conf->time_base.den;
+ video_output_file->codec_ctx->time_base.num = video_data_conf->time_base.num * video_data_conf->time_base.den / video_data_conf->framerate;
+ }
+ video_output_file->codec_ctx->pix_fmt = PIX_FMT_YUV420P;
+ video_output_file->codec_ctx->gop_size = video_data_conf->framerate;
+
+// video_output_file->codec_ctx->codec_id = video_codec->id;
+// video_output_file->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
+// 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->time_base = (AVRational) {1 ,
+// video_output_file->video_data_conf->framerate};
+// video_output_file->codec_ctx->codec->pix_fmt = PIX_FMT_YUV420P;
+ video_output_file->codec_ctx->gop_size = video_data_conf->framerate;
+//
+// 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);
+
+ /*
+ video_output_file->codec_ctx->max_b_frames = 0;
+ video_output_file->codec_ctx->thread_count = 1;
+ video_output_file->codec_ctx->delay = 0;
+ video_output_file->codec_ctx->rc_lookahead = 0;
+ */
+
+ /*
+ * video_stream->codec->gosize = video_output_file->vfr;
+ * videoStream->codec->gosize = 1;
+ * video_stream->codec->rc_lookahead = 0;
+ * videoStream->time_base = (AVRational) {1 , 1000000};
+ * videoStream->r_frame_rate = (AVRational) {outVideoCtx->video_framerate, 1};
+ * av_opt_set(videoStream->codec->priv_data, "preset", "slow", 0);
+ * videoStream->codec->me_range = 16;
+ * videoStream->codec->max_qdiff = 4;
+ * videoStream->codec->qmin = 10;
+ * videoStream->codec->qmax = 51;
+ * videoStream->codec->qcompress = 0.6;
+ * videoStream->codec->profile = FF_PROFILE_H264_BASELINE;
+ * videoStream->codec->level = 10;
+ *
+ */
+
+ if (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 {
+ 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, "preset", "ultrafast", 0);
+ av_opt_set(video_output_file->codec_ctx->priv_data, "tune", "zerolatency", 0);
+ }
+
+ if (video_output_file->gdr) {
+ av_opt_set_int(video_output_file->codec_ctx->priv_data, "intra-refresh", 1, 0);
+ av_opt_set_int(video_output_file->codec_ctx->priv_data, "key-int", video_output_file->gdr, 0);
+ }
+
+// if (video_output_file->av_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+ //the global header gives access to the extradata (SPS/PPS)
+ video_output_file->codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+// if (video_output_file->av_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+// video_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ video_output_file->vstream_idx = 0;//video_stream->index;
+
+ /* open the video codec - options are passed thru video_output_file->codec_ctx->priv_data */
+ if (avcodec_open2(video_output_file->codec_ctx, video_output_file->codec, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n"));
+ return -1;
+ }
+
+// /* open the video codec */
+// if (avcodec_open2(video_stream->codec, video_codec, NULL) < 0) {
+// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n"));
+// return -1;
+// }
+
+ video_output_file->rep_id = video_data_conf->filename;
+ return 0;
+}
+
+int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData *video_scaled_data)
+{
+ //AVPacket pkt;
+ VideoDataNode *video_data_node;
+ int ret;
+ //int out_size;
+
+// AVStream *video_stream = video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx];
+// AVCodecContext *video_codec_ctx = video_stream->codec;
+ AVCodecContext *video_codec_ctx = video_output_file->codec_ctx;
+
+ //FIXME: deadlock when pressing 'q' with BigBuckBunny_640x360.m4v
+ ret = dc_consumer_lock(&video_output_file->consumer, &video_scaled_data->circular_buf);
+ if (ret < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video encoder got an end of buffer!\n"));
+ return -2;
+ }
+
+ if (video_scaled_data->circular_buf.size > 1)
+ dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf);
+
+ video_data_node = (VideoDataNode*)dc_consumer_consume(&video_output_file->consumer, &video_scaled_data->circular_buf);
+
+ /*
+ * Set PTS (method 1)
+ */
+ if (!video_output_file->use_source_timing) {
+ video_data_node->vframe->pts = video_codec_ctx->frame_number;
+ }
+
+ /* Encoding video */
+ {
+ int got_packet = 0;
+ AVPacket pkt;
+ av_init_packet(&pkt);
+ pkt.data = video_output_file->vbuf;
+ pkt.size = video_output_file->vbuf_size;
+ pkt.pts = pkt.dts = video_data_node->vframe->pkt_dts = video_data_node->vframe->pkt_pts = video_data_node->vframe->pts;
+#ifdef GPAC_USE_LIBAV
+ 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
+ video_output_file->encoded_frame_size = avcodec_encode_video2(video_codec_ctx, &pkt, video_data_node->vframe, &got_packet);
+ //this is not true with libav !
+ if (video_output_file->encoded_frame_size >= 0)
+ video_output_file->encoded_frame_size = pkt.size;
+#endif
+ if (video_output_file->encoded_frame_size >= 0) {
+ if (got_packet) {
+ video_codec_ctx->coded_frame->pts = video_codec_ctx->coded_frame->pkt_pts = pkt.pts;
+ video_codec_ctx->coded_frame->pkt_dts = pkt.dts;
+ video_codec_ctx->coded_frame->key_frame = (pkt.flags & AV_PKT_FLAG_KEY) ? 1 : 0;
+ }
+ }
+ }
+
+ dc_consumer_advance(&video_output_file->consumer);
+
+ if (video_scaled_data->circular_buf.size == 1)
+ dc_consumer_unlock_previous(&video_output_file->consumer, &video_scaled_data->circular_buf);
+
+ if (video_output_file->encoded_frame_size < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error occured while encoding video frame.\n"));
+ 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() ));
+
+ /* if zero size, it means the image was buffered */
+// if (out_size > 0) {
+//
+// av_init_packet(&pkt);
+// pkt.data = NULL;
+// pkt.size = 0;
+//
+// if (video_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE) {
+// pkt.pts = av_rescale_q(video_codec_ctx->coded_frame->pts,
+// video_codec_ctx->time_base, video_stream->time_base);
+// }
+//
+//
+// if (video_codec_ctx->coded_frame->key_frame)
+// pkt.flags |= AV_PKT_FLAG_KEY;
+//
+// pkt.stream_index = video_stream->index;
+// pkt.data = video_output_file->vbuf;
+// pkt.size = out_size;
+//
+// // write the compressed frame in the media file
+// if (av_interleaved_write_frame(video_output_file->av_fmt_ctx, &pkt)
+// != 0) {
+// GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n"));
+// return -1;
+// }
+//
+// av_free_packet(&pkt);
+//
+// }
+
+ return video_output_file->encoded_frame_size;
+}
+
+void dc_video_encoder_close(VideoOutputFile *video_output_file)
+{
+// int i;
+//
+// // free the streams
+// for (i = 0; i < video_output_file->av_fmt_ctx->nb_streams; i++) {
+// avcodec_close(video_output_file->av_fmt_ctx->streams[i]->codec);
+// av_freep(&video_output_file->av_fmt_ctx->streams[i]->info);
+// }
+ av_free(video_output_file->vbuf);
+ avcodec_close(video_output_file->codec_ctx);
+ av_free(video_output_file->codec_ctx);
+}
diff --git a/applications/dashcast/video_encoder.h b/applications/dashcast/video_encoder.h
new file mode 100644
index 0000000..6bc7498
--- /dev/null
+++ b/applications/dashcast/video_encoder.h
@@ -0,0 +1,63 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef VIDEO_ENCODER_H_
+#define VIDEO_ENCODER_H_
+
+#include "video_muxer.h"
+
+
+/*
+ * Open an video stream
+ *
+ * @param video_output_file [in] add a video stream to the file
+ * with the parameters already passed to open_video_output
+ *
+ * @return 0 on success, -1 on failure
+ */
+int dc_video_encoder_open(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, Bool use_source_timing);
+
+/*
+ * Read the decoded video frames from circular buffer
+ * of the corresponding resolution
+ * and encode and write them on the output file
+ *
+ * @param video_output_file [in] video output file
+ * @param video_scaled_data [in] scaled video data structure which
+ * contains a circular buffer with video frames
+ *
+ * @return 0 on success, -1 on failure, -2 on finishing;
+ * when there is no more data on circular buffer to encode
+ */
+int dc_video_encoder_encode(VideoOutputFile *video_output_file, VideoScaledData *video_scaled_data);
+
+/*
+ * Close the output video file
+ *
+ * @param video_output_file [in] video output file
+ */
+void dc_video_encoder_close(VideoOutputFile *video_output_file);
+
+#endif /* VIDEO_ENCODER_H_ */
diff --git a/applications/dashcast/video_muxer.c b/applications/dashcast/video_muxer.c
new file mode 100644
index 0000000..5a8de38
--- /dev/null
+++ b/applications/dashcast/video_muxer.c
@@ -0,0 +1,690 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "video_muxer.h"
+#include "libavutil/opt.h"
+
+
+/**
+ * A function which takes FFmpeg H264 extradata (SPS/PPS) and bring them ready to be pushed to the MP4 muxer.
+ * @param extradata
+ * @param extradata_size
+ * @param dstcfg
+ * @returns GF_OK is the extradata was parsed and is valid, other values otherwise.
+ */
+static GF_Err avc_import_ffextradata(const u8 *extradata, const u64 extradata_size, GF_AVCConfig *dstcfg)
+{
+#ifdef GPAC_DISABLE_AV_PARSERS
+ return GF_OK;
+#else
+ u8 nal_size;
+ AVCState avc;
+ GF_BitStream *bs;
+ if (!extradata || !extradata_size)
+ return GF_BAD_PARAM;
+ bs = gf_bs_new(extradata, extradata_size, GF_BITSTREAM_READ);
+ if (!bs)
+ return GF_BAD_PARAM;
+ if (gf_bs_read_u32(bs) != 0x00000001) {
+ gf_bs_del(bs);
+ return GF_BAD_PARAM;
+ }
+
+ //SPS
+ {
+ s32 idx;
+ char *buffer = NULL;
+ const u64 nal_start = 4;
+ nal_size = gf_media_nalu_next_start_code_bs(bs);
+ if (nal_start + nal_size > extradata_size) {
+ gf_bs_del(bs);
+ return GF_BAD_PARAM;
+ }
+ buffer = (char*)gf_malloc(nal_size);
+ gf_bs_read_data(bs, buffer, nal_size);
+ gf_bs_seek(bs, nal_start);
+ if ((gf_bs_read_u8(bs) & 0x1F) != GF_AVC_NALU_SEQ_PARAM) {
+ gf_bs_del(bs);
+ gf_free(buffer);
+ return GF_BAD_PARAM;
+ }
+
+ idx = gf_media_avc_read_sps(buffer, nal_size, &avc, 0, NULL);
+ if (idx < 0) {
+ gf_bs_del(bs);
+ gf_free(buffer);
+ return GF_BAD_PARAM;
+ }
+
+ dstcfg->configurationVersion = 1;
+ dstcfg->profile_compatibility = avc.sps[idx].prof_compat;
+ dstcfg->AVCProfileIndication = avc.sps[idx].profile_idc;
+ dstcfg->AVCLevelIndication = avc.sps[idx].level_idc;
+ dstcfg->chroma_format = avc.sps[idx].chroma_format;
+ dstcfg->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8;
+ dstcfg->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8;
+
+ {
+ GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ slc->size = nal_size;
+ slc->id = idx;
+ slc->data = buffer;
+ gf_list_add(dstcfg->sequenceParameterSets, slc);
+ }
+ }
+
+ //PPS
+ {
+ s32 idx;
+ char *buffer = NULL;
+ const u64 nal_start = 4 + nal_size + 4;
+ gf_bs_seek(bs, nal_start);
+ nal_size = gf_media_nalu_next_start_code_bs(bs);
+ if (nal_start + nal_size > extradata_size) {
+ gf_bs_del(bs);
+ return GF_BAD_PARAM;
+ }
+ buffer = (char*)gf_malloc(nal_size);
+ gf_bs_read_data(bs, buffer, nal_size);
+ gf_bs_seek(bs, nal_start);
+ if ((gf_bs_read_u8(bs) & 0x1F) != GF_AVC_NALU_PIC_PARAM) {
+ gf_bs_del(bs);
+ gf_free(buffer);
+ return GF_BAD_PARAM;
+ }
+
+ idx = gf_media_avc_read_pps(buffer, nal_size, &avc);
+ if (idx < 0) {
+ gf_bs_del(bs);
+ gf_free(buffer);
+ return GF_BAD_PARAM;
+ }
+
+ {
+ GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_malloc(sizeof(GF_AVCConfigSlot));
+ slc->size = nal_size;
+ slc->id = idx;
+ slc->data = buffer;
+ gf_list_add(dstcfg->pictureParameterSets, slc);
+ }
+ }
+
+ gf_bs_del(bs);
+ return GF_OK;
+#endif
+}
+
+int dc_gpac_video_moov_create(VideoOutputFile *video_output_file, char *filename)
+{
+ GF_Err ret;
+ //AVStream *video_stream = video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx];
+ //AVCodecContext *video_codec_ctx = video_stream->codec;
+
+ AVCodecContext *video_codec_ctx = video_output_file->codec_ctx;
+ GF_AVCConfig *avccfg;
+ u32 di, track;
+
+ // T0D0: For the moment it is fixed
+ //u32 sample_dur = video_output_file->codec_ctx->time_base.den;
+
+ avccfg = gf_odf_avc_cfg_new();
+ if (!avccfg) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create AVCConfig\n"));
+ return -1;
+ }
+
+ //int64_t profile = 0;
+ //av_opt_get_int(video_output_file->codec_ctx->priv_data, "level", AV_OPT_SEARCH_CHILDREN, &profile);
+
+ {
+ GF_Err e = avc_import_ffextradata(video_codec_ctx->extradata, video_codec_ctx->extradata_size, avccfg);
+ if (e) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot parse H264 SPS/PPS\n"));
+ gf_odf_avc_cfg_del(avccfg);
+ return -1;
+ }
+ }
+
+ video_output_file->isof = gf_isom_open(filename, GF_ISOM_OPEN_WRITE, NULL);
+ if (!video_output_file->isof) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open iso file %s\n", filename));
+ return -1;
+ }
+ //gf_isom_store_movie_config(video_output_file->isof, 0);
+ track = gf_isom_new_track(video_output_file->isof, 0, GF_ISOM_MEDIA_VISUAL, video_codec_ctx->time_base.den);
+ video_output_file->trackID = gf_isom_get_track_id(video_output_file->isof, track);
+
+ video_output_file->timescale = video_codec_ctx->time_base.den;
+ if (!video_output_file->frame_dur)
+ video_output_file->frame_dur = video_codec_ctx->time_base.num;
+
+ if (!track) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create new track\n"));
+ return -1;
+ }
+
+ ret = gf_isom_set_track_enabled(video_output_file->isof, track, 1);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ ret = gf_isom_avc_config_new(video_output_file->isof, track, avccfg, NULL, NULL, &di);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_avc_config_new\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ gf_odf_avc_cfg_del(avccfg);
+ //fprintf(stdout, "time scale: %d \n", video_codec_ctx->time_base.den);
+
+ gf_isom_set_visual_info(video_output_file->isof, track, di, video_codec_ctx->width, video_codec_ctx->height);
+ gf_isom_set_sync_table(video_output_file->isof, track);
+
+ //inband SPS/PPS
+ if (video_output_file->muxer_type == GPAC_INIT_VIDEO_MUXER_AVC3) {
+ ret = gf_isom_avc_set_inband_config(video_output_file->isof, track, 1);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_avc_set_inband_config\n", gf_error_to_string(ret)));
+ return -1;
+ }
+ }
+
+ ret = gf_isom_setup_track_fragment(video_output_file->isof, track, 1, video_output_file->use_source_timing ? (u32) video_output_file->frame_dur : 1, 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)));
+ 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;
+ }
+
+ return 0;
+}
+
+int dc_gpac_video_isom_open_seg(VideoOutputFile *video_output_file, char *filename)
+{
+ GF_Err ret;
+ ret = gf_isom_start_segment(video_output_file->isof, filename, 1);
+ if (ret != GF_OK) {
+ 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;
+}
+
+int dc_gpac_video_isom_write(VideoOutputFile *video_output_file)
+{
+ GF_Err ret;
+ //AVStream *video_stream = video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx];
+ //AVCodecContext *video_codec_ctx = video_stream->codec;
+ AVCodecContext *video_codec_ctx = video_output_file->codec_ctx;
+
+ u32 sc_size = 0;
+ u32 nalu_size = 0;
+
+ u32 buf_len = video_output_file->encoded_frame_size;
+ u8 *buf_ptr = video_output_file->vbuf;
+
+ GF_BitStream *out_bs = gf_bs_new(NULL, 2 * buf_len, GF_BITSTREAM_WRITE);
+ nalu_size = gf_media_nalu_next_start_code(buf_ptr, buf_len, &sc_size);
+ if (nalu_size != 0) {
+ gf_bs_write_u32(out_bs, nalu_size);
+ gf_bs_write_data(out_bs, (const char*) buf_ptr, nalu_size);
+ }
+ if (sc_size) {
+ buf_ptr += (nalu_size + sc_size);
+ buf_len -= (nalu_size + sc_size);
+ }
+
+ while (buf_len) {
+ nalu_size = gf_media_nalu_next_start_code(buf_ptr, buf_len, &sc_size);
+ if (nalu_size != 0) {
+ gf_bs_write_u32(out_bs, nalu_size);
+ gf_bs_write_data(out_bs, (const char*) buf_ptr, nalu_size);
+ }
+
+ buf_ptr += nalu_size;
+
+ if (!sc_size || (buf_len < nalu_size + sc_size))
+ break;
+ buf_len -= nalu_size + sc_size;
+ buf_ptr += sc_size;
+ }
+
+ gf_bs_get_content(out_bs, &video_output_file->sample->data, &video_output_file->sample->dataLength);
+ //video_output_file->sample->data = //(char *) (video_output_file->vbuf + nalu_size + sc_size);
+ //video_output_file->sample->dataLength = //video_output_file->encoded_frame_size - (sc_size + nalu_size);
+
+ video_output_file->sample->DTS = video_codec_ctx->coded_frame->pkt_dts;
+ video_output_file->sample->CTS_Offset = (s32) (video_codec_ctx->coded_frame->pts - video_output_file->sample->DTS);
+ video_output_file->sample->IsRAP = video_codec_ctx->coded_frame->key_frame;
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Isom Write: RAP %d , DTS "LLD" CTS offset %d \n", video_output_file->sample->IsRAP, video_output_file->sample->DTS, video_output_file->sample->CTS_Offset));
+
+ ret = gf_isom_fragment_add_sample(video_output_file->isof, video_output_file->trackID, video_output_file->sample, 1, video_output_file->use_source_timing ? (u32) video_output_file->frame_dur : 1, 0, 0, 0);
+ if (ret != GF_OK) {
+ gf_bs_del(out_bs);
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_fragment_add_sample\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ //free data but keep sample structure alive
+ gf_free(video_output_file->sample->data);
+ video_output_file->sample->data = NULL;
+ video_output_file->sample->dataLength = 0;
+
+ gf_bs_del(out_bs);
+ return 0;
+}
+
+int dc_gpac_video_isom_close_seg(VideoOutputFile *video_output_file)
+{
+ GF_Err ret;
+ ret = gf_isom_close_segment(video_output_file->isof, 0, 0, 0, 0, 0, 0, 1, video_output_file->seg_marker, NULL, NULL);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close_segment\n", gf_error_to_string(ret)));
+ return -1;
+ }
+ GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] Rep %s Closing segment at UTC "LLU" ms\n", video_output_file->rep_id, gf_net_get_utc() ));
+
+ return 0;
+}
+
+int dc_gpac_video_isom_close(VideoOutputFile *video_output_file)
+{
+ GF_Err ret;
+ ret = gf_isom_close(video_output_file->isof);
+ if (ret != GF_OK) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close\n", gf_error_to_string(ret)));
+ return -1;
+ }
+
+ return 0;
+}
+
+int dc_raw_h264_open(VideoOutputFile *video_output_file, char *filename)
+{
+ video_output_file->file = fopen(filename, "w");
+ return 0;
+}
+
+int dc_raw_h264_write(VideoOutputFile *video_output_file)
+{
+ fwrite(video_output_file->vbuf, video_output_file->encoded_frame_size, 1, video_output_file->file);
+ return 0;
+}
+
+int dc_raw_h264_close(VideoOutputFile *video_output_file)
+{
+ fclose(video_output_file->file);
+ return 0;
+}
+
+int dc_ffmpeg_video_muxer_open(VideoOutputFile *video_output_file, char *filename)
+{
+ AVStream *video_stream;
+ AVOutputFormat *output_fmt;
+
+ AVCodecContext *video_codec_ctx = video_output_file->codec_ctx;
+ video_output_file->av_fmt_ctx = NULL;
+
+// video_output_file->vbr = video_data_conf->bitrate;
+// video_output_file->vfr = video_data_conf->framerate;
+// video_output_file->width = video_data_conf->width;
+// video_output_file->height = video_data_conf->height;
+// strcpy(video_output_file->filename, video_data_conf->filename);
+// strcpy(video_output_file->codec, video_data_conf->codec);
+
+ /* Find output format */
+ output_fmt = av_guess_format(NULL, filename, NULL);
+ if (!output_fmt) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find suitable output format\n"));
+ return -1;
+ }
+
+ video_output_file->av_fmt_ctx = avformat_alloc_context();
+ if (!video_output_file->av_fmt_ctx) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate memory for pOutVideoFormatCtx\n"));
+ return -1;
+ }
+
+ video_output_file->av_fmt_ctx->oformat = output_fmt;
+ strcpy(video_output_file->av_fmt_ctx->filename, filename);
+
+ /* Open the output file */
+ if (!(output_fmt->flags & AVFMT_NOFILE)) {
+ if (avio_open(&video_output_file->av_fmt_ctx->pb, filename, URL_WRONLY) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot not open '%s'\n", filename));
+ return -1;
+ }
+ }
+
+ video_stream = avformat_new_stream(video_output_file->av_fmt_ctx,
+ video_output_file->codec);
+ if (!video_stream) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create output video stream\n"));
+ return -1;
+ }
+
+ //video_stream->codec = video_output_file->codec_ctx;
+
+ video_stream->codec->codec_id = video_output_file->codec->id;
+ video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ video_stream->codec->bit_rate = video_codec_ctx->bit_rate; //video_output_file->video_data_conf->bitrate;
+ video_stream->codec->width = video_codec_ctx->width; //video_output_file->video_data_conf->width;
+ video_stream->codec->height = video_codec_ctx->height; //video_output_file->video_data_conf->height;
+
+ video_stream->codec->time_base = video_codec_ctx->time_base;
+
+ video_stream->codec->pix_fmt = PIX_FMT_YUV420P;
+ video_stream->codec->gop_size = video_codec_ctx->time_base.den; //video_output_file->video_data_conf->framerate;
+
+ av_opt_set(video_stream->codec->priv_data, "preset", "ultrafast", 0);
+ av_opt_set(video_stream->codec->priv_data, "tune", "zerolatency", 0);
+
+ /* open the video codec */
+ if (avcodec_open2(video_stream->codec, video_output_file->codec, NULL) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n"));
+ return -1;
+ }
+
+ avformat_write_header(video_output_file->av_fmt_ctx, NULL);
+
+ video_output_file->timescale = video_codec_ctx->time_base.den;
+ return 0;
+}
+
+int dc_ffmpeg_video_muxer_write(VideoOutputFile *video_output_file)
+{
+ AVPacket pkt;
+ AVStream *video_stream = video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx];
+ AVCodecContext *video_codec_ctx = video_stream->codec;
+
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ if (video_codec_ctx->coded_frame->pts != AV_NOPTS_VALUE) {
+ pkt.pts = av_rescale_q(video_codec_ctx->coded_frame->pts, video_codec_ctx->time_base, video_stream->time_base);
+ }
+
+ if (video_codec_ctx->coded_frame->key_frame)
+ pkt.flags |= AV_PKT_FLAG_KEY;
+
+ pkt.stream_index = video_stream->index;
+ pkt.data = video_output_file->vbuf;
+ pkt.size = video_output_file->encoded_frame_size;
+
+ // write the compressed frame in the media file
+ if (av_interleaved_write_frame(video_output_file->av_fmt_ctx, &pkt) != 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n"));
+ return -1;
+ }
+
+ av_free_packet(&pkt);
+
+ return 0;
+}
+
+int dc_ffmpeg_video_muxer_close(VideoOutputFile *video_output_file)
+{
+ u32 i;
+
+ av_write_trailer(video_output_file->av_fmt_ctx);
+
+ avio_close(video_output_file->av_fmt_ctx->pb);
+
+ // free the streams
+ for (i = 0; i < video_output_file->av_fmt_ctx->nb_streams; i++) {
+ avcodec_close(video_output_file->av_fmt_ctx->streams[i]->codec);
+ av_freep(&video_output_file->av_fmt_ctx->streams[i]->info);
+ }
+
+ //video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx]->codec = NULL;
+ avformat_free_context(video_output_file->av_fmt_ctx);
+
+ return 0;
+}
+
+int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, VideoMuxerType muxer_type, int frame_per_segment, int frame_per_fragment, u32 seg_marker, int gdr, int seg_dur, int frag_dur, int frame_dur, int gop_size, int video_cb_size)
+{
+ char name[GF_MAX_PATH];
+ memset(video_output_file, 0, sizeof(VideoOutputFile));
+ snprintf(name, sizeof(name), "video encoder %s", video_data_conf->filename);
+ dc_consumer_init(&video_output_file->consumer, video_cb_size, name);
+
+ video_output_file->sample = gf_isom_sample_new();
+ video_output_file->isof = NULL;
+ video_output_file->muxer_type = muxer_type;
+
+ video_output_file->frame_per_segment = frame_per_segment;
+ video_output_file->frame_per_fragment = frame_per_fragment;
+
+ video_output_file->seg_dur = seg_dur;
+ video_output_file->frag_dur = frag_dur;
+
+ video_output_file->seg_marker = seg_marker;
+ video_output_file->gdr = gdr;
+ video_output_file->gop_size = gop_size;
+ video_output_file->frame_dur = frame_dur;
+
+ return 0;
+}
+
+int dc_video_muxer_free(VideoOutputFile *video_output_file)
+{
+ if (video_output_file->isof != NULL) {
+ gf_isom_close(video_output_file->isof);
+ }
+
+ gf_isom_sample_del(&video_output_file->sample);
+
+ return 0;
+}
+
+GF_Err dc_video_muxer_open(VideoOutputFile *video_output_file, char *directory, char *id_name, int seg)
+{
+ char name[GF_MAX_PATH];
+
+ switch (video_output_file->muxer_type) {
+ case FFMPEG_VIDEO_MUXER:
+ snprintf(name, sizeof(name), "%s/%s_%d_ffmpeg.mp4", directory, id_name, seg);
+ return dc_ffmpeg_video_muxer_open(video_output_file, name);
+ 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);
+ 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) {
+ 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;
+ }
+ snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg);
+ return dc_gpac_video_isom_open_seg(video_output_file, name);
+ case GPAC_INIT_VIDEO_MUXER_AVC3:
+ 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;
+ }
+ snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg);
+ return dc_gpac_video_isom_open_seg(video_output_file, name);
+ default:
+ return GF_BAD_PARAM;
+ };
+
+ return -2;
+}
+
+int dc_video_muxer_write(VideoOutputFile *video_output_file, int frame_nb, Bool insert_utc)
+{
+ 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);
+ case GPAC_VIDEO_MUXER:
+ case GPAC_INIT_VIDEO_MUXER_AVC1:
+ case GPAC_INIT_VIDEO_MUXER_AVC3:
+ if (video_output_file->use_source_timing) {
+ 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;
+ 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) {
+ 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);
+ }
+ }
+ 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;
+ }
+
+ if (dc_gpac_video_isom_write(video_output_file) < 0) {
+ return -1;
+ }
+ 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) {
+ 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));
+ }
+
+ //we may have rounding errors on the input PTS :( add half frame dur safety
+ 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;
+ }
+ return 0;
+ }
+
+ if (frame_nb % video_output_file->frame_per_fragment == 0) {
+ gf_isom_start_fragment(video_output_file->isof, 1);
+
+ if (!video_output_file->segment_started) {
+ 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 ));
+
+ }
+ }
+
+
+ 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;
+ }
+
+ 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));
+ }
+
+ if (frame_nb + 1 == video_output_file->frame_per_segment)
+ return 1;
+
+ return 0;
+ default:
+ return -2;
+ }
+
+ return -2;
+}
+
+int dc_video_muxer_close(VideoOutputFile *video_output_file)
+{
+ video_output_file->fragment_started = video_output_file->segment_started = 0;
+
+ 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);
+ 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);
+ default:
+ return -2;
+ }
+
+ return -2;
+}
diff --git a/applications/dashcast/video_muxer.h b/applications/dashcast/video_muxer.h
new file mode 100644
index 0000000..3f9c03e
--- /dev/null
+++ b/applications/dashcast/video_muxer.h
@@ -0,0 +1,110 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef VIDEO_MUXER_H_
+#define VIDEO_MUXER_H_
+
+#include "../../modules/ffmpeg_in/ffmpeg_in.h"
+#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
+#include "libswscale/swscale.h"
+#include "libavutil/mathematics.h"
+#include
+#include
+
+#include "video_scaler.h"
+
+
+typedef enum {
+ FFMPEG_VIDEO_MUXER,
+ RAW_VIDEO_H264,
+ GPAC_VIDEO_MUXER,
+ GPAC_INIT_VIDEO_MUXER_AVC1,
+ GPAC_INIT_VIDEO_MUXER_AVC3
+} VideoMuxerType;
+
+/*
+ * VideoOutputFile structure has the data needed to encode video frames and write them on the file.
+ * It reads the data from a circular buffer so it needs to keep the index to that circular buffer. This index is
+ * available in Consumer data structure.
+ */
+typedef struct {
+ //VideoDataConf *video_data_conf;
+ VideoMuxerType muxer_type;
+
+ /* file format context structure */
+ AVFormatContext *av_fmt_ctx;
+ AVCodecContext *codec_ctx;
+ AVCodec *codec;
+
+ FILE *file;
+
+ GF_ISOFile *isof;
+ GF_ISOSample *sample;
+ u32 trackID;
+ /* Index of the video stream in the file */
+ int vstream_idx;
+ /* keeps the index with which encoder access to the circular buffer (as a consumer) */
+ Consumer consumer;
+
+ /* Variables that encoder needs to encode data */
+ uint8_t *vbuf;
+ int vbuf_size;
+ int encoded_frame_size;
+
+ int frame_per_fragment;
+ int frame_per_segment;
+
+ int seg_dur;
+ int frag_dur;
+
+ u64 first_dts;
+
+ u32 seg_marker;
+
+ int gop_size;
+ int gdr;
+
+ Bool use_source_timing;
+
+ u64 pts_at_segment_start;
+ u64 last_pts, last_dts;
+ u64 frame_dur;
+ u32 timescale;
+ Bool fragment_started, segment_started;
+ const char *rep_id;
+} VideoOutputFile;
+
+int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, VideoMuxerType muxer_type, int frame_per_segment, int frame_per_fragment, u32 seg_marker, int gdr, int seg_dur, int frag_dur, int frame_dur, int gop_size, int video_cb_size);
+
+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_close(VideoOutputFile *video_output_file);
+
+#endif /* VIDEO_MUXER_H_ */
diff --git a/applications/dashcast/video_scaler.c b/applications/dashcast/video_scaler.c
new file mode 100644
index 0000000..7c64f3e
--- /dev/null
+++ b/applications/dashcast/video_scaler.c
@@ -0,0 +1,257 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * 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 "video_scaler.h"
+
+
+#ifdef GPAC_USE_LIBAV
+#define av_frame_free av_free
+#endif
+
+VideoScaledDataNode * dc_video_scaler_node_create(int width, int height, int crop_x, int crop_y, int pix_fmt)
+{
+ VideoScaledDataNode *video_scaled_data_node = gf_malloc(sizeof(VideoDataNode));
+ if (video_scaled_data_node) {
+ video_scaled_data_node->v_frame = FF_ALLOC_FRAME();
+ if (crop_x || crop_y) {
+ video_scaled_data_node->cropped_frame = FF_ALLOC_FRAME();
+ } else {
+ video_scaled_data_node->cropped_frame = NULL;
+ }
+ }
+ if (!video_scaled_data_node || !video_scaled_data_node->v_frame || ((crop_x || crop_y) && !video_scaled_data_node->cropped_frame)) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate VideoNode!\n"));
+ av_frame_free(&video_scaled_data_node->v_frame);
+ av_frame_free(&video_scaled_data_node->cropped_frame);
+ gf_free(video_scaled_data_node);
+ return NULL;
+ }
+
+ /* Determine required buffer size and allocate buffer */
+ avpicture_alloc((AVPicture*)video_scaled_data_node->v_frame, pix_fmt, width, height);
+ if (video_scaled_data_node->cropped_frame) {
+ avpicture_alloc((AVPicture*)video_scaled_data_node->cropped_frame, pix_fmt, width-crop_x, height-crop_y);
+ }
+
+ return video_scaled_data_node;
+}
+
+void dc_video_scaler_node_destroy(VideoScaledDataNode *video_scaled_data_node)
+{
+ av_frame_free(&video_scaled_data_node->v_frame);
+ gf_free(video_scaled_data_node);
+}
+
+void dc_video_scaler_list_init(VideoScaledDataList *video_scaled_data_list, GF_List * video_lst)
+{
+ u32 i, j;
+ int found;
+
+ video_scaled_data_list->size = 0;
+ video_scaled_data_list->video_scaled_data = NULL;
+
+ for (i=0; isize; j++) {
+ if ( video_scaled_data_list->video_scaled_data[j]->out_height == video_data_conf->height
+ && video_scaled_data_list->video_scaled_data[j]->out_width == video_data_conf->width) {
+ found = 1;
+ video_scaled_data_list->video_scaled_data[j]->num_consumers++;
+ break;
+ }
+ }
+ if (!found) {
+ VideoScaledData *video_scaled_data;
+ GF_SAFEALLOC(video_scaled_data, VideoScaledData);
+ video_scaled_data->out_width = video_data_conf->width;
+ video_scaled_data->out_height = video_data_conf->height;
+ video_scaled_data->num_consumers = 1;
+
+ video_scaled_data_list->video_scaled_data = gf_realloc(video_scaled_data_list->video_scaled_data, (video_scaled_data_list->size+1)*sizeof(VideoScaledData*));
+
+ video_scaled_data_list->video_scaled_data[video_scaled_data_list->size] = video_scaled_data;
+ video_scaled_data_list->size++;
+ }
+ }
+}
+
+void dc_video_scaler_list_destroy(VideoScaledDataList *video_scaled_data_list)
+{
+ u32 i;
+ for (i=0; isize; i++)
+ gf_free(video_scaled_data_list->video_scaled_data[i]);
+
+ gf_free(video_scaled_data_list->video_scaled_data);
+}
+
+void dc_video_scaler_end_signal(VideoScaledData *video_scaled_data)
+{
+ dc_producer_end_signal(&video_scaled_data->producer, &video_scaled_data->circular_buf);
+ dc_producer_unlock_previous(&video_scaled_data->producer, &video_scaled_data->circular_buf);
+}
+
+int dc_video_scaler_data_init(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int max_source, int video_cb_size)
+{
+ int i;
+ char name[GF_MAX_PATH];
+ snprintf(name, sizeof(name), "video scaler %dx%d", video_scaled_data->out_width, video_scaled_data->out_height);
+
+ dc_producer_init(&video_scaled_data->producer, video_cb_size, name);
+ dc_consumer_init(&video_scaled_data->consumer, video_cb_size, name);
+
+ video_scaled_data->num_producers = max_source;
+ video_scaled_data->out_pix_fmt = PIX_FMT_YUV420P;
+ GF_SAFE_ALLOC_N(video_scaled_data->vsprop, max_source, VideoScaledProp);
+ memset(video_scaled_data->vsprop, 0, max_source * sizeof(VideoScaledProp));
+
+ dc_circular_buffer_create(&video_scaled_data->circular_buf, video_cb_size, video_input_data->circular_buf.mode, video_scaled_data->num_consumers);
+ for (i=0; icircular_buf.list[i].data = dc_video_scaler_node_create(video_scaled_data->out_width, video_scaled_data->out_height, video_input_data->vprop[i].crop_x, video_input_data->vprop[i].crop_y, video_scaled_data->out_pix_fmt);
+ }
+
+ return 0;
+}
+
+int dc_video_scaler_data_set_prop(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int index)
+{
+ video_scaled_data->vsprop[index].in_width = video_input_data->vprop[index].width - video_input_data->vprop[index].crop_x;
+ 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->vsprop[index].sws_ctx = sws_getContext(
+ video_scaled_data->vsprop[index].in_width,
+ video_scaled_data->vsprop[index].in_height,
+ video_scaled_data->vsprop[index].in_pix_fmt,
+ video_scaled_data->out_width, video_scaled_data->out_height,
+ video_scaled_data->out_pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ if (video_scaled_data->vsprop[index].sws_ctx == NULL) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize the conversion context!\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *video_scaled_data)
+{
+ int ret, index, src_height;
+ VideoDataNode *video_data_node;
+ 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;
+ }
+
+ 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);
+ dc_producer_unlock_previous(&video_scaled_data->producer, &video_scaled_data->circular_buf);
+
+ 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;
+
+ video_scaled_data->frame_duration = video_input_data->frame_duration;
+
+ //crop if necessary
+ if (video_input_data->vprop[index].crop_x || video_input_data->vprop[index].crop_y) {
+#if 0
+ av_frame_copy_props(video_scaled_data_node->cropped_frame, video_data_node->vframe);
+ video_scaled_data_node->cropped_frame->width = video_input_data->vprop[index].width - video_input_data->vprop[index].crop_x;
+ video_scaled_data_node->cropped_frame->height = video_input_data->vprop[index].height - video_input_data->vprop[index].crop_y;
+#endif
+ if (av_picture_crop((AVPicture*)video_scaled_data_node->cropped_frame, (AVPicture*)video_data_node->vframe, PIX_FMT_YUV420P, video_input_data->vprop[index].crop_y, video_input_data->vprop[index].crop_x) < 0) {
+ GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Video scaler: error while cropping picture.\n"));
+ return -1;
+ }
+ src_vframe = video_scaled_data_node->cropped_frame;
+ src_height = video_input_data->vprop[index].height - video_input_data->vprop[index].crop_y;
+ } else {
+ assert(!video_scaled_data_node->cropped_frame);
+ src_vframe = video_data_node->vframe;
+ 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);
+
+ video_scaled_data_node->v_frame->pts = video_data_node->vframe->pts;
+
+ if (video_data_node->nb_raw_frames_ref) {
+ if (video_data_node->nb_raw_frames_ref==1) {
+#ifndef GPAC_USE_LIBAV
+ av_frame_unref(video_data_node->vframe);
+#endif
+ av_free_packet(&video_data_node->raw_packet);
+ }
+ video_data_node->nb_raw_frames_ref--;
+ }
+
+ dc_consumer_advance(&video_scaled_data->consumer);
+ dc_producer_advance(&video_scaled_data->producer, &video_scaled_data->circular_buf);
+
+ if (video_input_data->circular_buf.size == 1)
+ dc_consumer_unlock_previous(&video_scaled_data->consumer, &video_input_data->circular_buf);
+ return 0;
+}
+
+int dc_video_scaler_data_destroy(VideoScaledData *video_scaled_data)
+{
+ int i;
+ for (i=0; i<(int) video_scaled_data->circular_buf.size; i++) {
+ if (video_scaled_data->circular_buf.list) {
+ dc_video_scaler_node_destroy(video_scaled_data->circular_buf.list[i].data);
+ }
+ }
+
+ for (i=0 ; inum_producers; i++) {
+ if (video_scaled_data->vsprop[i].sws_ctx)
+ av_free(video_scaled_data->vsprop[i].sws_ctx);
+ }
+ gf_free(video_scaled_data->vsprop);
+ //av_free(video_scaled_data->sws_ctx);
+
+ dc_circular_buffer_destroy(&video_scaled_data->circular_buf);
+
+ return 0;
+}
+
+VideoScaledData * dc_video_scaler_get_data(VideoScaledDataList *video_scaled_data_list, int width, int height)
+{
+ u32 i;
+ for (i=0; isize; i++) {
+ if (video_scaled_data_list->video_scaled_data[i]->out_width == width && video_scaled_data_list->video_scaled_data[i]->out_height == height)
+ return video_scaled_data_list->video_scaled_data[i];
+ }
+
+ return NULL;
+}
diff --git a/applications/dashcast/video_scaler.h b/applications/dashcast/video_scaler.h
new file mode 100644
index 0000000..b50b9c7
--- /dev/null
+++ b/applications/dashcast/video_scaler.h
@@ -0,0 +1,167 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Arash Shafiei
+ * Copyright (c) Telecom ParisTech 2000-2013
+ * All rights reserved
+ *
+ * This file is part of GPAC / dashcast
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef VIDEO_SCALER_H_
+#define VIDEO_SCALER_H_
+
+#include
+#include
+
+#include "video_data.h"
+
+
+typedef struct {
+ /* scaler of the libav */
+ struct SwsContext *sws_ctx;
+ /* width, height, and the pixel format of the scaled video */
+ int in_width;
+ int in_height;
+ int in_pix_fmt;
+} VideoScaledProp;
+
+/*
+ * VideoScaledData keeps a circular buffer
+ * of video frame with a defined resolution.
+ */
+typedef struct {
+ VideoScaledProp *vsprop;
+
+ int out_width;
+ int out_height;
+ int out_pix_fmt;
+
+ /* scaler of the libav */
+ //struct SwsContext * sws_ctx;
+ /* width, height, and the pixel format of the scaled video */
+ //int width;
+ //int height;
+ //int pix_fmt;
+
+ /* circular buffer containing the scaled video frames */
+ CircularBuffer circular_buf;
+
+ /* Scaler is a consumer and also producer.
+ * It consumes from the video input data and it produces the video scaled data.
+ * So it deals with two circular buffer and we need to keep the index for both. */
+ Producer producer;
+ Consumer consumer;
+
+ /* The number of consumers of this circular buffer.
+ * (Which are the encoders who are using this resolution) */
+ int num_consumers;
+ int num_producers;
+
+ u64 frame_duration;
+} VideoScaledData;
+
+/*
+ * Each node in a circular buffer is a pointer.
+ * To use the circular buffer for scaled video frame we must define the node. This structure contains the data needed to encode a video frame.
+ */
+typedef struct {
+ AVFrame *v_frame;
+ AVFrame *cropped_frame;
+} VideoScaledDataNode;
+
+/*
+ * A list of pointers to scaled video data.
+ */
+typedef struct {
+ VideoScaledData **video_scaled_data;
+ u32 size;
+} VideoScaledDataList;
+
+/*
+ * Read the configuration file info and fill the video scaled data list with all the resolution available.
+ * Each resolution is associated to a circular buffer in a video scaled data.
+ *
+ * @param cmd_data [in] Command data which contains the configuration file info
+ * @param video_scaled_data_list [out] the list to be filled
+ */
+void dc_video_scaler_list_init(VideoScaledDataList *video_scaled_data_list, GF_List *video_lst);
+
+/*
+ * Destroy a video scaled data list.
+ *
+ * @param video_scaled_data_list [in] the list to be destroyed.
+ */
+void dc_video_scaler_list_destroy(VideoScaledDataList *video_scaled_data_list);
+
+/*
+ * Signal to all the users of the circular buffer in the VideoScaledData
+ * which the current node is the last node to consume.
+ *
+ * @param video_scaled_data [in] the structure to be signaled on.
+ */
+void dc_video_scaler_end_signal(VideoScaledData *video_scaled_data);
+
+/*
+ * Initialize a VideoScaledData.
+ *
+ * @param video_input_data [in] contains the info of the input video.
+ * @param video_scaled_data [out] structure to be initialized.
+ *
+ * @return 0 on success, -1 on failure.
+ *
+ * @note Must use dc_video_scaler_data_destroy to free memory.
+ */
+int dc_video_scaler_data_init(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int num_producers, int video_cb_size);
+
+/*
+ * Set properties of a VideoScaledData.
+ */
+int dc_video_scaler_data_set_prop(VideoInputData *video_input_data, VideoScaledData *video_scaled_data, int index);
+
+/*
+ * Get a frame from the circular buffer on the input video,
+ * scale it and put the result on the circular buffer of the
+ * video scaled data
+ *
+ * @param video_input_data [in] contains input frames
+ * @param video_scaled_data [out] contains scaled frames
+ *
+ * return 0 on success, -2 if the node is the last node to scale
+ */
+int dc_video_scaler_scale(VideoInputData *video_input_data, VideoScaledData *video_scaled_data);
+
+/*
+ * Destroy a VideoScaledData
+ *
+ * @param video_scaled_data [in] structure to be destroyed.
+ */
+int dc_video_scaler_data_destroy(VideoScaledData *video_scaled_data);
+
+/*
+ * Return the VideoScaledData from the list which has width and height
+ *
+ * @param video_scaled_data_list [in] video scaled data list
+ * @param width [in] frame width
+ * @param height [in] frame height
+ *
+ * @return a VideoScaledData which corresponds to the width and height on success, NULL on failure
+ */
+VideoScaledData * dc_video_scaler_get_data(VideoScaledDataList *video_scaled_data_list, int width, int height);
+
+#endif /* VIDEO_SCALER_H_ */
diff --git a/applications/generators/MPEG4/Makefile b/applications/generators/MPEG4/Makefile
index 373acab..4bf4ec6 100644
--- a/applications/generators/MPEG4/Makefile
+++ b/applications/generators/MPEG4/Makefile
@@ -49,10 +49,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/generators/MPEG4/main.c b/applications/generators/MPEG4/main.c
index c940f06..d797fb7 100644
--- a/applications/generators/MPEG4/main.c
+++ b/applications/generators/MPEG4/main.c
@@ -1473,9 +1473,9 @@ void ParseTemplateFile(FILE *nodes, GF_List *BNodes, GF_List *NDTs, u32 version)
}
} else if (!strcmp(f->familly, "SFInt32")) {
if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) {
- strcpy(f->def, "2 << 31");
+ strcpy(f->def, "1 << 31");
} else if (!strcmp(f->def, "-I")) {
- strcpy(f->def, "- (2 << 31)");
+ strcpy(f->def, "- (1 << 31)");
}
}
}
diff --git a/applications/generators/SVG/Makefile b/applications/generators/SVG/Makefile
index f7ccf3a..53a8be6 100644
--- a/applications/generators/SVG/Makefile
+++ b/applications/generators/SVG/Makefile
@@ -54,10 +54,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/generators/X3D/Makefile b/applications/generators/X3D/Makefile
index fd0f71e..1a96c0e 100644
--- a/applications/generators/X3D/Makefile
+++ b/applications/generators/X3D/Makefile
@@ -49,10 +49,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/mp42avi/Makefile b/applications/mp42avi/Makefile
index 3dce49f..ebaf44c 100644
--- a/applications/mp42avi/Makefile
+++ b/applications/mp42avi/Makefile
@@ -45,10 +45,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/mp42ts/Makefile b/applications/mp42ts/Makefile
index a108db5..3e79f20 100644
--- a/applications/mp42ts/Makefile
+++ b/applications/mp42ts/Makefile
@@ -47,10 +47,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/mp42ts/main.c b/applications/mp42ts/main.c
index ee6f3cd..50e5915 100644
--- a/applications/mp42ts/main.c
+++ b/applications/mp42ts/main.c
@@ -36,9 +36,6 @@
#include
#endif
-#define USE_ISOBMF_REWRITE
-
-
#ifdef GPAC_DISABLE_ISOM
#error "Cannot compile MP42TS if GPAC is not built with ISO File Format support"
@@ -56,9 +53,11 @@
#define UDP_BUFFER_SIZE 0x40000
-#define MP42TS_PRINT_FREQ 634 /*refresh printed info every CLOCK_REFRESH ms*/
+#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;
+
static GFINLINE void usage(const char * progname)
{
fprintf(stderr, "USAGE: %s -rate=R [[-prog=prog1]..[-prog=progn]] [-audio=url] [-video=url] [-mpeg4-carousel=n] [-mpeg4] [-time=n] [-src=file] DST [[DST]]\n"
@@ -72,16 +71,21 @@ static GFINLINE void usage(const char * progname)
"\t-pcr-init=V sets initial value V for PCR - if not set, random value is used\n"
"\t-pcr-offset=V offsets all timestamps from PCR by V, in 90kHz. Default value: %d\n"
"\t-psi-rate=V sets PSI refresh rate V in ms (default 100ms). If 0, PSI data is only send once at the begining\n"
+ " or before each IDR when -rap option is set. This should be set to 0 for DASH streams.\n"
"\t-time=n request the program to stop after n ms\n"
"\t-single-au forces 1 PES = 1 AU (disabled by default)\n"
"\t-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"
+ "\t-flush-rap same as -rap but flushes all other streams (sends remaining PES packets) before inserting PAT/PMT\n"
"\t-prog=filename specifies an input file used for a TS service\n"
"\t * currently only supports ISO files and SDP files\n"
"\t * can be used several times, once for each program\n"
- "\t-audio=url may be mp3/udp or aac/http (shoutcast/icecast)\n"
- "\t-video=url shall be a raw h264 frame\n"
- "\t-src=filename update file: must be either an .sdp or a .bt file\n\n"
+ "\t-nb-pack=N specifies to pack N TS packets together before sending on network or writing to file\n"
+ "\t-ttl=N specifies Time-To-Live for multicast. Default is 1.\n"
+ "\t-ifce=IPIFCE specifies default IP interface to use. Default is IF_ANY.\n"
+ "\t-temi[=URL] Inserts TEMI time codes in adaptation field. URL is optionnal\n"
+ "\t-temi-delay=DelayMS Specifies delay between two TEMI url descriptors\n"
+
"\tDST : Destinations, at least one is mandatory\n"
"\t -dst-udp UDP_address:port (multicast or unicast)\n"
"\t -dst-rtp RTP_address:port\n"
@@ -98,6 +102,10 @@ static GFINLINE void usage(const char * progname)
"\t-4over2 same as -4on2 and uses PMT to carry OD Updates\n"
"\t-bifs-pes carries BIFS over PES instead of sections\n"
"\t-bifs-pes-ex carries BIFS over PES without writing timestamps in SL\n"
+ "\tMisc options\n"
+ "\t-audio=url may be mp3/udp or aac/http (shoutcast/icecast)\n"
+ "\t-video=url shall be a raw h264 frame\n"
+ "\t-src=filename update file: must be either an .sdp or a .bt file\n\n"
"\t\n"
"\t-logs set log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n"
"\t-h or -help print this screen\n"
@@ -143,12 +151,12 @@ typedef struct
void *dsi_and_rap;
Bool loop;
Bool is_repeat;
- u64 ts_offset;
+ s64 ts_offset;
M2TSProgram *prog;
-#ifndef USE_ISOBMF_REWRITE
- u32 nalu_size;
-#endif
+ const char *temi_url;
+ u32 last_temi_url;
+
} GF_ESIMP4;
typedef struct
@@ -188,8 +196,91 @@ enum
#endif
};
+static u32 format_af_descriptor(char *af_data, u64 timecode, u32 timescale, u64 ntp, const char *temi_url, u32 *last_url_time)
+{
+ u32 res;
+ u32 len;
+ u32 last_time;
+ GF_BitStream *bs = gf_bs_new(af_data, 188, GF_BITSTREAM_WRITE);
+
+ if (ntp) {
+ last_time = 1000*(ntp>>32);
+ last_time += 1000*(ntp&0xFFFFFFFF)/0xFFFFFFFF;
+ } else {
+ last_time = (u32) (1000*timecode/timescale);
+ }
+ if (!*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, 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
+
+ if (strlen(temi_url)) {
+ char *url = (char *)temi_url;
+ if (!strnicmp(temi_url, "http://", 7)) {
+ gf_bs_write_int(bs, 1, 8); //url_scheme
+ url = (char *) temi_url + 7;
+ } else if (!strnicmp(temi_url, "https://", 8)) {
+ gf_bs_write_int(bs, 2, 8); //url_scheme
+ url = (char *) temi_url + 8;
+ } else {
+ gf_bs_write_int(bs, 0, 8); //url_scheme
+ }
+ gf_bs_write_u8(bs, (u32) strlen(url)); //url_path_len
+ gf_bs_write_data(bs, url, (u32) strlen(url) ); //url
+ gf_bs_write_u8(bs, 0); //nb_addons
+ }
+ //rewrite len
+ len = (u32) gf_bs_get_position(bs) - 2;
+ af_data[1] = len;
+ }
+
+ if (timescale || ntp) {
+ len = 3; //3 bytes flags
+
+ if (timescale) len += 4 + (timecode > 0xFFFFFFFFUL) ? 8 : 4;
+ if (ntp) len += 8;
+
+ //write timeline descriptor
+ gf_bs_write_int(bs, 0x01, 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, ntp ? 1 : 0, 1); //has_ntp
+ gf_bs_write_int(bs, 0, 1); //has_ptp
+ gf_bs_write_int(bs, 0, 2); //has_timecode
+ gf_bs_write_int(bs, 0, 1); //force_reload
+ 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
+ if (timescale) {
+ gf_bs_write_u32(bs, timescale); //timescale
+ if (timecode > 0xFFFFFFUL)
+ gf_bs_write_u64(bs, timecode); //timestamp
+ else
+ gf_bs_write_u32(bs, (u32) timecode); //timestamp
+ }
+ if (ntp) {
+ gf_bs_write_u64(bs, ntp); //ntp
+ }
+ }
+ res = (u32) gf_bs_get_position(bs);
+ gf_bs_del(bs);
+ return res;
+}
+
static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param)
{
+ char af_data[188];
GF_ESIMP4 *priv = (GF_ESIMP4 *)ifce->input_udta;
if (!priv) return GF_BAD_PARAM;
@@ -204,12 +295,18 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param)
return GF_IO_ERR;
}
- pck.flags = 0;
+ memset(&pck, 0, sizeof(GF_ESIPacket));
+
pck.flags = GF_ESI_DATA_AU_START | GF_ESI_DATA_HAS_CTS;
if (priv->sample->IsRAP) pck.flags |= GF_ESI_DATA_AU_RAP;
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);
+ pck.mpeg2_af_descriptors = af_data;
+ }
+
if (priv->nb_repeat_last) {
pck.cts += priv->nb_repeat_last*ifce->timescale * priv->image_repeat_ms / 1000;
}
@@ -220,81 +317,19 @@ static GF_Err mp4_input_ctrl(GF_ESInterface *ifce, u32 act_type, void *param)
pck.flags |= GF_ESI_DATA_HAS_DTS;
}
-#ifndef USE_ISOBMF_REWRITE
- if (priv->nalu_size) {
- Bool nalu_delim_sent = 0;
- u32 remain = priv->sample->dataLength;
- char *ptr = priv->sample->data;
- u32 v, size;
- char sc[10];
-
-
- /*send nalus*/
- sc[0] = sc[1] = sc[2] = 0; sc[3] = 1;
- while (remain) {
- size = 0;
- v = priv->nalu_size;
- while (v) {
- size |= (u8) *ptr;
- ptr++;
- remain--;
- v-=1;
- if (v) size<<=8;
- }
- remain -= size;
-
- if (!nalu_delim_sent) {
- nalu_delim_sent = 1;
- /*send a NALU delim: copy over NAL ref idc*/
- sc[4] = (ptr[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT;
- sc[5] = 0xF0 /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
-
- pck.data = sc;
- pck.data_len = 6;
- ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
- pck.flags &= ~GF_ESI_DATA_AU_START;
-
- /*and send SPD / PPS if RAP - it is not clear in the specs whether SPS/PPS should be inserted after
- the AU delimiter NALU*/
- if (priv->sample->IsRAP && priv->dsi && priv->dsi_size) {
- pck.data = priv->dsi;
- pck.data_len = priv->dsi_size;
- ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
- pck.flags &= ~GF_ESI_DATA_AU_START;
- }
- }
-
- pck.data = sc;
- pck.data_len = 4;
- ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
-
- if (!remain) pck.flags |= GF_ESI_DATA_AU_END;
- pck.flags &= ~GF_ESI_DATA_AU_START;
-
- pck.data = ptr;
- pck.data_len = size;
- ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
- ptr += size;
- }
-
- } else
-#endif //USE_ISOBMF_REWRITE
-
- {
-
- if (priv->sample->IsRAP && priv->dsi && priv->dsi_size) {
- pck.data = priv->dsi;
- pck.data_len = priv->dsi_size;
- ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
- pck.flags &= ~GF_ESI_DATA_AU_START;
- }
-
- pck.flags |= GF_ESI_DATA_AU_END;
- pck.data = priv->sample->data;
- pck.data_len = priv->sample->dataLength;
+ if (priv->sample->IsRAP && priv->dsi && priv->dsi_size) {
+ pck.data = priv->dsi;
+ pck.data_len = priv->dsi_size;
ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
+ pck.flags &= ~GF_ESI_DATA_AU_START;
}
+ pck.flags |= GF_ESI_DATA_AU_END;
+ pck.data = priv->sample->data;
+ pck.data_len = priv->sample->dataLength;
+ ifce->output_ctrl(ifce, GF_ESI_OUTPUT_DATA_DISPATCH, &pck);
+ GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS Muxer] Track %d: sample %d CTS %d\n", priv->track, priv->sample_number+1, pck.cts));
+
gf_isom_sample_del(&priv->sample);
priv->sample_number++;
@@ -350,8 +385,10 @@ static void fill_isom_es_ifce(M2TSProgram *prog, GF_ESInterface *ifce, GF_ISOFil
{
GF_ESIMP4 *priv;
char _lan[4];
- GF_DecoderConfig *dcd;
+ GF_ESD *esd;
u64 avg_rate, duration;
+ s32 ref_count;
+ s64 mediaOffset;
GF_SAFEALLOC(priv, GF_ESIMP4);
@@ -366,62 +403,38 @@ static void fill_isom_es_ifce(M2TSProgram *prog, GF_ESInterface *ifce, GF_ISOFil
priv->prog = prog;
memset(ifce, 0, sizeof(GF_ESInterface));
ifce->stream_id = gf_isom_get_track_id(mp4, track_num);
- dcd = gf_isom_get_decoder_config(mp4, track_num, 1);
- ifce->stream_type = dcd->streamType;
- ifce->object_type_indication = dcd->objectTypeIndication;
- if (dcd->decoderSpecificInfo && dcd->decoderSpecificInfo->dataLength) {
- switch (dcd->objectTypeIndication) {
- case GPAC_OTI_AUDIO_AAC_MPEG4:
- case GPAC_OTI_AUDIO_AAC_MPEG2_MP:
- case GPAC_OTI_AUDIO_AAC_MPEG2_LCP:
- case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP:
- ifce->decoder_config = gf_malloc(sizeof(char)*dcd->decoderSpecificInfo->dataLength);
- ifce->decoder_config_size = dcd->decoderSpecificInfo->dataLength;
- memcpy(ifce->decoder_config, dcd->decoderSpecificInfo->data, dcd->decoderSpecificInfo->dataLength);
- break;
- case GPAC_OTI_VIDEO_MPEG4_PART2:
- priv->dsi = gf_malloc(sizeof(char)*dcd->decoderSpecificInfo->dataLength);
- priv->dsi_size = dcd->decoderSpecificInfo->dataLength;
- memcpy(priv->dsi, dcd->decoderSpecificInfo->data, dcd->decoderSpecificInfo->dataLength);
- break;
- case GPAC_OTI_VIDEO_HEVC:
- gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG);
- break;
- case GPAC_OTI_VIDEO_AVC:
- {
-#ifdef USE_ISOBMF_REWRITE
- gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG);
-
-#elif !defined(GPAC_DISABLE_AV_PARSERS)
- GF_AVCConfigSlot *slc;
- u32 i;
- GF_BitStream *bs;
- GF_AVCConfig *avccfg = gf_isom_avc_config_get(mp4, track_num, 1);
- priv->nalu_size = avccfg->nal_unit_size;
-
- bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
- for (i=0; isequenceParameterSets);i++) {
- slc = gf_list_get(avccfg->sequenceParameterSets, i);
- gf_bs_write_u32(bs, 1);
- gf_bs_write_data(bs, slc->data, slc->size);
- }
- for (i=0; ipictureParameterSets);i++) {
- slc = gf_list_get(avccfg->pictureParameterSets, i);
- gf_bs_write_u32(bs, 1);
- gf_bs_write_data(bs, slc->data, slc->size);
- }
- gf_bs_get_content(bs, (char **) &priv->dsi, &priv->dsi_size);
- gf_bs_del(bs);
- gf_odf_avc_cfg_del(avccfg);
-#endif
+ esd = gf_media_map_esd(mp4, track_num);
+
+ if (esd) {
+ ifce->stream_type = esd->decoderConfig->streamType;
+ ifce->object_type_indication = esd->decoderConfig->objectTypeIndication;
+ if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->dataLength) {
+ switch (esd->decoderConfig->objectTypeIndication) {
+ case GPAC_OTI_AUDIO_AAC_MPEG4:
+ case GPAC_OTI_AUDIO_AAC_MPEG2_MP:
+ case GPAC_OTI_AUDIO_AAC_MPEG2_LCP:
+ case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP:
+ case GPAC_OTI_VIDEO_MPEG4_PART2:
+ ifce->decoder_config = gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength);
+ ifce->decoder_config_size = esd->decoderConfig->decoderSpecificInfo->dataLength;
+ memcpy(ifce->decoder_config, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
+ break;
+ case GPAC_OTI_VIDEO_HEVC:
+ case GPAC_OTI_VIDEO_SHVC:
+ case GPAC_OTI_VIDEO_AVC:
+ case GPAC_OTI_VIDEO_SVC:
+ gf_isom_set_nalu_extract_mode(mp4, track_num, GF_ISOM_NALU_EXTRACT_LAYER_ONLY | GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG | GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG | GF_ISOM_NALU_EXTRACT_VDRD_FLAG);
+ break;
+ }
}
- break;
- }
+ gf_odf_desc_del((GF_Descriptor *)esd);
}
- gf_odf_desc_del((GF_Descriptor *)dcd);
gf_isom_get_media_language(mp4, track_num, _lan);
- ifce->lang = GF_4CC(_lan[0],_lan[1],_lan[2],' ');
+ if (!strcmp(_lan, "und"))
+ ifce->lang = 0;
+ else
+ ifce->lang = GF_4CC(_lan[0],_lan[1],_lan[2],' ');
ifce->timescale = gf_isom_get_media_timescale(mp4, track_num);
ifce->duration = gf_isom_get_media_timescale(mp4, track_num);
@@ -464,6 +477,19 @@ static void fill_isom_es_ifce(M2TSProgram *prog, GF_ESInterface *ifce, GF_ISOFil
gf_free(ifce->input_udta);
ifce->input_udta = priv;
}
+
+
+ if (! gf_isom_get_edit_list_type(mp4, track_num, &mediaOffset)) {
+ priv->ts_offset = mediaOffset;
+ }
+
+ ref_count = gf_isom_get_reference_count(mp4, track_num, GF_ISOM_REF_SCAL);
+ if (ref_count > 0) {
+ gf_isom_get_reference_ID(mp4, track_num, GF_ISOM_REF_SCAL, (u32) ref_count, &ifce->depends_on_stream);
+ }
+ else {
+ ifce->depends_on_stream = 0;
+ }
}
@@ -727,6 +753,7 @@ static void fill_rtp_es_ifce(GF_ESInterface *ifce, GF_SDPMedia *media, GF_SDPInf
rtp->cat_dsi = 1;
break;
case GPAC_OTI_VIDEO_AVC:
+ case GPAC_OTI_VIDEO_SVC:
rtp->is_264 = 1;
rtp->depacketizer->flags |= GF_RTP_AVC_USE_ANNEX_B;
{
@@ -1020,7 +1047,7 @@ static GF_ESIStream * set_broadcast_params(M2TSProgram *prog, u16 esid, u32 peri
#ifndef GPAC_DISABLE_SENG
-static Bool seng_output(void *param)
+static u32 seng_output(void *param)
{
GF_Err e;
u64 last_src_modif, mod_time;
@@ -1230,12 +1257,13 @@ void fill_seng_es_ifce(GF_ESInterface *ifce, u32 i, GF_SceneEngine *seng, u32 pe
}
#endif
-static Bool open_program(M2TSProgram *prog, 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)
+static Bool open_program(M2TSProgram *prog, 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)
{
#ifndef GPAC_DISABLE_STREAMING
GF_SDPInfo *sdp;
#endif
u32 i;
+ s64 min_offset = 0;
memset(prog, 0, sizeof(M2TSProgram));
prog->mpeg4_signaling = mpeg4_signaling;
@@ -1259,6 +1287,8 @@ static Bool open_program(M2TSProgram *prog, char *src, u32 carousel_rate, u32 mp
continue;
fill_isom_es_ifce(prog, &prog->streams[i], prog->mp4, i+1, bifs_use_pes);
+ if (min_offset > ((GF_ESIMP4 *)prog->streams[i].input_udta)->ts_offset)
+ min_offset = ((GF_ESIMP4 *)prog->streams[i].input_udta)->ts_offset;
switch(prog->streams[i].stream_type) {
case GF_STREAM_OD:
@@ -1280,7 +1310,10 @@ static Bool open_program(M2TSProgram *prog, char *src, u32 carousel_rate, u32 mp
check_deps = 1;
if (gf_isom_get_sample_count(prog->mp4, i+1)>1) {
/*get first visual stream as PCR*/
- if (!prog->pcr_idx) prog->pcr_idx = i+1;
+ if (!prog->pcr_idx) {
+ prog->pcr_idx = i+1;
+ ((GF_ESIMP4 *)prog->streams[i].input_udta)->temi_url = temi_url;
+ }
}
break;
}
@@ -1326,6 +1359,12 @@ static Bool open_program(M2TSProgram *prog, char *src, u32 carousel_rate, u32 mp
gf_isom_set_default_sync_track(prog->mp4, priv->track);
}
+ if (min_offset < 0) {
+ for (i=0; inb_streams; i++) {
+ ((GF_ESIMP4 *)prog->streams[i].input_udta)->ts_offset += -min_offset;
+ }
+ }
+
prog->iod = gf_isom_get_root_od(prog->mp4);
if (prog->iod) {
GF_ObjectDescriptor*iod = (GF_ObjectDescriptor*)prog->iod;
@@ -1402,7 +1441,7 @@ static Bool open_program(M2TSProgram *prog, char *src, u32 carousel_rate, u32 mp
gf_f64_seek(_sdp, 0, SEEK_SET);
sdp_buf = (char*)gf_malloc(sizeof(char)*sdp_size);
memset(sdp_buf, 0, sizeof(char)*sdp_size);
- sdp_size = fread(sdp_buf, 1, sdp_size, _sdp);
+ sdp_size = (u32) fread(sdp_buf, 1, sdp_size, _sdp);
fclose(_sdp);
sdp = gf_sdp_info_new();
@@ -1428,7 +1467,7 @@ static Bool open_program(M2TSProgram *prog, char *src, u32 carousel_rate, u32 mp
buf64 = strstr(iod_str, ",");
if (!buf64) break;
buf64 += 1;
- size64 = strlen(buf64) - 1;
+ size64 = (u32) strlen(buf64) - 1;
size = gf_base64_decode(buf64, size64, buf, 2000);
gf_odf_desc_read(buf, size, &prog->iod);
@@ -1619,7 +1658,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car
Bool *real_time, u32 *run_time, char **video_buffer, u32 *video_buffer_size,
u32 *audio_input_type, char **audio_input_ip, u16 *audio_input_port,
u32 *output_type, char **ts_out, char **udp_out, char **rtp_out, u16 *output_port,
- char** segment_dir, u32 *segment_duration, char **segment_manifest, u32 *segment_number, char **segment_http_prefix, Bool *split_rap)
+ char** segment_dir, u32 *segment_duration, char **segment_manifest, u32 *segment_number, char **segment_http_prefix, u32 *split_rap, u32 *nb_pck_pack, u32 *ttl, const char **ip_ifce, const char **temi_url)
{
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;
@@ -1661,9 +1700,9 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car
assert(*video_buffer_size);
*video_buffer = (char*) gf_malloc(*video_buffer_size);
{
- s32 readen = fread(*video_buffer, sizeof(char), *video_buffer_size, f);
- if (readen != *video_buffer_size)
- fprintf(stderr, "Error while reading video file, has readen %u chars instead of %u.\n", readen, *video_buffer_size);
+ s32 read = (u32) fread(*video_buffer, sizeof(char), *video_buffer_size, f);
+ 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);
} else if (!strnicmp(arg, "-audio=", 7)) {
@@ -1724,8 +1763,8 @@ 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();
- gf_sys_init(1);
- gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_DEBUG);
+ gf_sys_init(GF_TRUE);
+ gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO);
#else
fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
#endif
@@ -1736,7 +1775,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car
goto error;
}
rate_found = 1;
- *mux_rate = 1024*atoi(arg+6);
+ *mux_rate = 1000*atoi(arg+6);
} else if (!strnicmp(arg, "-mpeg4-carousel=", 16)) {
if (mpeg4_carousel_found) {
error_msg = "multiple '-mpeg4-carousel' found";
@@ -1763,6 +1802,13 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car
*single_au_pes = 1;
} else if (!stricmp(arg, "-rap")) {
*split_rap = 1;
+ } else if (!stricmp(arg, "-flush-rap")) {
+ *split_rap = 2;
+ }
+ else if (!strnicmp(arg, "-dst-udp=", 9)) {
+ *real_time = 1;
+ } else if (!strnicmp(arg, "-dst-rtp=", 9)) {
+ *real_time = 1;
}
}
if (*real_time) force_real_time = 1;
@@ -1778,7 +1824,7 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car
} else if (!strnicmp(arg, "-prog=", 6)) {
u32 res;
prog_name = arg+6;
- res = open_program(&progs[*nb_progs], prog_name, *carrousel_rate, mpeg4_signaling, *src_name, *audio_input_ip, *audio_input_port, *video_buffer, force_real_time, *bifs_use_pes);
+ res = open_program(&progs[*nb_progs], prog_name, *carrousel_rate, mpeg4_signaling, *src_name, *audio_input_ip, *audio_input_port, *video_buffer, force_real_time, *bifs_use_pes, *temi_url);
if (res) {
(*nb_progs)++;
if (res==2) *real_time=1;
@@ -1824,9 +1870,27 @@ static GFINLINE GF_Err parse_args(int argc, char **argv, u32 *mux_rate, u32 *car
src_found = 1;
*src_name = arg+5;
}
- else if (!strnicmp(arg, "-dst-file=", 10)) {
+ else if (!strnicmp(arg, "-nb-pack=", 9)) {
+ *nb_pck_pack = atoi(arg+9);
+ } else if (!strnicmp(arg, "-ttl=", 5)) {
+ *ttl = atoi(arg+5);
+ } else if (!strnicmp(arg, "-ifce=", 6)) {
+ *ip_ifce = arg+6;
+ } else if (!strnicmp(arg, "-dst-file=", 10)) {
dst_found = 1;
*ts_out = gf_strdup(arg+10);
+ } else if (!strnicmp(arg, "-temi", 5)) {
+ *temi_url = "";
+ if (arg[5]=='=') {
+ *temi_url = arg+6;
+ if (strlen(arg+6) > 150) {
+ fprintf(stderr, "URLs longer than 150 bytes are not currently supported\n");
+ return GF_NOT_SUPPORTED;
+ }
+ }
+ }
+ else if (!strnicmp(arg, "-temi-delay=", 12)) {
+ temi_url_insertion_delay = atoi(arg+12);
}
else if (!strnicmp(arg, "-dst-udp=", 9)) {
char *sep = strchr(arg+9, ':');
@@ -1964,11 +2028,13 @@ int main(int argc, char **argv)
/* declarations */
/********************/
const char *ts_pck;
+ char *ts_pack_buffer = NULL;
GF_Err e;
u32 run_time;
- Bool real_time, single_au_pes, split_rap;
+ Bool real_time, single_au_pes, is_stdout;
u64 pcr_init_val=0;
- u32 i, j, mux_rate, nb_progs, cur_pid, carrousel_rate, last_print_time, last_video_time, bifs_use_pes, psi_refresh_rate;
+ u32 usec_till_next, ttl, split_rap;
+ u32 i, j, mux_rate, nb_progs, cur_pid, carrousel_rate, last_print_time, last_video_time, bifs_use_pes, psi_refresh_rate, nb_pck_pack, nb_pck_in_pack;
char *ts_out = NULL, *udp_out = NULL, *rtp_out = NULL, *audio_input_ip = NULL;
FILE *ts_output_file = NULL;
GF_Socket *ts_output_udp_sk = NULL, *audio_input_udp_sk = NULL;
@@ -1984,25 +2050,28 @@ int main(int argc, char **argv)
char *audio_input_buffer = NULL;
u32 audio_input_buffer_length=65536;
char *src_name;
+ const char *insert_temi = 0;
M2TSProgram progs[MAX_MUX_SRC_PROG];
u32 segment_duration, segment_index, segment_number;
char segment_manifest_default[GF_MAX_PATH];
char *segment_manifest, *segment_http_prefix, *segment_dir;
char segment_prefix[GF_MAX_PATH];
char segment_name[GF_MAX_PATH];
+ const char *ip_ifce = NULL;
GF_M2TS_Time prev_seg_time;
GF_M2TS_Mux *muxer;
/*****************/
/* gpac init */
/*****************/
- gf_sys_init(0);
+ gf_sys_init(GF_FALSE);
gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);
/***********************/
/* initialisations */
/***********************/
real_time = 0;
+ is_stdout = 0;
ts_output_file = NULL;
video_buffer = NULL;
last_video_time = 0;
@@ -2029,6 +2098,7 @@ int main(int argc, char **argv)
prev_seg_time.sec = 0;
prev_seg_time.nanosec = 0;
video_buffer_size = 0;
+ nb_pck_pack = 1;
#ifndef GPAC_DISABLE_PLAYER
aac_reader = AAC_Reader_new();
#endif
@@ -2036,6 +2106,7 @@ int main(int argc, char **argv)
single_au_pes = 0;
bifs_use_pes = 0;
split_rap = 0;
+ ttl = 1;
psi_refresh_rate = GF_M2TS_PSI_DEFAULT_REFRESH_RATE;
pcr_offset = DEFAULT_PCR_OFFSET;
@@ -2046,7 +2117,7 @@ int main(int argc, char **argv)
&real_time, &run_time, &video_buffer, &video_buffer_size,
&audio_input_type, &audio_input_ip, &audio_input_port,
&output_type, &ts_out, &udp_out, &rtp_out, &output_port,
- &segment_dir, &segment_duration, &segment_manifest, &segment_number, &segment_http_prefix, &split_rap)) {
+ &segment_dir, &segment_duration, &segment_manifest, &segment_number, &segment_http_prefix, &split_rap, &nb_pck_pack, &ttl, &ip_ifce, &insert_temi)) {
goto exit;
}
@@ -2084,7 +2155,13 @@ 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");
+ if (!strcmp(ts_out, "stdout") || !strcmp(ts_out, "-") ) {
+ ts_output_file = stdout;
+ is_stdout = GF_TRUE;
+ } else {
+ ts_output_file = fopen(ts_out, "wb");
+ is_stdout = GF_FALSE;
+ }
if (!ts_output_file) {
fprintf(stderr, "Error opening %s\n", ts_out);
goto exit;
@@ -2093,9 +2170,9 @@ int main(int argc, char **argv)
if (udp_out != NULL) {
ts_output_udp_sk = gf_sk_new(GF_SOCK_TYPE_UDP);
if (gf_sk_is_multicast_address((char *)udp_out)) {
- e = gf_sk_setup_multicast(ts_output_udp_sk, (char *)udp_out, output_port, 32, 0, NULL);
+ e = gf_sk_setup_multicast(ts_output_udp_sk, (char *)udp_out, output_port, ttl, 0, (char *) ip_ifce);
} else {
- e = gf_sk_bind(ts_output_udp_sk, NULL, output_port, (char *)udp_out, output_port, GF_SOCK_REUSE_PORT);
+ e = gf_sk_bind(ts_output_udp_sk, ip_ifce, output_port, (char *)udp_out, output_port, GF_SOCK_REUSE_PORT);
}
if (e) {
fprintf(stderr, "Error initializing UDP socket: %s\n", gf_error_to_string(e));
@@ -2121,13 +2198,14 @@ int main(int argc, char **argv)
tr.client_port_last = output_port+1;
} else {
tr.source = (char *)rtp_out;
+ tr.TTL = ttl;
}
e = gf_rtp_setup_transport(ts_output_rtp, &tr, (char *)ts_out);
if (e != GF_OK) {
fprintf(stderr, "Cannot setup RTP transport info : %s\n", gf_error_to_string(e));
goto exit;
}
- e = gf_rtp_initialize(ts_output_rtp, 0, 1, 1500, 0, 0, NULL);
+ e = gf_rtp_initialize(ts_output_rtp, 0, 1, 1500, 0, 0, (char *) ip_ifce);
if (e != GF_OK) {
fprintf(stderr, "Cannot initialize RTP sockets : %s\n", gf_error_to_string(e));
goto exit;
@@ -2212,8 +2290,13 @@ int main(int argc, char **argv)
while (cur_pid % 10)
cur_pid ++;
}
+ muxer->flush_pes_at_rap = (split_rap == 2) ? GF_TRUE : GF_FALSE;
gf_m2ts_mux_update_config(muxer, 1);
+
+ if (nb_pck_pack>1) {
+ ts_pack_buffer = gf_malloc(sizeof(char) * 188 * nb_pck_pack);
+ }
/*****************/
/* main loop */
@@ -2256,9 +2339,24 @@ int main(int argc, char **argv)
}
/*flush all packets*/
- while ((ts_pck = gf_m2ts_mux_process(muxer, &status)) != NULL) {
+ nb_pck_in_pack=0;
+ while ((ts_pck = gf_m2ts_mux_process(muxer, &status, &usec_till_next)) != NULL) {
+
+ if (ts_pack_buffer ) {
+ memcpy(ts_pack_buffer + 188 * nb_pck_in_pack, ts_pck, 188);
+ nb_pck_in_pack++;
+
+ if (nb_pck_in_pack < nb_pck_pack)
+ continue;
+
+ ts_pck = (const char *) ts_pack_buffer;
+ } else {
+ nb_pck_in_pack = 1;
+ }
+
+call_flush:
if (ts_output_file != NULL) {
- gf_fwrite(ts_pck, 1, 188, ts_output_file);
+ 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);
@@ -2298,7 +2396,7 @@ int main(int argc, char **argv)
}
if (ts_output_udp_sk != NULL) {
- e = gf_sk_send(ts_output_udp_sk, (char*)ts_pck, 188);
+ e = gf_sk_send(ts_output_udp_sk, (char*)ts_pck, 188 * nb_pck_in_pack);
if (e) {
fprintf(stderr, "Error %s sending UDP packet\n", gf_error_to_string(e));
}
@@ -2312,16 +2410,23 @@ int main(int argc, char **argv)
/*FIXME - better discontinuity check*/
hdr.Marker = (ts < hdr.TimeStamp) ? 1 : 0;
hdr.TimeStamp = ts;
- e = gf_rtp_send_packet(ts_output_rtp, &hdr, (char*)ts_pck, 188, 0);
+ e = gf_rtp_send_packet(ts_output_rtp, &hdr, (char*)ts_pck, 188 * nb_pck_in_pack, 0);
if (e) {
fprintf(stderr, "Error %s sending RTP packet\n", gf_error_to_string(e));
}
}
#endif
+
+ nb_pck_in_pack = 0;
+
if (status>=GF_M2TS_STATE_PADDING) {
break;
}
}
+ if (nb_pck_in_pack) {
+ ts_pck = (const char *) ts_pack_buffer;
+ goto call_flush;
+ }
/*push video*/
{
@@ -2335,14 +2440,30 @@ int main(int argc, char **argv)
}
if (real_time) {
- /*refresh every MP42TS_PRINT_FREQ ms*/
+ /*refresh every MP42TS_PRINT_TIME_MS ms*/
u32 now=gf_sys_clock();
- if (now/MP42TS_PRINT_FREQ != last_print_time/MP42TS_PRINT_FREQ) {
+ 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->avg_br);
+ 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);
+
+ if (gf_prompt_has_input()) {
+ char c = gf_prompt_get_char();
+ if (c=='q') break;
+ }
+ }
+ if (status == GF_M2TS_STATE_IDLE) {
+#if 0
+ /*wait till next packet is ready to be sent*/
+ if (usec_till_next>1000) {
+ //fprintf(stderr, "%d usec till next packet\n", usec_till_next);
+ gf_sleep(usec_till_next / 1000);
+ }
+#else
+ //we don't have enough precision on usec counting and we end up eating one core on most machines, so let's just sleep
+ //one second whenever we are idle - it's maybe too much but the muxer will catchup afterwards
+ gf_sleep(1);
+#endif
}
- /*cpu load regulation*/
- gf_sleep(1);
}
@@ -2365,11 +2486,12 @@ int main(int argc, char **argv)
}
exit:
+ if (ts_pack_buffer) gf_free(ts_pack_buffer);
run = 0;
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) fclose(ts_output_file);
+ if (ts_output_file && !is_stdout) 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);
@@ -2381,9 +2503,6 @@ exit:
if (udp_out) gf_free(udp_out);
#ifndef GPAC_DISABLE_STREAMING
if (rtp_out) gf_free(rtp_out);
-#endif
-#ifndef GPAC_DISABLE_PLAYER
- if (aac_reader) AAC_Reader_del(aac_reader);
#endif
if (muxer) gf_m2ts_mux_del(muxer);
@@ -2410,7 +2529,12 @@ exit:
#endif
if (progs[i].th) gf_th_del(progs[i].th);
}
+
+#ifndef GPAC_DISABLE_PLAYER
+ if (aac_reader) AAC_Reader_del(aac_reader);
+#endif
+
gf_sys_close();
- return 1;
+ return 0;
}
diff --git a/applications/mp4box/Makefile b/applications/mp4box/Makefile
index a248ab4..320acab 100644
--- a/applications/mp4box/Makefile
+++ b/applications/mp4box/Makefile
@@ -26,7 +26,10 @@ ifeq ($(CONFIG_WIN32),yes)
EXE=.exe
PROG=MP4Box$(EXE)
ifeq ($(MP4BOX_STATIC),yes)
-LINKFLAGS+=-lgpac_static -lz $(EXTRALIBS)
+ifneq ($(CONFIG_ZLIB),no)
+LINKFLAGS+=-lz
+endif
+LINKFLAGS+=-lgpac_static $(EXTRALIBS)
else
LINKFLAGS+=-lgpac
endif
@@ -36,7 +39,10 @@ else
EXT=
PROG=MP4Box
ifeq ($(MP4BOX_STATIC),yes)
-LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS) -lz
+ifneq ($(CONFIG_ZLIB),no)
+LINKFLAGS+=-lz
+endif
+LINKFLAGS+=-lgpac_static $(EXTRALIBS) $(GPAC_SH_FLAGS)
# spidermonkey support
ifeq ($(CONFIG_JS),no)
@@ -74,10 +80,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/mp4box/filedump.c b/applications/mp4box/filedump.c
index 3971e03..e2d228d 100644
--- a/applications/mp4box/filedump.c
+++ b/applications/mp4box/filedump.c
@@ -52,6 +52,7 @@
#ifndef GPAC_DISABLE_SMGR
#include
#endif
+#include
extern u32 swf_flags;
extern Float swf_flatten_angle;
@@ -92,7 +93,7 @@ const char *GetLanguageCode(char *lang)
{
u32 i;
Bool check_2cc = 0;
- i = strlen(lang);
+ i = (u32) strlen(lang);
if (i==3) return lang;
if (i==2) check_2cc = 1;
@@ -144,7 +145,7 @@ GF_Err set_cover_art(GF_ISOFile *file, char *inName)
tag_len = (u32) gf_f64_tell(t);
gf_f64_seek(t, 0, SEEK_SET);
tag = gf_malloc(sizeof(char) * tag_len);
- tag_len = fread(tag, sizeof(char), tag_len, t);
+ tag_len = (u32) fread(tag, sizeof(char), tag_len, t);
fclose(t);
ext = strrchr(inName, '.');
@@ -873,14 +874,17 @@ void dump_file_timestamps(GF_ISOFile *file, char *inName)
}
-static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_hevc)
+#ifndef GPAC_DISABLE_AV_PARSERS
+static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_hevc, AVCState *avc)
{
u8 type;
u8 dependency_id, quality_id, temporal_id;
u8 track_ref_index;
- u32 data_offset, sps_id, pps_id;
+ u32 data_offset, idx;
+ GF_BitStream *bs;
if (is_hevc) {
+#ifndef GPAC_DISABLE_HEVC
type = (ptr[0] & 0x7E) >> 1;
fprintf(dump, "code=\"%d\" type=\"", type);
switch (type) {
@@ -910,31 +914,53 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_
case GF_HEVC_NALU_FILLER_DATA: fputs("Filler Data", dump); break;
case GF_HEVC_NALU_SEI_PREFIX: fputs("SEI Prefix", dump); break;
case GF_HEVC_NALU_SEI_SUFFIX: fputs("SEI Suffix", dump); break;
+ case 48:
+ fputs("HEVCAggregator", dump);
+ break;
+ case 49:
+ fputs("HEVCExtractor", dump);
+ track_ref_index = (u8) ptr[4];
+ data_offset = (ptr[6] << 12) + (ptr[7] << 8) + (ptr[8] << 4) + ptr[9];
+ fprintf(dump, "\" track_ref_index=\"%d\" data_offset=\"%d", track_ref_index, data_offset);
+ break;
default:
fputs("UNKNOWN", dump); break;
}
fputs("\"", dump);
+ fprintf(dump, " layer_id=\"%d\" temporal_id=\"%d\"", ((ptr[0] & 0x1) << 5) | (ptr[1]>>3), (ptr[1] & 0x7) );
+#endif //GPAC_DISABLE_HEVC
return;
}
+ bs = gf_bs_new(ptr, ptr_size, GF_BITSTREAM_READ);
type = ptr[0] & 0x1F;
fprintf(dump, "code=\"%d\" type=\"", type);
switch (type) {
- case GF_AVC_NALU_NON_IDR_SLICE: fputs("Non IDR slice", dump); break;
+ case GF_AVC_NALU_NON_IDR_SLICE:
+ gf_media_avc_parse_nalu(bs, ptr[0], avc);
+ fputs("Non IDR slice", dump);
+ fprintf(dump, "\" poc=\"%d", avc->s_info.poc);
+ break;
case GF_AVC_NALU_DP_A_SLICE: fputs("DP Type A slice", dump); break;
case GF_AVC_NALU_DP_B_SLICE: fputs("DP Type B slice", dump); break;
case GF_AVC_NALU_DP_C_SLICE: fputs("DP Type C slice", dump); break;
- case GF_AVC_NALU_IDR_SLICE: fputs("IDR slice", dump); break;
+ case GF_AVC_NALU_IDR_SLICE:
+ gf_media_avc_parse_nalu(bs, ptr[0], avc);
+ fputs("IDR slice", dump);
+ fprintf(dump, "\" poc=\"%d", avc->s_info.poc);
+ break;
case GF_AVC_NALU_SEI: fputs("SEI Message", dump); break;
case GF_AVC_NALU_SEQ_PARAM:
- fputs("SequenceParameterSet", dump);
- gf_avc_get_sps_info(ptr, ptr_size, &sps_id, NULL, NULL, NULL, NULL);
- fprintf(dump, "\" sps_id=\"%d", sps_id);
+ fputs("SequenceParameterSet", dump);
+ idx = gf_media_avc_read_sps(ptr, ptr_size, avc, 0, NULL);
+ assert (idx >= 0);
+ fprintf(dump, "\" sps_id=\"%d", idx);
break;
case GF_AVC_NALU_PIC_PARAM:
fputs("PictureParameterSet", dump);
- gf_avc_get_pps_info(ptr, ptr_size, &pps_id, &sps_id);
- fprintf(dump, "\" pps_id=\"%d\" sps_id=\"%d", pps_id, sps_id);
+ idx = gf_media_avc_read_pps(ptr, ptr_size, avc);
+ assert (idx >= 0);
+ fprintf(dump, "\" pps_id=\"%d\" sps_id=\"%d", idx, avc->pps[idx].sps_id);
break;
case GF_AVC_NALU_ACCESS_UNIT: fputs("AccessUnit delimiter", dump); break;
case GF_AVC_NALU_END_OF_SEQ: fputs("EndOfSequence", dump); break;
@@ -944,17 +970,20 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_
case GF_AVC_NALU_SVC_PREFIX_NALU: fputs("SVCPrefix", dump); break;
case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
fputs("SVCSubsequenceParameterSet", dump);
- gf_avc_get_sps_info(ptr, ptr_size, &sps_id, NULL, NULL, NULL, NULL);
- fprintf(dump, "\" sps_id=\"%d", sps_id);
+ idx = gf_media_avc_read_sps(ptr, ptr_size, avc, 1, NULL);
+ assert (idx >= 0);
+ fprintf(dump, "\" sps_id=\"%d", idx - GF_SVC_SSPS_ID_SHIFT);
break;
case GF_AVC_NALU_SLICE_AUX: fputs("Auxiliary Slice", dump); break;
case GF_AVC_NALU_SVC_SLICE:
+ gf_media_avc_parse_nalu(bs, ptr[0], avc);
fputs(is_svc ? "SVCSlice" : "CodedSliceExtension", dump);
dependency_id = (ptr[2] & 0x70) >> 4;
quality_id = (ptr[2] & 0x0F);
temporal_id = (ptr[3] & 0xE0) >> 5;
fprintf(dump, "\" dependency_id=\"%d\" quality_id=\"%d\" temporal_id=\"%d", dependency_id, quality_id, temporal_id);
+ fprintf(dump, "\" poc=\"%d", avc->s_info.poc);
break;
case 30: fputs("SVCAggregator", dump); break;
case 31:
@@ -968,18 +997,23 @@ static void dump_nalu(FILE *dump, char *ptr, u32 ptr_size, Bool is_svc, Bool is_
fputs("UNKNOWN", dump); break;
}
fputs("\"", dump);
+ if (bs) gf_bs_del(bs);
}
+#endif
void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
{
u32 i, count, track, nalh_size, timescale, cur_extract_mode;
- Bool is_hevc = 0;
FILE *dump;
s32 countRef;
#ifndef GPAC_DISABLE_AV_PARSERS
+ Bool is_hevc = 0;
+ AVCState avc;
GF_AVCConfig *avccfg, *svccfg;
- GF_HEVCConfig *hevccfg;
+ GF_HEVCConfig *hevccfg, *shvccfg;
GF_AVCConfigSlot *slc;
+
+ memset(&avc, 0, sizeof(AVCState));
#endif
if (inName) {
@@ -1004,14 +1038,15 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
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);
fprintf(dump, " \n");
#define DUMP_ARRAY(arr, name)\
if (arr) {\
for (i=0; isize);\
- dump_nalu(dump, slc->data, slc->size, svccfg ? 1 : 0, is_hevc);\
+ fprintf(dump, " <%s number=\"%d\" size=\"%d\" ", name, i+1, slc->size);\
+ dump_nalu(dump, slc->data, slc->size, svccfg ? 1 : 0, is_hevc, &avc);\
fprintf(dump, "/>\n");\
}\
}\
@@ -1031,10 +1066,31 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
DUMP_ARRAY(svccfg->pictureParameterSets, "SVCPPSArray")
}
if (hevccfg) {
+#ifndef GPAC_DISABLE_HEVC
+ u32 idx;
nalh_size = hevccfg->nal_unit_size;
is_hevc = 1;
- for (i=0; iparam_array); i++) {
- GF_HEVCParamArray *ar = gf_list_get(hevccfg->param_array, i);
+ for (idx=0; idxparam_array); idx++) {
+ GF_HEVCParamArray *ar = gf_list_get(hevccfg->param_array, idx);
+ if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
+ DUMP_ARRAY(ar->nalus, "HEVCSPSArray")
+ } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
+ DUMP_ARRAY(ar->nalus, "HEVCPPSArray")
+ } else if (ar->type==GF_HEVC_NALU_VID_PARAM) {
+ DUMP_ARRAY(ar->nalus, "HEVCVPSArray")
+ } else {
+ DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray")
+ }
+ }
+#endif
+ }
+ if (shvccfg) {
+#ifndef GPAC_DISABLE_HEVC
+ u32 idx;
+ nalh_size = shvccfg->nal_unit_size;
+ is_hevc = 1;
+ for (idx=0; idxparam_array); idx++) {
+ GF_HEVCParamArray *ar = gf_list_get(shvccfg->param_array, idx);
if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
DUMP_ARRAY(ar->nalus, "HEVCSPSArray")
} else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
@@ -1045,10 +1101,14 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
DUMP_ARRAY(ar->nalus, "HEVCUnknownPSArray")
}
}
+#endif
}
#endif
fprintf(dump, " \n");
+ /*fixme: for dumping encrypted track: we don't have neither avccfg nor svccfg*/
+ if (!nalh_size) nalh_size = 4;
+
/*for testing dependency*/
countRef = gf_isom_get_reference_count(file, track, GF_ISOM_REF_SCAL);
if (countRef > 0)
@@ -1094,7 +1154,9 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
break;
} else {
fprintf(dump, " \n");
}
idx++;
@@ -1111,8 +1173,15 @@ void dump_file_nal(GF_ISOFile *file, u32 trackID, char *inName)
fprintf(dump, "\n");
if (inName) fclose(dump);
+#ifndef GPAC_DISABLE_AV_PARSERS
if (avccfg) gf_odf_avc_cfg_del(avccfg);
if (svccfg) gf_odf_avc_cfg_del(svccfg);
+#ifndef GPAC_DISABLE_HEVC
+ if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
+ if (shvccfg) gf_odf_hevc_cfg_del(shvccfg);
+#endif
+
+#endif
gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
}
@@ -1279,14 +1348,21 @@ static char *format_date(u64 time, char *szTime)
-GF_Err dump_chapters(GF_ISOFile *file, char *inName)
+GF_Err dump_chapters(GF_ISOFile *file, char *inName, Bool dump_ogg)
{
char szName[1024];
FILE *t;
u32 i, count;
count = gf_isom_get_chapter_count(file, 0);
- sprintf(szName, "%s.chap", inName);
- GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Extracting chapters to %s\n", szName));
+ strcpy(szName, inName);
+ if (dump_ogg) {
+ strcat(szName, ".txt");
+ GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Extracting OGG chapters to %s\n", szName));
+ }
+ else {
+ strcat(szName, ".chap");
+ GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Extracting chapters to %s\n", szName));
+ }
t = gf_f64_open(szName, "wt");
if (!t) return GF_IO_ERR;
@@ -1294,9 +1370,15 @@ GF_Err dump_chapters(GF_ISOFile *file, char *inName)
for (i=0; iis_shvc ? "SHVC" : "HEVC", gf_hevc_get_profile_name(hevccfg->profile_idc), ((Double)hevccfg->level_idc) / 30.0, hevccfg->chromaFormat);
+ fprintf(stderr, "\tNAL Unit length bits: %d - general profile compatibility 0x%08X\n", 8*hevccfg->nal_unit_size, hevccfg->general_profile_compatibility_flags);
+ fprintf(stderr, "\tParameter Sets: ");
+ for (k=0; kparam_array); k++) {
+ GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k);
+ if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
+ fprintf(stderr, "%d SPS ", gf_list_count(ar->nalus));
+ }
+ else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
+ fprintf(stderr, "%d PPS ", gf_list_count(ar->nalus));
+ }
+ if (ar->type==GF_HEVC_NALU_VID_PARAM) {
+ fprintf(stderr, "%d VPS ", gf_list_count(ar->nalus));
+ }
+ }
+ fprintf(stderr, "\n");
+ for (k=0; kparam_array); k++) {
+ GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k);
+ u32 idx, width, height;
+ s32 par_n, par_d;
+ if (ar->type !=GF_HEVC_NALU_SEQ_PARAM) continue;
+ for (idx=0; idxnalus); idx++) {
+ GF_AVCConfigSlot *sps = gf_list_get(ar->nalus, idx);
+ par_n = par_d = -1;
+ gf_hevc_get_sps_info(sps->data, sps->size, NULL, &width, &height, &par_n, &par_d);
+ fprintf(stderr, "\tSPS resolution %dx%d", width, height);
+ if ((par_n>0) && (par_d>0)) {
+ u32 tw, th;
+ gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL);
+ fprintf(stderr, " - Pixel Aspect Ratio %d:%d - Indicated track size %d x %d", par_n, par_d, tw, th);
+ }
+ 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");
+ }
+}
+#endif
+
void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
{
Float scale;
@@ -1366,7 +1493,14 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
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));
-
+
+ if (gf_isom_is_track_fragmented(file, trackID) ) {
+ u32 frag_samples;
+ u64 frag_duration;
+ gf_isom_get_fragmented_samples_info(file, trackID, &frag_samples, &frag_duration);
+ fprintf(stderr, "Fragmented track: %d samples - Media Duration %s\n", frag_samples, format_duration(frag_duration, timescale, szDur));
+ }
+
if (!gf_isom_is_self_contained(file, trackNum, 1)) {
const char *url, *urn;
gf_isom_get_data_reference(file, trackNum, 1, &url, &urn);
@@ -1421,22 +1555,27 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
w = h = 0;
if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2) {
#ifndef GPAC_DISABLE_AV_PARSERS
- GF_M4VDecSpecInfo dsi;
- gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
- if (full_dump) fprintf(stderr, "\t");
- w = dsi.width;
- h = dsi.height;
- fprintf(stderr, "MPEG-4 Visual Size %d x %d - %s\n", w, h, gf_m4v_get_profile_name(dsi.VideoPL));
- if (dsi.par_den && dsi.par_num) {
- u32 tw, th;
- gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL);
- fprintf(stderr, "Pixel Aspect Ratio %d:%d - Indicated track size %d x %d\n", dsi.par_num, dsi.par_den, tw, th);
- }
+ if (!esd->decoderConfig->decoderSpecificInfo) {
#else
- gf_isom_get_visual_info(file, trackNum, 1, &w, &h);
- fprintf(stderr, "MPEG-4 Visual Size %d x %d\n", w, h);
+ gf_isom_get_visual_info(file, trackNum, 1, &w, &h);
+ fprintf(stderr, "MPEG-4 Visual Size %d x %d\n", w, h);
+#endif
+ fprintf(stderr, "\tNon-compliant MPEG-4 Visual track: video_object_layer infos not found in sample description\n");
+#ifndef GPAC_DISABLE_AV_PARSERS
+ } else {
+ GF_M4VDecSpecInfo dsi;
+ gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
+ if (full_dump) fprintf(stderr, "\t");
+ w = dsi.width;
+ h = dsi.height;
+ fprintf(stderr, "MPEG-4 Visual Size %d x %d - %s\n", w, h, gf_m4v_get_profile_name(dsi.VideoPL));
+ if (dsi.par_den && dsi.par_num) {
+ u32 tw, th;
+ gf_isom_get_track_layout_info(file, trackNum, &tw, &th, NULL, NULL, NULL);
+ fprintf(stderr, "Pixel Aspect Ratio %d:%d - Indicated track size %d x %d\n", dsi.par_num, dsi.par_den, tw, th);
+ }
+ }
#endif
-
} else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) {
#ifndef GPAC_DISABLE_AV_PARSERS
GF_AVCConfig *avccfg, *svccfg;
@@ -1491,38 +1630,29 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
#endif /*GPAC_DISABLE_AV_PARSERS*/
} else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_HEVC) {
-#ifndef GPAC_DISABLE_AV_PARSERS
- GF_HEVCConfig *hevccfg;
+#if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC)
+ GF_HEVCConfig *hevccfg, *shvccfg;
#endif
gf_isom_get_visual_info(file, trackNum, 1, &w, &h);
if (full_dump) fprintf(stderr, "\t");
fprintf(stderr, "HEVC Video - Visual Size %d x %d\n", w, h);
-#ifndef GPAC_DISABLE_AV_PARSERS
+#if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_HEVC)
hevccfg = gf_isom_hevc_config_get(file, trackNum, 1);
- if (!hevccfg ) {
- fprintf(stderr, "\n\n\tNon-compliant HEVC track: hvcC not found in sample description\n");
- } else {
- u32 k;
- fprintf(stderr, "\tHEVC Info: Profile IDC %d - Level IDC %d - Chroma Format %d\n", hevccfg->profile_idc, hevccfg->level_idc, hevccfg->chromaFormat);
- fprintf(stderr, "\tNAL Unit length bits: %d - profile compatibility 0x%08X\n", 8*hevccfg->nal_unit_size, hevccfg->profile_compatibility_indications);
- fprintf(stderr, "\tParameter Sets: ");
- for (k=0; kparam_array); k++) {
- GF_HEVCParamArray *ar=gf_list_get(hevccfg->param_array, k);
- if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
- fprintf(stderr, "%d SPS ", gf_list_count(ar->nalus));
- }
- else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
- fprintf(stderr, "%d PPS ", gf_list_count(ar->nalus));
- }
- if (ar->type==GF_HEVC_NALU_VID_PARAM) {
- fprintf(stderr, "%d VPS ", gf_list_count(ar->nalus));
- }
- }
- fprintf(stderr, "\n\tBit Depth luma %d - Chroma %d - %d temporal layers\n", hevccfg->luma_bit_depth, hevccfg->chroma_bit_depth, hevccfg->numTemporalLayers);
+ shvccfg = gf_isom_shvc_config_get(file, trackNum, 1);
+ if (!hevccfg && !shvccfg) {
+ fprintf(stderr, "\n\n\tNon-compliant HEVC track: No hvcC or shcC found in sample description\n");
+ }
+ if (hevccfg) {
+ dump_hevc_track_info(file, trackNum, hevccfg);
gf_odf_hevc_cfg_del(hevccfg);
+ fprintf(stderr, "\n");
}
-#endif /*GPAC_DISABLE_AV_PARSERS*/
+ if (shvccfg) {
+ dump_hevc_track_info(file, trackNum, shvccfg);
+ gf_odf_hevc_cfg_del(shvccfg);
+ }
+#endif /*GPAC_DISABLE_AV_PARSERS && defined(GPAC_DISABLE_HEVC)*/
}
/*OGG media*/
@@ -1726,6 +1856,10 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
fprintf(stderr, "Selective Encryption: %s\n", use_sel_enc ? "Yes" : "No");
if (IV_size) fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8);
+ } else if(gf_isom_is_cenc_media(file, trackNum, 1)) {
+ gf_isom_get_cenc_info(file, trackNum, 1, NULL, &scheme_type, &version, &IV_size);
+ fprintf(stderr, "\n*Encrypted stream - CENC scheme %s (version %d)\n", gf_4cc_to_str(scheme_type), version);
+ if (IV_size) fprintf(stderr, "Initialization Vector size: %d bits\n", IV_size*8);
} else {
fprintf(stderr, "\n*Encrypted stream - unknown scheme %s\n", gf_4cc_to_str(gf_isom_is_media_encrypted(file, trackNum, 1) ));
}
@@ -1798,12 +1932,12 @@ void DumpTrackInfo(GF_ISOFile *file, u32 trackID, Bool full_dump)
#endif
} else if (mtype==GF_ISOM_MEDIA_FLASH) {
fprintf(stderr, "Macromedia Flash Movie\n");
- } else if ((mtype==GF_ISOM_MEDIA_TEXT) || (mtype==GF_ISOM_MEDIA_SUBT)) {
+ } else if ((mtype==GF_ISOM_MEDIA_TEXT) || (mtype==GF_ISOM_MEDIA_SUBT) || (mtype==GF_ISOM_MEDIA_MPEG_SUBT)) {
u32 w, h;
s16 l;
s32 tx, ty;
gf_isom_get_track_layout_info(file, trackNum, &w, &h, &tx, &ty, &l);
- fprintf(stderr, "3GPP/MPEG-4 Timed Text - Size %d x %d - Translation X=%d Y=%d - Layer %d\n", 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);
} else if (mtype == GF_ISOM_MEDIA_META) {
Bool is_xml = 0;
const char *mime_or_namespace = NULL;
@@ -1973,8 +2107,18 @@ void DumpMovieInfo(GF_ISOFile *file)
DumpMetaItem(file, 1, 0, "Root Meta");
if (!gf_isom_has_movie(file)) {
if (gf_isom_has_segment(file, &brand, &min)) {
- fprintf(stderr, "File is a segment: \n");
- fprintf(stderr, "\tSegment Brand %s - version %d\n", gf_4cc_to_str(brand), min);
+ u32 j, count;
+ count = gf_isom_segment_get_fragment_count(file);
+ fprintf(stderr, "File is a segment - %d movie fragments - Brand %s (version %d):\n", count, gf_4cc_to_str(brand), min);
+ for (i=0; i=GF_ISOM_AVCTYPE_AVC_SVC)
check_track_for_svc = i+1;
+
+ if (gf_isom_get_hevc_shvc_type(import.dest, i+1, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC)
+ check_track_for_shvc = i+1;
+
+ if (tile_mode) {
+ switch (gf_isom_get_media_subtype(import.dest, i+1, 1)) {
+ case GF_ISOM_SUBTYPE_HVC1:
+ case GF_ISOM_SUBTYPE_HEV1:
+ tile_mode = 2;
+ break;
+ }
+ }
}
} else {
for (i=0; i0) {
gf_isom_set_rvc_config(import.dest, track, 1, rvc_predefined, NULL, NULL, 0);
}
-
+
gf_isom_set_composition_offset_mode(import.dest, track, negative_cts_offset);
if (gf_isom_get_avc_svc_type(import.dest, track, 1)>=GF_ISOM_AVCTYPE_AVC_SVC)
check_track_for_svc = track;
+
+ if (gf_isom_get_hevc_shvc_type(import.dest, track, 1)>=GF_ISOM_HEVCTYPE_HEVC_SHVC)
+ check_track_for_shvc = track;
+
+ if (tile_mode) {
+ switch (gf_isom_get_media_subtype(import.dest, track, 1)) {
+ case GF_ISOM_SUBTYPE_HVC1:
+ case GF_ISOM_SUBTYPE_HEV1:
+ tile_mode = 2;
+ break;
+ }
+ }
}
if (track_id) fprintf(stderr, "WARNING: Track ID %d not found in file\n", track_id);
else if (do_video) fprintf(stderr, "WARNING: Video track not found\n");
@@ -670,6 +713,18 @@ GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double forc
if (e) goto exit;
}
}
+ if (check_track_for_shvc) {
+ if (svc_mode) {
+ e = gf_media_split_shvc(import.dest, check_track_for_shvc, (svc_mode==1) ? 0 : 1, (svc_mode==3) ? 0 : 1 );
+ if (e) goto exit;
+ } else {
+ //TODO - merge
+ }
+ }
+ if (tile_mode == 2) {
+ gf_media_split_hevc_tiles(import.dest);
+ }
+
exit:
if (handler_name) gf_free(handler_name);
@@ -728,7 +783,9 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb,
}
- strcpy(szName, inName);
+ ext = strrchr(inName, '/');
+ if (!ext) ext = strrchr(inName, '\\');
+ strcpy(szName, ext ? ext+1 : inName);
ext = strrchr(szName, '.');
if (ext) ext[0] = 0;
ext = strrchr(inName, '.');
@@ -769,6 +826,7 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb,
/*we duplicate text samples at boundaries*/
case GF_ISOM_MEDIA_TEXT:
case GF_ISOM_MEDIA_SUBT:
+ case GF_ISOM_MEDIA_MPEG_SUBT:
tks[nb_tk].can_duplicate = 1;
case GF_ISOM_MEDIA_AUDIO:
break;
@@ -1152,11 +1210,8 @@ GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb,
break;
}
}
- if (rap_split) {
- if (time <= file_split_dur) break;
- } else {
- if (time < file_split_dur) break;
- }
+
+ if (time <= file_split_dur) break;
gf_isom_remove_sample(dest, tki->dst_tk, last_samp);
tki->last_sample--;
@@ -1276,9 +1331,128 @@ err_exit:
return e;
}
-GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines);
+GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command);
-GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines)
+static Bool merge_parameter_set(GF_List *src, GF_List *dst, const char *name)
+{
+ u32 j, k;
+ for (j=0; jsize==slc_dst->size) && !memcmp(slc->data, slc_dst->data, slc->size) ) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ return GF_FALSE;
+ }
+ }
+ return GF_TRUE;
+}
+
+static u32 merge_avc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 src_track, Bool force_cat)
+{
+ GF_AVCConfig *avc_src, *avc_dst;
+ u32 dst_tk = gf_isom_get_track_by_id(dest, tk_id);
+
+ avc_src = gf_isom_avc_config_get(orig, src_track, 1);
+ avc_dst = gf_isom_avc_config_get(dest, dst_tk, 1);
+
+ if (avc_src->AVCLevelIndication!=avc_dst->AVCLevelIndication) {
+ dst_tk = 0;
+ } else if (avc_src->AVCProfileIndication!=avc_dst->AVCProfileIndication) {
+ dst_tk = 0;
+ }
+ else {
+ /*rewrite all samples if using different NALU size*/
+ if (avc_src->nal_unit_size > avc_dst->nal_unit_size) {
+ gf_media_avc_rewrite_samples(dest, dst_tk, 8*avc_dst->nal_unit_size, 8*avc_src->nal_unit_size);
+ avc_dst->nal_unit_size = avc_src->nal_unit_size;
+ } else if (avc_src->nal_unit_size < avc_dst->nal_unit_size) {
+ gf_media_avc_rewrite_samples(orig, src_track, 8*avc_src->nal_unit_size, 8*avc_dst->nal_unit_size);
+ }
+
+ /*merge PS*/
+ if (!merge_parameter_set(avc_src->sequenceParameterSets, avc_dst->sequenceParameterSets, "SPS"))
+ dst_tk = 0;
+ if (!merge_parameter_set(avc_src->pictureParameterSets, avc_dst->pictureParameterSets, "PPS"))
+ dst_tk = 0;
+
+ gf_isom_avc_config_update(dest, dst_tk, 1, avc_dst);
+ }
+
+ gf_odf_avc_cfg_del(avc_src);
+ gf_odf_avc_cfg_del(avc_dst);
+
+ if (!dst_tk) {
+ dst_tk = gf_isom_get_track_by_id(dest, tk_id);
+ gf_isom_set_nalu_extract_mode(orig, src_track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
+ if (!force_cat) {
+ gf_isom_avc_set_inband_config(dest, dst_tk, 1);
+ } else {
+ fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id);
+ }
+ }
+ return dst_tk;
+}
+
+static u32 merge_hevc_config(GF_ISOFile *dest, u32 tk_id, GF_ISOFile *orig, u32 src_track, Bool force_cat)
+{
+ u32 i;
+ GF_HEVCConfig *hevc_src, *hevc_dst;
+ u32 dst_tk = gf_isom_get_track_by_id(dest, tk_id);
+
+ hevc_src = gf_isom_hevc_config_get(orig, src_track, 1);
+ hevc_dst = gf_isom_hevc_config_get(dest, dst_tk, 1);
+
+ if (hevc_src->profile_idc != hevc_dst->profile_idc) dst_tk = 0;
+ else if (hevc_src->level_idc != hevc_dst->level_idc) dst_tk = 0;
+ else if (hevc_src->general_profile_compatibility_flags != hevc_dst->general_profile_compatibility_flags ) dst_tk = 0;
+ else {
+ /*rewrite all samples if using different NALU size*/
+ if (hevc_src->nal_unit_size > hevc_dst->nal_unit_size) {
+ gf_media_avc_rewrite_samples(dest, dst_tk, 8*hevc_dst->nal_unit_size, 8*hevc_src->nal_unit_size);
+ hevc_dst->nal_unit_size = hevc_src->nal_unit_size;
+ } else if (hevc_src->nal_unit_size < hevc_dst->nal_unit_size) {
+ gf_media_avc_rewrite_samples(orig, src_track, 8*hevc_src->nal_unit_size, 8*hevc_dst->nal_unit_size);
+ }
+
+ /*merge PS*/
+ for (i=0; iparam_array); i++) {
+ u32 k;
+ GF_HEVCParamArray *src_ar = gf_list_get(hevc_src->param_array, i);
+ for (k=0; kparam_array); k++) {
+ GF_HEVCParamArray *dst_ar = gf_list_get(hevc_dst->param_array, k);
+ if (dst_ar->type==src_ar->type) {
+ if (!merge_parameter_set(src_ar->nalus, dst_ar->nalus, "SPS"))
+ dst_tk = 0;
+ break;
+ }
+ }
+ }
+
+ gf_isom_hevc_config_update(dest, dst_tk, 1, hevc_dst);
+ }
+
+ gf_odf_hevc_cfg_del(hevc_src);
+ gf_odf_hevc_cfg_del(hevc_dst);
+
+ if (!dst_tk) {
+ dst_tk = gf_isom_get_track_by_id(dest, tk_id);
+ gf_isom_set_nalu_extract_mode(orig, src_track, GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG);
+ if (!force_cat) {
+ gf_isom_hevc_set_inband_config(dest, dst_tk, 1);
+ } else {
+ fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id);
+ }
+ }
+ return dst_tk;
+}
+
+GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command)
{
u32 i, j, count, nb_tracks, nb_samp, nb_done;
GF_ISOFile *orig;
@@ -1292,9 +1466,9 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
GF_ISOSample *samp;
Double aligned_to_DTS = 0;
- if (strchr(fileName, '*')) return cat_multiple_files(dest, fileName, import_flags, force_fps, frames_per_sample, tmp_dir, force_cat, align_timelines);
+ if (strchr(fileName, '*')) return cat_multiple_files(dest, fileName, import_flags, force_fps, frames_per_sample, tmp_dir, force_cat, align_timelines, allow_add_in_command);
- multi_cat = strchr(fileName, '+');
+ multi_cat = allow_add_in_command ? strchr(fileName, '+') : NULL;
if (multi_cat) {
multi_cat[0] = 0;
multi_cat = &multi_cat[1];
@@ -1344,6 +1518,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
case GF_ISOM_MEDIA_AUDIO:
case GF_ISOM_MEDIA_TEXT:
case GF_ISOM_MEDIA_SUBT:
+ case GF_ISOM_MEDIA_MPEG_SUBT:
case GF_ISOM_MEDIA_VISUAL:
case GF_ISOM_MEDIA_SCENE:
case GF_ISOM_MEDIA_OCR:
@@ -1397,6 +1572,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
continue;
case GF_ISOM_MEDIA_TEXT:
case GF_ISOM_MEDIA_SUBT:
+ case GF_ISOM_MEDIA_MPEG_SUBT:
case GF_ISOM_MEDIA_SCENE:
use_ts_dur = 0;
case GF_ISOM_MEDIA_AUDIO:
@@ -1482,78 +1658,21 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
}
}
- /*merge AVC config if possible*/
- if (!dst_tk && ((stype == GF_ISOM_SUBTYPE_AVC_H264) || (stype == GF_ISOM_SUBTYPE_AVC2_H264) || (stype == GF_ISOM_SUBTYPE_AVC3_H264) || (stype == GF_ISOM_SUBTYPE_AVC4_H264)) ) {
- GF_AVCConfig *avc_src, *avc_dst;
- dst_tk = gf_isom_get_track_by_id(dest, tk_id);
-
- avc_src = gf_isom_avc_config_get(orig, i+1, 1);
- avc_dst = gf_isom_avc_config_get(dest, dst_tk, 1);
-
- if (avc_src->AVCLevelIndication!=avc_dst->AVCLevelIndication) {
- fprintf(stderr, "Cannot concatenate files: Different AVC Level Indication between source (%d) and destination (%d)\n", avc_src->AVCLevelIndication, avc_dst->AVCLevelIndication);
- dst_tk = 0;
- } else if (avc_src->AVCProfileIndication!=avc_dst->AVCProfileIndication) {
- fprintf(stderr, "Cannot concatenate files: Different AVC Profile Indication between source (%d) and destination (%d)\n", avc_src->AVCProfileIndication, avc_dst->AVCProfileIndication);
- dst_tk = 0;
+ if (!dst_tk) {
+ /*merge AVC config if possible*/
+ if ((stype == GF_ISOM_SUBTYPE_AVC_H264)
+ || (stype == GF_ISOM_SUBTYPE_AVC2_H264)
+ || (stype == GF_ISOM_SUBTYPE_AVC3_H264)
+ || (stype == GF_ISOM_SUBTYPE_AVC4_H264) ) {
+ dst_tk = merge_avc_config(dest, tk_id, orig, i+1, force_cat);
}
- else {
- u32 j, k;
- /*rewrite all samples if using different NALU size*/
- if (avc_src->nal_unit_size > avc_dst->nal_unit_size) {
- gf_media_avc_rewrite_samples(dest, dst_tk, 8*avc_dst->nal_unit_size, 8*avc_src->nal_unit_size);
- avc_dst->nal_unit_size = avc_src->nal_unit_size;
- } else if (avc_src->nal_unit_size < avc_dst->nal_unit_size) {
- gf_media_avc_rewrite_samples(orig, i+1, 8*avc_src->nal_unit_size, 8*avc_dst->nal_unit_size);
- }
-
- /*merge SPS*/
- for (j=0; jsequenceParameterSets); j++) {
- Bool found = 0;
- GF_AVCConfigSlot *slc = gf_list_get(avc_src->sequenceParameterSets, j);
- for (k=0; ksequenceParameterSets); k++) {
- GF_AVCConfigSlot *slc_dst = gf_list_get(avc_dst->sequenceParameterSets, k);
- if ( (slc->size==slc_dst->size) && !memcmp(slc->data, slc_dst->data, slc->size) ) {
- found = 1;
- break;
- }
- }
- if (!found) {
- fprintf(stderr, "WARNING: Concatenating track ID %d with different SPS - result file might be broken\n", tk_id);
- gf_list_rem(avc_src->sequenceParameterSets, j);
- j--;
- gf_list_add(avc_dst->sequenceParameterSets, slc);
- }
- }
-
- /*merge PPS*/
- for (j=0; jpictureParameterSets); j++) {
- Bool found = 0;
- GF_AVCConfigSlot *slc = gf_list_get(avc_src->pictureParameterSets, j);
- for (k=0; kpictureParameterSets); k++) {
- GF_AVCConfigSlot *slc_dst = gf_list_get(avc_dst->pictureParameterSets, k);
- if ( (slc->size==slc_dst->size) && !memcmp(slc->data, slc_dst->data, slc->size) ) {
- found = 1;
- break;
- }
- }
- if (!found) {
- fprintf(stderr, "WARNING: Concatenating track ID %d with different PPS - result file might be broken\n", tk_id);
- gf_list_rem(avc_src->pictureParameterSets, j);
- j--;
- gf_list_add(avc_dst->pictureParameterSets, slc);
- }
- }
- gf_isom_avc_config_update(dest, dst_tk, 1, avc_dst);
+ /*merge HEVC config if possible*/
+ else if ((stype == GF_ISOM_SUBTYPE_HVC1)
+ || (stype == GF_ISOM_SUBTYPE_HEV1)
+ || (stype == GF_ISOM_SUBTYPE_HVC2)
+ || (stype == GF_ISOM_SUBTYPE_HEV2)) {
+ dst_tk = merge_hevc_config(dest, tk_id, orig, i+1, force_cat);
}
-
- gf_odf_avc_cfg_del(avc_src);
- gf_odf_avc_cfg_del(avc_dst);
- }
-
- if (!dst_tk && force_cat) {
- dst_tk = gf_isom_get_track_by_id(dest, tk_id);
- fprintf(stderr, "WARNING: Concatenating track ID %d even though sample descriptions do not match\n", tk_id);
}
}
@@ -1661,8 +1780,7 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
gf_isom_set_edit_segment(dest, dst_tk, 0, (u64) (s64) (insert_dts*rescale), 0, GF_ISOM_EDIT_EMPTY);
gf_isom_set_edit_segment(dest, dst_tk, (u64) (s64) (insert_dts*rescale), (u64) (s64) (media_dur*rescale), 0, GF_ISOM_EDIT_NORMAL);
- }
- else if (merge_edits) {
+ } else if (merge_edits) {
/*convert from media time to track time*/
Double rescale = (Float) gf_isom_get_timescale(dest);
rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk);
@@ -1701,8 +1819,25 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
u32 j, count;
count = gf_isom_get_edit_segment_count(dest, dst_tk);
- gf_isom_get_edit_segment(dest, dst_tk, count, &editTime, &segmentDuration, &mediaTime, &editMode);
-
+ if (count) {
+ e = gf_isom_get_edit_segment(dest, dst_tk, count, &editTime, &segmentDuration, &mediaTime, &editMode);
+ if (e) {
+ fprintf(stderr, "Error: edit segment error on destination track %u could not be retrieved.\n", dst_tk);
+ goto err_exit;
+ }
+ } else if (gf_isom_get_edit_segment_count(orig, i+1)) {
+ /*fake empty edit segment*/
+ /*convert from media time to track time*/
+ Double rescale = (Float) gf_isom_get_timescale(dest);
+ rescale /= (Float) gf_isom_get_media_timescale(dest, dst_tk);
+ segmentDuration = (u64) (dest_track_dur_before_cat * rescale);
+ editTime = 0;
+ mediaTime = 0;
+ gf_isom_set_edit_segment(dest, dst_tk, editTime, segmentDuration, mediaTime, GF_ISOM_EDIT_NORMAL);
+ } else {
+ editTime = 0;
+ segmentDuration = 0;
+ }
/*convert to dst time scale*/
ts_scale = (Float) gf_isom_get_timescale(dest);
@@ -1715,7 +1850,9 @@ GF_Err cat_isomedia_file(GF_ISOFile *dest, char *fileName, u32 import_flags, Dou
t = (Double) (s64) editTime; t *= ts_scale; t += (s64) edit_offset; editTime = (s64) t;
t = (Double) (s64) segmentDuration; t *= ts_scale; segmentDuration = (s64) t;
t = (Double) (s64) mediaTime; t *= ts_scale; t+= (s64) dest_track_dur_before_cat; mediaTime = (s64) t;
-
+ if ((editMode == GF_ISOM_EDIT_EMPTY) && (mediaTime > 0)) {
+ editMode = GF_ISOM_EDIT_NORMAL;
+ }
gf_isom_set_edit_segment(dest, dst_tk, editTime, segmentDuration, mediaTime, editMode);
}
}
@@ -1761,7 +1898,7 @@ typedef struct
Double force_fps;
u32 frames_per_sample;
char *tmp_dir;
- Bool force_cat, align_timelines;
+ Bool force_cat, align_timelines, allow_add_in_command;
} CATEnum;
Bool cat_enumerate(void *cbk, char *szName, char *szPath)
@@ -1770,19 +1907,19 @@ Bool cat_enumerate(void *cbk, char *szName, char *szPath)
u32 len_rad1;
char szFileName[GF_MAX_PATH];
CATEnum *cat_enum = (CATEnum *)cbk;
- len_rad1 = strlen(cat_enum->szRad1);
+ len_rad1 = (u32) strlen(cat_enum->szRad1);
if (strnicmp(szName, cat_enum->szRad1, len_rad1)) return 0;
if (strlen(cat_enum->szRad2) && !strstr(szName + len_rad1, cat_enum->szRad2) ) return 0;
strcpy(szFileName, szName);
strcat(szFileName, cat_enum->szOpt);
- e = cat_isomedia_file(cat_enum->dest, szFileName, cat_enum->import_flags, cat_enum->force_fps, cat_enum->frames_per_sample, cat_enum->tmp_dir, cat_enum->force_cat, cat_enum->align_timelines);
+ e = cat_isomedia_file(cat_enum->dest, szFileName, cat_enum->import_flags, cat_enum->force_fps, cat_enum->frames_per_sample, cat_enum->tmp_dir, cat_enum->force_cat, cat_enum->align_timelines, cat_enum->allow_add_in_command);
if (e) return 1;
return 0;
}
-GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines)
+GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command)
{
CATEnum cat_enum;
char *sep;
@@ -1794,6 +1931,7 @@ GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Do
cat_enum.tmp_dir = tmp_dir;
cat_enum.force_cat = force_cat;
cat_enum.align_timelines = align_timelines;
+ cat_enum.allow_add_in_command = allow_add_in_command;
strcpy(cat_enum.szPath, fileName);
sep = strrchr(cat_enum.szPath, GF_PATH_SEPARATOR);
@@ -2117,12 +2255,12 @@ GF_Err EncodeBIFSChunk(GF_SceneManager *ctx, char *bifsOutputFile, GF_Err (*AUCa
#endif /*GPAC_DISABLE_BIFS_ENC*/
/**
- * @chunkFile BT chunk to be encoded
- * @bifs output file name for the BIFS data
- * @inputContext initial BT upon which the chunk is based (shall not be NULL)
- * @outputContext: file name to dump the context after applying the new chunk to the input context
+ * \param chunkFile BT chunk to be encoded
+ * \param bifs output file name for the BIFS data
+ * \param inputContext initial BT upon which the chunk is based (shall not be NULL)
+ * \param outputContext: file name to dump the context after applying the new chunk to the input context
can be NULL, without .bt
- * @logFile: can be NULL
+ * \param tmpdir can be NULL
*/
GF_Err EncodeFileChunk(char *chunkFile, char *bifs, char *inputContext, char *outputContext, const char *tmpdir)
{
@@ -2375,13 +2513,13 @@ GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool ma
if (e) goto exit;
/*add self ref*/
if (isom_src) {
- e = gf_isom_add_meta_item(file, 1, 0, 1, NULL, isom_src, NULL, NULL, NULL, NULL);
+ e = gf_isom_add_meta_item(file, 1, 0, 1, NULL, isom_src, 0, NULL, NULL, NULL, NULL);
if (e) goto exit;
}
e = gf_isom_set_meta_xml(file, 1, 0, file_name, !ascii);
if (e) goto exit;
- skip_chars = strlen(root_dir);
+ skip_chars = (u32) strlen(root_dir);
count = gf_list_count(imports);
for (i=0; i
#endif
+#include
+
+#ifndef GPAC_DISABLE_STREAMING
+#include
+#endif
+
#if defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE)
#error "Cannot compile MP4Box if GPAC is not built with ISO File Format support"
@@ -65,6 +71,13 @@ void PrintStreamerUsage()
);
}
+static void on_logs(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list)
+{
+ FILE *logs = cbk;
+ vfprintf(logs, fmt, list);
+ fflush(logs);
+}
+
int stream_file_rtp(int argc, char **argv)
{
GF_ISOMRTPStreamer *file_streamer;
@@ -72,9 +85,12 @@ int stream_file_rtp(int argc, char **argv)
char *ip_dest = "127.0.0.1";
char *ifce_addr = NULL;
char *inName = NULL;
+ char *logs=NULL;
+ FILE *logfile=NULL;
u16 port = 7000;
u32 ttl = 1;
Bool loop = 1;
+ Bool mem_track = 0;
Bool force_mpeg4 = 0;
u32 path_mtu = 1450;
u32 i;
@@ -94,17 +110,27 @@ int stream_file_rtp(int argc, char **argv)
else if (!strnicmp(arg, "-ttl=", 5)) ttl = atoi(arg+5);
else if (!strnicmp(arg, "-ifce=", 6)) ifce_addr = arg+6;
else if (!strnicmp(arg, "-sdp=", 5)) sdp_file = arg+5;
+ else if (!stricmp(arg, "-mem-track")) mem_track = 1;
+ else if (!strnicmp(arg, "-logs=", 6)) logs = arg+6;
+ else if (!strnicmp(arg, "-lf=", 4)) logfile = gf_f64_open(arg+4, "wt");
+ }
+
+ gf_sys_init(mem_track);
+ if (logs)
+ gf_log_set_tools_levels(logs);
+ else
+ gf_log_set_tool_level(GF_LOG_RTP, GF_LOG_INFO); //set to debug to have packet list
+ if (logfile) {
+ gf_log_set_callback(logfile, on_logs);
}
if (!gf_isom_probe_file(inName)) {
fprintf(stderr, "File %s is not a valid ISO Media file and cannot be streamed\n", inName);
+ if (logfile) fclose(logfile);
+ gf_sys_close();
return 1;
}
- gf_sys_init(0);
-
- gf_log_set_tool_level(GF_LOG_RTP, GF_LOG_WARNING); //set to debug to have packet list
-
file_streamer = gf_isom_streamer_new(inName, ip_dest, port, loop, force_mpeg4, path_mtu, ttl, ifce_addr);
if (!file_streamer) {
fprintf(stderr, "Cannot create file streamer\n");
@@ -126,6 +152,7 @@ int stream_file_rtp(int argc, char **argv)
}
gf_isom_streamer_del(file_streamer);
}
+ if (logfile) fclose(logfile);
gf_sys_close();
return 0;
}
@@ -261,7 +288,7 @@ static void live_session_callback(void *calling_object, u16 ESID, char *data, u3
fprintf(stderr, "Stream %d: Sending update at TS "LLD", %d bytes - RAP %d - critical %d\n", ESID, ts, size, rap, critical);
rtpch->rap = rtpch->critical = 0;
- if (rtpch->manual_rtcp) gf_rtp_streamer_send_rtcp(rtpch->rtp, 0, 0);
+ if (rtpch->manual_rtcp) gf_rtp_streamer_send_rtcp(rtpch->rtp, 0, 0, 0, 0, 0);
}
return;
}
@@ -282,7 +309,7 @@ static void live_session_send_carousel(LiveSession *livesess, RTPChannel *ch)
if (ch->manual_rtcp) {
ts = ch->carousel_ts + ch->timescale * ( gf_sys_clock() - ch->init_time + ch->ts_delta)/1000;
- gf_rtp_streamer_send_rtcp(ch->rtp, 1, (u32) ts);
+ gf_rtp_streamer_send_rtcp(ch->rtp, 1, (u32) ts, 0, 0, 0);
}
}
} else {
@@ -300,7 +327,7 @@ static void live_session_send_carousel(LiveSession *livesess, RTPChannel *ch)
if (ch->manual_rtcp) {
ts = ch->carousel_ts + ch->timescale*(gf_sys_clock()-ch->init_time + ch->ts_delta)/1000;
- gf_rtp_streamer_send_rtcp(ch->rtp, 1, (u32) ts);
+ gf_rtp_streamer_send_rtcp(ch->rtp, 1, (u32) ts, 0, 0, 0);
}
}
}
@@ -459,7 +486,7 @@ int live_session(int argc, char **argv)
aggregate_au = 1;
es_id = 0;
no_rap = 0;
- gf_sys_init(0);
+ gf_sys_init(GF_FALSE);
memset(&livesess, 0, sizeof(LiveSession));
@@ -813,3 +840,95 @@ exit:
#endif /*!defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)*/
#endif /*defined(GPAC_DISABLE_ISOM) || defined(GPAC_DISABLE_ISOM_WRITE)*/
+
+u32 grab_live_m2ts(const char *grab_m2ts, const char *outName)
+{
+ char data[0x80000];
+ u32 check = 50;
+ u64 nb_pck;
+ Bool first_run, is_rtp;
+ FILE *output;
+#ifndef GPAC_DISABLE_STREAMING
+ u16 seq_num;
+ GF_RTPReorder *ch = NULL;
+#endif
+ GF_Socket *sock;
+ GF_Err e = gf_m2ts_get_socket(grab_m2ts, NULL, 0x80000, &sock);
+
+ if (e) {
+ fprintf(stderr, "Cannot open %s: %s\n", grab_m2ts, gf_error_to_string(e));
+ return 1;
+ }
+ output = gf_f64_open(outName, "wb");
+ if (!output) {
+ fprintf(stderr, "Cannot open %s: check path and rights\n", outName);
+ gf_sk_del(sock);
+ return 1;
+ }
+
+ fprintf(stderr, "Dumping %s stream to %s - press q to abort\n", grab_m2ts, outName);
+
+ first_run = 1;
+ is_rtp = 0;
+ while (1) {
+ u32 size = 0;
+
+ check--;
+ if (!check) {
+ if (gf_prompt_has_input()) {
+ char c = (char) gf_prompt_get_char();
+ if (c=='q') break;
+ }
+ check = 50;
+ }
+
+ /*m2ts chunks by chunks*/
+ e = gf_sk_receive(sock, data, 0x40000, 0, &size);
+ if (!size || e) {
+ gf_sleep(1);
+ continue;
+ }
+ if (first_run) {
+ first_run = 0;
+ /*FIXME: we assume only simple RTP packaging (no CSRC nor extensions)*/
+ if ((data[0] != 0x47) && ((data[1] & 0x7F) == 33) ) {
+ is_rtp = 1;
+#ifndef GPAC_DISABLE_STREAMING
+ ch = gf_rtp_reorderer_new(100, 500);
+#endif
+ }
+ }
+ /*process chunk*/
+ if (is_rtp) {
+#ifndef GPAC_DISABLE_STREAMING
+ char *pck;
+ seq_num = ((data[2] << 8) & 0xFF00) | (data[3] & 0xFF);
+ gf_rtp_reorderer_add(ch, (void *) data, size, seq_num);
+
+ pck = (char *) gf_rtp_reorderer_get(ch, &size);
+ if (pck) {
+ fwrite(pck+12, size-12, 1, output);
+ gf_free(pck);
+ }
+#else
+ fwrite(data+12, size-12, 1, output);
+#endif
+ } else {
+ fwrite(data, size, 1, output);
+ }
+ }
+ nb_pck = gf_f64_tell(output);
+ nb_pck /= 188;
+ fprintf(stderr, "Captured "LLU" TS packets\n", nb_pck );
+ fclose(output);
+ gf_sk_del(sock);
+
+#ifndef GPAC_DISABLE_STREAMING
+ if (ch)
+ gf_rtp_reorderer_del(ch);
+#endif
+ return 0;
+}
+
+
+
diff --git a/applications/mp4box/main.c b/applications/mp4box/main.c
index a3f26d2..ece2eb2 100644
--- a/applications/mp4box/main.c
+++ b/applications/mp4box/main.c
@@ -71,7 +71,7 @@ void convert_file_info(char *inName, u32 trackID);
GF_Err import_file(GF_ISOFile *dest, char *inName, u32 import_flags, Double force_fps, u32 frames_per_sample);
GF_Err split_isomedia_file(GF_ISOFile *mp4, Double split_dur, u32 split_size_kb, char *inName, Double interleaving_time, Double chunk_start, Bool adjust_split_end, char *outName, const char *tmpdir);
-GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines);
+GF_Err cat_isomedia_file(GF_ISOFile *mp4, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command);
#if !defined(GPAC_DISABLE_SCENE_ENCODER)
GF_Err EncodeFile(char *in, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, FILE *logs);
@@ -83,7 +83,7 @@ GF_ISOFile *package_file(char *file_name, char *fcc, const char *tmpdir, Bool ma
#endif
GF_Err dump_cover_art(GF_ISOFile *file, char *inName);
-GF_Err dump_chapters(GF_ISOFile *file, char *inName);
+GF_Err dump_chapters(GF_ISOFile *file, char *inName, Bool dump_ogg);
u32 id3_get_genre_tag(const char *name);
/*in filedump.c*/
@@ -134,6 +134,10 @@ int live_session(int argc, char **argv);
void PrintLiveUsage();
#endif
+#if !defined(GPAC_DISABLE_STREAMING)
+u32 grab_live_m2ts(const char *grab_m2ts, const char *outName);
+#endif
+
int mp4boxTerminal(int argc, char **argv);
u32 quiet = 0;
@@ -185,7 +189,7 @@ void PrintGeneralUsage()
{
fprintf(stderr, "General Options:\n"
#ifdef GPAC_MEMORY_TRACKING
- " -mem-track: enables memory tracker\n"
+ " -mem-track: enables memory tracker\n"
#endif
" -strict-error exits after the first error is reported\n"
" -inter time_in_ms interleaves file data (track chunks of time_in_ms)\n"
@@ -260,6 +264,7 @@ void PrintGeneralUsage()
" -group-clean removes all group information from all tracks\n"
" -group-single puts all tracks in a single group\n"
" -ref id:XXXX:refID adds a reference of type 4CC from track ID to track refID\n"
+ " -keep-utc keeps UTC timing in the file after edit\n"
"\n");
}
@@ -280,10 +285,15 @@ void PrintDASHUsage()
" * Default profile is \"full\" in static mode, \"live\" in dynamic mode\n"
"\n"
"Input media files to dash can use the following modifiers\n"
+ " \"#trackID=N\" only uses the track ID N from the source file\n"
+ " \"#video\" only uses the first video track from the source file\n"
+ " \"#audio\" only uses the first video track from the source file\n"
" \":id=NAME\" sets the representation ID to NAME\n"
" \":period=NAME\" sets the representation's period to NAME. Multiple periods may be used\n"
" period appear in the MPD in the same order as specified with this option\n"
" \":bandwidth=VALUE\" sets the representation's bandwidth to a given value\n"
+ " \":xlink=VALUE\" sets the xlink value for the period containing this element\n"
+ " only the xlink declared on the first rep of a period will be used\n"
" \":role=VALUE\" sets the role of this representation (cf DASH spec).\n"
" media with different roles belong to different adaptation sets.\n"
"\n"
@@ -297,6 +307,8 @@ void PrintDASHUsage()
" If not set (default), segments are concatenated in output file\n"
" except in \"live\" profile where dash_%%s is used\n"
" -segment-ext name sets the segment extension. Default is m4s, \"null\" means no extension\n"
+ " -segment-timeline Uses SegmentTimeline when generating segments. NOT SUPPORTED BY LIVE/CTX MODE YET.\n"
+ " -segment-marker MARK Adds a box of type \'MARK\' at the end of each DASH segment. MARK shall be a 4CC identifier\n"
" -base-url string sets Base url at MPD level. Can be used several times.\n"
" -mpd-title string sets MPD title.\n"
" -mpd-source string sets MPD source.\n"
@@ -304,6 +316,7 @@ void PrintDASHUsage()
" -cprt string adds copyright string to MPD\n"
" -dash-live[=F] dur generates a live DASH session using dur segment duration, optionnally writing live context to F\n"
" MP4Box will run the live session until \'q\' is pressed or a fatal error occurs.\n"
+ " -ddbg-live[=F] dur same as -dash-live without time regulation for debug purposes.\n"
" -dash-ctx FILE stores/restore DASH timing from FILE.\n"
" -dynamic uses dynamic MPD type instead of static.\n"
" -mpd-refresh TIME specifies MPD update time in seconds.\n"
@@ -312,6 +325,10 @@ void PrintDASHUsage()
" NOTE: This does not change the segment duration: dashing stops once segments produced exceeded the duration.\n"
" -min-buffer TIME specifies MPD min buffer time in milliseconds\n"
" -ast-offset TIME specifies MPD AvailabilityStartTime offset in seconds. Default is 1 sec delay\n"
+ " -dash-scale SCALE specifies that timing for -dash and -frag are expressed in SCALE units per seconds\n"
+ " -mem-frags fragments will be produced in memory rather than on disk before flushing to disk\n"
+ " -pssh-moof stores PSSH boxes in first moof of each segments. By default PSSH are stored in movie box.\n"
+
"\n"
"Advanced Options, should not be needed when using -dash-profile:\n"
" -subsegs-per-sidx N sets the number of subsegments to be written in each SIDX box\n"
@@ -323,6 +340,9 @@ void PrintDASHUsage()
" -single-segment uses a single segment for the whole file (OnDemand profile). \n"
" -single-file uses a single file for the whole file (default). \n"
" -bs-switching MODE sets bitstream switching to \"inband\" (default), \"merge\", \"no\" or \"single\" to test with single input.\n"
+ " -moof-sn N sets sequence number of first moof to N\n"
+ " -tfdt N sets TFDT of first traf to N in SCALE units (cf -dash-scale)\n"
+ " -no-frags-default disables default flags in fragments\n"
" -dash-ts-prog N program_number to be considered in case of an MPTS input file.\n"
"\n");
}
@@ -394,12 +414,16 @@ void PrintImportUsage()
" \":packed\" same as -packed option\n"
" \":sbr\" same as -sbr option\n"
" \":sbrx\" same as -sbrx option\n"
- " \":ps\": same as -ps option\n"
- " \":psx\": same as -psx option\n"
- " \":ovsbr\": same as -ovsbr option\n"
+ " \":ps\" same as -ps option\n"
+ " \":psx\" same as -psx option\n"
+ " \":ovsbr\" same as -ovsbr option\n"
" \":mpeg4\" same as -mpeg4 option\n"
" \":svc\" import SVC with explicit signaling (no AVC base compatibility)\n"
" \":nosvc\" discard SVC data when importing\n"
+ " \":svcmode=MODE\" sets SVC import mode:\n"
+ " \" split : each AVC/SVC layer is in its own track\n"
+ " \" merge : all AVC/SVC layers are merged in a single track\n"
+ " \" splitbase : all SVC layers are merged in a track, and the AVC base in another\n"
" \":subsamples\" adds SubSample information for AVC+SVC\n"
" \":forcesync\" forces non IDR samples with I slices to be marked as sync points (AVC GDR)\n"
" !! RESULTING FILE IS NOT COMPLIANT WITH THE SPEC but will fix seeking in most players\n"
@@ -420,13 +444,25 @@ void PrintImportUsage()
" - X and Y can be omitted (:layout=WxH)\n"
" \":rescale=TS\" forces media timescale to TS !! changes the media duration\n"
" \":timescale=TS\" sets import timescale to TS\n"
+ " \":swf-global\" all SWF defines are placed in first scene replace\n"
+ " * Note: By default SWF defines are sent when needed\n"
+ " \":swf-no-ctrl\" uses a single stream for movie control and dictionary\n"
+ " * Note: this will disable ActionScript\n"
+ " \":swf-no-text\" removes all SWF text\n"
+ " \":swf-no-font\" removes all embedded SWF Fonts (terminal fonts used)\n"
+ " \":swf-no-line\" removes all lines from SWF shapes\n"
+ " \":swf-no-grad\" removes all gradients from swf shapes\n"
+ " \":swf-quad\" uses quadratic bezier curves instead of cubic ones\n"
+ " \":swf-xlp\" support for lines transparency and scalability\n"
+ " \":swf-flatten=ang\" complementary angle below which 2 lines are merged\n"
+ " * Note: angle \'0\' means no flattening\n"
"\n"
" \":negctts\" uses negative CTS-DTS offsets (ISO4 brand)\n"
" -add file add file tracks to (new) output file\n"
" -cat file concatenates file samples to (new) output file\n"
" * Note: creates tracks if needed\n"
- " * Note: aligns initial timestamp of the file to be concatenated."
- " * Note: new tracks can be imported before concatenation by specifying '+ADD_COMMAND'\n"
+ " * Note: aligns initial timestamp of the file to be concatenated.\n"
+ " -catx file same as cat but new tracks can be imported before concatenation by specifying '+ADD_COMMAND'\n"
" where ADD_COMMAND is a regular -add syntax\n"
" -unalign-cat does not attempt to align timestamps of samples inbetween tracks\n"
" -force-cat skips media configuration check when concatenating file\n"
@@ -442,9 +478,9 @@ void PrintImportUsage()
" -packed forces packed bitstream when importing raw ASP\n"
" -sbr backward compatible signaling of AAC-SBR\n"
" -sbrx non-backward compatible signaling of AAC-SBR\n"
- " -ps: backward compatible signaling of AAC-PS\n"
- " -psx: non-backward compatible signaling of AAC-PS\n"
- " -ovsbr: oversample SBR\n"
+ " -ps backward compatible signaling of AAC-PS\n"
+ " -psx non-backward compatible signaling of AAC-PS\n"
+ " -ovsbr oversample SBR\n"
" * Note: SBR AAC, PS AAC and oversampled SBR cannot be detected at import time\n"
" -fps FPS forces frame rate for video and SUB subtitles import\n"
" FPS is either a number or expressed as timescale-increment\n"
@@ -499,9 +535,9 @@ void PrintEncryptUsage()
"DRM file syntax for GPAC ISMACryp:\n"
" File is XML and shall start with xml header\n"
" File root is an \"ISMACryp\" element\n"
- " File is a list of \"ISMACrypTrack\" elements\n"
+ " File is a list of \"cryptrack\" elements\n"
"\n"
- "ISMACrypTrack attributes are\n"
+ "cryptrack attributes are\n"
" TrackID ID of track to en/decrypt\n"
" key AES-128 key formatted (hex string \'0x\'+32 chars)\n"
" salt CTR IV salt key (64 bits) (hex string \'0x\'+16 chars)\n"
@@ -558,13 +594,17 @@ void PrintHintUsage()
}
void PrintExtractUsage()
{
- fprintf(stderr, "Extracting Options\n"
+ fprintf(stderr, "Extracting Options:\n"
" -raw TrackID extracts track in raw format when supported\n"
+ " :output=FileName sets the output filename for this extraction \n"
" -raws TrackID extract each track sample to a file\n"
" * Note: \"TrackID:N\" extracts Nth sample\n"
" -nhnt TrackID extracts track in nhnt format\n"
" -nhml TrackID extracts track in nhml format (XML nhnt).\n"
- " * Note: \"-nhml +TrackID\" for full dump\n"
+ " * Note: \"-nhml TrackID:full\" for full dump\n"
+ " -webvtt-raw TrackID extracts raw media track in WebVTT as metadata.\n"
+ " * Note: \"-webvtt-raw TrackID:embedded\" to include media data in the WebVTT file\n"
+ " -six TrackID extracts raw media track in experimental XML streaming instructions.\n"
" -single TrackID extracts track to a new mp4 file\n"
" -avi TrackID extracts visual track to an avi file\n"
" -qcp TrackID same as \'-raw\' but defaults to QCP file for EVRC/SMV\n"
@@ -575,6 +615,10 @@ void PrintExtractUsage()
" * Note: can be used when encoding scene descriptions\n"
" -raw-layer ID same as -raw but skips SVC/MVC extractors when extracting\n"
" -diod extracts file IOD in raw format when supported\n"
+ "\n"
+#if !defined(GPAC_DISABLE_STREAMING)
+ " -grab-ts IP:port grabs TS over UDP or RTP at IP:port location to output TS file\n"
+#endif
"\n");
}
void PrintDumpUsage()
@@ -630,6 +674,7 @@ void PrintMetaUsage()
" name=str: item name\n"
" mime=mtype: item mime type\n"
" encoding=enctype: item content-encoding type\n"
+ " id=id: item ID\n"
" * file_path \"this\" or \"self\": item is the file itself\n"
" -rem-item args removes resource from meta - syntax: item_ID[:tk=ID]\n"
" -set-primary args sets item as primary for meta - syntax: item_ID[:tk=ID]\n"
@@ -926,7 +971,7 @@ static void check_media_profile(GF_ISOFile *file, u32 track)
GF_M4VDecSpecInfo dsi;
gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
if (dsi.VideoPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, dsi.VideoPL);
- } else if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) {
+ } else if ((esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_AVC) || (esd->decoderConfig->objectTypeIndication==GPAC_OTI_VIDEO_SVC)) {
gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0x15);
} else if (!PL) {
gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0xFE);
@@ -1063,7 +1108,6 @@ typedef struct
char *line;
} SDPLine;
-
typedef struct
{
/*actions:
@@ -1087,11 +1131,13 @@ typedef struct
} MetaAction;
#ifndef GPAC_DISABLE_ISOM_WRITE
-static Bool parse_meta_args(MetaAction *meta, char *opts)
+static Bool parse_meta_args(MetaAction *meta, u32 act_type, char *opts)
{
Bool ret = 0;
char szSlot[1024], *next;
+ memset(meta, 0, sizeof(MetaAction));
+ meta->act_type = act_type;
meta->mime_type[0] = 0;
meta->enc_type[0] = 0;
meta->szName[0] = 0;
@@ -1114,6 +1160,7 @@ static Bool parse_meta_args(MetaAction *meta, char *opts)
meta->root_meta = 0;
ret = 1;
}
+ else if (!strnicmp(szSlot, "id=", 3)) { meta->item_id = atoi(szSlot+3); ret = 1; }
else if (!strnicmp(szSlot, "name=", 5)) { strcpy(meta->szName, szSlot+5); ret = 1; }
else if (!strnicmp(szSlot, "path=", 5)) { strcpy(meta->szPath, szSlot+5); ret = 1; }
else if (!strnicmp(szSlot, "mime=", 5)) { strcpy(meta->mime_type, szSlot+5); ret = 1; }
@@ -1255,6 +1302,7 @@ typedef struct
6: enables track
7: disables track
8: referenceTrack
+ 9: raw extraction
*/
u32 act_type;
/*track ID*/
@@ -1264,6 +1312,8 @@ typedef struct
const char *kms;
const char *hdl_name;
s32 par_num, par_den;
+ u32 dump_type, sample_num;
+ char *out_name;
} TrackAction;
enum
@@ -1279,11 +1329,18 @@ enum
if (mpd_base_urls) gf_free(mpd_base_urls); \
if (sdp_lines) gf_free(sdp_lines); \
if (metas) gf_free(metas); \
- if (tracks) gf_free(tracks); \
+ if (tracks) { \
+ for (i=0; irepresentationID, opts+3, 99);
- else if (!strnicmp(opts, "period=", 7)) strncpy(di->periodID, opts+7, 99);
+
+ if (!strnicmp(opts, "id=", 3)) {
+ u32 i;
+ strncpy(di->representationID, opts+3, 99);
+ /* check to see if this representation Id has already been assigned */
+ for (i=0; i<(*nb_dash_inputs)-1;i++) {
+ GF_DashSegmenterInput *other_di;
+ other_di = &dash_inputs[i];
+ if (!strcmp(other_di->representationID, di->representationID)) {
+ 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, "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"));
+ }
+ strncpy(di->xlink, opts+6, 199);
+ }
if (!sep) break;
sep[0] = ':';
@@ -1320,6 +1400,56 @@ GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *
return dash_inputs;
}
+static GF_Err parse_track_action_params(char *string, TrackAction *action)
+{
+ char *param = string;
+ while (param) {
+ param = strchr(param, ':');
+ if (param) {
+ *param = 0;
+ param++;
+#ifndef GPAC_DISABLE_MEDIA_EXPORT
+ if (!strncmp("vttnomerge", param, 10)) {
+ action->dump_type |= GF_EXPORT_WEBVTT_NOMERGE;
+ } else if (!strncmp("layer", param, 5)) {
+ action->dump_type |= GF_EXPORT_SVC_LAYER;
+ } else if (!strncmp("full", param, 4)) {
+ action->dump_type |= GF_EXPORT_NHML_FULL;
+ } else if (!strncmp("embedded", param, 8)) {
+ action->dump_type |= GF_EXPORT_WEBVTT_META_EMBEDDED;
+ } else if (!strncmp("output=", param, 7)) {
+ action->out_name = gf_strdup(param+7);
+ } else if (action->dump_type == GF_EXPORT_RAW_SAMPLES) {
+ action->sample_num = atoi(param);
+ }
+#endif
+ }
+ }
+ if (!strcmp(string, "*")) {
+ action->trackID = (u32) -1;
+ } else {
+ action->trackID = atoi(string);
+ }
+ return GF_OK;
+}
+
+static u32 create_new_track_action(char *string, TrackAction **actions, u32 *nb_track_act, u32 dump_type)
+{
+ *actions = (TrackAction *)gf_realloc(*actions, sizeof(TrackAction) * (*nb_track_act+1));
+ memset(&(*actions)[*nb_track_act], 0, sizeof(TrackAction) );
+ (*actions)[*nb_track_act].act_type = 9;
+ (*actions)[*nb_track_act].dump_type = dump_type;
+ parse_track_action_params(string, &(*actions)[*nb_track_act]);
+ (*nb_track_act)++;
+ return dump_type;
+}
+
+static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list)
+{
+ FILE *logs = cbk;
+ vfprintf(logs, fmt, list);
+ fflush(logs);
+}
int mp4boxMain(int argc, char **argv)
{
@@ -1333,19 +1463,23 @@ int mp4boxMain(int argc, char **argv)
MetaAction *metas = NULL;
TrackAction *tracks = NULL;
TSELAction *tsel_acts = NULL;
- u64 movie_time;
+ u64 movie_time, initial_tfdt;
s32 subsegs_per_sidx;
u32 *brand_add = NULL;
u32 *brand_rem = NULL;
GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_INBAND;
- u32 i, stat_level, hint_flags, info_track_id, import_flags, nb_add, nb_cat, ismaCrypt, 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;
- Bool HintIt, needSave, FullInter, Frag, HintInter, dump_std, dump_rtp, dump_mode, regular_iod, trackID, remove_sys_tracks, remove_hint, force_new, remove_root_od, import_subtitle, dump_chap;
- Bool print_sdp, print_info, open_edit, track_dump_type, 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;
+ 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;
+ 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;
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;
+ u32 dump_chap = 0;
char **mpd_base_urls = NULL;
u32 nb_mpd_base_urls=0;
+ u32 dash_scale = 1000;
#ifndef GPAC_DISABLE_MPD
Bool do_mpd = 0;
@@ -1363,14 +1497,20 @@ int mp4boxMain(int argc, char **argv)
Bool live_scene=0;
Bool enable_mem_tracker = 0;
Bool dump_iod=0;
+ Bool pssh_in_moof=0;
Bool daisy_chain_sidx=0;
Bool single_segment=0;
Bool single_file=0;
+ Bool segment_timeline=0;
+ u32 segment_marker = 0;
GF_DashProfile dash_profile = GF_DASH_PROFILE_UNKNOWN;
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;
+ const char *do_wget = NULL;
GF_DashSegmenterInput *dash_inputs = NULL;
u32 nb_dash_inputs = 0;
char *gf_logs = NULL;
@@ -1378,12 +1518,11 @@ int mp4boxMain(int argc, char **argv)
const char *dash_title = NULL;
const char *dash_source = NULL;
const char *dash_more_info = NULL;
-
- if (argc < 2) {
- PrintUsage();
- MP4BOX_EXIT_WITH_CODE(1);
- }
-
+#if !defined(GPAC_DISABLE_STREAMING)
+ const char *grab_m2ts = NULL;
+#endif
+ FILE *logfile = NULL;
+
nb_tsel_acts = nb_add = nb_cat = nb_track_act = nb_sdp_ex = max_ptime = raw_sample_num = nb_meta_act = rtp_rate = major_brand = nb_alt_brand_add = nb_alt_brand_rem = car_dur = minor_version = 0;
e = GF_OK;
split_duration = 0.0;
@@ -1397,17 +1536,20 @@ int mp4boxMain(int argc, char **argv)
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;
- conv_type = HintIt = needSave = print_sdp = print_info = regular_iod = dump_std = open_edit = dump_isom = dump_rtp = dump_cr = dump_chap = dump_srt = dump_ttxt = force_new = dump_timestamps = dump_m2ts = dump_cart = import_subtitle = force_cat = pack_wgt = dash_live = 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;
/*align cat is the new default behaviour for -cat*/
align_cat = 1;
subsegs_per_sidx = 0;
track_dump_type = 0;
- ismaCrypt = 0;
+ crypt = 0;
time_shift_depth = 0;
file = NULL;
itunes_tags = pes_dump = NULL;
seg_name = dash_ctx_file = NULL;
+ initial_moof_sn = 0;
+ initial_tfdt = 0;
#ifndef GPAC_DISABLE_SCENE_ENCODER
memset(&opts, 0, sizeof(opts));
@@ -1425,6 +1567,26 @@ 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
+ enable_mem_tracker = 1;
+#else
+ fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
+#endif
+ break;
+ }
+ }
+
+ gf_sys_init(enable_mem_tracker);
+ if (argc < 2) {
+ PrintUsage();
+ MP4BOX_EXIT_WITH_CODE(1);
+ }
+
+
/*parse our args*/
for (i = 1; i < (u32) argc ; i++) {
arg = argv[i];
@@ -1457,11 +1619,20 @@ int mp4boxMain(int argc, char **argv)
else if (!stricmp(arg, "-version")) { PrintVersion(); MP4BOX_EXIT_WITH_CODE(0); }
else if (!stricmp(arg, "-sdp")) print_sdp = 1;
else if (!stricmp(arg, "-quiet")) quiet = 2;
+ else if (!strcmp(argv[i], "-mem-track")) continue;
+
else if (!stricmp(arg, "-logs")) {
CHECK_NEXT_ARG
gf_logs = argv[i+1];
+ if (gf_logs)
+ gf_log_set_tools_levels(gf_logs);
i++;
}
+ else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) {
+ logfile = gf_f64_open(argv[i+1], "wt");
+ gf_log_set_callback(logfile, on_gpac_log);
+ i++;
+ }
else if (!stricmp(arg, "-noprog")) quiet = 1;
else if (!stricmp(arg, "-info")) {
print_info = 1;
@@ -1474,6 +1645,20 @@ int mp4boxMain(int argc, char **argv)
info_track_id=0;
}
}
+#if !defined(GPAC_DISABLE_STREAMING)
+ else if (!stricmp(arg, "-grab-ts")) {
+ CHECK_NEXT_ARG
+ grab_m2ts = argv[i+1];
+ i++;
+ }
+#endif
+#if !defined(GPAC_DISABLE_CORE_TOOLS)
+ else if (!stricmp(arg, "-wget")) {
+ CHECK_NEXT_ARG
+ do_wget = argv[i+1];
+ i++;
+ }
+#endif
/*******************************************************************************/
else if (!stricmp(arg, "-dvbhdemux")) {
dvbhdemux = 1;
@@ -1482,20 +1667,17 @@ int mp4boxMain(int argc, char **argv)
#ifndef GPAC_DISABLE_MEDIA_EXPORT
else if (!stricmp(arg, "-raw")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_NATIVE;
- trackID = atoi(argv[i+1]);
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE);
i++;
}
else if (!stricmp(arg, "-raw-layer")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER;
- trackID = atoi(argv[i+1]);
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER);
i++;
}
else if (!stricmp(arg, "-qcp")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP;
- trackID = atoi(argv[i+1]);
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP);
i++;
}
else if (!stricmp(arg, "-aviraw")) {
@@ -1511,35 +1693,32 @@ int mp4boxMain(int argc, char **argv)
}
else if (!stricmp(arg, "-raws")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_RAW_SAMPLES;
- if (strchr(argv[i+1], ':')) {
- sscanf(argv[i+1], "%u:%u", &trackID, &raw_sample_num);
- } else {
- trackID = atoi(argv[i+1]);
- }
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_RAW_SAMPLES);
i++;
}
else if (!stricmp(arg, "-nhnt")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_NHNT;
- trackID = atoi(argv[i+1]);
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NHNT);
i++;
}
else if (!stricmp(arg, "-nhml")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_NHML;
- if (argv[i+1][0]=='+') {
- track_dump_type |= GF_EXPORT_NHML_FULL;
- trackID = atoi(argv[i+1] + 1);
- } else {
- trackID = atoi(argv[i+1]);
- }
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_NHML);
+ i++;
+ }
+ else if (!stricmp(arg, "-webvtt-raw")) {
+ CHECK_NEXT_ARG
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_WEBVTT_META);
+ i++;
+ }
+ else if (!stricmp(arg, "-six")) {
+ CHECK_NEXT_ARG
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_SIX);
i++;
}
else if (!stricmp(arg, "-avi")) {
CHECK_NEXT_ARG
- track_dump_type = GF_EXPORT_AVI;
- trackID = atoi(argv[i+1]);
+ track_dump_type = create_new_track_action(argv[i+1], &tracks, &nb_track_act, GF_EXPORT_AVI);
i++;
}
#endif /*GPAC_DISABLE_MEDIA_EXPORT*/
@@ -1583,6 +1762,7 @@ int mp4boxMain(int argc, char **argv)
else if (!stricmp(arg, "-diso")) dump_isom = 1;
else if (!stricmp(arg, "-dump-cover")) dump_cart = 1;
else if (!stricmp(arg, "-dump-chap")) dump_chap = 1;
+ else if (!stricmp(arg, "-dump-chap-ogg")) dump_chap = 2;
else if (!stricmp(arg, "-hash")) do_hash = 1;
else if (!stricmp(arg, "-dmp4")) {
@@ -1663,13 +1843,7 @@ int mp4boxMain(int argc, char **argv)
}
else if (!stricmp(arg, "-cprt")) { CHECK_NEXT_ARG cprt = argv[i+1]; i++; if (!dash_duration) open_edit = 1; }
else if (!stricmp(arg, "-chap")) { CHECK_NEXT_ARG chap_file = argv[i+1]; i++; open_edit = 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, "-strict-error")) {
+ else if (!strcmp(arg, "-strict-error")) {
gf_log_set_strict_error(1);
} else if (!stricmp(arg, "-inter") || !stricmp(arg, "-old-inter")) {
CHECK_NEXT_ARG
@@ -1686,11 +1860,19 @@ int mp4boxMain(int argc, char **argv)
Frag = 1;
} else if (!stricmp(arg, "-dash")) {
CHECK_NEXT_ARG
- dash_duration = atof(argv[i+1]) / 1000;
+ dash_duration = atof(argv[i+1]) / 1000;
i++;
} else if (!stricmp(arg, "-subdur")) {
CHECK_NEXT_ARG
- dash_subduration = atof(argv[i+1]) / 1000;
+ dash_subduration = atof(argv[i+1]) / 1000;
+ i++;
+ } else if (!stricmp(arg, "-dash-scale")) {
+ CHECK_NEXT_ARG
+ dash_scale = atoi(argv[i+1]);
+ if (!dash_scale) {
+ fprintf(stderr, "\tERROR: \"-dash-scale\": invalid parameter %s\n", argv[i+1]);
+ MP4BOX_EXIT_WITH_CODE(1);
+ }
i++;
} else if (!stricmp(arg, "-dash-ts-prog")) {
CHECK_NEXT_ARG
@@ -1745,6 +1927,17 @@ int mp4boxMain(int argc, char **argv)
ast_shift_sec = (u32) atoi(argv[i+1]);
i++;
}
+ else if (!stricmp(arg, "-moof-sn")) {
+ CHECK_NEXT_ARG
+ initial_moof_sn = (u32) atoi(argv[i+1]);
+ i++;
+ }
+ else if (!stricmp(arg, "-tfdt")) {
+ CHECK_NEXT_ARG
+ sscanf(argv[i+1], LLU, &initial_tfdt);
+ i++;
+ }
+ else if (!stricmp(arg, "-no-frags-default")) { no_fragments_defaults = 1; }
else if (!stricmp(arg, "-mpd-title")) { CHECK_NEXT_ARG dash_title = argv[i+1]; i++; }
else if (!stricmp(arg, "-mpd-source")) { CHECK_NEXT_ARG dash_source = argv[i+1]; i++; }
else if (!stricmp(arg, "-mpd-info-url")) { CHECK_NEXT_ARG dash_more_info = argv[i+1]; i++; }
@@ -1767,11 +1960,19 @@ int mp4boxMain(int argc, char **argv)
single_segment = 1;
} else if (!stricmp(arg, "-single-file")) {
single_file = 1;
+ } else if (!stricmp(arg, "-pssh-moof")) {
+ pssh_in_moof = 1;
} else if (!stricmp(arg, "-dash-profile") || !stricmp(arg, "-profile")) {
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], "main")) dash_profile = GF_DASH_PROFILE_MAIN;
+ 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 (!strnicmp(arg, "-url-template", 13)) {
@@ -1779,8 +1980,16 @@ int mp4boxMain(int argc, char **argv)
if ((arg[13]=='=') && arg[14]) {
if (!strcmp( &arg[14], "simulate")) use_url_template = 2;
}
- }
- else if (!stricmp(arg, "-itags")) { CHECK_NEXT_ARG itunes_tags = argv[i+1]; i++; open_edit = 1; }
+ } else if (!stricmp(arg, "-segment-timeline")) {
+ segment_timeline = 1;
+ } else if (!stricmp(arg, "-mem-frags")) {
+ memory_frags = 1;
+ } else if (!stricmp(arg, "-segment-marker")) {
+ char *m;
+ CHECK_NEXT_ARG
+ m = argv[i+1];
+ segment_marker = GF_4CC(m[0], m[1], m[2], m[3]);
+ } else if (!stricmp(arg, "-itags")) { CHECK_NEXT_ARG itunes_tags = argv[i+1]; i++; open_edit = 1; }
#ifndef GPAC_DISABLE_ISOM_HINTING
else if (!stricmp(arg, "-hint")) { open_edit = 1; HintIt = 1; }
else if (!stricmp(arg, "-unhint")) { open_edit = 1; remove_hint = 1; }
@@ -1856,12 +2065,18 @@ int mp4boxMain(int argc, char **argv)
#ifndef GPAC_DISABLE_MEDIA_EXPORT
CHECK_NEXT_ARG
track_dump_type = GF_EXPORT_MP4;
- trackID = atoi(argv[i+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 = 9;
+ tracks[nb_track_act].trackID = atoi(argv[i+1]);
+ tracks[nb_track_act].dump_type = GF_EXPORT_MP4;
+ nb_track_act++;
i++;
#endif
}
else if (!stricmp(arg, "-iod")) regular_iod = 1;
else if (!stricmp(arg, "-flat")) do_flat = 1;
+ else if (!stricmp(arg, "-keep-utc")) keep_utc = 1;
else if (!stricmp(arg, "-new")) force_new = 1;
else if (!stricmp(arg, "-add") || !stricmp(arg, "-import") || !stricmp(arg, "-convert")) {
CHECK_NEXT_ARG
@@ -1870,7 +2085,7 @@ int mp4boxMain(int argc, char **argv)
nb_add++;
i++;
}
- else if (!stricmp(arg, "-cat")) {
+ else if (!stricmp(arg, "-cat") || !stricmp(arg, "-catx")) {
CHECK_NEXT_ARG
nb_cat++;
i++;
@@ -1899,6 +2114,7 @@ int mp4boxMain(int argc, char **argv)
else if (!stricmp(arg, "-rem") || !stricmp(arg, "-disable") || !stricmp(arg, "-enable")) {
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
if (!stricmp(arg, "-enable")) tracks[nb_track_act].act_type = 6;
else if (!stricmp(arg, "-disable")) tracks[nb_track_act].act_type = 7;
@@ -1912,6 +2128,7 @@ int mp4boxMain(int argc, char **argv)
char szTK[20], *ext;
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
tracks[nb_track_act].act_type = 4;
assert(strlen(argv[i+1])+1 <= sizeof(szTK));
@@ -1942,6 +2159,7 @@ int mp4boxMain(int argc, char **argv)
char szTK[20], *ext;
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
tracks[nb_track_act].act_type = 1;
tracks[nb_track_act].lang[3] = 0;
@@ -1966,6 +2184,7 @@ int mp4boxMain(int argc, char **argv)
char szTK[20], *ext;
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
strcpy(szTK, argv[i+1]);
ext = strchr(szTK, '=');
@@ -1985,6 +2204,7 @@ int mp4boxMain(int argc, char **argv)
char *szTK, *ext;
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
szTK = argv[i+1];
ext = strchr(szTK, ':');
@@ -2011,6 +2231,7 @@ int mp4boxMain(int argc, char **argv)
char szTK[GF_MAX_PATH], *ext;
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
strcpy(szTK, argv[i+1]);
ext = strchr(szTK, '=');
@@ -2125,14 +2346,14 @@ int mp4boxMain(int argc, char **argv)
#endif /*GPAC_DISABLE_SCENE_ENCODER*/
else if (!strcmp(arg, "-crypt")) {
CHECK_NEXT_ARG
- ismaCrypt = 1;
+ crypt = 1;
drm_file = argv[i+1];
open_edit = 1;
i += 1;
}
else if (!strcmp(arg, "-decrypt")) {
CHECK_NEXT_ARG
- ismaCrypt = 2;
+ crypt = 2;
if (get_file_type_by_ext(argv[i+1])!=1) {
drm_file = argv[i+1];
i += 1;
@@ -2143,6 +2364,7 @@ int mp4boxMain(int argc, char **argv)
char szTK[20], *ext;
CHECK_NEXT_ARG
tracks = gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
+ memset(&tracks[nb_track_act], 0, sizeof(TrackAction) );
strncpy(szTK, argv[i+1], 19);
ext = strchr(szTK, '=');
@@ -2176,8 +2398,7 @@ int mp4boxMain(int argc, char **argv)
}
else if (!stricmp(arg, "-split-size") || !stricmp(arg, "-splits")) {
CHECK_NEXT_ARG
- split_size = atoi(argv[i+1]);
- if (split_size<0) split_size = 0;
+ split_size = (u32) atoi(argv[i+1]);
i++;
split_duration = 0;
}
@@ -2201,70 +2422,54 @@ int mp4boxMain(int argc, char **argv)
/*meta*/
else if (!stricmp(arg, "-set-meta")) {
metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1));
-
- metas[nb_meta_act].act_type = 0;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 0, 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));
-
- metas[nb_meta_act].act_type = 1;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 1, 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));
-
- metas[nb_meta_act].act_type = 2;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 2, 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));
-
- metas[nb_meta_act].act_type = 3;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 3, 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));
-
- metas[nb_meta_act].act_type = 4;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 4, 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));
-
- metas[nb_meta_act].act_type = 6;
- if (parse_meta_args(&metas[nb_meta_act], argv[i+1])) i++;
+ if (parse_meta_args(&metas[nb_meta_act], 6, 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));
-
- metas[nb_meta_act].act_type = 7;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 7, argv[i+1]);
nb_meta_act++;
i++;
}
else if (!stricmp(arg, "-dump-item")) {
metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act+1));
-
- metas[nb_meta_act].act_type = 8;
- parse_meta_args(&metas[nb_meta_act], argv[i+1]);
+ parse_meta_args(&metas[nb_meta_act], 8, argv[i+1]);
nb_meta_act++;
i++;
}
@@ -2443,7 +2648,7 @@ int mp4boxMain(int argc, char **argv)
gf_f64_seek(fin, 0, SEEK_SET);
done = 0;
while (1) {
- u32 nb_bytes = fread(chunk, 1, 4096, fin);
+ u32 nb_bytes = (u32) fread(chunk, 1, 4096, fin);
gf_fwrite(chunk, 1, nb_bytes, fout);
done += nb_bytes;
fprintf(stderr, "Appending file %s - %02.2f done\r", raw_cat, 100.0*done/to_copy);
@@ -2453,12 +2658,19 @@ int mp4boxMain(int argc, char **argv)
fclose(fout);
MP4BOX_EXIT_WITH_CODE(0);
}
-
+#if !defined(GPAC_DISABLE_STREAMING)
+ if (grab_m2ts) {
+ return grab_live_m2ts(grab_m2ts, inName);
+ }
+#endif
/*init libgpac*/
- gf_sys_init(enable_mem_tracker);
+ if (enable_mem_tracker) {
+ gf_sys_close();
+ gf_sys_init(enable_mem_tracker);
+ }
if (gf_logs) {
- gf_log_set_tools_levels(gf_logs);
+ //gf_log_set_tools_levels(gf_logs);
} else {
u32 level = verbose ? GF_LOG_DEBUG : GF_LOG_INFO;
gf_log_set_tool_level(GF_LOG_CONTAINER, level);
@@ -2477,11 +2689,22 @@ int mp4boxMain(int argc, char **argv)
}
}
+#if !defined(DISABLE_CORE_TOOLS)
+ if (do_wget != NULL) {
+ e = gf_dm_wget(do_wget, inName, 0, 0);
+ if (e != GF_OK) {
+ fprintf(stderr, "Cannot retrieve %s: %s\n", do_wget, gf_error_to_string(e) );
+ }
+ MP4BOX_EXIT_WITH_CODE(1);
+ }
+#endif
+
#ifndef GPAC_DISABLE_MPD
if (do_mpd) {
Bool remote = 0;
char *mpd_base_url = gf_strdup(inName);
if (!strnicmp(inName, "http://", 7)) {
+#if !defined(GPAC_DISABLE_CORE_TOOLS)
e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0);
if (e != GF_OK) {
fprintf(stderr, "Cannot retrieve M3U8 (%s): %s\n", inName, gf_error_to_string(e));
@@ -2490,9 +2713,14 @@ int mp4boxMain(int argc, char **argv)
}
inName = "tmp_main.m3u8";
remote = 1;
+#else
+ 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);
+ 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);
+
if (remote) {
//gf_delete_file("tmp_main.m3u8");
}
@@ -2645,8 +2873,8 @@ int mp4boxMain(int argc, char **argv)
}
}
for (i=0; i<(u32)argc; i++) {
- if (!strcmp(argv[i], "-cat")) {
- e = cat_isomedia_file(file, argv[i+1], import_flags, import_fps, agg_samples, tmpdir, force_cat, align_cat);
+ if (!strcmp(argv[i], "-cat") || !strcmp(argv[i], "-catx")) {
+ e = cat_isomedia_file(file, argv[i+1], import_flags, import_fps, agg_samples, tmpdir, force_cat, align_cat, !strcmp(argv[i], "-catx") ? GF_TRUE : GF_FALSE);
if (e) {
fprintf(stderr, "Error appending %s: %s\n", argv[i+1], gf_error_to_string(e));
gf_isom_delete(file);
@@ -2722,8 +2950,8 @@ int mp4boxMain(int argc, char **argv)
}
#endif
-
if (dash_duration) {
+ Bool del_file = GF_FALSE;
char szMPD[GF_MAX_PATH], *sep;
GF_Config *dash_ctx = NULL;
u32 do_abort = 0;
@@ -2735,7 +2963,8 @@ int mp4boxMain(int argc, char **argv)
strcpy(szMPD, outfile);
strcat(szMPD, ".mpd");
- fprintf(stderr, "Live DASH-ing - press 'q' to quit, 's' to save context and quit\n");
+ if (dash_dynamic && dash_live)
+ fprintf(stderr, "Live DASH-ing - press 'q' to quit, 's' to save context and quit\n");
if (!dash_ctx_file && dash_live) {
dash_ctx = gf_cfg_new(NULL, NULL);
@@ -2758,13 +2987,20 @@ int mp4boxMain(int argc, char **argv)
fprintf(stderr, "Using default MPD refresh of %d seconds\n", mpd_update_time);
}
+ if (file && needSave) {
+ gf_isom_close(file);
+ file = NULL;
+ del_file = GF_TRUE;
+ }
while (!do_abort) {
+
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, single_segment, single_file, bitstream_switching_mode,
- seg_at_rap, dash_duration, seg_name, seg_ext,
+ 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_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);
if (e) break;
if (dash_live) {
@@ -2776,11 +3012,14 @@ int mp4boxMain(int argc, char **argv)
if (c=='q') { do_abort = 1; break; }
if (c=='s') { do_abort = 2; break; }
}
- if (sleep_for<100) break;
- if (dash_dynamic != 2) {
- gf_sleep(100);
+ if (dash_dynamic == 2) {
+ break;
}
+ if (sleep_for<100)
+ break;
+ gf_sleep(100);
+
sleep_for = gf_dasher_next_update_time(dash_ctx, mpd_update_time);
}
} else {
@@ -2800,8 +3039,10 @@ int mp4boxMain(int argc, char **argv)
gf_cfg_del(dash_ctx);
}
if (e) fprintf(stderr, "Error DASHing file: %s\n", gf_error_to_string(e));
-
- gf_sys_close();
+ if (file) gf_isom_delete(file);
+ if (del_file)
+ gf_delete_file(inName);
+
MP4BOX_EXIT_WITH_CODE( (e!=GF_OK) ? 1 : 0 );
}
@@ -2842,7 +3083,7 @@ int mp4boxMain(int argc, char **argv)
case 3:
/*allowed for svg->lsr**/
case 4:
- /*allowed for swf->bt, swf->xmt*/
+ /*allowed for swf->bt, swf->xmt, swf->svg*/
case 5:
break;
/*used for .saf / .lsr dump*/
@@ -2907,6 +3148,10 @@ int mp4boxMain(int argc, char **argv)
}
}
+ if (file && keep_utc && open_edit) {
+ gf_isom_keep_utc_times(file, 1);
+ }
+
strcpy(outfile, outName ? outName : inName);
if (strrchr(outfile, '.')) {
char *szExt = strrchr(outfile, '.');
@@ -2949,13 +3194,27 @@ int mp4boxMain(int argc, char **argv)
}
if (!open_edit && !gf_isom_probe_file(inName) && track_dump_type) {
GF_MediaExporter mdump;
- memset(&mdump, 0, sizeof(mdump));
- mdump.in_name = inName;
- mdump.flags = track_dump_type;
- mdump.trackID = trackID;
- mdump.out_name = outfile;
- e = gf_media_export(&mdump);
- if (e) goto err_exit;
+ char szFile[1024];
+ for (i=0; iact_type != 9) continue;
+ memset(&mdump, 0, sizeof(mdump));
+ mdump.in_name = inName;
+ mdump.flags = tka->dump_type;
+ mdump.trackID = tka->trackID;
+ mdump.sample_num = raw_sample_num;
+ if (outName) {
+ mdump.out_name = outName;
+ mdump.flags |= GF_EXPORT_MERGE;
+ } else if (nb_track_act>1) {
+ sprintf(szFile, "%s_track%d", outfile, mdump.trackID);
+ mdump.out_name = szFile;
+ } else {
+ mdump.out_name = outfile;
+ }
+ e = gf_media_export(&mdump);
+ if (e) goto err_exit;
+ }
MP4BOX_EXIT_WITH_CODE(0);
}
@@ -3004,7 +3263,7 @@ int mp4boxMain(int argc, char **argv)
fprintf(stderr, "\n");
}
if (dump_cart) dump_cover_art(file, outfile);
- if (dump_chap) dump_chapters(file, outfile);
+ if (dump_chap) dump_chapters(file, outfile, (dump_chap==2) ? 1 : 0);
if (dump_iod) {
GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)gf_isom_get_root_od(file);
@@ -3045,25 +3304,46 @@ int mp4boxMain(int argc, char **argv)
#endif
#ifndef GPAC_DISABLE_MEDIA_EXPORT
- if (do_saf || track_dump_type) {
+ if (track_dump_type) {
char szFile[1024];
GF_MediaExporter mdump;
- memset(&mdump, 0, sizeof(mdump));
- mdump.file = file;
- mdump.flags = do_saf ? GF_EXPORT_SAF : track_dump_type;
- if (!do_saf) {
- mdump.trackID = trackID;
+ for (i=0; iact_type != 9) continue;
+ memset(&mdump, 0, sizeof(mdump));
+ mdump.file = file;
+ mdump.flags = tka->dump_type;
+ mdump.trackID = tka->trackID;
mdump.sample_num = raw_sample_num;
- if (outName) {
+ if (tka->out_name) {
+ mdump.out_name = tka->out_name;
+ } else if (outName) {
mdump.out_name = outName;
mdump.flags |= GF_EXPORT_MERGE;
} else {
- sprintf(szFile, "%s_track%d", outfile, trackID);
+ sprintf(szFile, "%s_track%d", outfile, mdump.trackID);
mdump.out_name = szFile;
}
- } else {
- mdump.out_name = outfile;
+ if (tka->trackID==(u32) -1) {
+ u32 j;
+ for (j=0; jszPath, "NULL") || !stricmp(meta->szPath, "this") || !stricmp(meta->szPath, "self");
e = gf_isom_add_meta_item(file, meta->root_meta, tk, self_ref, self_ref ? NULL : meta->szPath,
strlen(meta->szName) ? meta->szName : NULL,
+ meta->item_id,
strlen(meta->mime_type) ? meta->mime_type : NULL,
strlen(meta->enc_type) ? meta->enc_type : NULL,
meta->use_dref ? meta->szPath : NULL, NULL);
@@ -3134,7 +3415,6 @@ int mp4boxMain(int argc, char **argv)
}
if (!open_edit && !needSave) {
if (file) gf_isom_delete(file);
- gf_sys_close();
MP4BOX_EXIT_WITH_CODE(0);
}
@@ -3198,7 +3478,6 @@ int mp4boxMain(int argc, char **argv)
if (!encode) {
if (!file) {
fprintf(stderr, "Nothing to do - exiting\n");
- gf_sys_close();
MP4BOX_EXIT_WITH_CODE(0);
}
if (outName) {
@@ -3226,7 +3505,7 @@ int mp4boxMain(int argc, char **argv)
if ((conv_type == GF_ISOM_CONV_TYPE_ISMA) || (conv_type == GF_ISOM_CONV_TYPE_ISMA_EX)) {
fprintf(stderr, "Converting to ISMA Audio-Video MP4 file...\n");
/*keep ESIDs when doing ISMACryp*/
- e = gf_media_make_isma(file, ismaCrypt ? 1 : 0, 0, (conv_type==GF_ISOM_CONV_TYPE_ISMA_EX) ? 1 : 0);
+ e = gf_media_make_isma(file, crypt ? 1 : 0, 0, (conv_type==GF_ISOM_CONV_TYPE_ISMA_EX) ? 1 : 0);
if (e) goto err_exit;
needSave = 1;
}
@@ -3303,16 +3582,16 @@ int mp4boxMain(int argc, char **argv)
}
#ifndef GPAC_DISABLE_MCRYPT
- if (ismaCrypt) {
- if (ismaCrypt == 1) {
- if (!drm_file) {
- fprintf(stderr, "Missing DRM file location - usage '-%s drm_file input_file\n", (ismaCrypt==1) ? "crypt" : "decrypt");
- e = GF_BAD_PARAM;
- goto err_exit;
- }
- e = gf_ismacryp_crypt_file(file, drm_file);
- } else if (ismaCrypt ==2) {
- e = gf_ismacryp_decrypt_file(file, drm_file);
+ if (crypt) {
+ if (!drm_file) {
+ fprintf(stderr, "Missing DRM file location - usage '-%s drm_file input_file\n", (crypt==1) ? "crypt" : "decrypt");
+ e = GF_BAD_PARAM;
+ goto err_exit;
+ }
+ if (crypt == 1) {
+ e = gf_crypt_file(file, drm_file);
+ } else if (crypt ==2) {
+ e = gf_decrypt_file(file, drm_file);
}
if (e) goto err_exit;
needSave = 1;
@@ -3453,7 +3732,7 @@ int mp4boxMain(int argc, char **argv)
if ((val[0]==':') || !val[0] || !stricmp(val, "NULL") ) val = NULL;
}
- tlen = val ? strlen(val) : 0;
+ tlen = val ? (u32) strlen(val) : 0;
switch (itag) {
case GF_ISOM_ITUNE_COVER_ART:
{
@@ -3463,7 +3742,7 @@ int mp4boxMain(int argc, char **argv)
tlen = (u32) gf_f64_tell(t);
gf_f64_seek(t, 0, SEEK_SET);
d = gf_malloc(sizeof(char) * tlen);
- tlen = fread(d, sizeof(char), tlen, t);
+ tlen = (u32) fread(d, sizeof(char), tlen, t);
fclose(t);
ext = strrchr(val, '.');
@@ -3481,7 +3760,7 @@ int mp4boxMain(int argc, char **argv)
if (_v) {
gf_isom_apple_set_tag(file, itag, NULL, _v);
} else {
- gf_isom_apple_set_tag(file, itag, val, strlen(val) );
+ gf_isom_apple_set_tag(file, itag, val, (u32) strlen(val) );
}
}
break;
@@ -3543,7 +3822,6 @@ int mp4boxMain(int argc, char **argv)
if (gf_delete_file(inName)) fprintf(stderr, "Error removing file %s\n", inName);
else if (gf_move_file(outfile, inName)) fprintf(stderr, "Error renaming file %s to %s\n", outfile, inName);
}
- gf_sys_close();
MP4BOX_EXIT_WITH_CODE( (e!=GF_OK) ? 1 : 0 );
}
#endif
@@ -3659,21 +3937,17 @@ int mp4boxMain(int argc, char **argv)
} else {
gf_isom_delete(file);
}
- /*close libgpac*/
- gf_sys_close();
if (e) fprintf(stderr, "Error: %s\n", gf_error_to_string(e));
MP4BOX_EXIT_WITH_CODE( (e!=GF_OK) ? 1 : 0 );
#else
/*close libgpac*/
- gf_sys_close();
gf_isom_delete(file);
fprintf(stderr, "Error: Read-only version of MP4Box.\n");
MP4BOX_EXIT_WITH_CODE(1);
#endif
err_exit:
/*close libgpac*/
- gf_sys_close();
if (file) gf_isom_delete(file);
fprintf(stderr, "\n\tError: %s\n", gf_error_to_string(e));
MP4BOX_EXIT_WITH_CODE(1);
diff --git a/applications/mp4client/Makefile b/applications/mp4client/Makefile
index 00d37e4..b699020 100644
--- a/applications/mp4client/Makefile
+++ b/applications/mp4client/Makefile
@@ -56,10 +56,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c
index 7fcd459..013724a 100644
--- a/applications/mp4client/main.c
+++ b/applications/mp4client/main.c
@@ -31,10 +31,12 @@
#include
#include
#include
+#include
/*ISO 639 languages*/
#include
+//FIXME we need a plugin for playlists
#include
@@ -59,43 +61,45 @@ void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 ind
void ViewODs(GF_Terminal *term, Bool show_timing);
void PrintGPACConfig();
-static Bool gui_mode = 0;
+static u32 gui_mode = 0;
-static Bool restart = 0;
-static Bool reload = 0;
+static Bool restart = GF_FALSE;
+static Bool reload = GF_FALSE;
#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;
#else
static u32 threading_flags = 0;
#endif
-static Bool no_audio = 0;
-static Bool term_step = 0;
-static Bool no_regulation = 0;
-static Bool bench_mode = 0;
-Bool is_connected = 0;
-Bool startup_file = 0;
+static Bool no_audio = GF_FALSE;
+static Bool term_step = GF_FALSE;
+static Bool no_regulation = GF_FALSE;
+static u32 bench_mode = 0;
+static u32 bench_mode_start = 0;
+static u32 bench_buffer = 0;
+static Bool eos_seen = GF_FALSE;
+Bool is_connected = GF_FALSE;
+Bool startup_file = GF_FALSE;
GF_User user;
GF_Terminal *term;
u64 Duration;
GF_Err last_error = GF_OK;
-static Fixed bench_speed = FLT2FIX(20);
-
-static Bool request_next_playlist_item = 0;
+static Bool request_next_playlist_item = GF_FALSE;
FILE *playlist = NULL;
-static Bool readonly_playlist = 0;
+static Bool readonly_playlist = GF_FALSE;
static GF_Config *cfg_file;
-static Bool display_rti = 0;
+static u32 display_rti = 0;
static Bool Run;
-static Bool CanSeek = 0;
+static Bool CanSeek = GF_FALSE;
static char the_url[GF_MAX_PATH];
static char pl_path[GF_MAX_PATH];
-static Bool no_mime_check = 1;
-static Bool be_quiet = 0;
+static Bool no_mime_check = GF_TRUE;
+static Bool be_quiet = GF_FALSE;
static u32 log_time_start = 0;
-static Bool loop_at_end = 0;
+static Bool log_utc_time = GF_FALSE;
+static Bool loop_at_end = GF_FALSE;
static u32 forced_width=0;
static u32 forced_height=0;
@@ -104,7 +108,7 @@ u32 align_mode = 0;
u32 init_w = 0;
u32 init_h = 0;
u32 last_x, last_y;
-Bool right_down = 0;
+Bool right_down = GF_FALSE;
void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum);
Bool dump_file(char *the_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times);
@@ -175,6 +179,9 @@ void PrintUsage()
"\t \"mutex\" : mutex\n"
"\t \"all\" : all tools logged - other tools can be specified afterwards.\n"
"\n"
+ "\t-log-clock or -lc : logs time in ms since start time of GPAC before each log line.\n"
+ "\t-log-utc or -lu : logs UTC time in ms before each log line.\n"
+ "\t-ifce IPIFCE : Sets default Multicast interface\n"
"\t-size WxH: specifies visual size (default: scene size)\n"
#if defined(__DARWIN__) || defined(__APPLE__)
"\t-thread: enables thread usage for terminal and compositor \n"
@@ -192,6 +199,9 @@ void PrintUsage()
"\t-pause: pauses at first frame\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"
@@ -248,6 +258,7 @@ void PrintHelp()
"\tt: print current timing\n"
"\n"
"\tu: sends a command (BIFS or LASeR) to the main scene\n"
+ "\te: evaluates JavaScript code\n"
"\tZ: dumps output video to PNG\n"
"\n"
"\tw: view world info\n"
@@ -295,8 +306,6 @@ void PrintHelp()
}
-
-
static void PrintTime(u64 time)
{
u32 ms, h, m, s;
@@ -307,6 +316,8 @@ static void PrintTime(u64 time)
fprintf(stderr, "%02d:%02d:%02d.%03d", h, m, s, ms);
}
+void PrintAVInfo(Bool final);
+
static u32 rti_update_time_ms = 200;
static FILE *rti_logs = NULL;
@@ -323,15 +334,18 @@ static void UpdateRTInfo(const char *legend)
if (display_rti) {
char szMsg[1024];
- if (rti.total_cpu_usage) {
- sprintf(szMsg, "FPS %02.2f - CPU %02d (%02d) - Mem %d kB",
- gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 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));
} else {
- sprintf(szMsg, "FPS %02.2f - CPU %02d - Mem %d kB",
- gf_term_get_framerate(term, 0), rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
+ 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) );
}
-
+
if (display_rti==2) {
+ if (bench_mode==2) {
+ PrintAVInfo(GF_FALSE);
+ }
fprintf(stderr, "%s\r", szMsg);
} else {
GF_Event evt;
@@ -400,15 +414,14 @@ u32 get_sys_col(int idx)
}
#endif
-void switch_bench()
+void switch_bench(u32 is_on)
{
- if (is_connected) {
- bench_mode = !bench_mode;
- display_rti = !display_rti;
- ResetCaption();
- gf_term_set_speed(term, bench_mode ? bench_speed : FIX_ONE);
- }
+ bench_mode = is_on;
+ display_rti = is_on ? 2 : 0;
+ ResetCaption();
+ gf_term_set_option(term, GF_OPT_VIDEO_BENCH, is_on);
}
+
#ifndef WIN32
#include
int getch() {
@@ -438,7 +451,8 @@ int getch(){
/**
* Reads a line of input from stdin
* @param line the buffer to fill
- * @param
+ * @param maxSize the maximum size of the line to read
+ * @param showContent boolean indicating if the line read should be printed on stderr or not
*/
static const char * read_line_input(char * line, int maxSize, Bool showContent){
char read;
@@ -471,7 +485,9 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
if (!term) return 0;
if (gui_mode==1) {
- if (evt->type==GF_EVENT_QUIT) Run = 0;
+ if (evt->type==GF_EVENT_QUIT) {
+ Run = 0;
+ }
return 0;
}
@@ -492,6 +508,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
servName = evt->message.service;
}
+
if (!evt->message.message) return 0;
if (evt->message.error) {
@@ -506,13 +523,23 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
}
break;
case GF_EVENT_PROGRESS:
- {
- char *szTitle = "";
- if (evt->progress.progress_type==0) szTitle = "Buffer ";
- else if (evt->progress.progress_type==1) szTitle = "Download ";
- else if (evt->progress.progress_type==2) szTitle = "Import ";
- gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
- }
+ {
+ char *szTitle = "";
+ if (evt->progress.progress_type==0) {
+ szTitle = "Buffer ";
+ if (bench_mode) {
+ if (evt->progress.done >= evt->progress.total) bench_buffer = 0;
+ else bench_buffer = 1 + 100*evt->progress.done / evt->progress.total;
+ break;
+ }
+ }
+ else if (evt->progress.progress_type==1) {
+ if (bench_mode) break;
+ szTitle = "Download ";
+ }
+ else if (evt->progress.progress_type==2) szTitle = "Import ";
+ gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
+ }
break;
@@ -548,7 +575,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
case GF_EVENT_KEYUP:
switch (evt->key.key_code) {
case GF_KEY_SPACE:
- if (evt->key.flags & GF_KEY_MOD_CTRL) switch_bench();
+ if (evt->key.flags & GF_KEY_MOD_CTRL) switch_bench(!bench_mode);
break;
}
break;
@@ -558,7 +585,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
case GF_KEY_SPACE:
if (evt->key.flags & GF_KEY_MOD_CTRL) {
/*ignore key repeat*/
- if (!bench_mode) switch_bench();
+ if (!bench_mode) switch_bench(!bench_mode);
}
break;
case GF_KEY_PAGEDOWN:
@@ -637,6 +664,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
if (evt->connect.is_connected) {
is_connected = 1;
fprintf(stderr, "Service Connected\n");
+ eos_seen = GF_FALSE;
} else if (is_connected) {
fprintf(stderr, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed");
is_connected = 0;
@@ -648,6 +676,7 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
ResetCaption();
break;
case GF_EVENT_EOS:
+ eos_seen = GF_TRUE;
if (!playlist && loop_at_end) restart = 1;
break;
case GF_EVENT_SIZE:
@@ -701,6 +730,9 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
return 1;
case GF_EVENT_QUIT:
+ if (evt->message.error) {
+ fprintf(stderr, "A fatal error was encoutered: %s (%s) - exiting ...\n", evt->message.message ? evt->message.message : "no details", gf_error_to_string(evt->message.error) );
+ }
Run = 0;
break;
case GF_EVENT_DISCONNECT:
@@ -747,7 +779,6 @@ Bool GPAC_EventProc(void *ptr, GF_Event *evt)
}
return 1;
}
-
}
return 0;
}
@@ -850,6 +881,13 @@ static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list
UpdateRTInfo(szMsg + 6 /*"[RTI] "*/);
} else {
if (log_time_start) fprintf(logs, "[At %d]", gf_sys_clock() - log_time_start);
+ if (log_utc_time) {
+ u64 utc_clock = gf_net_get_utc() ;
+ time_t secs = utc_clock/1000;
+ struct tm t;
+ t = *gmtime(&secs);
+ fprintf(logs, "[UTC %d-%02d-%02dT%02d:%02d:%02dZ - TS "LLU"]", 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, utc_clock);
+ }
vfprintf(logs, fmt, list);
fflush(logs);
}
@@ -911,16 +949,16 @@ int main (int argc, char **argv)
const char *str;
u32 i, times[100], nb_times, dump_mode;
u32 simulation_time_in_ms = 0;
- Bool auto_exit = 0;
- Bool logs_set = 0;
- Bool start_fs = 0;
- Bool use_rtix = 0;
- Bool rgbds_dump = 0;
- Bool rgbd_dump = 0;
- Bool depth_dump = 0;
- Bool pause_at_first = 0;
+ Bool auto_exit = GF_FALSE;
+ 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;
#ifdef GPAC_MEMORY_TRACKING
- Bool enable_mem_tracker = 0;
+ Bool enable_mem_tracker = GF_FALSE;
#endif
Double fps = GF_IMPORT_DEFAULT_FPS;
Bool fill_ar, visible;
@@ -937,7 +975,7 @@ int main (int argc, char **argv)
memset(&user, 0, sizeof(GF_User));
dump_mode = 0;
- fill_ar = visible = 0;
+ fill_ar = visible = GF_FALSE;
url_arg = the_cfg = rti_file = views = NULL;
nb_times = 0;
times[0] = 0;
@@ -951,7 +989,7 @@ int main (int argc, char **argv)
}
else if (!strcmp(arg, "-mem-track")) {
#ifdef GPAC_MEMORY_TRACKING
- enable_mem_tracker = 1;
+ enable_mem_tracker = GF_TRUE;
#else
fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
#endif
@@ -965,7 +1003,7 @@ int main (int argc, char **argv)
#ifdef GPAC_MEMORY_TRACKING
gf_sys_init(enable_mem_tracker);
#else
- gf_sys_init(0);
+ gf_sys_init(GF_FALSE);
#endif
cfg_file = gf_cfg_init(the_cfg, NULL);
@@ -979,7 +1017,7 @@ int main (int argc, char **argv)
}
if( gf_cfg_get_key(cfg_file, "General", "Logs") != NULL ){
- logs_set = 1;
+ logs_set = GF_TRUE;
}
for (i=1; i<(u32) argc; i++) {
@@ -996,9 +1034,9 @@ int main (int argc, char **argv)
} else if (!strcmp(arg, "-rtix")) {
rti_file = argv[i+1];
i++;
- use_rtix = 1;
+ use_rtix = GF_TRUE;
} else if (!strcmp(arg, "-fill")) {
- fill_ar = 1;
+ fill_ar = GF_TRUE;
} else if (!strcmp(arg, "-gui")) {
gui_mode = 1;
} else if (!strcmp(arg, "-guid")) {
@@ -1059,10 +1097,12 @@ int main (int argc, char **argv)
if (gf_log_set_tools_levels(argv[i+1]) != GF_OK) {
return 1;
}
- logs_set = 1;
+ logs_set = GF_TRUE;
i++;
} else if (!strcmp(arg, "-log-clock") || !strcmp(arg, "-lc")) {
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;
@@ -1091,10 +1131,17 @@ int main (int argc, char **argv)
#endif
}
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, "-opt")) {
set_cfg_option(argv[i+1]);
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++;
@@ -1128,7 +1175,6 @@ int main (int argc, char **argv)
}
if (gui_mode) {
- threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD;
if (gui_mode==1) {
hide_shell(1);
user.init_flags |= GF_TERM_WINDOW_NO_DECORATION;
@@ -1144,6 +1190,13 @@ int main (int argc, char **argv)
if (rti_file) init_rti_logs(rti_file, url_arg, use_rtix);
+ {
+ GF_SystemRTInfo rti;
+ if (gf_sys_get_rti(0, &rti, 0))
+ fprintf(stderr, "System info: %d MB RAM - %d cores\n", (u32) (rti.physical_memory/1024/1024), rti.nb_cores);
+ }
+
+
/*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*/;
@@ -1153,27 +1206,17 @@ int main (int argc, char **argv)
init_h = forced_height;
}
- fprintf(stderr, "Loading modules\n");
- str = gf_cfg_get_key(cfg_file, "General", "ModulesDirectory");
- if (! str ) {
- fprintf(stderr, "Mmodule directory not found - check the configuration file exit and the \"ModulesDirectory\" key is set\n");
- gf_cfg_del(cfg_file);
- gf_sys_close();
- if (logfile) fclose(logfile);
- return 1;
- }
-
- user.modules = gf_modules_new((const unsigned char *) str, cfg_file);
+ user.modules = gf_modules_new(NULL, cfg_file);
if (user.modules) i = gf_modules_get_count(user.modules);
if (!i || !user.modules) {
- fprintf(stderr, "Error: no modules found in %s - exiting\n", str);
+ fprintf(stderr, "Error: no modules found - exiting\n");
if (user.modules) gf_modules_del(user.modules);
gf_cfg_del(cfg_file);
gf_sys_close();
if (logfile) fclose(logfile);
return 1;
}
- fprintf(stderr, "Modules Found (%d in dir %s)\n", i, str);
+ fprintf(stderr, "Modules Found : %d \n", i);
user.config = cfg_file;
user.EventProc = GPAC_EventProc;
@@ -1185,6 +1228,20 @@ int main (int argc, char **argv)
if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = 1;
+
+ if (bench_mode) {
+ gf_cfg_discard_changes(user.config);
+ auto_exit = 1;
+ 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");
+ gf_cfg_set_key(user.config, "RAWVideo", "RawOutput", "null");
+ gf_cfg_set_key(user.config, "Compositor", "ForceOpenGL", "no");
+ } else {
+ gf_cfg_set_key(user.config, "Video", "DisableVSync", "yes");
+ }
+ }
+
fprintf(stderr, "Loading GPAC Terminal\n");
i = gf_sys_clock();
term = gf_term_new(&user);
@@ -1192,6 +1249,7 @@ int main (int argc, char **argv)
fprintf(stderr, "\nInit error - check you have at least one video out and one rasterizer...\nFound modules:\n");
list_modules(user.modules);
gf_modules_del(user.modules);
+ gf_cfg_discard_changes(cfg_file);
gf_cfg_del(cfg_file);
gf_sys_close();
if (logfile) fclose(logfile);
@@ -1199,13 +1257,19 @@ int main (int argc, char **argv)
}
fprintf(stderr, "Terminal Loaded in %d ms\n", gf_sys_clock()-i);
+ if (bench_mode) {
+ display_rti = 2;
+ gf_term_set_option(term, GF_OPT_VIDEO_BENCH, (bench_mode==3) ? 2 : 1);
+ bench_mode=2;
+ }
+
if (dump_mode) {
// gf_term_set_option(term, GF_OPT_VISIBLE, 0);
if (fill_ar) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
} else {
/*check video output*/
str = gf_cfg_get_key(cfg_file, "Video", "DriverName");
- if (!strcmp(str, "Raw Video Output")) fprintf(stderr, "WARNING: using raw output video (memory only) - no display used\n");
+ if (!bench_mode && !strcmp(str, "Raw Video Output")) fprintf(stderr, "WARNING: using raw output video (memory only) - no display used\n");
/*check audio output*/
str = gf_cfg_get_key(cfg_file, "Audio", "DriverName");
if (!str || !strcmp(str, "No Audio Output Available")) fprintf(stderr, "WARNING: no audio output available - make sure no other program is locking the sound card\n");
@@ -1303,6 +1367,10 @@ int main (int argc, char **argv)
sprintf(szTemp, "views://%s", views);
gf_term_connect(term, szTemp);
}
+ if (bench_mode) {
+ rti_update_time_ms = 500;
+ bench_mode_start = gf_sys_clock();
+ }
while (Run) {
/*we don't want getchar to block*/
@@ -1324,12 +1392,13 @@ int main (int argc, char **argv)
if (!use_rtix || display_rti) UpdateRTInfo(NULL);
if (term_step) {
gf_term_process_step(term);
- if (auto_exit && gf_term_get_option(term, GF_OPT_IS_OVER)) {
- Run = 0;
- }
} else {
gf_sleep(rti_update_time_ms);
}
+ if (auto_exit && eos_seen && gf_term_get_option(term, GF_OPT_IS_OVER)) {
+ Run = 0;
+ }
+
/*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))
@@ -1646,6 +1715,21 @@ force_input:
if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e));
}
break;
+ case 'e':
+ {
+ GF_Err e;
+ char jsCode[8192];
+ fprintf(stderr, "Enter JavaScript code to evaluate:\n");
+ fflush(stdin);
+ jsCode[0] = 0;
+ if (1 > scanf("%[^\t\n]", jsCode)){
+ fprintf(stderr, "Cannot read code to evaluate, aborting.\n");
+ break;
+ }
+ 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;
case 'L':
{
@@ -1678,12 +1762,23 @@ force_input:
}
break;
+ case 'H':
+ {
+ u32 http_bitrate = gf_term_get_option(term, GF_OPT_HTTP_MAX_RATE);
+ do {
+ fprintf(stderr, "Enter new http bitrate in bps (0 for none) - current limit: %d\n", http_bitrate);
+ } while (1 > scanf("%ud", &http_bitrate));
+
+ gf_term_set_option(term, GF_OPT_HTTP_MAX_RATE, http_bitrate);
+ }
+ break;
+
case 'E':
gf_term_set_option(term, GF_OPT_RELOAD_CONFIG, 1);
break;
case 'B':
- switch_bench();
+ switch_bench(!bench_mode);
break;
case 'Y':
@@ -1773,6 +1868,10 @@ force_input:
}
}
+ if (bench_mode) {
+ PrintAVInfo(GF_TRUE);
+ }
+
i = gf_sys_clock();
gf_term_disconnect(term);
if (rti_file) UpdateRTInfo("Disconnected\n");
@@ -1796,6 +1895,160 @@ force_input:
return 0;
}
+static GF_ObjectManager *video_odm = NULL;
+static GF_ObjectManager *audio_odm = NULL;
+static GF_ObjectManager *scene_odm = NULL;
+static u32 last_odm_count = 0;
+void PrintAVInfo(Bool final)
+{
+ GF_MediaInfo a_odi, v_odi, s_odi;
+ Float avg_dec_time=0;
+ u32 tot_time=0;
+ Bool print_codecs = final;
+
+ if (scene_odm) {
+ GF_ObjectManager *root_odm = gf_term_get_root_object(term);
+ u32 count = gf_term_get_object_count(term, root_odm);
+ if (last_odm_count != count) {
+ last_odm_count = count;
+ scene_odm = NULL;
+ }
+ }
+ if (!video_odm && !audio_odm && !scene_odm) {
+ u32 count, i;
+ GF_ObjectManager *root_odm = root_odm = gf_term_get_root_object(term);
+ if (!root_odm) return;
+
+ if (gf_term_get_object_info(term, root_odm, &v_odi)==GF_OK) {
+ if (!scene_odm && (v_odi.generated_scene== 0)) {
+ scene_odm = root_odm;
+ }
+ }
+
+ count = gf_term_get_object_count(term, root_odm);
+ for (i=0; i1)) ) {
+ video_odm = odm;
+ }
+ else if (!audio_odm && (v_odi.od_type == GF_STREAM_AUDIO)) {
+ audio_odm = odm;
+ }
+ else if (!scene_odm && (v_odi.od_type == GF_STREAM_SCENE)) {
+ scene_odm = odm;
+ }
+ }
+ }
+ }
+
+ if (bench_buffer) {
+ fprintf(stderr, "Buffering %d %% ", bench_buffer-1);
+ return;
+ }
+
+ if (video_odm) {
+ gf_term_get_object_info(term, video_odm, &v_odi);
+ avg_dec_time = 0;
+ if (v_odi.nb_dec_frames && v_odi.total_dec_time) {
+ avg_dec_time = (Float) 1000 * v_odi.nb_dec_frames;
+ avg_dec_time /= v_odi.total_dec_time;
+ }
+ }
+ if (print_codecs && audio_odm) {
+ gf_term_get_object_info(term, audio_odm, &a_odi);
+ }
+ if ((print_codecs || !video_odm) && scene_odm) {
+ gf_term_get_object_info(term, scene_odm, &s_odi);
+ }
+
+ if (final) {
+ tot_time = gf_sys_clock() - bench_mode_start;
+ fprintf(stderr, " \r");
+ fprintf(stderr, "************** Bench Mode Done in %d ms ********************\n", tot_time);
+
+ if (!video_odm) {
+ u32 nb_frames_drawn;
+ Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn);
+ fprintf(stderr, "Drawn %d frames FPS %.2f (simulation FPS %.2f) - duration %d ms\n", nb_frames_drawn, ((Float)nb_frames_drawn*1000)/tot_time, FPS, gf_term_get_time_in_ms(term) );
+ }
+ }
+ if (print_codecs) {
+ if (video_odm) {
+ fprintf(stderr, "%s %dx%d sar=%d:%d duration %.2fs\n", v_odi.codec_name, v_odi.width, v_odi.height, v_odi.par ? (v_odi.par>>16)&0xFF : 1, v_odi.par ? (v_odi.par)&0xFF : 1, v_odi.duration);
+ if (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 %d ms/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, "\n");
+ }
+ }
+ if (audio_odm) {
+ fprintf(stderr, "%s SR %d num channels %d bpp %d duration %.2fs\n", a_odi.codec_name, a_odi.sample_rate, a_odi.num_channels, a_odi.bits_per_sample, a_odi.duration);
+ if (final) {
+ u32 dec_run_time = a_odi.last_frame_time - a_odi.first_frame_time;
+ 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 %d 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, (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);
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+ if (scene_odm) {
+ u32 w, h;
+ gf_term_get_visual_output_size(term, &w, &h);
+ fprintf(stderr, "%s scene size %dx%d rastered to %dx%d duration %.2fs\n", s_odi.codec_name, s_odi.width, s_odi.height, w, h, s_odi.duration);
+ if (final) {
+ if (s_odi.nb_dec_frames>2 && s_odi.total_dec_time) {
+ u32 dec_run_time = s_odi.last_frame_time - s_odi.first_frame_time;
+ if (!dec_run_time) dec_run_time = 1;
+ fprintf(stderr, "%d frames FPS %.2f (max %d ms/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;
+ Double FPS = gf_term_get_simulation_frame_rate(term, &nb_frames_drawn);
+ tot_time = gf_sys_clock() - bench_mode_start;
+ FPS = gf_term_get_framerate(term, 0);
+ fprintf(stderr, "%d frames FPS %.2f (abs %.2f)\n", nb_frames_drawn, (1000.0*nb_frames_drawn / tot_time), FPS);
+ }
+ }
+ }
+ if (final) {
+ fprintf(stderr, "**********************************************************\n\n");
+ return;
+ }
+ }
+
+ if (video_odm) {
+ tot_time = v_odi.last_frame_time - v_odi.first_frame_time;
+ if (!tot_time) tot_time=1;
+ if (v_odi.duration) fprintf(stderr, "%d%% ", (u32) (100*v_odi.current_time / v_odi.duration ) );
+ fprintf(stderr, "%d frames FPS %.2f (%dms max) - rate %d ", v_odi.nb_dec_frames, ((Float)v_odi.nb_dec_frames*1000) / tot_time, v_odi.max_dec_time, (u32) v_odi.instant_bitrate/1000);
+ }
+ else if (scene_odm) {
+
+ avg_dec_time = 0;
+ if (s_odi.nb_dec_frames>2 && s_odi.total_dec_time) {
+ avg_dec_time = (Float) 1000 * 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 frames %.2f (%dms 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);
+ tot_time = gf_sys_clock() - bench_mode_start;
+ FPS = gf_term_get_framerate(term, 1);
+ fprintf(stderr, "%d frames FPS %.2f (abs %.2f) ", nb_frames_drawn, (1000.0*nb_frames_drawn / tot_time), FPS);
+ }
+ }
+}
void PrintWorldInfo(GF_Terminal *term)
{
diff --git a/applications/testapps/bmp4demux/Makefile b/applications/testapps/bmp4demux/Makefile
new file mode 100644
index 0000000..35b02f1
--- /dev/null
+++ b/applications/testapps/bmp4demux/Makefile
@@ -0,0 +1,50 @@
+include ../../../config.mak
+
+vpath %.c $(SRC_PATH)/applications/testapps/bmp4demux
+
+CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include"
+
+ifeq ($(DEBUGBUILD), yes)
+CFLAGS+=-g
+LDFLAGS+=-g
+endif
+
+ifeq ($(GPROFBUILD), yes)
+CFLAGS+=-pg
+LDFLAGS+=-pg
+endif
+
+#common obj
+OBJS= main.o
+
+LINKFLAGS=-L../../../bin/gcc
+ifeq ($(CONFIG_WIN32),yes)
+EXE=.exe
+PROG=bmp4demux$(EXE)
+else
+EXT=
+PROG=bmp4demux
+endif
+LINKFLAGS+=-lgpac
+
+
+SRCS := $(OBJS:.o=.c)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS)
+
+clean:
+ rm -f $(OBJS) ../../../bin/gcc/$(PROG)
+
+dep: depend
+
+depend:
+ rm -f .depend
+ $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
+
+distclean: clean
+ rm -f Makefile.bak .depend
+
+-include .depend
diff --git a/applications/testapps/bmp4demux/bmp4demux.sln b/applications/testapps/bmp4demux/bmp4demux.sln
new file mode 100644
index 0000000..e304373
--- /dev/null
+++ b/applications/testapps/bmp4demux/bmp4demux.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmp4demux", "bmp4demux.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/bmp4demux/bmp4demux.vcxproj b/applications/testapps/bmp4demux/bmp4demux.vcxproj
new file mode 100644
index 0000000..0cdd147
--- /dev/null
+++ b/applications/testapps/bmp4demux/bmp4demux.vcxproj
@@ -0,0 +1,189 @@
+
+
+
+
+ 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
+ v100
+ 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_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
+
+
+
+
+
+
\ No newline at end of file
diff --git a/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters b/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters
new file mode 100644
index 0000000..5aa4a72
--- /dev/null
+++ b/applications/testapps/bmp4demux/bmp4demux.vcxproj.filters
@@ -0,0 +1,131 @@
+
+
+
+
+ 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
+
+
+
+
+ {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
new file mode 100644
index 0000000..36dab12
--- /dev/null
+++ b/applications/testapps/bmp4demux/build.sh
@@ -0,0 +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
diff --git a/applications/testapps/bmp4demux/main.c b/applications/testapps/bmp4demux/main.c
new file mode 100644
index 0000000..fc3efeb
--- /dev/null
+++ b/applications/testapps/bmp4demux/main.c
@@ -0,0 +1,93 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Cyril Concolato
+ * Copyright (c) Telecom ParisTech 2013-
+ * All rights reserved
+ *
+ * This file is part of GPAC / sample MP4 demultiplexing application
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include
+#include
+
+int main(int argc, char **argv)
+{
+ /* The ISO progressive reader */
+ GF_ISOFile *movie;
+ /* Error indicator */
+ GF_Err e;
+ /* Number of bytes required to finish the current ISO Box reading */
+ u64 missing_bytes;
+ /* Return value for the program */
+ int ret = 0;
+ u32 track_id = 1;
+ u32 track_number;
+ u32 sample_count;
+ u32 sample_index;
+
+ /* Usage */
+ if (argc < 2) {
+ fprintf(stdout, "Usage: %s filename [track_id]\n", argv[0]);
+ return 1;
+ }
+ if (argc == 3) {
+ track_id = atoi(argv[2]);
+ }
+
+ e = gf_isom_open_progressive(argv[1], 0, 0, &movie, &missing_bytes);
+ if ((e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) || movie == NULL) {
+ fprintf(stdout, "Could not open file %s for reading (%s).\n", argv[1], gf_error_to_string(e));
+ return 1;
+ }
+
+ track_number = gf_isom_get_track_by_id(movie, track_id);
+ if (track_number == 0) {
+ fprintf(stdout, "Could not find track ID=%u of file %s.\n", track_id, argv[1]);
+ ret = 1;
+ goto exit;
+ }
+
+ sample_count = gf_isom_get_sample_count(movie, track_number);
+ sample_index = 1;
+ while (sample_index <= sample_count) {
+ GF_ISOSample *iso_sample;
+ u32 sample_description_index;
+
+ iso_sample = gf_isom_get_sample(movie, track_number, sample_index, &sample_description_index);
+ if (iso_sample) {
+ fprintf(stdout, "Found sample #%5d/%5d of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\n", sample_index, sample_count, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset);
+ sample_index++;
+
+ /*release the sample data, once you're done with it*/
+ gf_isom_sample_del(&iso_sample);
+ } else {
+ e = gf_isom_last_error(movie);
+ if (e == GF_ISOM_INCOMPLETE_FILE) {
+ missing_bytes = gf_isom_get_missing_bytes(movie, track_number);
+ fprintf(stdout, "Missing "LLU" bytes on input file\n", missing_bytes);
+ gf_sleep(1000);
+ }
+ }
+ }
+
+exit:
+ gf_isom_close(movie);
+
+ return ret;
+}
diff --git a/applications/testapps/fmp4demux/Makefile b/applications/testapps/fmp4demux/Makefile
new file mode 100644
index 0000000..b736725
--- /dev/null
+++ b/applications/testapps/fmp4demux/Makefile
@@ -0,0 +1,50 @@
+include ../../../config.mak
+
+vpath %.c $(SRC_PATH)/applications/testapps/fmp4demux
+
+CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include"
+
+ifeq ($(DEBUGBUILD), yes)
+CFLAGS+=-g
+LDFLAGS+=-g
+endif
+
+ifeq ($(GPROFBUILD), yes)
+CFLAGS+=-pg
+LDFLAGS+=-pg
+endif
+
+#common obj
+OBJS= main.o
+
+LINKFLAGS=-L../../../bin/gcc
+ifeq ($(CONFIG_WIN32),yes)
+EXE=.exe
+PROG=fmp4demux$(EXE)
+else
+EXT=
+PROG=fmp4demux
+endif
+LINKFLAGS+=-lgpac
+
+
+SRCS := $(OBJS:.o=.c)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS)
+
+clean:
+ rm -f $(OBJS) ../../../bin/gcc/$(PROG)
+
+dep: depend
+
+depend:
+ rm -f .depend
+ $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
+
+distclean: clean
+ rm -f Makefile.bak .depend
+
+-include .depend
diff --git a/applications/testapps/fmp4demux/build.sh b/applications/testapps/fmp4demux/build.sh
new file mode 100755
index 0000000..36dab12
--- /dev/null
+++ b/applications/testapps/fmp4demux/build.sh
@@ -0,0 +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
diff --git a/applications/testapps/fmp4demux/fmp4demux.sln b/applications/testapps/fmp4demux/fmp4demux.sln
new file mode 100644
index 0000000..26bfd3d
--- /dev/null
+++ b/applications/testapps/fmp4demux/fmp4demux.sln
@@ -0,0 +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
diff --git a/applications/testapps/fmp4demux/fmp4demux.vcxproj b/applications/testapps/fmp4demux/fmp4demux.vcxproj
new file mode 100644
index 0000000..2593ef0
--- /dev/null
+++ b/applications/testapps/fmp4demux/fmp4demux.vcxproj
@@ -0,0 +1,188 @@
+
+
+
+
+ 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
+ v100
+ 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_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/fmp4demux.bsc
+
+
+
+
+ .\Release/fmp4demux.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/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
new file mode 100644
index 0000000..d7e2dc7
--- /dev/null
+++ b/applications/testapps/fmp4demux/fmp4demux.vcxproj.filters
@@ -0,0 +1,134 @@
+
+
+
+
+ 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
+
+
+
+
+ {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
new file mode 100644
index 0000000..3135128
--- /dev/null
+++ b/applications/testapps/fmp4demux/main.c
@@ -0,0 +1,315 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Cyril Concolato
+ * Copyright (c) Telecom ParisTech 2013-
+ * All rights reserved
+ *
+ * This file is part of GPAC / sample MP4 demultiplexing application
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+//#define GPAC_HAVE_CONFIG_H
+
+#include
+#include
+#include
+
+#define BUFFER_BLOC_SIZE 1000
+#define MAX_BUFFER_SIZE 200000
+
+typedef struct iso_progressive_reader {
+
+ /* data buffer to be read by the parser */
+ u8 *data;
+ /* size of the data buffer */
+ u32 data_size;
+ /* number of valid bytes in the buffer */
+ u32 valid_data_size;
+ /* URL used to pass a buffer to the parser */
+ char data_url[256];
+
+ /* The ISO file structure created for the parsing of data */
+ GF_ISOFile *movie;
+
+ /* Mutex to protect the reading from concurrent adding of media data */
+ GF_Mutex *mutex;
+
+ /* Boolean indicating if the thread should stop */
+ volatile Bool do_run;
+
+ /* Boolean state to indicate if the needs to be parsed */
+ Bool refresh_boxes;
+
+ /* id of the track in the ISO to be read */
+ u32 track_id;
+
+} ISOProgressiveReader;
+
+
+static u32 iso_progressive_read_thread(void *param)
+{
+ ISOProgressiveReader *reader = (ISOProgressiveReader *)param;
+ u32 track_number;
+ GF_ISOSample *iso_sample;
+ u32 samples_processed;
+ u32 sample_index;
+ u32 sample_count;
+
+ samples_processed = 0;
+ sample_count = 0;
+ track_number = 0;
+ /* samples are numbered starting from 1 */
+ sample_index = 1;
+
+ while (reader->do_run == GF_TRUE) {
+
+ /* we can only parse if there is a movie */
+ if (reader->movie) {
+
+ /* block the data input until we are done in the parsing */
+ gf_mx_p(reader->mutex);
+
+ /* get the track number we want */
+ if (track_number == 0) {
+ track_number = gf_isom_get_track_by_id(reader->movie, reader->track_id);
+ }
+
+ /* only if we have the track number can we try to get the sample data */
+ if (track_number != 0) {
+ u32 new_sample_count;
+ u32 di; /*descriptor index*/
+
+ /* let's see how many samples we have since the last parsed */
+ new_sample_count = gf_isom_get_sample_count(reader->movie, track_number);
+ if (new_sample_count > sample_count) {
+ /* New samples have been added to the file */
+ fprintf(stdout, "Found %d new samples (total: %d)\n", new_sample_count - sample_count, new_sample_count);
+ if (sample_count == 0) {
+ sample_count = new_sample_count;
+ }
+ }
+ if (sample_count == 0) {
+ /* no sample yet, let the data input force a reparsing of the data */
+ reader->refresh_boxes = GF_TRUE;
+ /*let the reader push new data */
+ gf_mx_v(reader->mutex);
+ //gf_sleep(1000);
+ } else {
+ /* we have some samples, lets keep things stable in the parser for now and
+ don't let the data input force a reparsing of the data */
+ reader->refresh_boxes = GF_FALSE;
+
+ /* let's analyze the samples we have parsed so far one by one */
+ iso_sample = gf_isom_get_sample(reader->movie, track_number, sample_index, &di);
+ if (iso_sample) {
+ /* if you want the sample description data, you can call:
+ GF_Descriptor *desc = gf_isom_get_decoder_config(reader->movie, reader->track_handle, di);
+ */
+
+ samples_processed++;
+ /*here we dump some sample info: samp->data, samp->dataLength, samp->isRAP, samp->DTS, samp->CTS_Offset */
+ fprintf(stdout, "Found sample #%5d (#%5d) of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\r", sample_index, samples_processed, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset);
+ sample_index++;
+
+ /*release the sample data, once you're done with it*/
+ gf_isom_sample_del(&iso_sample);
+
+ /* once we have read all the samples, we can release some data and force a reparse of the input buffer */
+ if (sample_index > sample_count) {
+ u64 new_buffer_start;
+ u64 missing_bytes;
+
+ fprintf(stdout, "\nReleasing unnecessary buffers\n");
+ /* release internal structures associated with the samples read so far */
+ gf_isom_reset_tables(reader->movie, GF_TRUE);
+
+#if 1
+ /* release the associated input data as well */
+ gf_isom_reset_data_offset(reader->movie, &new_buffer_start);
+ if (new_buffer_start) {
+ u32 offset = (u32)new_buffer_start;
+ memmove(reader->data, reader->data+offset, reader->data_size-offset);
+ reader->valid_data_size -= offset;
+ }
+ sprintf(reader->data_url, "gmem://%d@%p", reader->valid_data_size, reader->data);
+ gf_isom_refresh_fragmented(reader->movie, &missing_bytes, reader->data_url);
+#endif
+
+ /* update the sample count and sample index */
+ sample_count = new_sample_count - sample_count;
+ assert(sample_count == 0);
+ sample_index = 1;
+ }
+ } else {
+ GF_Err e = gf_isom_last_error(reader->movie);
+ fprintf(stdout, "Could not get sample %s\r", gf_error_to_string(e));
+ }
+ /* and finally, let the data reader push more data */
+ gf_mx_v(reader->mutex);
+ }
+ }
+ } else {
+ //gf_sleep(1);
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ /* The ISO progressive reader */
+ ISOProgressiveReader reader;
+ /* Error indicator */
+ GF_Err e;
+ /* input file to be read in the data buffer */
+ FILE *input;
+ /* number of bytes read from the file at each read operation */
+ u32 read_bytes;
+ /* number of bytes read from the file (total) */
+ u64 total_read_bytes;
+ /* size of the input file */
+ u64 file_size;
+ /* number of bytes required to finish the current ISO Box reading (not used here)*/
+ u64 missing_bytes;
+ /* Thread used to run the ISO parsing in */
+ GF_Thread *reading_thread;
+ /* Return value for the program */
+ int ret = 0;
+
+ /* Usage */
+ if (argc != 2) {
+ fprintf(stdout, "Usage: %s filename\n", argv[0]);
+ return 1;
+ }
+
+ /* Initializing GPAC framework */
+ /* Enables GPAC memory tracking in debug mode only */
+#if defined(DEBUG) || defined(_DEBUG)
+ gf_sys_init(GF_TRUE);
+ gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);
+ gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO);
+#else
+ gf_sys_init(GF_FALSE);
+ gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);
+#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");
+ 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);
+
+ /* Initializing the progressive reader */
+ memset(&reader, 0, sizeof(ISOProgressiveReader));
+ reading_thread = gf_th_new("ISO reading thread");
+ reader.mutex = gf_mx_new("ISO Segment");
+ reader.do_run = GF_TRUE;
+ /* we want to parse the first track */
+ reader.track_id = 1;
+ /* start the async parsing */
+ gf_th_run(reading_thread, iso_progressive_read_thread, &reader);
+
+ /* start the data reading */
+ reader.data_size = BUFFER_BLOC_SIZE;
+ reader.data = (u8 *)gf_malloc(reader.data_size);
+ reader.valid_data_size = 0;
+ total_read_bytes = 0;
+ while (1) {
+ /* block the parser until we are done manipulating the data buffer */
+ gf_mx_p(reader.mutex);
+
+ if (reader.valid_data_size + BUFFER_BLOC_SIZE > MAX_BUFFER_SIZE) {
+ /* regulate the reader to limit the max buffer size and let some time to the parser to release buffer data */
+ fprintf(stdout, "Buffer full (%d/%d)- waiting to read next data \r", reader.valid_data_size, reader.data_size);
+ gf_mx_v(reader.mutex);
+ //gf_sleep(10);
+ } else {
+ /* make sure we have enough space in the buffer to read the next bloc of data */
+ if (reader.valid_data_size + BUFFER_BLOC_SIZE > reader.data_size) {
+ reader.data = (u8 *)gf_realloc(reader.data, reader.data_size + BUFFER_BLOC_SIZE);
+ reader.data_size += BUFFER_BLOC_SIZE;
+ }
+
+ /* read the next bloc of data and update the data buffer url */
+ read_bytes = fread(reader.data+reader.valid_data_size, 1, BUFFER_BLOC_SIZE, input);
+ total_read_bytes += read_bytes;
+ fprintf(stdout, "Read "LLD" bytes of "LLD" bytes from input file %s (buffer status: %5d/%5d)\r", total_read_bytes, file_size, argv[1], reader.valid_data_size, reader.data_size);
+ if (read_bytes) {
+ reader.valid_data_size += read_bytes;
+ sprintf(reader.data_url, "gmem://%d@%p", reader.valid_data_size, reader.data);
+ } else {
+ /* end of file we can quit */
+ gf_mx_v(reader.mutex);
+ break;
+ }
+
+ /* if the file is not yet opened (no movie), open it in progressive mode (to update its data later on) */
+ if (!reader.movie) {
+ /* let's initialize the parser */
+ e = gf_isom_open_progressive(reader.data_url, 0, 0, &reader.movie, &missing_bytes);
+ if (reader.movie) {
+ gf_isom_set_single_moof_mode(reader.movie, GF_TRUE);
+ }
+ /* we can let parser try to work now */
+ gf_mx_v(reader.mutex);
+
+ if ((e == GF_OK || e == GF_ISOM_INCOMPLETE_FILE) && reader.movie) {
+ /* nothing to do, this is normal */
+ } else {
+ fprintf(stdout, "Error opening fragmented mp4 in progressive mode: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes);
+ ret = 1;
+ goto exit;
+ }
+ } else {
+ /* let inform the parser that the buffer has been updated with new data */
+ e = gf_isom_refresh_fragmented(reader.movie, &missing_bytes, reader.data_url);
+
+ /* we can let parser try to work now */
+ gf_mx_v(reader.mutex);
+
+ if (e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) {
+ fprintf(stdout, "Error refreshing fragmented mp4: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes);
+ ret = 1;
+ goto exit;
+ }
+ }
+
+ //gf_sleep(1);
+ }
+ }
+
+exit:
+ /* stop the parser */
+ reader.do_run = GF_FALSE;
+ gf_th_stop(reading_thread);
+
+ /* clean structures */
+ gf_th_del(reading_thread);
+ gf_mx_del(reader.mutex);
+ gf_free(reader.data);
+ gf_isom_close(reader.movie);
+ fclose(input);
+ gf_sys_close();
+
+ return ret;
+}
diff --git a/applications/testapps/loadcompare/Makefile b/applications/testapps/loadcompare/Makefile
index 8241c09..8dc31d1 100644
--- a/applications/testapps/loadcompare/Makefile
+++ b/applications/testapps/loadcompare/Makefile
@@ -52,10 +52,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/testapps/mpedemux/Makefile b/applications/testapps/mpedemux/Makefile
index 315079e..7f3c21b 100644
--- a/applications/testapps/mpedemux/Makefile
+++ b/applications/testapps/mpedemux/Makefile
@@ -62,10 +62,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/applications/testapps/segmp4demux/Makefile b/applications/testapps/segmp4demux/Makefile
new file mode 100644
index 0000000..964c077
--- /dev/null
+++ b/applications/testapps/segmp4demux/Makefile
@@ -0,0 +1,50 @@
+include ../../../config.mak
+
+vpath %.c $(SRC_PATH)/applications/testapps/segmp4demux
+
+CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include"
+
+ifeq ($(DEBUGBUILD), yes)
+CFLAGS+=-g
+LDFLAGS+=-g
+endif
+
+ifeq ($(GPROFBUILD), yes)
+CFLAGS+=-pg
+LDFLAGS+=-pg
+endif
+
+#common obj
+OBJS= main.o
+
+LINKFLAGS=-L../../../bin/gcc
+ifeq ($(CONFIG_WIN32),yes)
+EXE=.exe
+PROG=segmp4demux$(EXE)
+else
+EXT=
+PROG=segmp4demux
+endif
+LINKFLAGS+=-lgpac
+
+
+SRCS := $(OBJS:.o=.c)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o ../../../bin/gcc/$@ $(OBJS) $(LINKFLAGS)
+
+clean:
+ rm -f $(OBJS) ../../../bin/gcc/$(PROG)
+
+dep: depend
+
+depend:
+ rm -f .depend
+ $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
+
+distclean: clean
+ rm -f Makefile.bak .depend
+
+-include .depend
diff --git a/applications/testapps/segmp4demux/build.sh b/applications/testapps/segmp4demux/build.sh
new file mode 100644
index 0000000..36dab12
--- /dev/null
+++ b/applications/testapps/segmp4demux/build.sh
@@ -0,0 +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
diff --git a/applications/testapps/segmp4demux/main.c b/applications/testapps/segmp4demux/main.c
new file mode 100644
index 0000000..7adae49
--- /dev/null
+++ b/applications/testapps/segmp4demux/main.c
@@ -0,0 +1,139 @@
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Authors: Romain Bouqueau - Cyril Concolato
+ * Copyright (c) Romain Bouqueau 2013-
+ * Copyright (c) Telecom ParisTech 2013-
+ * All rights reserved
+ *
+ * This file is part of GPAC / sample MP4 demultiplexing application
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include
+#include
+
+static void process_samples_from_track(GF_ISOFile *movie, u32 track_id, u32 *sample_index)
+{
+ u32 track_number;
+ u32 sample_count;
+ /* Error indicator */
+ GF_Err e;
+ /* Number of bytes required to finish the current ISO Box reading */
+ u64 missing_bytes;
+
+ track_number = gf_isom_get_track_by_id(movie, track_id);
+ if (track_number == 0) {
+ fprintf(stdout, "Could not find track ID=%u. Ignore segment.\n", track_id);
+ return;
+ }
+
+ sample_count = gf_isom_get_sample_count(movie, track_number);
+ while (*sample_index <= sample_count) {
+ GF_ISOSample *iso_sample;
+ u32 sample_description_index;
+
+ iso_sample = gf_isom_get_sample(movie, track_number, *sample_index, &sample_description_index);
+ if (iso_sample) {
+ fprintf(stdout, "Found sample #%5d/%5d of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\n", *sample_index, sample_count, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset);
+ (*sample_index)++;
+
+ /* Release the sample data, once you're done with it*/
+ gf_isom_sample_del(&iso_sample);
+ } else {
+ e = gf_isom_last_error(movie);
+ if (e == GF_ISOM_INCOMPLETE_FILE) {
+ missing_bytes = gf_isom_get_missing_bytes(movie, track_number);
+ fprintf(stdout, "Missing "LLU" bytes on input file\n", missing_bytes);
+ gf_sleep(1000);
+ }
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ /* The ISO progressive reader */
+ GF_ISOFile *movie;
+ /* Error indicator */
+ GF_Err e;
+ /* Number of bytes required to finish the current ISO Box reading */
+ u64 missing_bytes;
+ /* Return value for the program */
+ int ret = 0;
+ /* Maximum index of the segments*/
+ u32 seg_max = argc-2;
+ /* Number of the segment being processed*/
+ u32 seg_curr = 0;
+ u32 track_id = 1;
+ u32 sample_index = 1;
+
+ /* Usage */
+ if (argc < 2) {
+ fprintf(stdout, "Usage: %s filename0 [filename1 filename2 ...]\n", argv[0]);
+ return 1;
+ }
+
+#if defined(DEBUG) || defined(_DEBUG)
+ /* Enables GPAC memory tracking in debug mode only */
+ gf_sys_init(GF_TRUE);
+ gf_log_set_tool_level(GF_LOG_CONTAINER, GF_LOG_INFO);
+ gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO);
+#endif
+
+ /* First or init segment */
+ fprintf(stdout, "Process segment %5d/%5d: %s\n", seg_curr, seg_max, argv[seg_curr+1]);
+ e = gf_isom_open_progressive(argv[seg_curr+1], 0, 0, &movie, &missing_bytes);
+ if ((e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) || movie == NULL) {
+ fprintf(stdout, "Could not open file %s for reading (%s).\n", argv[seg_curr+1], gf_error_to_string(e));
+ return 1;
+ }
+ process_samples_from_track(movie, track_id, &sample_index);
+ seg_curr++;
+
+ /* Process segments */
+ while (seg_curr <= seg_max) {
+ fprintf(stdout, "Process segment %5d/%5d: %s\n", seg_curr, seg_max, argv[seg_curr+1]);
+
+ /* Open the segment */
+ e = gf_isom_open_segment(movie, argv[seg_curr+1], 0, 0, GF_FALSE);
+ if (e != GF_OK) {
+ fprintf(stdout, "Could not open segment %s for reading (%s).\n", argv[seg_curr+1], gf_error_to_string(e));
+ ret = 1;
+ goto exit;
+ }
+
+ /* Process the segment */
+ process_samples_from_track(movie, track_id, &sample_index);
+
+ /* Release the segment */
+ gf_isom_release_segment(movie, 1);
+
+ seg_curr++;
+ }
+
+exit:
+ fprintf(stdout, "Total nb Samples: %d\n", gf_isom_get_sample_count(movie, gf_isom_get_track_by_id(movie, track_id) ) );
+ gf_isom_release_segment(movie, 1);
+ gf_isom_close(movie);
+#if defined(DEBUG) || defined(_DEBUG)
+ /* Closes GPAC memory tracking in debug mode only */
+ gf_sys_close();
+#endif
+
+ return ret;
+}
diff --git a/applications/testapps/segmp4demux/segmp4demux.sln b/applications/testapps/segmp4demux/segmp4demux.sln
new file mode 100644
index 0000000..8430f20
--- /dev/null
+++ b/applications/testapps/segmp4demux/segmp4demux.sln
@@ -0,0 +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
diff --git a/applications/testapps/segmp4demux/segmp4demux.vcxproj b/applications/testapps/segmp4demux/segmp4demux.vcxproj
new file mode 100644
index 0000000..1470614
--- /dev/null
+++ b/applications/testapps/segmp4demux/segmp4demux.vcxproj
@@ -0,0 +1,189 @@
+
+
+
+
+ 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
+ v100
+ 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_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/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
new file mode 100644
index 0000000..5aa4a72
--- /dev/null
+++ b/applications/testapps/segmp4demux/segmp4demux.vcxproj.filters
@@ -0,0 +1,131 @@
+
+
+
+
+ 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
+
+
+
+
+ {c9a8f639-328c-4505-be50-4859357c2c00}
+
+
+ {e5ca7285-ca00-49d8-ac81-dff3d494be9a}
+
+
+
\ No newline at end of file
diff --git a/applications/ts2hds/Makefile b/applications/ts2hds/Makefile
index 675572d..b0695e3 100644
--- a/applications/ts2hds/Makefile
+++ b/applications/ts2hds/Makefile
@@ -1,56 +1,50 @@
-include ../../config.mak
-
-vpath %.c $(SRC_PATH)/applications/ts2hds
-
-CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include"
-
-ifeq ($(DEBUGBUILD), yes)
-CFLAGS+=-g
-LDFLAGS+=-g
-endif
-
-ifeq ($(GPROFBUILD), yes)
-CFLAGS+=-pg
-LDFLAGS+=-pg
-endif
-
-#common obj
-OBJS= main.o f4v.o f4m.o
-
-LINKFLAGS=-L../../bin/gcc
-ifeq ($(CONFIG_WIN32),yes)
-EXE=.exe
-PROG=ts2hds$(EXE)
-else
-EXT=
-PROG=ts2hds
-endif
-LINKFLAGS+=-lgpac
-
-
-SRCS := $(OBJS:.o=.c)
-
-all: $(PROG)
-
-$(PROG): $(OBJS)
- $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS)
-
-clean:
- rm -f $(OBJS) ../../bin/gcc/$(PROG)
-
-dep: depend
-
-depend:
- rm -f .depend
- $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
-
-distclean: clean
- rm -f Makefile.bak .depend
-
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+include ../../config.mak
+
+vpath %.c $(SRC_PATH)/applications/ts2hds
+
+CFLAGS= $(OPTFLAGS) -I"$(SRC_PATH)/include"
+
+ifeq ($(DEBUGBUILD), yes)
+CFLAGS+=-g
+LDFLAGS+=-g
+endif
+
+ifeq ($(GPROFBUILD), yes)
+CFLAGS+=-pg
+LDFLAGS+=-pg
+endif
+
+#common obj
+OBJS= main.o f4v.o f4m.o
+
+LINKFLAGS=-L../../bin/gcc
+ifeq ($(CONFIG_WIN32),yes)
+EXE=.exe
+PROG=ts2hds$(EXE)
+else
+EXT=
+PROG=ts2hds
+endif
+LINKFLAGS+=-lgpac
+
+
+SRCS := $(OBJS:.o=.c)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o ../../bin/gcc/$@ $(OBJS) $(LINKFLAGS)
+
+clean:
+ rm -f $(OBJS) ../../bin/gcc/$(PROG)
+
+dep: depend
+
+depend:
+ rm -f .depend
+ $(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
+
+distclean: clean
+ rm -f Makefile.bak .depend
+
+-include .depend
diff --git a/applications/ts2hds/f4m.c b/applications/ts2hds/f4m.c
index 92b31b6..ab52259 100644
--- a/applications/ts2hds/f4m.c
+++ b/applications/ts2hds/f4m.c
@@ -1,173 +1,173 @@
-/*
- * GPAC - Multimedia Framework C SDK
- *
- * Author: Romain Bouqueau
- * Copyright (c) Romain Bouqueau 2012-
- * All rights reserved
- *
- * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com)
- *
- * This file is part of GPAC / TS to HDS (ts2hds) application
- *
- * GPAC is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GPAC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "ts2hds.h"
-
-#include
-
-//#define ADOBE_INLINED_BOOTSTRAP
-
-struct __tag_adobe_stream
-{
- FILE *f;
- const char *id;
- const char *base_url;
- u32 bitrate;
-};
-
-struct __tag_adobe_multirate
-{
- FILE *f;
- const char *id;
- const char *base_url;
- GF_List *streams;
-};
-
-static GF_Err adobe_gen_stream_manifest(AdobeStream *as)
-{
- fprintf(as->f, "\n");
- fprintf(as->f, "\n");
- fprintf(as->f, "%s\n", as->id);
- if (as->base_url)
- fprintf(as->f, "%s\n", as->base_url);
- fprintf(as->f, "\n", as->id, as->bitrate, as->id, as->bitrate);
- fprintf(as->f, "\n", as->id, as->bitrate, as->bitrate, as->id, as->bitrate);
- fprintf(as->f, "\n");
-
- return GF_OK;
-}
-
-AdobeMultirate *adobe_alloc_multirate_manifest(char *id)
-{
- AdobeMultirate *am = gf_calloc(1, sizeof(AdobeMultirate));
- char filename[GF_MAX_PATH];
-
- //default init
- am->base_url = "http://localhost/hds/tmp";
- am->id = id;
- sprintf(filename, "%s.f4m", am->id);
- am->f = fopen(filename, "wt");
- if (!am->f) {
- fprintf(stderr, "Couldn't create Adobe multirate manifest file: %s\n", filename);
- assert(0);
- gf_free(am);
- return NULL;
- }
- am->streams = gf_list_new();
-
- //create a fake stream
- {
- AdobeStream *as = gf_calloc(1, sizeof(AdobeStream));
- as->id = "HD";
- as->bitrate = 100;
- sprintf(filename, "%s_%s_%d.f4m", am->id, as->id, as->bitrate);
- as->f = fopen(filename, "wt");
- if (!as->f) {
- fprintf(stderr, "Couldn't create Adobe stream manifest file: %s\n", filename);
- assert(0);
- gf_list_del(am->streams);
- gf_free(as);
- gf_free(am);
- return NULL;
- }
- gf_list_add(am->streams, as);
- }
-
- return am;
-}
-
-void adobe_free_multirate_manifest(AdobeMultirate *am)
-{
- u32 i;
-
- if (am->f)
- fclose(am->f);
-
- for (i=0; istreams); i++) {
- AdobeStream *as = gf_list_get(am->streams, i);
- assert(as);
- if (as->f)
- 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);
- }
- gf_list_del(am->streams);
-
- gf_free(am);
-}
-
-GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size)
-{
- GF_Err e;
- u32 i;
-#ifdef ADOBE_INLINED_BOOTSTRAP
- char bootstrap64[GF_MAX_PATH];
- u32 bootstrap64_len;
-#endif
-
- fprintf(am->f, "\n");
- fprintf(am->f, "\n");
- fprintf(am->f, "%s\n", am->id);
- fprintf(am->f, "%s\n", am->base_url);
- fprintf(am->f, "live\n");
-
- assert(am->streams);
- for (i=0; istreams); i++) {
- AdobeStream *as = gf_list_get(am->streams, i);
- assert(as);
-#ifdef ADOBE_INLINED_BOOTSTRAP
- fprintf(am->f, "\n", as->id, as->bitrate);
- bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_size, bootstrap64, GF_MAX_PATH);
- fwrite(bootstrap64, bootstrap64_len, 1, am->f);
- if (bootstrap64_len >= GF_MAX_PATH) {
- fprintf(stderr, "Bootstrap may have been truncated for stream %s_%d.\n", as->id, as->bitrate);
- assert(0);
- }
- fprintf(am->f, "\n\n");
-#else
- {
- char filename[GF_MAX_PATH];
- FILE *bstfile;
- sprintf(filename, "%s_%d.bootstrap", as->id, as->bitrate);
- bstfile = fopen(filename, "wb");
- gf_fwrite(bootstrap, bootstrap_size, 1, bstfile);
- fclose(bstfile);
- }
-#endif
- e = adobe_gen_stream_manifest(as);
- if (!e) {
- if (!am->base_url && !as->base_url)
- fprintf(stderr, "Warning: no base_url specified\n");
-
- fprintf(am->f, "\n", am->id, as->id, as->bitrate, as->bitrate);
- }
- }
- fprintf(am->f, "\n");
-
- return GF_OK;
-}
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Author: Romain Bouqueau
+ * Copyright (c) Romain Bouqueau 2012-
+ * All rights reserved
+ *
+ * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com)
+ *
+ * This file is part of GPAC / TS to HDS (ts2hds) application
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "ts2hds.h"
+
+#include
+
+//#define ADOBE_INLINED_BOOTSTRAP
+
+struct __tag_adobe_stream
+{
+ FILE *f;
+ const char *id;
+ const char *base_url;
+ u32 bitrate;
+};
+
+struct __tag_adobe_multirate
+{
+ FILE *f;
+ const char *id;
+ const char *base_url;
+ GF_List *streams;
+};
+
+static GF_Err adobe_gen_stream_manifest(AdobeStream *as)
+{
+ fprintf(as->f, "\n");
+ fprintf(as->f, "\n");
+ fprintf(as->f, "%s\n", as->id);
+ if (as->base_url)
+ fprintf(as->f, "%s\n", as->base_url);
+ fprintf(as->f, "\n", as->id, as->bitrate, as->id, as->bitrate);
+ fprintf(as->f, "\n", as->id, as->bitrate, as->bitrate, as->id, as->bitrate);
+ fprintf(as->f, "\n");
+
+ return GF_OK;
+}
+
+AdobeMultirate *adobe_alloc_multirate_manifest(char *id)
+{
+ AdobeMultirate *am = gf_calloc(1, sizeof(AdobeMultirate));
+ char filename[GF_MAX_PATH];
+
+ //default init
+ am->base_url = "http://localhost/hds/tmp";
+ am->id = id;
+ sprintf(filename, "%s.f4m", am->id);
+ am->f = fopen(filename, "wt");
+ if (!am->f) {
+ fprintf(stderr, "Couldn't create Adobe multirate manifest file: %s\n", filename);
+ assert(0);
+ gf_free(am);
+ return NULL;
+ }
+ am->streams = gf_list_new();
+
+ //create a fake stream
+ {
+ AdobeStream *as = gf_calloc(1, sizeof(AdobeStream));
+ as->id = "HD";
+ as->bitrate = 100;
+ sprintf(filename, "%s_%s_%d.f4m", am->id, as->id, as->bitrate);
+ as->f = fopen(filename, "wt");
+ if (!as->f) {
+ fprintf(stderr, "Couldn't create Adobe stream manifest file: %s\n", filename);
+ assert(0);
+ gf_list_del(am->streams);
+ gf_free(as);
+ gf_free(am);
+ return NULL;
+ }
+ gf_list_add(am->streams, as);
+ }
+
+ return am;
+}
+
+void adobe_free_multirate_manifest(AdobeMultirate *am)
+{
+ u32 i;
+
+ if (am->f)
+ fclose(am->f);
+
+ for (i=0; istreams); i++) {
+ AdobeStream *as = gf_list_get(am->streams, i);
+ assert(as);
+ if (as->f)
+ 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);
+ }
+ gf_list_del(am->streams);
+
+ gf_free(am);
+}
+
+GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size)
+{
+ GF_Err e;
+ u32 i;
+#ifdef ADOBE_INLINED_BOOTSTRAP
+ char bootstrap64[GF_MAX_PATH];
+ u32 bootstrap64_len;
+#endif
+
+ fprintf(am->f, "\n");
+ fprintf(am->f, "\n");
+ fprintf(am->f, "%s\n", am->id);
+ fprintf(am->f, "%s\n", am->base_url);
+ fprintf(am->f, "live\n");
+
+ assert(am->streams);
+ for (i=0; istreams); i++) {
+ AdobeStream *as = gf_list_get(am->streams, i);
+ assert(as);
+#ifdef ADOBE_INLINED_BOOTSTRAP
+ fprintf(am->f, "\n", as->id, as->bitrate);
+ bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_size, bootstrap64, GF_MAX_PATH);
+ fwrite(bootstrap64, bootstrap64_len, 1, am->f);
+ if (bootstrap64_len >= GF_MAX_PATH) {
+ fprintf(stderr, "Bootstrap may have been truncated for stream %s_%d.\n", as->id, as->bitrate);
+ assert(0);
+ }
+ fprintf(am->f, "\n\n");
+#else
+ {
+ char filename[GF_MAX_PATH];
+ FILE *bstfile;
+ sprintf(filename, "%s_%d.bootstrap", as->id, as->bitrate);
+ bstfile = fopen(filename, "wb");
+ gf_fwrite(bootstrap, bootstrap_size, 1, bstfile);
+ fclose(bstfile);
+ }
+#endif
+ e = adobe_gen_stream_manifest(as);
+ if (!e) {
+ if (!am->base_url && !as->base_url)
+ fprintf(stderr, "Warning: no base_url specified\n");
+
+ fprintf(am->f, "\n", am->id, as->id, as->bitrate, as->bitrate);
+ }
+ }
+ fprintf(am->f, "\n");
+
+ return GF_OK;
+}
diff --git a/applications/ts2hds/f4v.c b/applications/ts2hds/f4v.c
index 9a80b65..c65f166 100644
--- a/applications/ts2hds/f4v.c
+++ b/applications/ts2hds/f4v.c
@@ -1,185 +1,185 @@
-/*
- * GPAC - Multimedia Framework C SDK
- *
- * Author: Romain Bouqueau
- * Copyright (c) Romain Bouqueau 2012-
- * All rights reserved
- *
- * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com)
- *
- * This file is part of GPAC / TS to HDS (ts2hds) application
- *
- * GPAC is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GPAC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "ts2hds.h"
-
-//we need to write Adobe custom boxes
-#include
-
-GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx)
-{
- GF_Err e;
- GF_BitStream *bs;
-
- GF_AdobeFragRandomAccessBox *afra = (GF_AdobeFragRandomAccessBox*) afra_New();
- GF_AfraEntry *ae = (GF_AfraEntry*) gf_calloc(1, sizeof(GF_AfraEntry));
- GF_AdobeBootstrapInfoBox *abst = (GF_AdobeBootstrapInfoBox*) abst_New();
- GF_AdobeSegmentRunTableBox *asrt = (GF_AdobeSegmentRunTableBox*) asrt_New();
- GF_AdobeSegmentRunEntry *asre = (GF_AdobeSegmentRunEntry*) gf_calloc(1, sizeof(GF_AdobeSegmentRunEntry));
- GF_AdobeFragmentRunTableBox *afrt = (GF_AdobeFragmentRunTableBox*) afrt_New();
- GF_AdobeFragmentRunEntry *afre = (GF_AdobeFragmentRunEntry*) gf_calloc(1, sizeof(GF_AdobeFragmentRunEntry));
-
- u64 init_seg_time = ctx->curr_time;
- u32 seg_duration = (u32)gf_isom_get_duration(isom_file);
-
- //update context
- ctx->curr_time += seg_duration;
-
- //Adobe specific boxes
- //Random Access
- afra->type = GF_4CC('a', 'f', 'r', 'a');
- afra->version = 0;
- afra->flags = 0;
- afra->long_ids = 1;
- afra->long_offsets = 1;
- afra->global_entries = 0;
- afra->time_scale = gf_isom_get_timescale(isom_file);
-
- afra->entry_count = 1;
- ae->time = init_seg_time;
- ae->offset = 3999;
- gf_list_add(afra->local_access_entries, ae);
-
- afra->global_entries = 0;
- afra->global_entry_count = 0;
-
- e = gf_list_add(isom_file->TopBoxes, afra);
- if (e) {
- fprintf(stderr, "Impossible to write AFRA box: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
-
- //Bootstrap Info
- abst->type = GF_4CC('a', 'b', 's', 't');
- abst->version = 0;
- abst->flags = 0;
- abst->bootstrapinfo_version = 1;
- abst->profile = 0;
- abst->live = 1;
- abst->update = 0;
- abst->time_scale = gf_isom_get_timescale(isom_file);
- abst->current_media_time = init_seg_time+seg_duration;
- abst->smpte_time_code_offset = 0;
-
- abst->movie_identifier = NULL;
- abst->drm_data = NULL;
- abst->meta_data = NULL;
-
- abst->server_entry_count = 0;
- abst->quality_entry_count = 0;
-
- abst->segment_run_table_count = 1;
- {
- //Segment Run
- asrt->type = GF_4CC('a', 's', 'r', 't');
- asrt->version = 0;
- asrt->flags = 0;
- asrt->segment_run_entry_count = 1;
- {
- asre->first_segment = ctx->segnum;
- asre->fragment_per_segment = 1;
- }
- e = gf_list_add(asrt->segment_run_entry_table, asre);
- if (e) {
- fprintf(stderr, "Impossible to write ASR Entry: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
- }
- e = gf_list_add(abst->segment_run_table_entries, asrt);
- if (e) {
- fprintf(stderr, "Impossible to write ASRT box: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
-
- abst->fragment_run_table_count = 1;
- {
- //Fragment Run
- afrt->type = GF_4CC('a', 'f', 'r', 't');
- afrt->version = 0;
- afrt->flags = 0;
- afrt->timescale = gf_isom_get_timescale(isom_file);
- afrt->fragment_run_entry_count = 1;
- {
- afre->first_fragment = 1;
- afre->first_fragment_timestamp = 0;
- afre->fragment_duration = seg_duration;
- }
- e = gf_list_add(afrt->fragment_run_entry_table, afre);
- if (e) {
- fprintf(stderr, "Impossible to write AFR Entry: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
- }
- e = gf_list_add(abst->fragment_run_table_entries, afrt);
- if (e) {
- fprintf(stderr, "Impossible to write AFRT box: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
-
- e = gf_list_add(isom_file->TopBoxes, abst);
- if (e) {
- fprintf(stderr, "Impossible to write ABST box: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
-
- e = abst_Size((GF_Box*)abst);
- if (e) {
- fprintf(stderr, "Impossible to compute ABST box size: %s\n", gf_error_to_string(e));
- assert(0);
- return e;
- }
- ctx->bootstrap_size = (size_t)abst->size;
- ctx->bootstrap = gf_malloc(ctx->bootstrap_size);
- bs = gf_bs_new(ctx->bootstrap, ctx->bootstrap_size, GF_BITSTREAM_WRITE);
- e = abst_Write((GF_Box*)abst, bs);
- if (e) {
- fprintf(stderr, "Impossible to code the ABST box: %s\n", gf_error_to_string(e));
- assert(0);
- gf_bs_del(bs);
- return e;
- }
- gf_bs_del(bs);
-
- //set brands as reversed engineered from f4v files
- /*e = gf_isom_reset_alt_brands(isom_file);
- if (e) {
- fprintf(stderr, "Warning: couldn't reset ISOM brands: %s\n", gf_error_to_string(e));
- assert(0);
- }*/
- gf_isom_set_brand_info(isom_file, GF_4CC('f','4','v',' '), 1);
- gf_isom_modify_alternate_brand(isom_file, GF_4CC('i','s','o','m'), 1);
- gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','p','4','2'), 1);
- gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','4','v',' '), 1);
-
- return GF_OK;
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Author: Romain Bouqueau
+ * Copyright (c) Romain Bouqueau 2012-
+ * All rights reserved
+ *
+ * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com)
+ *
+ * This file is part of GPAC / TS to HDS (ts2hds) application
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "ts2hds.h"
+
+//we need to write Adobe custom boxes
+#include
+
+GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx)
+{
+ GF_Err e;
+ GF_BitStream *bs;
+
+ GF_AdobeFragRandomAccessBox *afra = (GF_AdobeFragRandomAccessBox*) afra_New();
+ GF_AfraEntry *ae = (GF_AfraEntry*) gf_calloc(1, sizeof(GF_AfraEntry));
+ GF_AdobeBootstrapInfoBox *abst = (GF_AdobeBootstrapInfoBox*) abst_New();
+ GF_AdobeSegmentRunTableBox *asrt = (GF_AdobeSegmentRunTableBox*) asrt_New();
+ GF_AdobeSegmentRunEntry *asre = (GF_AdobeSegmentRunEntry*) gf_calloc(1, sizeof(GF_AdobeSegmentRunEntry));
+ GF_AdobeFragmentRunTableBox *afrt = (GF_AdobeFragmentRunTableBox*) afrt_New();
+ GF_AdobeFragmentRunEntry *afre = (GF_AdobeFragmentRunEntry*) gf_calloc(1, sizeof(GF_AdobeFragmentRunEntry));
+
+ u64 init_seg_time = ctx->curr_time;
+ u32 seg_duration = (u32)gf_isom_get_duration(isom_file);
+
+ //update context
+ ctx->curr_time += seg_duration;
+
+ //Adobe specific boxes
+ //Random Access
+ afra->type = GF_4CC('a', 'f', 'r', 'a');
+ afra->version = 0;
+ afra->flags = 0;
+ afra->long_ids = 1;
+ afra->long_offsets = 1;
+ afra->global_entries = 0;
+ afra->time_scale = gf_isom_get_timescale(isom_file);
+
+ afra->entry_count = 1;
+ ae->time = init_seg_time;
+ ae->offset = 3999;
+ gf_list_add(afra->local_access_entries, ae);
+
+ afra->global_entries = 0;
+ afra->global_entry_count = 0;
+
+ e = gf_list_add(isom_file->TopBoxes, afra);
+ if (e) {
+ fprintf(stderr, "Impossible to write AFRA box: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+
+ //Bootstrap Info
+ abst->type = GF_4CC('a', 'b', 's', 't');
+ abst->version = 0;
+ abst->flags = 0;
+ abst->bootstrapinfo_version = 1;
+ abst->profile = 0;
+ abst->live = 1;
+ abst->update = 0;
+ abst->time_scale = gf_isom_get_timescale(isom_file);
+ abst->current_media_time = init_seg_time+seg_duration;
+ abst->smpte_time_code_offset = 0;
+
+ abst->movie_identifier = NULL;
+ abst->drm_data = NULL;
+ abst->meta_data = NULL;
+
+ abst->server_entry_count = 0;
+ abst->quality_entry_count = 0;
+
+ abst->segment_run_table_count = 1;
+ {
+ //Segment Run
+ asrt->type = GF_4CC('a', 's', 'r', 't');
+ asrt->version = 0;
+ asrt->flags = 0;
+ asrt->segment_run_entry_count = 1;
+ {
+ asre->first_segment = ctx->segnum;
+ asre->fragment_per_segment = 1;
+ }
+ e = gf_list_add(asrt->segment_run_entry_table, asre);
+ if (e) {
+ fprintf(stderr, "Impossible to write ASR Entry: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+ }
+ e = gf_list_add(abst->segment_run_table_entries, asrt);
+ if (e) {
+ fprintf(stderr, "Impossible to write ASRT box: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+
+ abst->fragment_run_table_count = 1;
+ {
+ //Fragment Run
+ afrt->type = GF_4CC('a', 'f', 'r', 't');
+ afrt->version = 0;
+ afrt->flags = 0;
+ afrt->timescale = gf_isom_get_timescale(isom_file);
+ afrt->fragment_run_entry_count = 1;
+ {
+ afre->first_fragment = 1;
+ afre->first_fragment_timestamp = 0;
+ afre->fragment_duration = seg_duration;
+ }
+ e = gf_list_add(afrt->fragment_run_entry_table, afre);
+ if (e) {
+ fprintf(stderr, "Impossible to write AFR Entry: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+ }
+ e = gf_list_add(abst->fragment_run_table_entries, afrt);
+ if (e) {
+ fprintf(stderr, "Impossible to write AFRT box: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+
+ e = gf_list_add(isom_file->TopBoxes, abst);
+ if (e) {
+ fprintf(stderr, "Impossible to write ABST box: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+
+ e = abst_Size((GF_Box*)abst);
+ if (e) {
+ fprintf(stderr, "Impossible to compute ABST box size: %s\n", gf_error_to_string(e));
+ assert(0);
+ return e;
+ }
+ ctx->bootstrap_size = (size_t)abst->size;
+ ctx->bootstrap = gf_malloc(ctx->bootstrap_size);
+ bs = gf_bs_new(ctx->bootstrap, ctx->bootstrap_size, GF_BITSTREAM_WRITE);
+ e = abst_Write((GF_Box*)abst, bs);
+ if (e) {
+ fprintf(stderr, "Impossible to code the ABST box: %s\n", gf_error_to_string(e));
+ assert(0);
+ gf_bs_del(bs);
+ return e;
+ }
+ gf_bs_del(bs);
+
+ //set brands as reversed engineered from f4v files
+ /*e = gf_isom_reset_alt_brands(isom_file);
+ if (e) {
+ fprintf(stderr, "Warning: couldn't reset ISOM brands: %s\n", gf_error_to_string(e));
+ assert(0);
+ }*/
+ gf_isom_set_brand_info(isom_file, GF_4CC('f','4','v',' '), 1);
+ gf_isom_modify_alternate_brand(isom_file, GF_4CC('i','s','o','m'), 1);
+ gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','p','4','2'), 1);
+ gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','4','v',' '), 1);
+
+ return GF_OK;
}
\ No newline at end of file
diff --git a/applications/ts2hds/main.c b/applications/ts2hds/main.c
index 09fc32b..9f677a6 100644
--- a/applications/ts2hds/main.c
+++ b/applications/ts2hds/main.c
@@ -1,305 +1,305 @@
-/*
- * GPAC - Multimedia Framework C SDK
- *
- * Author: Romain Bouqueau
- * Copyright (c) Romain Bouqueau 2012-
- * All rights reserved
- *
- * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com)
- *
- * This file is part of GPAC / TS to HDS (ts2hds) application
- *
- * GPAC is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GPAC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "ts2hds.h"
-
-//FIXME: test only
-//#include
-//#include
-
-#ifdef WIN32
-#define strnicmp _strnicmp
-#endif
-
-#define CHECK_NEXT_ARG if (i+1==(u32)argc) { fprintf(stderr, "Missing arg - please check usage\n"); exit(1); }
-
-#ifdef GPAC_DISABLE_ISOM
-
-#error "Cannot compile TS2HDS if GPAC is not built with ISO File Format support"
-
-#endif
-
-
-static GFINLINE void usage(const char * progname)
-{
- fprintf(stderr, "USAGE: %s -i input -o output\n"
- "\n"
-#ifdef GPAC_MEMORY_TRACKING
- "\t-mem-track: enables memory tracker\n"
-#endif
- );
-}
-
-
-/*parse TS2HDS arguments*/
-static GFINLINE GF_Err parse_args(int argc, char **argv, char **input, char **output, u64 *curr_time, u32 *segnum)
-{
- Bool input_found=0, output_found=0;
- char *arg = NULL, *error_msg = "no argument found";
- s32 i;
-
- for (i=1; isize = bootstrap[2]*256+bootstrap[3];
- assert(abst->size
+//#include
+
+#ifdef WIN32
+#define strnicmp _strnicmp
+#endif
+
+#define CHECK_NEXT_ARG if (i+1==(u32)argc) { fprintf(stderr, "Missing arg - please check usage\n"); exit(1); }
+
+#ifdef GPAC_DISABLE_ISOM
+
+#error "Cannot compile TS2HDS if GPAC is not built with ISO File Format support"
+
+#endif
+
+
+static GFINLINE void usage(const char * progname)
+{
+ fprintf(stderr, "USAGE: %s -i input -o output\n"
+ "\n"
+#ifdef GPAC_MEMORY_TRACKING
+ "\t-mem-track: enables memory tracker\n"
+#endif
+ );
+}
+
+
+/*parse TS2HDS arguments*/
+static GFINLINE GF_Err parse_args(int argc, char **argv, char **input, char **output, u64 *curr_time, u32 *segnum)
+{
+ Bool input_found=0, output_found=0;
+ char *arg = NULL, *error_msg = "no argument found";
+ s32 i;
+
+ for (i=1; isize = bootstrap[2]*256+bootstrap[3];
+ assert(abst->size
-
-//f4m
-typedef struct __tag_adobe_stream AdobeStream;
-typedef struct __tag_adobe_multirate AdobeMultirate;
-AdobeMultirate *adobe_alloc_multirate_manifest(char *id);
-void adobe_free_multirate_manifest(AdobeMultirate *am);
-GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size);
-
-//context
-typedef struct
-{
- u64 curr_time;
- u32 segnum;
- char *bootstrap;
- size_t bootstrap_size;
- AdobeMultirate *multirate_manifest;
-} AdobeHDSCtx;
-
-//f4v
-GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx);
+/*
+ * GPAC - Multimedia Framework C SDK
+ *
+ * Author: Romain Bouqueau
+ * Copyright (c) Romain Bouqueau 2012-
+ * All rights reserved
+ *
+ * Note: this development was kindly sponsorized by Vizion'R (http://vizionr.com)
+ *
+ * This file is part of GPAC / TS to HDS (ts2hds) application
+ *
+ * GPAC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GPAC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include
+
+//f4m
+typedef struct __tag_adobe_stream AdobeStream;
+typedef struct __tag_adobe_multirate AdobeMultirate;
+AdobeMultirate *adobe_alloc_multirate_manifest(char *id);
+void adobe_free_multirate_manifest(AdobeMultirate *am);
+GF_Err adobe_gen_multirate_manifest(AdobeMultirate* am, char *bootstrap, size_t bootstrap_size);
+
+//context
+typedef struct
+{
+ u64 curr_time;
+ u32 segnum;
+ char *bootstrap;
+ size_t bootstrap_size;
+ AdobeMultirate *multirate_manifest;
+} AdobeHDSCtx;
+
+//f4v
+GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx);
diff --git a/applications/udptsseg/Makefile b/applications/udptsseg/Makefile
index cfcadb1..8732643 100644
--- a/applications/udptsseg/Makefile
+++ b/applications/udptsseg/Makefile
@@ -67,10 +67,4 @@ depend:
distclean: clean
rm -f Makefile.bak .depend
-
-
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+-include .depend
diff --git a/bin/win32/release/nsis_install/default.out b/bin/win32/release/nsis_install/default.out
deleted file mode 100644
index b24ca9f..0000000
--- a/bin/win32/release/nsis_install/default.out
+++ /dev/null
@@ -1,7 +0,0 @@
-;--------------------------------
-;This default configuration file will generate an unversioned installer.
-;Please Check the readme.txt file.
-
-!define /date RELDATE "%Y%m%d_%H%M"
-Name "GPAC Framework ${GPAC_VERSION}"
-OutFile "GPAC.Framework.Setup-${GPAC_VERSION}-${RELDATE}_unversioned.exe"
diff --git a/configure b/configure
index 54a9c3a..311b689 100755
--- a/configure
+++ b/configure
@@ -22,7 +22,7 @@ GPAC_CONFIGURATION="$@"
TMPC="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.c"
TMPH="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.h"
-TMPCPP="${TMPDIR1}/gpac-conf-${RANDOM}-$$-${RANDOM}.cpp"
+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"
@@ -33,17 +33,17 @@ DESTDIR=""
prefix="/usr/local"
mandir=""
cross_prefix=""
+targetos=""
dxsdk_path=""
moz_path="local"
cc_orig="gcc"
-cc="${cc_orig}"
-cpp_orig="g++"
-cpp="${cpp_orig}"
+cxx_orig="g++"
ar="ar"
ranlib="ranlib"
make="make"
strip="strip"
pkg_config="pkg-config"
+windres="windres"
readelf="readelf"
install="${INSTALL:=install}"
instflags="${INSTFLAGS:=-p}"
@@ -58,6 +58,7 @@ xul_flags=""
libdir="lib"
#GPAC module config
+static_modules="no"
js_flags="XP_UNIX"
js_lib="-ljs"
lm_lib=""
@@ -151,12 +152,14 @@ disable_scenegraph="no"
disable_dvbx="yes"
disable_vobsub="no"
disable_ttxt="no"
+disable_hevc="no"
enable_depth_compositor="no"
enable_renoir="no"
has_avcap="no"
avcap_cflags=""
avcap_ldflags="-lavcap"
has_opensvc="no"
+has_openhevc="no"
win32="no"
mingw32="no"
@@ -172,7 +175,7 @@ bigendian="no"
SHFLAGS=-shared
need_inet_aton="no"
CFLAGS=""
-CPPFLAGS=""
+CXXFLAGS=""
GPAC_SH_FLAGS=-lpthread
DYN_LIB_SUFFIX="so"
X11_PATH="/usr/X11R6"
@@ -198,8 +201,9 @@ GPAC configuration options:
--verbose enable verbose building [$verbose]
--source-path=PATH path of source code [$source_path]
--cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]
- --cc =CC use C compiler CC [$cc]
- --cpp=CPP use C++ compiler CPP [$cpp]
+ --target-os=TARGETOS use TARGETOS for compile tools [$targetos]
+ --cc=CC use C compiler CC [$cc]
+ --cxx=CXX use C++ compiler CXX [$cxx]
--make=MAKE use specified make [$make]
--extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS]
--extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS]
@@ -217,6 +221,7 @@ GPAC configuration options:
--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
--disable-opt disable GCC optimizations
--disable-ipv6 disable IPV6 support
@@ -286,6 +291,7 @@ Configuration options for libgpac - all options can be enabled with --enable-opt
--disable-ttxt disable TTXT (3GPP / MPEG-4 Timed Text) support
--disable-player disable player (terminal and compositor)
--disable-scenegraph disable scenegraph, scene parsers and player (terminal and compositor)
+ --disable-hevc disable HEVC support
Extra libraries configuration. You can turn a libray off or force using the local version in gpac/extra_lib/
--use-js=OPT force SpiderMonkey ECMAScript OPT=[no,local]
@@ -316,11 +322,15 @@ for opt do
;;
--mandir=*) mandir=`echo $opt | cut -d '=' -f 2`
;;
- --source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
- ;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` && echo "\ncross-prefix detected: $cross_prefix"
;;
- --cc=*) cc=`echo $opt | cut -d '=' -f 2`
+ --target-os=*) targetos=`echo $opt | cut -d '=' -f 2` && echo "\ntarget-os detected: $targetos"
+ ;;
+ --cc=*) cc_orig=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --cxx=*) cxx_orig=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --cpp=*) cxx_orig=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
@@ -343,6 +353,9 @@ for opt do
esac
done
+cc="${cc_orig}"
+cxx="${cxx_orig}"
+
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="x86"
@@ -404,29 +417,30 @@ if test -z "$CFLAGS"; then
CFLAGS=""
fi
-if test "$win32" = "yes" ; then
- cross_prefix=""
-fi
+#if test "$win32" = "yes" ; then
+# cross_prefix=""
+#fi
-if test "$mingw32" = "yes" ; then
- cross_prefix=""
-fi
+#if test "$mingw32" = "yes" ; then
+# cross_prefix=""
+#fi
cc="${cross_prefix}${cc}"
#for ccache
cc="${cc}"
-cpp="${cross_prefix}${cpp}"
+cxx="${cross_prefix}${cxx}"
ar="${cross_prefix}${ar}"
ranlib="${cross_prefix}${ranlib}"
strip="${cross_prefix}${strip}"
-pkg_config="${cross_prefix}${pkg_config}"
+pkg_config="${pkg_config}"
+windres="${cross_prefix}${windres}"
#check pkg_config
if test "$cross_prefix" = "" ; then
if ! $pkg_config --version >/dev/null 2>&1 ; then
- echo "$pkg_config not found, configure may detect wrong libraries"
+ pkg_config="no"
fi
fi
@@ -443,7 +457,9 @@ fi
#OS specific
-targetos=`uname -s`
+if test "$targetos" = "" ; then
+ targetos=`uname -s`
+fi
case $targetos in
BeOS)
js_flags=-DXP_BEOS
@@ -474,7 +490,7 @@ case $targetos in
SunOS)
make="gmake"
readelf="greadelf"
- LDFLAGS="${opt#--extra-ldflags=}"
+ LDFLAGS="$LDFLAGS"
instflags=""
#check for 64-bit
cat > $TMPC << EOF
@@ -555,6 +571,10 @@ EOF
mingw32="yes"
win32="yes"
extralibs="$extralibs -lws2_32 -lwinmm"
+ CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
+ if test "$cross_prefix" != "" ; then
+ GPAC_SH_FLAGS=""
+ fi
;;
CYGWIN*)
@@ -610,7 +630,7 @@ CFLAGS="$CFLAGS -Wall"
if $cc -o $TMPO $TMPC -fno-strict-aliasing 2> /dev/null ; then
CFLAGS="$CFLAGS -fno-strict-aliasing"
fi
-CPPFLAGS="$CFLAGS"
+CXXFLAGS="$CFLAGS"
if $cc -o $TMPO $TMPC -lz -Wno-pointer-sign 2> /dev/null ; then
CFLAGS="$CFLAGS -Wno-pointer-sign"
fi
@@ -625,17 +645,20 @@ fi
#GCC PIC
+if test "$cross_prefix" != "" ; then
+ want_pic="no"
+fi
if test "$want_pic" = "yes" ; then
CFLAGS="$CFLAGS -fPIC -DPIC"
- CPPFLAGS="$CPPFLAGS -fPIC -DPIC"
+ CXXFLAGS="$CXXFLAGS -fPIC -DPIC"
fi
#force use of cflags with cc
cc_naked=$cc
-cpp_naked=$cpp
+cxx_naked=$cxx
cc="$cc $CFLAGS"
-cpp="$cpp $CPPFLAGS"
+cxx="$cxx $CXXFLAGS"
#look for zlib
@@ -644,12 +667,12 @@ cat > $TMPC << EOF
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 test "$cross_prefix" = "" ; then
if $cc -o $TMPO $TMPC -lz $LDFLAGS 2> /dev/null ; then
has_zlib="system"
fi
-fi
-if test "$has_zlib" = "force-no" ; then
+#fi
+if test "$has_zlib" = "no" ; then
if $cc -o $TMPO $TMPC -I"$local_inc/zlib" -L$local_lib -lz 2> /dev/null ; then
has_zlib="local"
fi
@@ -687,7 +710,7 @@ EOF
if $cc -o $TMPO $TMPC $js_flags -L$local_lib -ljs -lpthread 2> /dev/null ; then
has_js="local"
#dc added
- else
+ elif test "$pkg_config" != "no"; then
#try pkg-config
if $pkg_config --exists mozilla-js 2> /dev/null ; then
mozjs_pkgcfg="mozilla-js"
@@ -785,19 +808,20 @@ EOF
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
has_js="prefix"
#dc added end
- else
+ elif test "$pkg_config" != "no"; then
if $pkg_config --exists mozilla-js 2> /dev/null ; then
- mozjs_pkgcfg="mozilla-js"
+ mozjs_pkgcfg="mozilla-js"
elif $pkg_config --exists mozjs 2> /dev/null ; then
- mozjs_pkgcfg="mozjs"
+ mozjs_pkgcfg="mozjs"
elif $pkg_config --exists mozjs185 2> /dev/null ; then
- mozjs_pkgcfg="mozjs185"
+ mozjs_pkgcfg="mozjs185"
fi
if test mozjs_pkgcfg != "no" ; then
@@ -808,7 +832,8 @@ EOF
js_lib=`$pkg_config --libs $mozjs_pkgcfg`
fi
fi
- if test "$has_js" = "no" ; then
+ fi
+ if test "$has_js" = "no" ; then
if $cc -o $TMPO $TMPC $js_flags $LDFLAGS -ljs 2> /dev/null ; then
js_inc="/usr/include"
has_js="system"
@@ -836,8 +861,6 @@ EOF
fi
fi
fi
- fi
-
fi
if test "$has_js" != "no" ; then
@@ -912,7 +935,7 @@ cat > $TMPC << EOF
#include
int main( void ) { return 0; }
EOF
-if $cpp -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread 2> /dev/null ; then
+if $cxx -o $TMPO $TMPC -I$local_inc/platinum $LDFLAGS -L$local_lib -lPlatinum -lPltMediaServer -lPltMediaConnect -lPltMediaRenderer -lNeptune -lZlib -lpthread 2> /dev/null ; then
has_platinum="yes"
fi
@@ -934,7 +957,7 @@ int main( void ) {
return 0;
}
EOF
-if $cpp -o $TMPO $TMPC $LDFLAGS $avcap_cflags $avcap_ldflags 2> /dev/null ; then
+if $cxx -o $TMPO $TMPC $LDFLAGS $avcap_cflags $avcap_ldflags 2> /dev/null ; then
has_avcap="yes"
else
if test "$darwin" = "yes" ; then
@@ -944,7 +967,7 @@ else
avcap_cflags="-I$local_inc -I$local_inc/avcap/linux"
avcap_ldflags="-lavcap -lpthread"
fi
- if $cpp -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags 2> /dev/null ; then
+ if $cxx -o $TMPO $TMPC $avcap_cflags $LDFLAGS -L$local_lib $avcap_ldflags 2> /dev/null ; then
has_avcap="yes"
avcap_ldflags="-L../../$local_lib $avcap_ldflags"
fi
@@ -965,19 +988,48 @@ cat > $TMPC << EOF
#include
int main( void ) { return 0; }
EOF
-if $cpp -o $TMPO $TMPC $osvc_cflags $LDFLAGS $osvc_ldflags 2> /dev/null ; then
+if $cxx -o $TMPO $TMPC $osvc_cflags $LDFLAGS $osvc_ldflags 2> /dev/null ; then
has_opensvc="yes"
else
osvc_cflags="-I$local_inc"
osvc_ldflags="-lOpenSVCDec"
-if $cpp -o $TMPO $TMPC $osvc_cflags $LDFLAGS -L$local_lib $osvc_ldflags 2> /dev/null ; then
+if $cxx -o $TMPO $TMPC $osvc_cflags $LDFLAGS -L$local_lib $osvc_ldflags 2> /dev/null ; then
has_opensvc="yes"
osvc_ldflags="-L../../$local_lib $osvc_ldflags"
fi
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 -lpthread"
+elif test "$cross_prefix" = "" ; then
+ohevc_cflags=""
+ohevc_ldflags="-lLibOpenHevcWrapper -lpthread -lm"
+else
+ohevc_cflags="-I${prefix}include"
+ohevc_ldflags="-lLibOpenHevcWrapper -lpthread"
+fi
+
+cat > $TMPC << EOF
+#include
+#include
+int main( void ) { libOpenHevcInit(1, 1); return 0; }
+EOF
+if $cc -o $TMPO $TMPC $ohevc_cflags $LDFLAGS $ohevc_ldflags 2> /dev/null ; then
+ has_openhevc="yes"
+else
+ ohevc_cflags="-I$local_inc"
+ ohevc_ldflags="-lLibOpenHevcWrapper -lpthread -lm"
+ if $cc -o $TMPO $TMPC $ohevc_cflags $LDFLAGS -L$local_lib $ohevc_ldflags 2> /dev/null ; then
+ has_openhevc="yes"
+ ohevc_ldflags="-L../../$local_lib $ohevc_ldflags"
+ fi
+fi
+
#look for freetype support
cat > $TMPC << EOF
@@ -1225,18 +1277,19 @@ fi
#look for FFMPEG support
-if $pkg_config --exists libavcodec libavformat libswscale 2> /dev/null ; then
- ffmpeg_cflags=`$pkg_config --cflags libavcodec libavformat libswscale libavutil`
- ffmpeg_lflags=`$pkg_config --libs libavcodec libavformat libswscale libavutil`
+ffmpeg_cflags=""
+ffmpeg_lflags="-lz -lavcodec -lavformat -lavutil -lswscale -lavdevice"
+if test "$cross_prefix" = "" -a "$pkg_config" != "no"; then
+ if $pkg_config --exists libavcodec libavformat libswscale libavdevice libavutil 2> /dev/null ; then
+ ffmpeg_cflags=`$pkg_config --cflags libavcodec libavformat libswscale libavutil libavdevice`
+ ffmpeg_lflags=`$pkg_config --libs libavcodec libavformat libswscale libavutil libavdevice`
has_ffmpeg="system"
-else
- ffmpeg_cflags=""
- ffmpeg_lflags="-lz -lavcodec -lavformat"
+ fi
fi
cat > $TMPC << EOF
#include
-int main( void ) { return 0; }
+int main(void) {return 0;}
EOF
if $cc -o $TMPO $TMPC $ffmpeg_cflags $ffmpeg_lflags $LDFLAGS 2> /dev/null ; then
@@ -1246,7 +1299,12 @@ else
cat > $TMPC << EOF
#include
-int main( void ) { return 0; }
+int main(void) {
+ AVFrame *f1, *f2;
+ f2 = av_frame_clone(f1);
+ AV_CODEC_ID_H264;
+ return 0;
+}
EOF
fi
@@ -1274,21 +1332,33 @@ if test "$has_ffmpeg" = "no" ; then
fi
fi
+cat > $TMPC << EOF
+#include
+int main(void) {return 0;}
+EOF
+if $cc -o $TMPO $TMPC $ffmpeg_cflags $ffmpeg_lflags 2> /dev/null ; then
+ is_libav="no"
+else
+ is_libav="yes"
+fi
+
#look for FREENECT support
freenect_flags=""
freenect_ld="-lfreenect"
+has_freenect="no"
+if test "$pkg_config" != "no"; then
+ if $pkg_config --exists libfreenect 2> /dev/null ; then
+ freenect_flags=`$pkg_config --cflags libfreenect`
+ freenect_libs=`$pkg_config --libs libfreenect`
+ has_freenect="system"
+ freenect_flags="-DFREENECT_FLAT_HEADERS $freenect_flags"
+ fi
+fi
-if $pkg_config --exists libfreenect 2> /dev/null ; then
- freenect_flags=`$pkg_config --cflags libfreenect`
- freenect_libs=`$pkg_config --libs libfreenect`
- has_freenect="system"
- freenect_flags="-DFREENECT_FLAT_HEADERS $freenect_flags"
-
-else
+if test "$has_freenect" = "no"; then
-has_freenect="no"
cat > $TMPC << EOF
#include
int main( void ) { return 0; }
@@ -1445,12 +1515,12 @@ if test "$cross_prefix" = "" ; then
fi
fi
- cat > $TMPCPP << EOF
+ cat > $TMPCXX << EOF
#include
int main( void ) { return 0; }
EOF
- if $cc $wx_cflags -o $TMPO $TMPCPP $wx_lflags > /dev/null 2>&1 ; then
+ if $cc $wx_cflags -o $TMPO $TMPCXX $wx_lflags > /dev/null 2>&1 ; then
wx_version=`wx-config --version | sed 's/[^0-9]//g'`
if test "$wx_version" -lt 254 ; then
wx_too_old="yes"
@@ -1604,6 +1674,8 @@ fi
#overwrite detection with manual settings
for opt do
case "$opt" in
+ --static-modules) static_modules="yes"
+ ;;
--sdl-cfg=*) sdl_path=`echo $opt | cut -d '=' -f 2`; sdl_local="yes"
;;
--enable-sdl-static=*) sdl_static="yes"
@@ -1733,10 +1805,10 @@ for opt do
;;
--enable-pulseaudio=*) has_pulseaudio="yes"
;;
-
- --disable-all) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_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_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds = "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_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_isoff_hds="yes"; disable_hevc="yes"
+ ;;
+ --isomedia-only) has_pulseaudio="no"; has_alsa="no"; disable_core_tools="yes"; disable_3d="yes"; disable_svg="yes"; disable_vrml="yes"; disable_od="yes"; disable_bifs="yes"; disable_bifs_enc="yes"; disable_laser="yes"; disable_seng="yes"; disable_qtvr="yes"; disable_avi="yes"; disable_ogg="yes"; disable_m2ps="yes"; disable_m2ts="yes"; disable_m2ts_mux="yes"; disable_parsers="yes"; disable_import="yes"; disable_export="yes"; disable_swf="yes"; disable_scene_stats="yes"; disable_scene_dump="yes"; disable_scene_encode="yes"; disable_loader_isoff="yes"; disable_od_dump="yes"; disable_od_parse="yes"; disable_isom_dump="yes"; disable_mcrypt="yes"; disable_streaming="yes"; disable_x3d="yes"; disable_loader_bt="yes"; disable_loader_xmt="yes"; has_dvb4linux="no"; disable_player="yes"; disable_vobsub="yes"; disable_scenegraph="yes"; disable_dvbx="yes"; disable_ttxt="yes"; disable_saf="yes"; disable_smgr="yes"; disable_mpd="yes"; disable_dash="yes"; disable_hevc="no"; disable_isoff="no"; disable_isoff_hds="no"; disable_isoff_write="no"; disable_isoff_hint="no"; disable_isoff_frag="no"
;;
-
--disable-3d) disable_3d="yes"
;;
--enable-3d) disable_3d="no"
@@ -1919,6 +1991,10 @@ for opt do
;;
--enable-core) disable_core_tools="no"
;;
+ --disable-hevc) disable_hevc="yes"
+ ;;
+ --enable-hevc) disable_hevc="no"
+ ;;
esac
done
@@ -2002,33 +2078,35 @@ fi
#look for GECKO support
-cat > $TMPCPP << EOF
+cat > $TMPCXX << EOF
#include
int main( void ) { return 0; }
EOF
-if $cc -o $TMPO $TMPCPP -I$xulsdk_path $LDFLAGS 2> /dev/null ; then
+if $cc -o $TMPO $TMPCXX -I$xulsdk_path $LDFLAGS 2> /dev/null ; then
has_xul="system"
xul_flags="-I$xulsdk_path $xul_flags"
fi
-if test "$has_xul" = "no" ; then
+if test "$pkg_config" != "no"; then
+ if test "$has_xul" = "no" ; then
if $pkg_config --exists libxul 2> /dev/null ; then
- if $cpp -o $TMPO $TMPCPP `$pkg_config --cflags libxul` `$pkg_config --libs libxul` ; then
+ if $cxx -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
fi
+ fi
fi
if test "$has_xul" = "no" ; then
- if $cc -o $TMPO $TMPCPP $xul_flags -I$local_inc/gecko-sdk/include $LDFLAGS 2> /dev/null ; then
+ if $cc -o $TMPO $TMPCXX $xul_flags -I$local_inc/gecko-sdk/include $LDFLAGS 2> /dev/null ; 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 $TMPCPP $js_flags $js_lib_pkg $LDFLAGS 2> /dev/null ; then
+ if $cc -o $TMPO $TMPCXX $js_flags $js_lib_pkg $LDFLAGS 2> /dev/null ; then
if test "$mozjs_pkgcfg" != "no" ; then
xul_flags=`$pkg_config --cflags $mozjs_pkgcfg`
has_xul="$has_js"
@@ -2079,14 +2157,50 @@ fi
#look for SDL support
sdl_too_old=no
has_sdl=no
-sdl_config="sdl-config"
+
+sdl_config="sdl2-config"
if test "$sdl_local" = "yes"; then
- sdl_config="$sdl_path/sdl-config"
+ sdl_config="$sdl_path/sdl2-config"
sdl_static="yes"
fi
-if test "$cross_prefix" = "" ; then
+#if test "$cross_prefix" = "" ; then
+ if type $sdl_config >/dev/null 2>&1; then
+
+ cat > $TMPC << EOF
+#include
+#undef main
+int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
+EOF
+
+ if test "$sdl_static" = "yes"; then
+ sdl_lib_flags=`$sdl_config --static-libs`
+ else
+ sdl_lib_flags=`$sdl_config --libs`
+ fi
+ sdl_cflags=`$sdl_config --cflags`
+
+ if $cc -o $TMPO $sdl_cflags $TMPC $LDFLAGS $sdl_lib_flags > /dev/null 2>&1 ; then
+ _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
+ if test "$_sdlversion" -lt 121 ; then
+ sdl_too_old=yes
+ else
+ has_sdl=yes
+ fi
+ fi
+ fi
+#fi
+
+if test "$has_sdl" = "no" ; then
+
+ sdl_config="sdl-config"
+ if test "$sdl_local" = "yes"; then
+ sdl_config="$sdl_path/sdl-config"
+ sdl_static="yes"
+ fi
+
+ if test "$cross_prefix" = "" ; then
if type $sdl_config >/dev/null 2>&1; then
cat > $TMPC << EOF
@@ -2111,6 +2225,7 @@ EOF
fi
fi
fi
+ fi
fi
#end SDL check
@@ -2222,7 +2337,7 @@ version_micro=`grep '#define GPAC_VERSION_MICRO ' $source_path/include/gpac/vers
soname_version="${version_major}.${version_minor}.${version_micro}"
if [ -d ".svn" ]; then
- if which svnversion 2>/dev/null
+ if which svnversion 2> /dev/null
then
revision="`svnversion \"$source_path\"`"
echo "#define GPAC_SVN_REVISION \"$revision\"" > $source_path/include/gpac/revision.h
@@ -2240,7 +2355,7 @@ echo "** System Configuration"
echo "Install prefix: $prefix"
echo "Source path: $source_path"
echo "C compiler: $cc_naked"
-echo "C++ compiler: $cpp_naked"
+echo "C++ compiler: $cxx_naked"
echo "make: $make"
echo "CPU: $cpu"
echo "Big Endian: $bigendian"
@@ -2254,9 +2369,9 @@ 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 "Fixed-Point Version: $use_fixed_point"
echo "IPV6 Support: $has_ipv6"
-
+echo "Static Modules: $static_modules"
if test "$disable_player" = "yes" ; then
echo "Player disabled"
@@ -2444,6 +2559,7 @@ fi
if test "$disable_mpd" = "yes" ; then
echo "HLS and DASH Manifest Disabled"
+ echo "#define GPAC_DISABLE_MPD" >> $TMPH
fi
if test "$disable_dash" = "yes" ; then
@@ -2451,6 +2567,11 @@ if test "$disable_dash" = "yes" ; then
echo "#define GPAC_DISABLE_DASH_CLIENT" >> $TMPH
fi
+if test "$disable_hevc" = "yes" ; then
+ echo "HEVC Support disabled"
+ echo "#define GPAC_DISABLE_HEVC" >> $TMPH
+fi
+
echo ""
echo "** Detected libraries **"
@@ -2518,6 +2639,7 @@ else
fi
echo "A52 (AC3): $has_a52"
echo "OpenSVCDecoder: $has_opensvc"
+echo "OpenHEVCDecoder: $has_openhevc"
echo "Freenect: $has_freenect"
if test "$enable_renoir" = "yes" ; then
@@ -2575,8 +2697,11 @@ if test "$darwin" = "yes" ; then
fi
ldir=`pwd`
-CFLAGS="$CFLAGS -fvisibility=\"hidden\" -DGPAC_HAVE_CONFIG_H -I\"$ldir\""
-CPPFLAGS="$CPPFLAGS"
+CFLAGS="$CFLAGS -DGPAC_HAVE_CONFIG_H -I\"$ldir\""
+if test "$win32" = "no" ; then
+ CFLAGS="$CFLAGS -fvisibility=\"hidden\""
+fi
+CXXFLAGS="$CXXFLAGS"
echo "Creating config.mak"
@@ -2597,22 +2722,25 @@ echo "CC=$cc_naked" >> config.mak
echo "AR=$ar" >> config.mak
echo "RANLIB=$ranlib" >> config.mak
echo "STRIP=$strip" >> config.mak
+echo "WINDRES=$windres" >> config.mak
else
echo "CC=@$cc_naked" >> config.mak
echo "AR=@$ar" >> config.mak
echo "RANLIB=@$ranlib" >> config.mak
echo "STRIP=@$strip" >> config.mak
+echo "WINDRES=$windres" >> config.mak
fi
echo "INSTALL=$install" >> config.mak
echo "LIBTOOL=libtool" >> config.mak
echo "INSTFLAGS=$instflags" >> config.mak
echo "OPTFLAGS=$CFLAGS" >> config.mak
-echo "CPPFLAGS=$CPPFLAGS" >> config.mak
+echo "CXXFLAGS=$CXXFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
echo "SHFLAGS=$SHFLAGS" >> config.mak
echo "libdir=$libdir" >> config.mak
+echo "STATIC_MODULES=$static_modules" >> config.mak
#for cross-compilation
if test "$cross_prefix" != "" ; then
@@ -2658,6 +2786,10 @@ if test "$win32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> config.mak
echo "CONFIG_OS=CONFIG_WIN32" >> config.mak
echo "#define GPAC_CONFIG_WIN32" >> $TMPH
+ if test "$cygwin" = "yes" ; then
+ echo "#define ftello64 ftell" >> $TMPH
+ echo "#define fseeko64 fseek" >> $TMPH
+ fi
elif test "$linux" = "yes" ; then
echo "CONFIG_LINUX=yes" >> config.mak
echo "CONFIG_OS=CONFIG_LINUX" >> config.mak
@@ -2705,9 +2837,11 @@ else
echo "JS_LIBS=$js_lib" >> config.mak
echo "#define GPAC_HAS_SPIDERMONKEY" >> $TMPH
fi
-echo "CONFIG_ZLIB=$has_zlib" >> config.mak
-if test "$has_zlib" = "no" ; then
+if test "$has_zlib" = "no" -o "$has_zlib" = "force-no" ; then
echo "#define GPAC_DISABLE_ZLIB" >> $TMPH
+ echo "CONFIG_ZLIB=no" >> config.mak
+else
+ echo "CONFIG_ZLIB=$has_zlib" >> config.mak
fi
echo "CONFIG_FT=$has_ft" >> config.mak
@@ -2729,10 +2863,13 @@ echo "CONFIG_OGG=$has_ogg" >> config.mak
echo "CONFIG_VORBIS=$has_vorbis" >> config.mak
echo "CONFIG_THEORA=$has_theora" >> config.mak
echo "CONFIG_FFMPEG=$has_ffmpeg" >> config.mak
-if test "$has_ffmpeg" != "no"
-then
+if test "$has_ffmpeg" = "no"; then
+echo "DISABLE_DASHCAST=yes" >> config.mak
+else
echo "ffmpeg_cflags=$ffmpeg_cflags" >> config.mak
echo "ffmpeg_lflags=$ffmpeg_lflags" >> config.mak
+# echo "DISABLE_DASHCAST=$is_libav" >> config.mak
+ echo "CONFIG_LIBAV=$is_libav" >> config.mak
fi
echo "CONFIG_FFMPEG_OLD=$old_ffmpeg_inc" >> config.mak
@@ -2870,6 +3007,12 @@ if test "$has_opensvc" = "yes" ; then
echo "OSVC_LDFLAGS=$osvc_ldflags" >> config.mak
fi
+echo "CONFIG_OPENHEVC=$has_openhevc" >> config.mak
+if test "$has_openhevc" = "yes" ; then
+ echo "OHEVC_CFLAGS=$ohevc_cflags" >> config.mak
+ echo "OHEVC_LDFLAGS=$ohevc_ldflags" >> config.mak
+fi
+
echo "MOZILLA_DIR=$moz_path" >> config.mak
echo "CONFIG_XUL=$has_xul" >> config.mak
@@ -3006,7 +3149,7 @@ else
fi
-rm -f $TMPO $TMPC $TMPE $TMPS $TMPCPP $TMPH
+rm -f $TMPO $TMPC $TMPE $TMPS $TMPCXX $TMPH
if [ ! -d "./bin" ] ; then
diff --git a/doc/configuration.html b/doc/configuration.html
index 1eae4e4..20194b0 100644
--- a/doc/configuration.html
+++ b/doc/configuration.html
@@ -10,7 +10,7 @@
GPAC Configuration file documentation Version 0.5.0
-Last Modified $LastChangedDate: 2012-12-06 19:08:32 +0000 (Thu, 06 Dec 2012) $
+Last Modified $LastChangedDate: 2014-02-20 18:47:55 +0000 (Do, 20. Feb 2014) $
@@ -43,6 +43,7 @@ The config file is based on the win32 .ini file model, thus is ordered by sectio
DASHALSAShortcuts
+OpenHEVCDSMCC
@@ -218,9 +219,9 @@ Specifies the user prefered language as expressed in ISO 639-2. This is used to
Specifies the user prefered language as expressed in ISO 639-1. This is used to select streams in case of alternate content in an audio object.
-If set, late BIFS frame will still be drawn. If not set, the scene won't be redrawn untill BIFS streams are back in sync. This is by default off to keep better sync, but may be usefull when testing heavy content or slow renderers.
+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 off to keep better sync, but may be usefull when testing heavy content or slow renderers.
ForceSingleClock [value: "yes" "no"]
@@ -240,7 +241,7 @@ Specifies the priority of the decoders (priority is applied to decoder thread(s)
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 tiÅe+; Depending on the threqding Åodem this option cqn be ignored;
+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"]
@@ -319,11 +320,15 @@ Specifies whether scalable zoom should be used or not. When scalable zoom is ena
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.
-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.
+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).
@@ -716,9 +721,6 @@ 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.
-MaxCacheDuration [value: positive integer]
-
-Specifies minimum cache duration in seconds. Default is 30 sec
KeepFiles [value: yes, no]
Specifies whether downloaded files should not be deleted.
@@ -730,13 +732,30 @@ For debug purposes, instructs the player to switch representation every N segmen
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 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
Instructs the DASH client to start playing the indicated representation before doing any switching. Default is minBandwidth.
+InitialTimeshift [value: positive integer between 0 and 100 ]
+
+Uses the given percentage of 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 no.
+
@@ -799,6 +818,21 @@ The "DSMCC" section of the config file holds the configuration option for the pr
Specifies if the DSMCC data will be processed (true). It implies creations of directories and files in the temp directory.
+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.
+Specifies the threading type for the openHEVC decoder. Default is frame (wpp disabled).
+
+
diff --git a/doc/doxyfile b/doc/doxyfile
index d545a45..bd9c46d 100644
--- a/doc/doxyfile
+++ b/doc/doxyfile
@@ -1,16 +1,113 @@
-# Doxyfile 1.4.3
+# Doxyfile 1.8.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
PROJECT_NAME = libgpac
-PROJECT_NUMBER = 0.5.0
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Documentation of the core library of GPAC. For more information, check out http://gpac.wp.mines-telecom.fr"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO = ..\regression_tests\auxiliary_files\logo.jpg
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-
+# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en,
+# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
OUTPUT_LANGUAGE = English
-USE_WINDOWS_ENCODING = YES
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
REPEAT_BRIEF = NO
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
@@ -22,67 +119,651 @@ ABBREVIATE_BRIEF = "The $name class" \
a \
an \
the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
INLINE_INHERITED_MEMB = NO
-FULL_PATH_NAMES = YES
-STRIP_FROM_PATH = ../include
-STRIP_FROM_INC_PATH = ../include
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
MULTILINE_CPP_IS_BRIEF = NO
-DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
INHERIT_DOCS = NO
-DISTRIBUTE_GROUP_DOC = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
TAB_SIZE = 8
-ALIASES =
-OPTIMIZE_OUTPUT_FOR_C = NO
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = YES
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
-EXTRACT_ALL = NO
-EXTRACT_PRIVATE = NO
-EXTRACT_STATIC = NO
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
INLINE_INFO = NO
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
SORT_MEMBER_DOCS = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note the this
+# will also influence the order of the classes in the class list.
+# The default value is: NO.
+
SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
GENERATE_DEPRECATEDLIST= YES
-ENABLED_SECTIONS =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if ... \endif and \cond
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
SHOW_USED_FILES = YES
-SHOW_DIRECTORIES = NO
-FILE_VERSION_FILTER =
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
WARN_FORMAT = "$file:$line: $text"
-WARN_LOGFILE =
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE = doxygen_warnings.txt
+
#---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
#---------------------------------------------------------------------------
-INPUT = ../include/gpac \
- ../include/gpac/internal
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../include/gpac/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
@@ -109,150 +790,1527 @@ FILE_PATTERNS = *.c \
*.m \
*.mm \
*.dox
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
RECURSIVE = NO
-EXCLUDE =
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
EXCLUDE_SYMLINKS = NO
-EXCLUDE_PATTERNS =
-EXAMPLE_PATH =
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
EXAMPLE_RECURSIVE = NO
-IMAGE_PATH =
-INPUT_FILTER =
-FILTER_PATTERNS =
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+#
+#
+# where is the value of the INPUT_FILTER tag, and is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
#---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
VERBATIM_HEADERS = NO
+
#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
COLS_IN_ALPHA_INDEX = 5
-IGNORE_PREFIX =
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
#---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
GENERATE_HTML = YES
-HTML_OUTPUT = html
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html-libgpac
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
HTML_FILE_EXTENSION = .html
-HTML_HEADER =
-HTML_FOOTER =
-HTML_STYLESHEET =
-HTML_ALIGN_MEMBERS = YES
-GENERATE_HTMLHELP = NO
-CHM_FILE =
-HHC_LOCATION =
-GENERATE_CHI = NO
-BINARY_TOC = NO
-TOC_EXPAND = NO
-DISABLE_INDEX = NO
-ENUM_VALUES_PER_LINE = 4
-GENERATE_TREEVIEW = NO
-TREEVIEW_WIDTH = 250
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-GENERATE_LATEX = NO
-LATEX_OUTPUT = latex
-LATEX_CMD_NAME = latex
-MAKEINDEX_CMD_NAME = makeindex
-COMPACT_LATEX = NO
-PAPER_TYPE = a4wide
-EXTRA_PACKAGES =
-LATEX_HEADER =
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use + S
+# (what the is depends on the OS and browser, but it is typically
+# , /