From c570868e0e6e3b2bd2026dc67658137c53ce6e32 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 5 Jun 2018 04:34:40 -0400 Subject: [PATCH 001/186] Update wipe-tests example to latest API The `src/effects/Openshot Wipe Tests.py` was no longer usable since the code was way out of date with respect to the current libopenshot APIs. This updates the code to execute properly. (Also: Output the frame numbers on a single line, instead of one per line, for readability.) --- src/examples/OpenShot Wipe Tests.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/examples/OpenShot Wipe Tests.py b/src/examples/OpenShot Wipe Tests.py index 4fb86c85..91b00917 100644 --- a/src/examples/OpenShot Wipe Tests.py +++ b/src/examples/OpenShot Wipe Tests.py @@ -1,16 +1,17 @@ import openshot -# Create a empty clip -t = openshot.Timeline(720, 480, openshot.Fraction(24,1), 44100, 2) +# Create an empty timeline +t = openshot.Timeline(720, 480, openshot.Fraction(24,1), 44100, 2, openshot.LAYOUT_STEREO) +t.Open() # lower layer -lower = openshot.ImageReader("/home/jonathan/apps/libopenshot/src/examples/back.png") +lower = openshot.QtImageReader("back.png") c1 = openshot.Clip(lower) c1.Layer(1) t.AddClip(c1) # higher layer -higher = openshot.ImageReader("/home/jonathan/apps/libopenshot/src/examples/front3.png") +higher = openshot.QtImageReader("front3.png") c2 = openshot.Clip(higher) c2.Layer(2) #c2.alpha = openshot.Keyframe(0.5) @@ -18,25 +19,26 @@ t.AddClip(c2) # Wipe / Transition brightness = openshot.Keyframe() -brightness.AddPoint(1, 100.0, openshot.BEZIER) -brightness.AddPoint(24, -100.0, openshot.BEZIER) +brightness.AddPoint(1, 1.0, openshot.BEZIER) +brightness.AddPoint(24, -1.0, openshot.BEZIER) contrast = openshot.Keyframe() contrast.AddPoint(1, 20.0, openshot.BEZIER) contrast.AddPoint(24, 20.0, openshot.BEZIER) -e = openshot.Wipe("/home/jonathan/apps/libopenshot/src/examples/mask.png", brightness, contrast) +reader = openshot.QtImageReader("mask.png") +e = openshot.Mask(reader, brightness, contrast) e.Layer(2) e.End(60) t.AddEffect(e) -e1 = openshot.Wipe("/home/jonathan/apps/libopenshot/src/examples/mask2.png", brightness, contrast) +reader1 = openshot.QtImageReader("mask2.png") +e1 = openshot.Mask(reader1, brightness, contrast) e1.Layer(2) e1.Order(2) e1.End(60) #t.AddEffect(e1) - for n in range(1,25): - print n + print(n, end=" ", flush=1) t.GetFrame(n).Save("%s.png" % n, 1.0) From 95abdcf66b7c471d40732d791c967f76b5f5f9c5 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 11 Aug 2018 18:22:18 -0500 Subject: [PATCH 002/186] FFmpeg4 support. Compile warnings fixes. Credit goes to many people, including ferdnyc, peterM, and other awesome folks! --- cmake/Modules/FindFFmpeg.cmake | 70 ++++++++++++++++++++++++------- include/CrashHandler.h | 8 ++-- include/FFmpegUtilities.h | 76 +++++++++++++++++++++++++++++++++- include/FFmpegWriter.h | 4 +- include/Frame.h | 2 +- include/FrameMapper.h | 2 +- include/ZmqLogger.h | 12 +++++- src/Clip.cpp | 11 ++--- src/EffectInfo.cpp | 1 + src/FFmpegReader.cpp | 30 +++++++------- src/FFmpegWriter.cpp | 51 ++++++++++++++++------- src/FrameMapper.cpp | 14 +++---- src/Timeline.cpp | 22 +++++----- tests/ReaderBase_Tests.cpp | 4 +- 14 files changed, 228 insertions(+), 79 deletions(-) diff --git a/cmake/Modules/FindFFmpeg.cmake b/cmake/Modules/FindFFmpeg.cmake index 4af6cc93..45a27a9e 100644 --- a/cmake/Modules/FindFFmpeg.cmake +++ b/cmake/Modules/FindFFmpeg.cmake @@ -91,6 +91,20 @@ FIND_LIBRARY( AVRESAMPLE_LIBRARY avresample avresample-2 avresample-3 $ENV{FFMPEGDIR}/lib/ffmpeg/ $ENV{FFMPEGDIR}/bin/ ) +#FindSwresample +FIND_PATH( SWRESAMPLE_INCLUDE_DIR libswresample/swresample.h + PATHS /usr/include/ + /usr/include/ffmpeg/ + $ENV{FFMPEGDIR}/include/ + $ENV{FFMPEGDIR}/include/ffmpeg/ ) + +FIND_LIBRARY( SWRESAMPLE_LIBRARY swresample + PATHS /usr/lib/ + /usr/lib/ffmpeg/ + $ENV{FFMPEGDIR}/lib/ + $ENV{FFMPEGDIR}/lib/ffmpeg/ + $ENV{FFMPEGDIR}/bin/ ) + SET( FFMPEG_FOUND FALSE ) IF ( AVFORMAT_INCLUDE_DIR AND AVFORMAT_LIBRARY ) @@ -117,27 +131,51 @@ IF ( AVRESAMPLE_INCLUDE_DIR AND AVRESAMPLE_LIBRARY ) SET ( AVRESAMPLE_FOUND TRUE ) ENDIF ( AVRESAMPLE_INCLUDE_DIR AND AVRESAMPLE_LIBRARY ) -IF ( AVFORMAT_INCLUDE_DIR OR AVCODEC_INCLUDE_DIR OR AVUTIL_INCLUDE_DIR OR AVDEVICE_FOUND OR SWSCALE_FOUND OR AVRESAMPLE_FOUND ) +IF ( SWRESAMPLE_INCLUDE_DIR AND SWRESAMPLE_LIBRARY ) + SET ( SWRESAMPLE_FOUND TRUE ) +ENDIF ( SWRESAMPLE_INCLUDE_DIR AND SWRESAMPLE_LIBRARY ) + +IF ( AVFORMAT_INCLUDE_DIR OR AVCODEC_INCLUDE_DIR OR AVUTIL_INCLUDE_DIR OR AVDEVICE_FOUND OR SWSCALE_FOUND OR AVRESAMPLE_FOUND OR SWRESAMPLE_FOUND ) SET ( FFMPEG_FOUND TRUE ) - SET ( FFMPEG_INCLUDE_DIR - ${AVFORMAT_INCLUDE_DIR} - ${AVCODEC_INCLUDE_DIR} - ${AVUTIL_INCLUDE_DIR} - ${AVDEVICE_INCLUDE_DIR} - ${SWSCALE_INCLUDE_DIR} - ${AVRESAMPLE_INCLUDE_DIR} ) + IF ( SWRESAMPLE_FOUND ) + SET ( FFMPEG_INCLUDE_DIR + ${AVFORMAT_INCLUDE_DIR} + ${AVCODEC_INCLUDE_DIR} + ${AVUTIL_INCLUDE_DIR} + ${AVDEVICE_INCLUDE_DIR} + ${SWSCALE_INCLUDE_DIR} + ${AVRESAMPLE_INCLUDE_DIR} + ${SWRESAMPLE_INCLUDE_DIR} ) - SET ( FFMPEG_LIBRARIES - ${AVFORMAT_LIBRARY} - ${AVCODEC_LIBRARY} - ${AVUTIL_LIBRARY} - ${AVDEVICE_LIBRARY} - ${SWSCALE_LIBRARY} - ${AVRESAMPLE_LIBRARY} ) + SET ( FFMPEG_LIBRARIES + ${AVFORMAT_LIBRARY} + ${AVCODEC_LIBRARY} + ${AVUTIL_LIBRARY} + ${AVDEVICE_LIBRARY} + ${SWSCALE_LIBRARY} + ${AVRESAMPLE_LIBRARY} + ${SWRESAMPLE_LIBRARY} ) + ELSE () + SET ( FFMPEG_INCLUDE_DIR + ${AVFORMAT_INCLUDE_DIR} + ${AVCODEC_INCLUDE_DIR} + ${AVUTIL_INCLUDE_DIR} + ${AVDEVICE_INCLUDE_DIR} + ${SWSCALE_INCLUDE_DIR} + ${AVRESAMPLE_INCLUDE_DIR} ) + + SET ( FFMPEG_LIBRARIES + ${AVFORMAT_LIBRARY} + ${AVCODEC_LIBRARY} + ${AVUTIL_LIBRARY} + ${AVDEVICE_LIBRARY} + ${SWSCALE_LIBRARY} + ${AVRESAMPLE_LIBRARY} ) + ENDIF () -ENDIF ( AVFORMAT_INCLUDE_DIR OR AVCODEC_INCLUDE_DIR OR AVUTIL_INCLUDE_DIR OR AVDEVICE_FOUND OR SWSCALE_FOUND OR AVRESAMPLE_FOUND ) +ENDIF ( AVFORMAT_INCLUDE_DIR OR AVCODEC_INCLUDE_DIR OR AVUTIL_INCLUDE_DIR OR AVDEVICE_FOUND OR SWSCALE_FOUND OR AVRESAMPLE_FOUND OR SWRESAMPLE_FOUND ) MARK_AS_ADVANCED( FFMPEG_LIBRARY_DIR diff --git a/include/CrashHandler.h b/include/CrashHandler.h index e3a4bbe5..12c79a86 100644 --- a/include/CrashHandler.h +++ b/include/CrashHandler.h @@ -53,13 +53,15 @@ namespace openshot { class CrashHandler { private: /// Default constructor - CrashHandler(){}; // Don't allow user to create an instance of this singleton + CrashHandler(){return;}; // Don't allow user to create an instance of this singleton /// Default copy method - CrashHandler(CrashHandler const&){}; // Don't allow the user to copy this instance + //CrashHandler(CrashHandler const&){}; // Don't allow the user to copy this instance + CrashHandler(CrashHandler const&) = delete; // Don't allow the user to copy this instance /// Default assignment operator - CrashHandler & operator=(CrashHandler const&){}; // Don't allow the user to assign this instance + //CrashHandler & operator=(CrashHandler const&){}; // Don't allow the user to assign this instance + CrashHandler & operator=(CrashHandler const&) = delete; // Don't allow the user to assign this instance /// Private variable to keep track of singleton instance static CrashHandler *m_pInstance; diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 578c6586..346da541 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -43,7 +43,15 @@ #include #include #include + // Change this to the first version swrescale works + #if (LIBAVFORMAT_VERSION_MAJOR >= 57) + #define USE_SW + #endif + #ifdef USE_SW + #include + #else #include + #endif #include #include #include @@ -106,7 +114,65 @@ #define PIX_FMT_YUV420P AV_PIX_FMT_YUV420P #endif - #if IS_FFMPEG_3_2 + #ifdef USE_SW + #define SWR_CONVERT(ctx, out, linesize, out_count, in, linesize2, in_count) \ + swr_convert(ctx, out, out_count, (const uint8_t **)in, in_count) + #define SWR_ALLOC() swr_alloc() + #define SWR_CLOSE(ctx) {} + #define SWR_FREE(ctx) swr_free(ctx) + #define SWR_INIT(ctx) swr_init(ctx) + #define SWRCONTEXT SwrContext + #else + #define SWR_CONVERT(ctx, out, linesize, out_count, in, linesize2, in_count) \ + avresample_convert(ctx, out, linesize, out_count, (uint8_t **)in, linesize2, in_count) + #define SWR_ALLOC() avresample_alloc_context() + #define SWR_CLOSE(ctx) avresample_close(ctx) + #define SWR_FREE(ctx) avresample_free(ctx) + #define SWR_INIT(ctx) avresample_open(ctx) + #define SWRCONTEXT AVAudioResampleContext + #endif + + + #if (LIBAVFORMAT_VERSION_MAJOR >= 58) + #define AV_REGISTER_ALL + #define AVCODEC_REGISTER_ALL + #define AV_FILENAME url + #define MY_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE + #define AV_ALLOCATE_FRAME() av_frame_alloc() + #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) av_image_alloc(av_frame->data, av_frame->linesize, width, height, pix_fmt, 1) + #define AV_RESET_FRAME(av_frame) av_frame_unref(av_frame) + #define AV_FREE_FRAME(av_frame) av_frame_free(av_frame) + #define AV_FREE_PACKET(av_packet) av_packet_unref(av_packet) + #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context) + #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type + #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id + auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \ + AVCodecContext *context = avcodec_alloc_context3(av_codec); \ + avcodec_parameters_to_context(context, av_stream->codecpar); \ + return context; \ + }; + #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec; + #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in) + #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar + #define AV_GET_CODEC_PIXEL_FORMAT(av_stream, av_context) (AVPixelFormat) av_stream->codecpar->format + #define AV_GET_SAMPLE_FORMAT(av_stream, av_context) av_stream->codecpar->format + #define AV_GET_IMAGE_SIZE(pix_fmt, width, height) av_image_get_buffer_size(pix_fmt, width, height, 1) + #define AV_COPY_PICTURE_DATA(av_frame, buffer, pix_fmt, width, height) av_image_fill_arrays(av_frame->data, av_frame->linesize, buffer, pix_fmt, width, height, 1) + #define AV_OUTPUT_CONTEXT(output_context, path) avformat_alloc_output_context2( output_context, NULL, NULL, path) + #define AV_OPTION_FIND(priv_data, name) av_opt_find(priv_data, name, NULL, 0, 0) + #define AV_OPTION_SET( av_stream, priv_data, name, value, avcodec) av_opt_set(priv_data, name, value, 0); avcodec_parameters_from_context(av_stream->codecpar, avcodec); + #define AV_FORMAT_NEW_STREAM(oc, st_codec, av_codec, av_st) av_st = avformat_new_stream(oc, NULL);\ + if (!av_st) \ + throw OutOfMemory("Could not allocate memory for the video stream.", path); \ + c = avcodec_alloc_context3(av_codec); \ + st_codec = c; \ + av_st->codecpar->codec_id = av_codec->id; + #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) avcodec_parameters_from_context(av_stream->codecpar, av_codec); + #elif IS_FFMPEG_3_2 + #define AV_REGISTER_ALL av_register_all(); + #define AVCODEC_REGISTER_ALL avcodec_register_all(); + #define AV_FILENAME filename + #define MY_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE #define AV_ALLOCATE_FRAME() av_frame_alloc() #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) av_image_alloc(av_frame->data, av_frame->linesize, width, height, pix_fmt, 1) #define AV_RESET_FRAME(av_frame) av_frame_unref(av_frame) @@ -138,6 +204,10 @@ av_st->codecpar->codec_id = av_codec->id; #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) avcodec_parameters_from_context(av_stream->codecpar, av_codec); #elif LIBAVFORMAT_VERSION_MAJOR >= 55 + #define AV_REGISTER_ALL av_register_all(); + #define AVCODEC_REGISTER_ALL avcodec_register_all(); + #define AV_FILENAME filename + #define MY_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE #define AV_ALLOCATE_FRAME() av_frame_alloc() #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) avpicture_alloc((AVPicture *) av_frame, pix_fmt, width, height) #define AV_RESET_FRAME(av_frame) av_frame_unref(av_frame) @@ -164,6 +234,10 @@ c = av_st->codec; #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) #else + #define AV_REGISTER_ALL av_register_all(); + #define AVCODEC_REGISTER_ALL avcodec_register_all(); + #define AV_FILENAME filename + #define MY_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE #define AV_ALLOCATE_FRAME() avcodec_alloc_frame() #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) avpicture_alloc((AVPicture *) av_frame, pix_fmt, width, height) #define AV_RESET_FRAME(av_frame) avcodec_get_frame_defaults(av_frame) diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 8343002e..7eefacb7 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -174,8 +174,8 @@ namespace openshot int initial_audio_input_frame_size; int audio_input_position; int audio_encoder_buffer_size; - AVAudioResampleContext *avr; - AVAudioResampleContext *avr_planar; + SWRCONTEXT *avr; + SWRCONTEXT *avr_planar; /* Resample options */ int original_sample_rate; diff --git a/include/Frame.h b/include/Frame.h index a7ad509f..eba7f8bb 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -62,7 +62,7 @@ #include "AudioResampler.h" #include "Fraction.h" - +#pragma SWIG nowarn=362 using namespace std; namespace openshot diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 06511666..216fe73f 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -146,7 +146,7 @@ namespace openshot ReaderBase *reader; // The source video reader CacheMemory final_cache; // Cache of actual Frame objects bool is_dirty; // When this is true, the next call to GetFrame will re-init the mapping - AVAudioResampleContext *avr; // Audio resampling context object + SWRCONTEXT *avr; // Audio resampling context object // Internal methods used by init void AddField(int64_t frame); diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index c134f2cf..e825ed0e 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -72,11 +72,19 @@ namespace openshot { /// Default constructor ZmqLogger(){}; // Don't allow user to create an instance of this singleton +#if __GNUC__ >=7 /// Default copy method - ZmqLogger(ZmqLogger const&){}; // Don't allow the user to copy this instance + ZmqLogger(ZmqLogger const&) = delete; // Don't allow the user to assign this instance /// Default assignment operator - ZmqLogger & operator=(ZmqLogger const&){}; // Don't allow the user to assign this instance + ZmqLogger & operator=(ZmqLogger const&) = delete; // Don't allow the user to assign this instance +#else + /// Default copy method + ZmqLogger(ZmqLogger const&) {}; // Don't allow the user to assign this instance + + /// Default assignment operator + ZmqLogger & operator=(ZmqLogger const&); // Don't allow the user to assign this instance +#endif /// Private variable to keep track of singleton instance static ZmqLogger * m_pInstance; diff --git a/src/Clip.cpp b/src/Clip.cpp index 913fd71f..63e77412 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -925,13 +925,14 @@ void Clip::SetJsonValue(Json::Value root) { if (!existing_effect["type"].isNull()) { // Create instance of effect - e = EffectInfo().CreateEffect(existing_effect["type"].asString()); + if (e = EffectInfo().CreateEffect(existing_effect["type"].asString())) { - // Load Json into Effect - e->SetJsonValue(existing_effect); + // Load Json into Effect + e->SetJsonValue(existing_effect); - // Add Effect to Timeline - AddEffect(e); + // Add Effect to Timeline + AddEffect(e); + } } } } diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index 23bc9d02..f9e4c409 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -82,6 +82,7 @@ EffectBase* EffectInfo::CreateEffect(string effect_type) { else if (effect_type == "Wave") return new Wave(); + return NULL; } // Generate Json::JsonValue for this object diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 0b100050..ceccbe23 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -40,8 +40,8 @@ FFmpegReader::FFmpegReader(string path) current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), packet(NULL) { // Initialize FFMpeg, and register all formats and codecs - av_register_all(); - avcodec_register_all(); + AV_REGISTER_ALL + AVCODEC_REGISTER_ALL // Init cache working_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * info.fps.ToDouble() * 2, info.width, info.height, info.sample_rate, info.channels); @@ -61,8 +61,8 @@ FFmpegReader::FFmpegReader(string path, bool inspect_reader) current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), packet(NULL) { // Initialize FFMpeg, and register all formats and codecs - av_register_all(); - avcodec_register_all(); + AV_REGISTER_ALL + AVCODEC_REGISTER_ALL // Init cache working_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * info.fps.ToDouble() * 2, info.width, info.height, info.sample_rate, info.channels); @@ -974,7 +974,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr int data_size = 0; // re-initialize buffer size (it gets changed in the avcodec_decode_audio2 method call) - int buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE; + int buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE; #pragma omp critical (ProcessAudioPacket) { #if IS_FFMPEG_3_2 @@ -1079,7 +1079,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // Allocate audio buffer - int16_t *audio_buf = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; + int16_t *audio_buf = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE]; ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (ReSample)", "packet_samples", packet_samples, "info.channels", info.channels, "info.sample_rate", info.sample_rate, "aCodecCtx->sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx), "AV_SAMPLE_FMT_S16", AV_SAMPLE_FMT_S16, "", -1); @@ -1089,11 +1089,11 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr audio_converted->nb_samples = audio_frame->nb_samples; av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, audio_frame->nb_samples, AV_SAMPLE_FMT_S16, 0); - AVAudioResampleContext *avr = NULL; + SWRCONTEXT *avr = NULL; int nb_samples = 0; // setup resample context - avr = avresample_alloc_context(); + avr = SWR_ALLOC(); av_opt_set_int(avr, "in_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); av_opt_set_int(avr, "out_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); av_opt_set_int(avr, "in_sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx), 0); @@ -1102,10 +1102,10 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr, "in_channels", info.channels, 0); av_opt_set_int(avr, "out_channels", info.channels, 0); - int r = avresample_open(avr); + int r = SWR_INIT(avr); // Convert audio samples - nb_samples = avresample_convert(avr, // audio resample context + nb_samples = SWR_CONVERT(avr, // audio resample context audio_converted->data, // output data pointers audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) audio_converted->nb_samples, // maximum number of samples that the output buffer can hold @@ -1117,8 +1117,8 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr memcpy(audio_buf, audio_converted->data[0], audio_converted->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * info.channels); // Deallocate resample buffer - avresample_close(avr); - avresample_free(&avr); + SWR_CLOSE(avr); + SWR_FREE(&avr); avr = NULL; // Free AVFrames @@ -1344,7 +1344,7 @@ void FFmpegReader::Seek(int64_t requested_frame) { seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount); if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { - fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->filename); + fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->AV_FILENAME); } else { // VIDEO SEEK @@ -1358,7 +1358,7 @@ void FFmpegReader::Seek(int64_t requested_frame) { seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount); if (av_seek_frame(pFormatCtx, info.audio_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { - fprintf(stderr, "%s: error while seeking audio stream\n", pFormatCtx->filename); + fprintf(stderr, "%s: error while seeking audio stream\n", pFormatCtx->AV_FILENAME); } else { // AUDIO SEEK @@ -1853,6 +1853,8 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram void FFmpegReader::CheckFPS() { check_fps = true; + AV_ALLOCATE_IMAGE(pFrame, AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx), info.width, info.height); + int first_second_counter = 0; int second_second_counter = 0; int third_second_counter = 0; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index ede07a43..ed4fc3fb 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -46,7 +46,7 @@ FFmpegWriter::FFmpegWriter(string path) : info.has_video = false; // Initialize FFMpeg, and register all formats and codecs - av_register_all(); + AV_REGISTER_ALL // auto detect format auto_detect_format(); @@ -299,7 +299,7 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) /// Determine if codec name is valid bool FFmpegWriter::IsValidCodec(string codec_name) { // Initialize FFMpeg, and register all formats and codecs - av_register_all(); + AV_REGISTER_ALL // Find the codec (if any) if (avcodec_find_encoder_by_name(codec_name.c_str()) == NULL) @@ -342,7 +342,7 @@ void FFmpegWriter::WriteHeader() } // Force the output filename (which doesn't always happen for some reason) - snprintf(oc->filename, sizeof(oc->filename), "%s", path.c_str()); + snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", path.c_str()); // Write the stream header, if any // TODO: add avoptions / parameters instead of NULL @@ -559,8 +559,10 @@ void FFmpegWriter::flush_encoders() { if (info.has_audio && audio_codec && AV_GET_CODEC_TYPE(audio_st) == AVMEDIA_TYPE_AUDIO && AV_GET_CODEC_ATTRIBUTES(audio_st, audio_codec)->frame_size <= 1) return; +#if (LIBAVFORMAT_VERSION_MAJOR < 58) if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) return; +#endif int error_code = 0; int stop_encoding = 1; @@ -751,14 +753,14 @@ void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) // Deallocate resample buffer if (avr) { - avresample_close(avr); - avresample_free(&avr); + SWR_CLOSE(avr); + SWR_FREE(&avr); avr = NULL; } if (avr_planar) { - avresample_close(avr_planar); - avresample_free(&avr_planar); + SWR_CLOSE(avr_planar); + SWR_FREE(&avr_planar); avr_planar = NULL; } } @@ -898,7 +900,11 @@ AVStream* FFmpegWriter::add_audio_stream() // some formats want stream headers to be separate if (oc->oformat->flags & AVFMT_GLOBALHEADER) +#if (LIBAVCODEC_VERSION_MAJOR >= 57) + c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else c->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif AV_COPY_PARAMS_FROM_CONTEXT(st, c); ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_audio_stream", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->channels", c->channels, "c->sample_fmt", c->sample_fmt, "c->channel_layout", c->channel_layout, "c->sample_rate", c->sample_rate); @@ -970,7 +976,11 @@ AVStream* FFmpegWriter::add_video_stream() c->mb_decision = 2; // some formats want stream headers to be separate if (oc->oformat->flags & AVFMT_GLOBALHEADER) +#if (LIBAVCODEC_VERSION_MAJOR >= 57) + c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else c->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif // Find all supported pixel formats for this codec const PixelFormat* supported_pixel_formats = codec->pix_fmts; @@ -987,10 +997,12 @@ AVStream* FFmpegWriter::add_video_stream() // Raw video should use RGB24 c->pix_fmt = PIX_FMT_RGB24; +#if (LIBAVFORMAT_VERSION_MAJOR < 58) if (strcmp(fmt->name, "gif") != 0) // If not GIF format, skip the encoding process // Set raw picture flag (so we don't encode this video) oc->oformat->flags |= AVFMT_RAWPICTURE; +#endif } else { // Set the default codec c->pix_fmt = PIX_FMT_YUV420P; @@ -998,7 +1010,11 @@ AVStream* FFmpegWriter::add_video_stream() } AV_COPY_PARAMS_FROM_CONTEXT(st, c); +#if (LIBAVFORMAT_VERSION_MAJOR < 58) ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_video_stream (" + (string)fmt->name + " : " + (string)av_get_pix_fmt_name(c->pix_fmt) + ")", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->pix_fmt", c->pix_fmt, "oc->oformat->flags", oc->oformat->flags, "AVFMT_RAWPICTURE", AVFMT_RAWPICTURE, "", -1); +#else + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::add_video_stream (" + (string)fmt->name + " : " + (string)av_get_pix_fmt_name(c->pix_fmt) + ")", "c->codec_id", c->codec_id, "c->bit_rate", c->bit_rate, "c->pix_fmt", c->pix_fmt, "oc->oformat->flags", oc->oformat->flags, "", -1, "", -1); +#endif return st; } @@ -1073,7 +1089,7 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_audio", "audio_codec->thread_count", audio_codec->thread_count, "audio_input_frame_size", audio_input_frame_size, "buffer_size", AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_audio", "audio_codec->thread_count", audio_codec->thread_count, "audio_input_frame_size", audio_input_frame_size, "buffer_size", AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE, "", -1, "", -1, "", -1); } @@ -1239,7 +1255,7 @@ void FFmpegWriter::write_audio_packets(bool final) // setup resample context if (!avr) { - avr = avresample_alloc_context(); + avr = SWR_ALLOC(); av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0); av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0); av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); @@ -1248,12 +1264,12 @@ void FFmpegWriter::write_audio_packets(bool final) av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr, "in_channels", channels_in_frame, 0); av_opt_set_int(avr, "out_channels", info.channels, 0); - avresample_open(avr); + SWR_INIT(avr); } int nb_samples = 0; // Convert audio samples - nb_samples = avresample_convert(avr, // audio resample context + nb_samples = SWR_CONVERT(avr, // audio resample context audio_converted->data, // output data pointers audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) audio_converted->nb_samples, // maximum number of samples that the output buffer can hold @@ -1314,7 +1330,7 @@ void FFmpegWriter::write_audio_packets(bool final) // setup resample context if (!avr_planar) { - avr_planar = avresample_alloc_context(); + avr_planar = SWR_ALLOC(); av_opt_set_int(avr_planar, "in_channel_layout", info.channel_layout, 0); av_opt_set_int(avr_planar, "out_channel_layout", info.channel_layout, 0); av_opt_set_int(avr_planar, "in_sample_fmt", output_sample_fmt, 0); @@ -1323,7 +1339,7 @@ void FFmpegWriter::write_audio_packets(bool final) av_opt_set_int(avr_planar, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr_planar, "in_channels", info.channels, 0); av_opt_set_int(avr_planar, "out_channels", info.channels, 0); - avresample_open(avr_planar); + SWR_INIT(avr_planar); } // Create input frame (and allocate arrays) @@ -1346,7 +1362,7 @@ void FFmpegWriter::write_audio_packets(bool final) av_samples_alloc(frame_final->data, frame_final->linesize, info.channels, frame_final->nb_samples, audio_codec->sample_fmt, 0); // Convert audio samples - int nb_samples = avresample_convert(avr_planar, // audio resample context + int nb_samples = SWR_CONVERT(avr_planar, // audio resample context frame_final->data, // output data pointers frame_final->linesize[0], // output plane size, in bytes. (0 if unknown) frame_final->nb_samples, // maximum number of samples that the output buffer can hold @@ -1577,6 +1593,9 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) // write video frame bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* frame_final) { +#if (LIBAVFORMAT_VERSION_MAJOR >= 58) + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags, "", -1, "", -1, "", -1, "", -1); +#else ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE, "", -1, "", -1, "", -1, "", -1); if (oc->oformat->flags & AVFMT_RAWPICTURE) { @@ -1604,7 +1623,9 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Deallocate packet AV_FREE_PACKET(&pkt); - } else { + } else +#endif + { AVPacket pkt; av_init_packet(&pkt); diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index f49cbc4d..c4c68f5a 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -650,8 +650,8 @@ void FrameMapper::Close() // Deallocate resample buffer if (avr) { - avresample_close(avr); - avresample_free(&avr); + SWR_CLOSE(avr); + SWR_FREE(&avr); avr = NULL; } } @@ -741,8 +741,8 @@ void FrameMapper::ChangeMapping(Fraction target_fps, PulldownType target_pulldow // Deallocate resample buffer if (avr) { - avresample_close(avr); - avresample_free(&avr); + SWR_CLOSE(avr); + SWR_FREE(&avr); avr = NULL; } @@ -817,7 +817,7 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig // setup resample context if (!avr) { - avr = avresample_alloc_context(); + avr = SWR_ALLOC(); av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0); av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0); av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); @@ -826,11 +826,11 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); av_opt_set_int(avr, "in_channels", channels_in_frame, 0); av_opt_set_int(avr, "out_channels", info.channels, 0); - avresample_open(avr); + SWR_INIT(avr); } // Convert audio samples - nb_samples = avresample_convert(avr, // audio resample context + nb_samples = SWR_CONVERT(avr, // audio resample context audio_converted->data, // output data pointers audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) audio_converted->nb_samples, // maximum number of samples that the output buffer can hold diff --git a/src/Timeline.cpp b/src/Timeline.cpp index d042aeeb..35b91283 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -1000,13 +1000,14 @@ void Timeline::SetJsonValue(Json::Value root) { if (!existing_effect["type"].isNull()) { // Create instance of effect - e = EffectInfo().CreateEffect(existing_effect["type"].asString()); + if (e = EffectInfo().CreateEffect(existing_effect["type"].asString())) { - // Load Json into Effect - e->SetJsonValue(existing_effect); + // Load Json into Effect + e->SetJsonValue(existing_effect); - // Add Effect to Timeline - AddEffect(e); + // Add Effect to Timeline + AddEffect(e); + } } } } @@ -1270,13 +1271,14 @@ void Timeline::apply_json_to_effects(Json::Value change, EffectBase* existing_ef EffectBase *e = NULL; // Init the matching effect object - e = EffectInfo().CreateEffect(effect_type); + if (e = EffectInfo().CreateEffect(effect_type)) { - // Load Json into Effect - e->SetJsonValue(change["value"]); + // Load Json into Effect + e->SetJsonValue(change["value"]); - // Add Effect to Timeline - AddEffect(e); + // Add Effect to Timeline + AddEffect(e); + } } else if (change_type == "update") { diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp index 9d435304..70ca90d5 100644 --- a/tests/ReaderBase_Tests.cpp +++ b/tests/ReaderBase_Tests.cpp @@ -44,9 +44,9 @@ TEST(ReaderBase_Derived_Class) std::shared_ptr GetFrame(int64_t number) { std::shared_ptr f(new Frame()); return f; } void Close() { }; void Open() { }; - string Json() { }; + string Json() { return NULL; }; void SetJson(string value) { }; - Json::Value JsonValue() { }; + Json::Value JsonValue() { return (int) NULL; }; void SetJsonValue(Json::Value root) { }; bool IsOpen() { return true; }; string Name() { return "TestReader"; }; From 8216795c33a4297cb4728a0a53c88a6fc06c3ac2 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 12 Aug 2018 00:15:23 -0500 Subject: [PATCH 003/186] Adding environment checking to enable/disable omp taskwait after each video/audio frame is processed. This is experimental for some users with crashes. --- include/FFmpegReader.h | 1 + include/OpenMPUtilities.h | 22 ++++++++++++++++++++-- src/FFmpegReader.cpp | 18 ++++++++++++++---- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index 6072756a..e2c4863a 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -105,6 +105,7 @@ namespace openshot bool check_interlace; bool check_fps; bool has_missing_frames; + bool use_omp_threads; CacheMemory working_cache; CacheMemory missing_frames; diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index 8a95a950..c0f5597b 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -29,8 +29,26 @@ #define OPENSHOT_OPENMP_UTILITIES_H #include +#include +#include - // Calculate the # of OpenMP Threads to allow - #define OPEN_MP_NUM_PROCESSORS omp_get_num_procs() +// Calculate the # of OpenMP Threads to allow +#define OPEN_MP_NUM_PROCESSORS omp_get_num_procs() + +using namespace std; + +namespace openshot { + + // Check if OS2_OMP_THREADS environment variable is present, and return + // if multiple threads should be used with OMP + static bool IsOMPEnabled() { + char* OS2_OMP_THREADS = getenv("OS2_OMP_THREADS"); + if (OS2_OMP_THREADS != NULL && strcmp(OS2_OMP_THREADS, "0") == 0) + return false; + else + return true; + } + +} #endif diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index ceccbe23..736e95ee 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -37,7 +37,8 @@ FFmpegReader::FFmpegReader(string path) audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0), prev_samples(0), prev_pts(0), pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0), - current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), packet(NULL) { + current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), + packet(NULL), use_omp_threads(true) { // Initialize FFMpeg, and register all formats and codecs AV_REGISTER_ALL @@ -58,7 +59,8 @@ FFmpegReader::FFmpegReader(string path, bool inspect_reader) audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0), prev_samples(0), prev_pts(0), pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0), - current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), packet(NULL) { + current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), + packet(NULL), use_omp_threads(true) { // Initialize FFMpeg, and register all formats and codecs AV_REGISTER_ALL @@ -227,6 +229,9 @@ void FFmpegReader::Open() missing_frames.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); + // Initialize OMP threading support + use_omp_threads = openshot::IsOMPEnabled(); + // Mark as "open" is_open = true; } @@ -633,8 +638,13 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) ProcessAudioPacket(requested_frame, location.frame, location.sample_start); } + if (!use_omp_threads) { + // Wait on each OMP task to complete before moving on to the next one. This slows + // down processing considerably, but might be more stable on some systems. + #pragma omp taskwait + } + // Check if working frames are 'finished' - bool is_cache_found = false; if (!is_seeking) { // Check for any missing frames CheckMissingFrame(requested_frame); @@ -644,7 +654,7 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) } // Check if requested 'final' frame is available - is_cache_found = (final_cache.GetFrame(requested_frame) != NULL); + bool is_cache_found = (final_cache.GetFrame(requested_frame) != NULL); // Increment frames processed packets_processed++; From 6b5e2d427bc7e026b0d0037986c25efaa4de0ae8 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 12 Aug 2018 00:36:03 -0500 Subject: [PATCH 004/186] Moving `omp taskwait` to after the ProcessVideoPacket() method, since that is the only place it is useful. --- src/FFmpegReader.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 736e95ee..adf957f1 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -607,6 +607,12 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) // Process Video Packet ProcessVideoPacket(requested_frame); + + if (!use_omp_threads) { + // Wait on each OMP task to complete before moving on to the next one. This slows + // down processing considerably, but might be more stable on some systems. + #pragma omp taskwait + } } } @@ -638,12 +644,6 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) ProcessAudioPacket(requested_frame, location.frame, location.sample_start); } - if (!use_omp_threads) { - // Wait on each OMP task to complete before moving on to the next one. This slows - // down processing considerably, but might be more stable on some systems. - #pragma omp taskwait - } - // Check if working frames are 'finished' if (!is_seeking) { // Check for any missing frames From 340803e31eb3385d32a0b8de5e24f227c2b07a1b Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 31 Aug 2018 21:36:23 -0700 Subject: [PATCH 005/186] Initial rudimentary support for hardware acceleration (encode and decode) Only Linux vaapi for now --- include/FFmpegReader.h | 3 + include/FFmpegUtilities.h | 3 + src/FFmpegReader.cpp | 132 ++++++++++++++++++++++++++++- src/FFmpegWriter.cpp | 171 +++++++++++++++++++++++++++++++++++++- 4 files changed, 301 insertions(+), 8 deletions(-) diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index e2c4863a..fcc995ae 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -97,6 +97,9 @@ namespace openshot AVFormatContext *pFormatCtx; int i, videoStream, audioStream; AVCodecContext *pCodecCtx, *aCodecCtx; + #if (LIBAVFORMAT_VERSION_MAJOR >= 57) + AVBufferRef *hw_device_ctx = NULL; //PM + #endif AVStream *pStream, *aStream; AVPacket *packet; AVFrame *pFrame; diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 346da541..0cc08f52 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -42,6 +42,9 @@ extern "C" { #include #include + #if (LIBAVFORMAT_VERSION_MAJOR >= 57) + #include //PM + #endif #include // Change this to the first version swrescale works #if (LIBAVFORMAT_VERSION_MAJOR >= 57) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index adf957f1..86b7cb0d 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -32,6 +32,9 @@ using namespace openshot; +int hw_de_on = 1; // Is set in UI +int hw_de_supported = 0; // Is set by FFmpegReader + FFmpegReader::FFmpegReader(string path) : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), @@ -103,6 +106,45 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 return false; } +#if IS_FFMPEG_3_2 +#if defined(__linux__) +#pragma message "You are compiling with experimental hardware decode" + +static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + if (*p == AV_PIX_FMT_VAAPI) + return *p; + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using VA-API.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + hw_de_supported = 0; + return AV_PIX_FMT_NONE; +} + +int is_hardware_decode_supported(int codecid) +{ + int ret; + switch (codecid) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_MPEG2VIDEO: + case AV_CODEC_ID_VC1: + case AV_CODEC_ID_WMV1: + case AV_CODEC_ID_WMV2: + case AV_CODEC_ID_WMV3: + ret = 1; + break; + default : + ret = 0; + break; + } + return ret; +} + +#endif +#endif + void FFmpegReader::Open() { // Open reader if not already open @@ -111,6 +153,14 @@ void FFmpegReader::Open() // Initialize format context pFormatCtx = NULL; + char * val = getenv( "OS2_DECODE_HW" ); + if (val == NULL) { + hw_de_on = 0; + } + else{ + hw_de_on = (val[0] == '1')? 1 : 0; + } + // Open video file if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, NULL) != 0) throw InvalidFile("File could not be opened.", path); @@ -151,7 +201,11 @@ void FFmpegReader::Open() // Get codec and codec context from stream AVCodec *pCodec = avcodec_find_decoder(codecId); pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); - + #if IS_FFMPEG_3_2 + #if defined(__linux__) + hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); + #endif + #endif // Set number of threads equal to number of processors (not to exceed 16) pCodecCtx->thread_count = min(OPEN_MP_NUM_PROCESSORS, 16); @@ -163,6 +217,23 @@ void FFmpegReader::Open() AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "experimental", 0); + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_de_on & hw_de_supported) { + // Open Hardware Acceleration + hw_device_ctx = NULL; + pCodecCtx->get_format = get_vaapi_format; + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed.", path); + } + } + else { + throw InvalidCodec("Hardware device create failed.", path); + } + } + #endif + #endif // Open video codec if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) throw InvalidCodec("A video codec was found, but could not be opened.", path); @@ -252,6 +323,16 @@ void FFmpegReader::Close() { avcodec_flush_buffers(pCodecCtx); AV_FREE_CONTEXT(pCodecCtx); + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_de_on) { + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; + } + } + #endif + #endif } if (info.has_audio) { @@ -703,9 +784,13 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) int FFmpegReader::GetNextPacket() { int found_packet = 0; - AVPacket *next_packet = new AVPacket(); + AVPacket *next_packet; + #pragma omp critical(getnextpacket) + { + next_packet = new AVPacket(); found_packet = av_read_frame(pFormatCtx, next_packet); + if (packet) { // Remove previous packet before getting next one RemoveAVPacket(packet); @@ -717,7 +802,7 @@ int FFmpegReader::GetNextPacket() // Update current packet pointer packet = next_packet; } - +} // Return if packet was found (or error number) return found_packet; } @@ -734,17 +819,51 @@ bool FFmpegReader::GetAVFrame() { #if IS_FFMPEG_3_2 frameFinished = 0; + ret = avcodec_send_packet(pCodecCtx, packet); + if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Packet not sent)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } else { + AVFrame *next_frame2; + #if defined(__linux__) + if (hw_de_on && hw_de_supported) { + next_frame2 = AV_ALLOCATE_FRAME(); + } + else + #endif + { + next_frame2 = next_frame; + } pFrame = new AVFrame(); while (ret >= 0) { - ret = avcodec_receive_frame(pCodecCtx, next_frame); + ret = avcodec_receive_frame(pCodecCtx, next_frame2); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } + if (ret != 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + #if defined(__linux__) + if (hw_de_on && hw_de_supported) { + int err; + if (next_frame2->format == AV_PIX_FMT_VAAPI) { + next_frame->format = AV_PIX_FMT_YUV420P; + if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + if ((err = av_frame_copy_props(next_frame,next_frame2)) < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to copy props to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + } + } + else + #endif + { // No hardware acceleration used -> no copy from GPU memory needed + next_frame = next_frame2; + } + //} // TODO also handle possible further frames // Use only the first frame like avcodec_decode_video2 if (frameFinished == 0 ) { @@ -759,6 +878,11 @@ bool FFmpegReader::GetAVFrame() } } } + #if defined(__linux__) + if (hw_de_on && hw_de_supported) { + AV_FREE_FRAME(&next_frame2); + } + #endif } #else avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index ed4fc3fb..a62e8287 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -32,6 +32,49 @@ using namespace openshot; +#if IS_FFMPEG_3_2 +int hw_en_on = 1; // Is set in UI +int hw_en_supported = 0; // Is set by FFmpegWriter +static AVBufferRef *hw_device_ctx = NULL; +AVFrame *hw_frame = NULL; + +static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int64_t width, int64_t height) +{ + AVBufferRef *hw_frames_ref; + AVHWFramesContext *frames_ctx = NULL; + int err = 0; + + if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { + fprintf(stderr, "Failed to create VAAPI frame context.\n"); + return -1; + } + frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + frames_ctx->format = AV_PIX_FMT_VAAPI; + frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->width = width; + frames_ctx->height = height; + frames_ctx->initial_pool_size = 20; + if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { + fprintf(stderr, "Failed to initialize VAAPI frame context." + "Error code: %s\n",av_err2str(err)); + av_buffer_unref(&hw_frames_ref); + return err; + } + ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref); + if (!ctx->hw_frames_ctx) + err = AVERROR(ENOMEM); + + av_buffer_unref(&hw_frames_ref); + return err; +} +#endif + +#if IS_FFMPEG_3_2 +#if defined(__linux__) +#pragma message "You are compiling with experimental hardware encode" +#endif +#endif + FFmpegWriter::FFmpegWriter(string path) : path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), @@ -116,7 +159,26 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i // Set the video options if (codec.length() > 0) { - AVCodec *new_codec = avcodec_find_encoder_by_name(codec.c_str()); + AVCodec *new_codec; + // Check if the codec selected is a hardware accelerated codec + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if ( (strcmp(codec.c_str(),"h264_vaapi") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; + } + #else // is FFmpeg 3 but not linux + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + #endif //__linux__ + #else // not ffmpeg 3 + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + #endif //IS_FFMPEG_3_2 if (new_codec == NULL) throw InvalidCodec("A valid video codec could not be found for this file.", path); else { @@ -506,6 +568,7 @@ void FFmpegWriter::write_queued_frames() is_writing = false; } // end omp single + } // end omp parallel // Raise exception from main thread @@ -735,6 +798,16 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { AV_FREE_CONTEXT(video_codec); video_codec = NULL; + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; + } + } + #endif + #endif } // Close the audio codec @@ -1102,6 +1175,23 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) // Set number of threads equal to number of processors (not to exceed 16) video_codec->thread_count = min(OPEN_MP_NUM_PROCESSORS, 16); + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + // Use the hw device given in the environment variable HW_DEVICE_SET or the default if not set + char *dev_hw = getenv( "HW_DEVICE_SET" ); + // Check if it is there and writable + if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { + dev_hw = NULL; // use default + } + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, + dev_hw, NULL, 0) < 0) { + cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; + throw InvalidCodec("Could not create hwdevice", path); + } + } + #endif + #endif /* find the video encoder */ codec = avcodec_find_encoder_by_name(info.vcodec.c_str()); if (!codec) @@ -1117,6 +1207,24 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "experimental", 0); + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames + video_codec->pix_fmt = AV_PIX_FMT_VAAPI; + video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; + av_opt_set(video_codec->priv_data,"preset","slow",0); + av_opt_set(video_codec->priv_data,"tune","zerolatency",0); + av_opt_set(video_codec->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); + // set hw_frames_ctx for encoder's AVCodecContext + int err; + if ((err = set_hwframe_ctx(video_codec, hw_device_ctx, info.width, info.height)) < 0) { + fprintf(stderr, "Failed to set hwframe context.\n"); + } + } + #endif + #endif + /* open the codec */ if (avcodec_open2(video_codec, codec, &opts) < 0) throw InvalidCodec("Could not open codec", path); @@ -1566,7 +1674,15 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) // Init AVFrame for source image & final (converted image) frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t*) pixels); #if IS_FFMPEG_3_2 - AVFrame *frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); + AVFrame *frame_final; + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); + } else + #endif + { + frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); + } #else AVFrame *frame_final = allocate_avframe(video_codec->pix_fmt, info.width, info.height, &bytes_final, NULL); #endif @@ -1641,14 +1757,41 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; - + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + if (!(hw_frame = av_frame_alloc())) { + fprintf(stderr, "Error code: av_hwframe_alloc\n"); + } + if (av_hwframe_get_buffer(video_codec->hw_frames_ctx, hw_frame, 0) < 0) { + fprintf(stderr, "Error code: av_hwframe_get_buffer\n"); + } + if (!hw_frame->hw_frames_ctx) { + fprintf(stderr, "Error hw_frames_ctx.\n"); + } + hw_frame->format = AV_PIX_FMT_NV12; + if ( av_hwframe_transfer_data(hw_frame, frame_final, 0) < 0) { + fprintf(stderr, "Error while transferring frame data to surface.\n"); + } + av_frame_copy_props(hw_frame, frame_final); + } + #endif + #endif /* encode the image */ int got_packet_ptr = 0; int error_code = 0; #if IS_FFMPEG_3_2 // Write video packet (latest version of FFmpeg) int frameFinished = 0; - int ret = avcodec_send_frame(video_codec, frame_final); + int ret; + #if defined(__linux__) + #if IS_FFMPEG_3_2 + if (hw_en_on && hw_en_supported) { + ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! + } else + #endif + #endif + ret = avcodec_send_frame(video_codec, frame_final); error_code = ret; if (ret < 0 ) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame not sent)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); @@ -1709,6 +1852,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra //pkt.pts = pkt.dts = write_video_count; // set the timestamp +// av_packet_rescale_ts(&pkt, video_st->time_base,video_codec->time_base); if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, video_codec->time_base, video_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) @@ -1732,6 +1876,16 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Deallocate packet AV_FREE_PACKET(&pkt); + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + if (hw_frame) { + av_frame_free(&hw_frame); + hw_frame = NULL; + } + } + #endif + #endif } // Success @@ -1752,7 +1906,16 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) for (int x = 0; x < num_of_rescalers; x++) { // Init the software scaler from FFMpeg + #if IS_FFMPEG_3_2 + #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); + } else + #endif + #endif + { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL); + } // Add rescaler to vector image_rescalers.push_back(img_convert_ctx); From 384b6e0bc3e08435c641eab38a237f0c0b35039b Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 31 Aug 2018 21:50:23 -0700 Subject: [PATCH 006/186] Set limit of threads for OpenMP and ffmpeg by setting the environment variables LIMIT_OMP_THREADS and LIMIT_FF_THREADS If they are not set the normal values are used --- include/OpenMPUtilities.h | 3 ++- src/FFmpegReader.cpp | 4 ++-- src/FFmpegWriter.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index c0f5597b..6ebde218 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -33,7 +33,8 @@ #include // Calculate the # of OpenMP Threads to allow -#define OPEN_MP_NUM_PROCESSORS omp_get_num_procs() +#define OPEN_MP_NUM_PROCESSORS ((getenv( "LIMIT_OMP_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_OMP_THREADS" ))) ))) +#define FF_NUM_PROCESSORS ((getenv( "LIMIT_FF_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_FF_THREADS" ))) ))) using namespace std; diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 86b7cb0d..3386d8ef 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -207,7 +207,7 @@ void FFmpegReader::Open() #endif #endif // Set number of threads equal to number of processors (not to exceed 16) - pCodecCtx->thread_count = min(OPEN_MP_NUM_PROCESSORS, 16); + pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); if (pCodec == NULL) { throw InvalidCodec("A valid video codec could not be found for this file.", path); @@ -262,7 +262,7 @@ void FFmpegReader::Open() aCodecCtx = AV_GET_CODEC_CONTEXT(aStream, aCodec); // Set number of threads equal to number of processors (not to exceed 16) - aCodecCtx->thread_count = min(OPEN_MP_NUM_PROCESSORS, 16); + aCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); if (aCodec == NULL) { throw InvalidCodec("A valid audio codec could not be found for this file.", path); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index a62e8287..5c902021 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1099,7 +1099,7 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) AV_GET_CODEC_FROM_STREAM(st, audio_codec) // Set number of threads equal to number of processors (not to exceed 16) - audio_codec->thread_count = min(OPEN_MP_NUM_PROCESSORS, 16); + audio_codec->thread_count = min(FF_NUM_PROCESSORS, 16); // Find the audio encoder codec = avcodec_find_encoder_by_name(info.acodec.c_str()); @@ -1173,7 +1173,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) AV_GET_CODEC_FROM_STREAM(st, video_codec) // Set number of threads equal to number of processors (not to exceed 16) - video_codec->thread_count = min(OPEN_MP_NUM_PROCESSORS, 16); + video_codec->thread_count = min(FF_NUM_PROCESSORS, 16); #if IS_FFMPEG_3_2 #if defined(__linux__) From 314177bceba3280d3d2c465dc9e34f533252ef88 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 2 Sep 2018 18:46:04 -0700 Subject: [PATCH 007/186] Let the user choose which installed graphics card to use for decoding HW_DE_DEVICE_SET and/or encoding HW_EN_DEVICE_SET Possible options are /dev/dri/renderD128 for the first, /dev/dri/renderD129 for the second, and so on. --- src/FFmpegReader.cpp | 8 +++++++- src/FFmpegWriter.cpp | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 3386d8ef..7910693c 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -221,9 +221,15 @@ void FFmpegReader::Open() #if defined(__linux__) if (hw_de_on & hw_de_supported) { // Open Hardware Acceleration + // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set + char *dev_hw = getenv( "HW_DE_DEVICE_SET" ); + // Check if it is there and writable + if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { + dev_hw = NULL; // use default + } hw_device_ctx = NULL; pCodecCtx->get_format = get_vaapi_format; - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0) >= 0) { + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); } diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 5c902021..24ccec0a 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1178,8 +1178,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #if IS_FFMPEG_3_2 #if defined(__linux__) if (hw_en_on && hw_en_supported) { - // Use the hw device given in the environment variable HW_DEVICE_SET or the default if not set - char *dev_hw = getenv( "HW_DEVICE_SET" ); + // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set + char *dev_hw = getenv( "HW_EN_DEVICE_SET" ); // Check if it is there and writable if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default From 063faefa694ac72b242c039666c7946cb58212a5 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 4 Sep 2018 10:08:01 -0700 Subject: [PATCH 008/186] Hardware acceleration for Windows and Mac, still disabled but code is there. This should show where modifications are to be made to support Linux, Mac, and Windows Only decoding, encoding will follow soon --- src/FFmpegReader.cpp | 155 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 140 insertions(+), 15 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 7910693c..5ee6a7b2 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -107,8 +107,8 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 } #if IS_FFMPEG_3_2 -#if defined(__linux__) #pragma message "You are compiling with experimental hardware decode" +#if defined(__linux__) static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { @@ -141,8 +141,109 @@ int is_hardware_decode_supported(int codecid) } return ret; } - #endif + +#if defined(_WIN32) +// Works for Windows 64 and Windows 32 +// FIXME Here goes the detection for Windows +// AV_HWDEVICE_TYPE_DXVA2 AV_PIX_FMT_DXVA2_VLD AV_HWDEVICE_TYPE_D3D11VA AV_PIX_FMT_D3D11 + +static enum AVPixelFormat get_dxva2_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + if (*p == AV_PIX_FMT_DXVA2_VLD) + return *p; + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using DXVA2.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + hw_de_supported = 0; + return AV_PIX_FMT_NONE; +} + +int is_hardware_decode_supported(int codecid) +{ + /* int ret; + switch (codecid) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_MPEG2VIDEO: + case AV_CODEC_ID_VC1: + case AV_CODEC_ID_WMV1: + case AV_CODEC_ID_WMV2: + case AV_CODEC_ID_WMV3: + ret = 1; + break; + default : + ret = 0; + break; + } + return ret;*/ + return 0; +} +#endif + +#if defined(__APPLE__) +// FIXME Here goes the detection for Mac +// Constants for MAC: AV_HWDEVICE_TYPE_QSV AV_PIX_FMT_QSV +int is_hardware_decode_supported(int codecid) +{ +/* int ret; + switch (codecid) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_MPEG2VIDEO: + case AV_CODEC_ID_VC1: + case AV_CODEC_ID_WMV1: + case AV_CODEC_ID_WMV2: + case AV_CODEC_ID_WMV3: + ret = 1; + break; + default : + ret = 0; + break; + } + return ret;*/ + return 0; +} +static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) +{ + while (*pix_fmts != AV_PIX_FMT_NONE) { + if (*pix_fmts == AV_PIX_FMT_QSV) { + DecodeContext *decode = avctx->opaque; + AVHWFramesContext *frames_ctx; + AVQSVFramesContext *frames_hwctx; + int ret; + + /* create a pool of surfaces to be used by the decoder */ + avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref); + if (!avctx->hw_frames_ctx) + return AV_PIX_FMT_NONE; + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + frames_hwctx = frames_ctx->hwctx; + + frames_ctx->format = AV_PIX_FMT_QSV; + frames_ctx->sw_format = avctx->sw_pix_fmt; + frames_ctx->width = FFALIGN(avctx->coded_width, 32); + frames_ctx->height = FFALIGN(avctx->coded_height, 32); + frames_ctx->initial_pool_size = 32; + + frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) + return AV_PIX_FMT_NONE; + + return AV_PIX_FMT_QSV; + } + + pix_fmts++; + } + + fprintf(stderr, "The QSV pixel format not offered in get_format()\n"); + + return AV_PIX_FMT_NONE; +} +#endif + #endif void FFmpegReader::Open() @@ -202,9 +303,9 @@ void FFmpegReader::Open() AVCodec *pCodec = avcodec_find_decoder(codecId); pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); - #endif +// #endif #endif // Set number of threads equal to number of processors (not to exceed 16) pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); @@ -218,8 +319,8 @@ void FFmpegReader::Open() av_dict_set(&opts, "strict", "experimental", 0); #if IS_FFMPEG_3_2 - #if defined(__linux__) - if (hw_de_on & hw_de_supported) { +// #if defined(__linux__) + if (hw_de_on && hw_de_supported) { // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set char *dev_hw = getenv( "HW_DE_DEVICE_SET" ); @@ -228,8 +329,23 @@ void FFmpegReader::Open() dev_hw = NULL; // use default } hw_device_ctx = NULL; +// FIXME get_XXX_format +// FIXME AV_HWDEVICE_TYPE_.... +// IMPORTANT: The get_format has different names because even for one plattform +// like Linux there are different modes of access like vaapi and vdpau and these +// should be chosen by the user in the future + #if defined(__linux__) pCodecCtx->get_format = get_vaapi_format; if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) { + #endif + #if defined(_WIN32) + pCodecCtx->get_format = get_dxva2_format; + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, dev_hw, NULL, 0) >= 0) { + #endif + #if defined(__APPLE__) + pCodecCtx->get_format = get_qsv_format; + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, dev_hw, NULL, 0) >= 0) { + #endif if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); } @@ -238,7 +354,7 @@ void FFmpegReader::Open() throw InvalidCodec("Hardware device create failed.", path); } } - #endif +// #endif #endif // Open video codec if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) @@ -330,14 +446,14 @@ void FFmpegReader::Close() avcodec_flush_buffers(pCodecCtx); AV_FREE_CONTEXT(pCodecCtx); #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_de_on) { if (hw_device_ctx) { av_buffer_unref(&hw_device_ctx); hw_device_ctx = NULL; } } - #endif +// #endif #endif } if (info.has_audio) @@ -833,12 +949,12 @@ bool FFmpegReader::GetAVFrame() } else { AVFrame *next_frame2; - #if defined(__linux__) +// #if defined(__linux__) if (hw_de_on && hw_de_supported) { next_frame2 = AV_ALLOCATE_FRAME(); } else - #endif +// #endif { next_frame2 = next_frame; } @@ -851,10 +967,19 @@ bool FFmpegReader::GetAVFrame() if (ret != 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } - #if defined(__linux__) +// #if defined(__linux__) if (hw_de_on && hw_de_supported) { int err; +// FIXME AV_PIX_FMT_VAAPI + #if defined(__linux__) if (next_frame2->format == AV_PIX_FMT_VAAPI) { + #endif + #if defined(__WIN32__) + if (next_frame2->format == AV_PIX_FMT_DXVA2_VLD) { + #endif + #if defined(__APPLE__) + if (next_frame2->format == AV_PIX_FMT_QSV) { + #endif next_frame->format = AV_PIX_FMT_YUV420P; if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); @@ -865,7 +990,7 @@ bool FFmpegReader::GetAVFrame() } } else - #endif +// #endif { // No hardware acceleration used -> no copy from GPU memory needed next_frame = next_frame2; } @@ -884,11 +1009,11 @@ bool FFmpegReader::GetAVFrame() } } } - #if defined(__linux__) +// #if defined(__linux__) if (hw_de_on && hw_de_supported) { AV_FREE_FRAME(&next_frame2); } - #endif +// #endif } #else avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet); From be979cd78c7562d3a3ec2208b7d6f7bf50dd3f80 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 6 Sep 2018 08:28:50 -0700 Subject: [PATCH 009/186] Accelerated encode now supported by Windows and Mac. Only tested on Linux though due to absense of hardware/software. Tested to compile on Ubuntu 14.04, 16.04, 18.04, and 18.10 Acceleration only available on systems with ffmpeg 3.2 and up Very early code, work in progress. Issues to be fixed soon: if hardware cannot decode because the size is too big it keeps trying. more interfaces supported like vdpau in Linux error handling user interface Many commented lines of code are still in the source to help people start who may want to help. --- src/FFmpegWriter.cpp | 80 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 24ccec0a..d0a542ae 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -49,7 +49,13 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 return -1; } frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + #if defined(__linux__) frames_ctx->format = AV_PIX_FMT_VAAPI; + #elif defined(_WIN32) + frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; + #elif defined(__APPLE__) + frames_ctx->format = AV_PIX_FMT_QSV; + #endif frames_ctx->sw_format = AV_PIX_FMT_NV12; frames_ctx->width = width; frames_ctx->height = height; @@ -70,9 +76,9 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 #endif #if IS_FFMPEG_3_2 -#if defined(__linux__) +//#if defined(__linux__) #pragma message "You are compiling with experimental hardware encode" -#endif +//#endif #endif FFmpegWriter::FFmpegWriter(string path) : @@ -171,6 +177,28 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 0; + hw_en_supported = 0; + } + #elif defined(_WIN32) + if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; + } + #elif defined(__APPLE__) + if ( (strcmp(codec.c_str(),"h264_qsv") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; hw_en_supported = 0; } #else // is FFmpeg 3 but not linux @@ -799,14 +827,14 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) AV_FREE_CONTEXT(video_codec); video_codec = NULL; #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (hw_device_ctx) { av_buffer_unref(&hw_device_ctx); hw_device_ctx = NULL; } } - #endif +// #endif #endif } @@ -1176,8 +1204,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) video_codec->thread_count = min(FF_NUM_PROCESSORS, 16); #if IS_FFMPEG_3_2 - #if defined(__linux__) if (hw_en_on && hw_en_supported) { + #if defined(__linux__) // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set char *dev_hw = getenv( "HW_EN_DEVICE_SET" ); // Check if it is there and writable @@ -1189,8 +1217,20 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; throw InvalidCodec("Could not create hwdevice", path); } + #elif defined(_WIN32) + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, + NULL, NULL, 0) < 0) { + cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; + throw InvalidCodec("Could not create hwdevice", path); + } + #elif defined(__APPLE__) + if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, + NULL, NULL, 0) < 0) { + cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; + throw InvalidCodec("Could not create hwdevice", path); + } + #endif } - #endif #endif /* find the video encoder */ codec = avcodec_find_encoder_by_name(info.vcodec.c_str()); @@ -1208,10 +1248,15 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) av_dict_set(&opts, "strict", "experimental", 0); #if IS_FFMPEG_3_2 - #if defined(__linux__) if (hw_en_on && hw_en_supported) { video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames + #if defined(__linux__) video_codec->pix_fmt = AV_PIX_FMT_VAAPI; + #elif defined(_WIN32) + video_codec->pix_fmt = AV_PIX_FMT_DXVA2_VLD + #elif defined(__APPLE__) + video_codec->pix_fmt = AV_PIX_FMT_QSV + #endif video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; av_opt_set(video_codec->priv_data,"preset","slow",0); av_opt_set(video_codec->priv_data,"tune","zerolatency",0); @@ -1222,7 +1267,6 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) fprintf(stderr, "Failed to set hwframe context.\n"); } } - #endif #endif /* open the codec */ @@ -1675,11 +1719,11 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t*) pixels); #if IS_FFMPEG_3_2 AVFrame *frame_final; - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); } else - #endif +// #endif { frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); } @@ -1758,7 +1802,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (!(hw_frame = av_frame_alloc())) { fprintf(stderr, "Error code: av_hwframe_alloc\n"); @@ -1775,7 +1819,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } av_frame_copy_props(hw_frame, frame_final); } - #endif +// #endif #endif /* encode the image */ int got_packet_ptr = 0; @@ -1784,13 +1828,13 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Write video packet (latest version of FFmpeg) int frameFinished = 0; int ret; - #if defined(__linux__) +// #if defined(__linux__) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! } else #endif - #endif +// #endif ret = avcodec_send_frame(video_codec, frame_final); error_code = ret; if (ret < 0 ) { @@ -1877,14 +1921,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Deallocate packet AV_FREE_PACKET(&pkt); #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (hw_frame) { av_frame_free(&hw_frame); hw_frame = NULL; } } - #endif +// #endif #endif } @@ -1907,11 +1951,11 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) { // Init the software scaler from FFMpeg #if IS_FFMPEG_3_2 - #if defined(__linux__) +// #if defined(__linux__) if (hw_en_on && hw_en_supported) { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); } else - #endif +// #endif #endif { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL); From 6925f6f7c2fdbf179d549bee5ee4c73b6a221aec Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 7 Sep 2018 10:44:18 -0700 Subject: [PATCH 010/186] Use the static scheduler in ordered clause. Otherwise OpenMP uses a scheduler it thinks is best which can be dynamic or guided. Both sometimes let other threads continue before the block is finished. That will crash the program with high thread counts and a cache that is not large enough to hold old enough frames, which leads to a crash when in some cases like transitions two different frames are used although one is no longer in the cache. The static scheduler always waits until the block is finished before enabling other threads. --- src/Timeline.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 35b91283..34dab1d8 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -717,7 +717,8 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame) #pragma omp parallel { // Loop through all requested frames - #pragma omp for ordered firstprivate(nearby_clips, requested_frame, minimum_frames) + // The scheduler has to be static! + #pragma omp for ordered schedule(static,1) firstprivate(nearby_clips, requested_frame, minimum_frames) for (int64_t frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++) { // Debug output From f7dd2b18c38612d41f6c05a30e8e0c88c49d010c Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 16:31:03 -0700 Subject: [PATCH 011/186] First adjustment to later include NVENC (nvidia encoder) --- src/FFmpegWriter.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d0a542ae..e01e2f83 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -35,6 +35,8 @@ using namespace openshot; #if IS_FFMPEG_3_2 int hw_en_on = 1; // Is set in UI int hw_en_supported = 0; // Is set by FFmpegWriter +AVPixelFormat hw_en_av_pix_fmt = AV_PIX_FMT_NONE; +AVHWDeviceType hw_en_av_device_type = AV_HWDEVICE_TYPE_VAAPI; static AVBufferRef *hw_device_ctx = NULL; AVFrame *hw_frame = NULL; @@ -50,7 +52,7 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 } frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); #if defined(__linux__) - frames_ctx->format = AV_PIX_FMT_VAAPI; + frames_ctx->format = hw_en_av_pix_fmt; #elif defined(_WIN32) frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; #elif defined(__APPLE__) @@ -173,6 +175,8 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_VAAPI; + hw_en_av_device_type = AV_HWDEVICE_TYPE_VAAPI; } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); @@ -1212,7 +1216,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default } - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, dev_hw, NULL, 0) < 0) { cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; throw InvalidCodec("Could not create hwdevice", path); @@ -1251,7 +1255,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) if (hw_en_on && hw_en_supported) { video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames #if defined(__linux__) - video_codec->pix_fmt = AV_PIX_FMT_VAAPI; + video_codec->pix_fmt = hw_en_av_pix_fmt; #elif defined(_WIN32) video_codec->pix_fmt = AV_PIX_FMT_DXVA2_VLD #elif defined(__APPLE__) From 16c8302f485d530f8c2513c4f96d6fbb43df310e Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 16:53:53 -0700 Subject: [PATCH 012/186] Basic support for nvidia encode (decode later) --- src/FFmpegWriter.cpp | 55 ++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e01e2f83..924f3490 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -47,23 +47,17 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 int err = 0; if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { - fprintf(stderr, "Failed to create VAAPI frame context.\n"); + fprintf(stderr, "Failed to create HW frame context.\n"); return -1; } frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); - #if defined(__linux__) frames_ctx->format = hw_en_av_pix_fmt; - #elif defined(_WIN32) - frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; - #elif defined(__APPLE__) - frames_ctx->format = AV_PIX_FMT_QSV; - #endif frames_ctx->sw_format = AV_PIX_FMT_NV12; frames_ctx->width = width; frames_ctx->height = height; frames_ctx->initial_pool_size = 20; if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { - fprintf(stderr, "Failed to initialize VAAPI frame context." + fprintf(stderr, "Failed to initialize HW frame context." "Error code: %s\n",av_err2str(err)); av_buffer_unref(&hw_frames_ref); return err; @@ -178,16 +172,27 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i hw_en_av_pix_fmt = AV_PIX_FMT_VAAPI; hw_en_av_device_type = AV_HWDEVICE_TYPE_VAAPI; } - else { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 0; - hw_en_supported = 0; - } + else { + if ( (strcmp(codec.c_str(),"h264_nvenc") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; + hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; + } + } #elif defined(_WIN32) if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; + hw_en_av_device_type = AV_HWDEVICE_TYPE_DXVA2; } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); @@ -199,6 +204,8 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_QSV; + hw_en_av_device_type = AV_HWDEVICE_TYPE_QSV; } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); @@ -1216,24 +1223,14 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default } + #else + dev_hw = NULL; // use default + #endif if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, dev_hw, NULL, 0) < 0) { cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; throw InvalidCodec("Could not create hwdevice", path); } - #elif defined(_WIN32) - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, - NULL, NULL, 0) < 0) { - cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; - throw InvalidCodec("Could not create hwdevice", path); - } - #elif defined(__APPLE__) - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, - NULL, NULL, 0) < 0) { - cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; - throw InvalidCodec("Could not create hwdevice", path); - } - #endif } #endif /* find the video encoder */ @@ -1254,13 +1251,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames - #if defined(__linux__) video_codec->pix_fmt = hw_en_av_pix_fmt; - #elif defined(_WIN32) - video_codec->pix_fmt = AV_PIX_FMT_DXVA2_VLD - #elif defined(__APPLE__) - video_codec->pix_fmt = AV_PIX_FMT_QSV - #endif video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; av_opt_set(video_codec->priv_data,"preset","slow",0); av_opt_set(video_codec->priv_data,"tune","zerolatency",0); From e7c1ced0da1590e79a992d4ac8634edd46bc66a2 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 21:17:24 -0700 Subject: [PATCH 013/186] Cleanup import video hardware accelerated and first attempt with nvidia cards. Still no error handling when the dimensions of the video are too large --- src/FFmpegReader.cpp | 242 ++++++++++++++++++------------------------- 1 file changed, 98 insertions(+), 144 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 5ee6a7b2..7d9c27ca 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -34,6 +34,8 @@ using namespace openshot; int hw_de_on = 1; // Is set in UI int hw_de_supported = 0; // Is set by FFmpegReader +AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; +AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; FFmpegReader::FFmpegReader(string path) : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), @@ -108,112 +110,60 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if IS_FFMPEG_3_2 #pragma message "You are compiling with experimental hardware decode" -#if defined(__linux__) static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - if (*p == AV_PIX_FMT_VAAPI) - return *p; + if (*p == AV_PIX_FMT_VAAPI) { + hw_de_av_pix_fmt = AV_PIX_FMT_VAAPI; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + return *p; + } + if (*p == AV_PIX_FMT_CUDA) { + hw_de_av_pix_fmt = AV_PIX_FMT_CUDA; + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + return *p; + } } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using VA-API.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); hw_de_supported = 0; return AV_PIX_FMT_NONE; } -int is_hardware_decode_supported(int codecid) -{ - int ret; - switch (codecid) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_MPEG2VIDEO: - case AV_CODEC_ID_VC1: - case AV_CODEC_ID_WMV1: - case AV_CODEC_ID_WMV2: - case AV_CODEC_ID_WMV3: - ret = 1; - break; - default : - ret = 0; - break; - } - return ret; -} -#endif - -#if defined(_WIN32) -// Works for Windows 64 and Windows 32 -// FIXME Here goes the detection for Windows -// AV_HWDEVICE_TYPE_DXVA2 AV_PIX_FMT_DXVA2_VLD AV_HWDEVICE_TYPE_D3D11VA AV_PIX_FMT_D3D11 - -static enum AVPixelFormat get_dxva2_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - if (*p == AV_PIX_FMT_DXVA2_VLD) - return *p; + if (*p == AV_PIX_FMT_DXVA2_VLD) { + hw_de_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + return *p; + } + if (*p == AV_PIX_FMT_D3D11) { + hw_de_av_pix_fmt = AV_PIX_FMT_D3D11; + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; + return *p; + } } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using DXVA2.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); hw_de_supported = 0; + hw_de_av_pix_fmt = AV_PIX_FMT_NONE; return AV_PIX_FMT_NONE; } -int is_hardware_decode_supported(int codecid) -{ - /* int ret; - switch (codecid) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_MPEG2VIDEO: - case AV_CODEC_ID_VC1: - case AV_CODEC_ID_WMV1: - case AV_CODEC_ID_WMV2: - case AV_CODEC_ID_WMV3: - ret = 1; - break; - default : - ret = 0; - break; - } - return ret;*/ - return 0; -} -#endif - -#if defined(__APPLE__) -// FIXME Here goes the detection for Mac -// Constants for MAC: AV_HWDEVICE_TYPE_QSV AV_PIX_FMT_QSV -int is_hardware_decode_supported(int codecid) -{ -/* int ret; - switch (codecid) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_MPEG2VIDEO: - case AV_CODEC_ID_VC1: - case AV_CODEC_ID_WMV1: - case AV_CODEC_ID_WMV2: - case AV_CODEC_ID_WMV3: - ret = 1; - break; - default : - ret = 0; - break; - } - return ret;*/ - return 0; -} static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) { - while (*pix_fmts != AV_PIX_FMT_NONE) { + /* while (*pix_fmts != AV_PIX_FMT_NONE) { if (*pix_fmts == AV_PIX_FMT_QSV) { DecodeContext *decode = avctx->opaque; AVHWFramesContext *frames_ctx; AVQSVFramesContext *frames_hwctx; int ret; - /* create a pool of surfaces to be used by the decoder */ + // create a pool of surfaces to be used by the decoder avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref); if (!avctx->hw_frames_ctx) return AV_PIX_FMT_NONE; @@ -239,10 +189,40 @@ static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_f } fprintf(stderr, "The QSV pixel format not offered in get_format()\n"); + */ + const enum AVPixelFormat *p; + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + if (*p == AV_PIX_FMT_QSV) { + hw_de_av_pix_fmt = AV_PIX_FMT_QSV; + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + return *p; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using QSV.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + hw_de_supported = 0; + hw_de_av_pix_fmt = AV_PIX_FMT_NONE; return AV_PIX_FMT_NONE; } -#endif + +int is_hardware_decode_supported(int codecid) +{ + int ret; + switch (codecid) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_MPEG2VIDEO: + case AV_CODEC_ID_VC1: + case AV_CODEC_ID_WMV1: + case AV_CODEC_ID_WMV2: + case AV_CODEC_ID_WMV3: + ret = 1; + break; + default : + ret = 0; + break; + } + return ret; +} #endif @@ -303,9 +283,7 @@ void FFmpegReader::Open() AVCodec *pCodec = avcodec_find_decoder(codecId); pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); #if IS_FFMPEG_3_2 -// #if defined(__linux__) - hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); -// #endif + hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); #endif // Set number of threads equal to number of processors (not to exceed 16) pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); @@ -319,42 +297,36 @@ void FFmpegReader::Open() av_dict_set(&opts, "strict", "experimental", 0); #if IS_FFMPEG_3_2 -// #if defined(__linux__) - if (hw_de_on && hw_de_supported) { - // Open Hardware Acceleration - // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set - char *dev_hw = getenv( "HW_DE_DEVICE_SET" ); - // Check if it is there and writable - if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { - dev_hw = NULL; // use default - } - hw_device_ctx = NULL; -// FIXME get_XXX_format -// FIXME AV_HWDEVICE_TYPE_.... -// IMPORTANT: The get_format has different names because even for one plattform -// like Linux there are different modes of access like vaapi and vdpau and these -// should be chosen by the user in the future - #if defined(__linux__) - pCodecCtx->get_format = get_vaapi_format; - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) { - #endif - #if defined(_WIN32) - pCodecCtx->get_format = get_dxva2_format; - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, dev_hw, NULL, 0) >= 0) { - #endif - #if defined(__APPLE__) - pCodecCtx->get_format = get_qsv_format; - if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, dev_hw, NULL, 0) >= 0) { - #endif - if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed.", path); - } - } - else { - throw InvalidCodec("Hardware device create failed.", path); + if (hw_de_on && hw_de_supported) { + // Open Hardware Acceleration + // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set + char *dev_hw = getenv( "HW_DE_DEVICE_SET" ); + // Check if it is there and writable + if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { + dev_hw = NULL; // use default + } + hw_device_ctx = NULL; + #if defined(__linux__) + pCodecCtx->get_format = get_vaapi_format; + //if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) { + #endif + #if defined(_WIN32) + pCodecCtx->get_format = get_dx_format; + //if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, dev_hw, NULL, 0) >= 0) { + #endif + #if defined(__APPLE__) + pCodecCtx->get_format = get_qsv_format; + //if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, dev_hw, NULL, 0) >= 0) { + #endif + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed.", path); } } -// #endif + else { + throw InvalidCodec("Hardware device create failed.", path); + } + } #endif // Open video codec if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) @@ -446,14 +418,12 @@ void FFmpegReader::Close() avcodec_flush_buffers(pCodecCtx); AV_FREE_CONTEXT(pCodecCtx); #if IS_FFMPEG_3_2 -// #if defined(__linux__) - if (hw_de_on) { - if (hw_device_ctx) { - av_buffer_unref(&hw_device_ctx); - hw_device_ctx = NULL; - } + if (hw_de_on) { + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; } -// #endif + } #endif } if (info.has_audio) @@ -949,37 +919,25 @@ bool FFmpegReader::GetAVFrame() } else { AVFrame *next_frame2; -// #if defined(__linux__) if (hw_de_on && hw_de_supported) { next_frame2 = AV_ALLOCATE_FRAME(); } else -// #endif { next_frame2 = next_frame; } pFrame = new AVFrame(); while (ret >= 0) { ret = avcodec_receive_frame(pCodecCtx, next_frame2); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { - break; - } + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } if (ret != 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } -// #if defined(__linux__) if (hw_de_on && hw_de_supported) { int err; -// FIXME AV_PIX_FMT_VAAPI - #if defined(__linux__) - if (next_frame2->format == AV_PIX_FMT_VAAPI) { - #endif - #if defined(__WIN32__) - if (next_frame2->format == AV_PIX_FMT_DXVA2_VLD) { - #endif - #if defined(__APPLE__) - if (next_frame2->format == AV_PIX_FMT_QSV) { - #endif + if (next_frame2->format == hw_de_av_pix_fmt) { next_frame->format = AV_PIX_FMT_YUV420P; if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); @@ -990,11 +948,9 @@ bool FFmpegReader::GetAVFrame() } } else -// #endif { // No hardware acceleration used -> no copy from GPU memory needed next_frame = next_frame2; } - //} // TODO also handle possible further frames // Use only the first frame like avcodec_decode_video2 if (frameFinished == 0 ) { @@ -1009,11 +965,9 @@ bool FFmpegReader::GetAVFrame() } } } -// #if defined(__linux__) - if (hw_de_on && hw_de_supported) { - AV_FREE_FRAME(&next_frame2); - } -// #endif + if (hw_de_on && hw_de_supported) { + AV_FREE_FRAME(&next_frame2); + } } #else avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet); From 0191ff5dbb6a4934e5a28a65d0488f626def93ae Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 21:32:04 -0700 Subject: [PATCH 014/186] Further cleanup --- src/FFmpegReader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 7d9c27ca..5602e40c 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -300,23 +300,23 @@ void FFmpegReader::Open() if (hw_de_on && hw_de_supported) { // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set - char *dev_hw = getenv( "HW_DE_DEVICE_SET" ); + char *dev_hw = NULL; + #if defined(__linux__) + dev_hw = getenv( "HW_DE_DEVICE_SET" ); // Check if it is there and writable if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default } + #endif hw_device_ctx = NULL; #if defined(__linux__) pCodecCtx->get_format = get_vaapi_format; - //if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, dev_hw, NULL, 0) >= 0) { #endif #if defined(_WIN32) pCodecCtx->get_format = get_dx_format; - //if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, dev_hw, NULL, 0) >= 0) { #endif #if defined(__APPLE__) pCodecCtx->get_format = get_qsv_format; - //if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, dev_hw, NULL, 0) >= 0) { #endif if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { From 36cbba2a3d8f5df2aebc0c867ce9a52ded8790f2 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 21:55:23 -0700 Subject: [PATCH 015/186] More cleanup --- src/FFmpegReader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 5602e40c..70b235df 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -111,6 +111,7 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if IS_FFMPEG_3_2 #pragma message "You are compiling with experimental hardware decode" +#if defined(__linux__) static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -131,7 +132,9 @@ static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPix hw_de_supported = 0; return AV_PIX_FMT_NONE; } +#endif +#if defined(_WIN32) static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -153,7 +156,9 @@ static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelF hw_de_av_pix_fmt = AV_PIX_FMT_NONE; return AV_PIX_FMT_NONE; } +#endif +#if defined(__APPLE__) static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) { /* while (*pix_fmts != AV_PIX_FMT_NONE) { @@ -204,6 +209,7 @@ static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_f hw_de_av_pix_fmt = AV_PIX_FMT_NONE; return AV_PIX_FMT_NONE; } +#endif int is_hardware_decode_supported(int codecid) { From e7c94e700add4af1ba2235efc6b886083e070ab8 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 22:19:41 -0700 Subject: [PATCH 016/186] hide dx11 --- src/FFmpegReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 70b235df..9f4bb514 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -145,11 +145,11 @@ static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelF hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; return *p; } - if (*p == AV_PIX_FMT_D3D11) { +/* if (*p == AV_PIX_FMT_D3D11) { hw_de_av_pix_fmt = AV_PIX_FMT_D3D11; hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; return *p; - } + }*/ } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using DXVA2.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); hw_de_supported = 0; From d6f52ead3bfd5ae3646e6226c4371fa7d52c644e Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 22:30:16 -0700 Subject: [PATCH 017/186] Only use the hw accel variables when ffmpeg >= 3.2 --- src/FFmpegReader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 9f4bb514..c067f3fe 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -32,10 +32,12 @@ using namespace openshot; +#if IS_FFMPEG_3_2 int hw_de_on = 1; // Is set in UI int hw_de_supported = 0; // Is set by FFmpegReader AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; +#endif FFmpegReader::FFmpegReader(string path) : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), From 2a80ccacaac4e028664de5968ede58bb4f997e6a Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Sep 2018 22:57:46 -0700 Subject: [PATCH 018/186] Let hw_de_on be visible to all versions of ffmpeg --- src/FFmpegReader.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index c067f3fe..4ce92889 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -32,9 +32,9 @@ using namespace openshot; -#if IS_FFMPEG_3_2 int hw_de_on = 1; // Is set in UI int hw_de_supported = 0; // Is set by FFmpegReader +#if IS_FFMPEG_3_2 AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; #endif @@ -147,11 +147,11 @@ static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelF hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; return *p; } -/* if (*p == AV_PIX_FMT_D3D11) { + if (*p == AV_PIX_FMT_D3D11) { hw_de_av_pix_fmt = AV_PIX_FMT_D3D11; hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; return *p; - }*/ + } } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using DXVA2.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); hw_de_supported = 0; @@ -291,7 +291,9 @@ void FFmpegReader::Open() AVCodec *pCodec = avcodec_find_decoder(codecId); pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); #if IS_FFMPEG_3_2 - hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); + if (hw_de_on) { + hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); + } #endif // Set number of threads equal to number of processors (not to exceed 16) pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); @@ -309,13 +311,11 @@ void FFmpegReader::Open() // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set char *dev_hw = NULL; - #if defined(__linux__) dev_hw = getenv( "HW_DE_DEVICE_SET" ); // Check if it is there and writable if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default } - #endif hw_device_ctx = NULL; #if defined(__linux__) pCodecCtx->get_format = get_vaapi_format; From c29bf21c75ee2342709021ded86e262f37f0f176 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 9 Sep 2018 09:05:16 -0700 Subject: [PATCH 019/186] Simplifications of FFmpegReader and start of setting parameters per input file --- include/FFmpegReader.h | 5 +++ src/FFmpegReader.cpp | 83 ++++-------------------------------------- 2 files changed, 12 insertions(+), 76 deletions(-) diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index fcc995ae..caf68e5e 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -146,6 +146,11 @@ namespace openshot int64_t largest_frame_processed; int64_t current_video_frame; // can't reliably use PTS of video to determine this + //int hw_de_supported = 0; // Is set by FFmpegReader + //AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; + + int is_hardware_decode_supported(int codecid); + /// Check for the correct frames per second value by scanning the 1st few seconds of video packets. void CheckFPS(); diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 4ce92889..083de926 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -113,12 +113,12 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if IS_FFMPEG_3_2 #pragma message "You are compiling with experimental hardware decode" -#if defined(__linux__) -static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + //Linux formats if (*p == AV_PIX_FMT_VAAPI) { hw_de_av_pix_fmt = AV_PIX_FMT_VAAPI; hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; @@ -129,19 +129,7 @@ static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, const enum AVPix hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; return *p; } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using VA-API.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - hw_de_supported = 0; - return AV_PIX_FMT_NONE; -} -#endif - -#if defined(_WIN32) -static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + // Windows formats if (*p == AV_PIX_FMT_DXVA2_VLD) { hw_de_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; @@ -152,68 +140,19 @@ static enum AVPixelFormat get_dx_format(AVCodecContext *ctx, const enum AVPixelF hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; return *p; } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using DXVA2.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - hw_de_supported = 0; - hw_de_av_pix_fmt = AV_PIX_FMT_NONE; - return AV_PIX_FMT_NONE; -} -#endif - -#if defined(__APPLE__) -static int get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) -{ - /* while (*pix_fmts != AV_PIX_FMT_NONE) { - if (*pix_fmts == AV_PIX_FMT_QSV) { - DecodeContext *decode = avctx->opaque; - AVHWFramesContext *frames_ctx; - AVQSVFramesContext *frames_hwctx; - int ret; - - // create a pool of surfaces to be used by the decoder - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref); - if (!avctx->hw_frames_ctx) - return AV_PIX_FMT_NONE; - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - frames_hwctx = frames_ctx->hwctx; - - frames_ctx->format = AV_PIX_FMT_QSV; - frames_ctx->sw_format = avctx->sw_pix_fmt; - frames_ctx->width = FFALIGN(avctx->coded_width, 32); - frames_ctx->height = FFALIGN(avctx->coded_height, 32); - frames_ctx->initial_pool_size = 32; - - frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; - - ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (ret < 0) - return AV_PIX_FMT_NONE; - - return AV_PIX_FMT_QSV; - } - - pix_fmts++; - } - - fprintf(stderr, "The QSV pixel format not offered in get_format()\n"); - */ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + //Mac format if (*p == AV_PIX_FMT_QSV) { hw_de_av_pix_fmt = AV_PIX_FMT_QSV; hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; return *p; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using QSV.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); hw_de_supported = 0; - hw_de_av_pix_fmt = AV_PIX_FMT_NONE; return AV_PIX_FMT_NONE; } -#endif -int is_hardware_decode_supported(int codecid) +int FFmpegReader::is_hardware_decode_supported(int codecid) { int ret; switch (codecid) { @@ -317,15 +256,7 @@ void FFmpegReader::Open() dev_hw = NULL; // use default } hw_device_ctx = NULL; - #if defined(__linux__) - pCodecCtx->get_format = get_vaapi_format; - #endif - #if defined(_WIN32) - pCodecCtx->get_format = get_dx_format; - #endif - #if defined(__APPLE__) - pCodecCtx->get_format = get_qsv_format; - #endif + pCodecCtx->get_format = get_hw_dec_format; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); From aff1be93b8056fdd15bd062aba71d407e6dab8af Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 9 Sep 2018 10:54:31 -0700 Subject: [PATCH 020/186] Support for multiple input files --- include/FFmpegReader.h | 7 +++++-- src/FFmpegReader.cpp | 32 ++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index caf68e5e..f571af73 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -146,8 +146,11 @@ namespace openshot int64_t largest_frame_processed; int64_t current_video_frame; // can't reliably use PTS of video to determine this - //int hw_de_supported = 0; // Is set by FFmpegReader - //AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; + int hw_de_supported = 0; // Is set by FFmpegReader + #if IS_FFMPEG_3_2 + AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; + AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + #endif int is_hardware_decode_supported(int codecid); diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 083de926..4ec46191 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -33,10 +33,10 @@ using namespace openshot; int hw_de_on = 1; // Is set in UI -int hw_de_supported = 0; // Is set by FFmpegReader +//int hw_de_supported = 0; // Is set by FFmpegReader #if IS_FFMPEG_3_2 -AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; -AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; +AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE; +AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; #endif FFmpegReader::FFmpegReader(string path) @@ -120,35 +120,35 @@ static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPi for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { //Linux formats if (*p == AV_PIX_FMT_VAAPI) { - hw_de_av_pix_fmt = AV_PIX_FMT_VAAPI; - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; return *p; } if (*p == AV_PIX_FMT_CUDA) { - hw_de_av_pix_fmt = AV_PIX_FMT_CUDA; - hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; return *p; } // Windows formats if (*p == AV_PIX_FMT_DXVA2_VLD) { - hw_de_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; return *p; } if (*p == AV_PIX_FMT_D3D11) { - hw_de_av_pix_fmt = AV_PIX_FMT_D3D11; - hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; + hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; return *p; } //Mac format if (*p == AV_PIX_FMT_QSV) { - hw_de_av_pix_fmt = AV_PIX_FMT_QSV; - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; return *p; } } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - hw_de_supported = 0; + //hw_de_supported = 0; return AV_PIX_FMT_NONE; } @@ -853,6 +853,10 @@ bool FFmpegReader::GetAVFrame() ret = avcodec_send_packet(pCodecCtx, packet); + // Get the format from the variables set in get_hw_dec_format + hw_de_av_pix_fmt = hw_de_av_pix_fmt_global; + hw_de_av_device_type = hw_de_av_device_type_global; + if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Packet not sent)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } From f8fed171cef786c2dc4e572207ed4c361162d19f Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 9 Sep 2018 12:57:04 -0700 Subject: [PATCH 021/186] More code cleanup (easier to read) Comment included with start of error handling --- src/FFmpegReader.cpp | 60 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 4ec46191..4dabce7e 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -118,37 +118,35 @@ static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPi const enum AVPixelFormat *p; for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - //Linux formats - if (*p == AV_PIX_FMT_VAAPI) { - hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; - return *p; - } - if (*p == AV_PIX_FMT_CUDA) { - hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; - return *p; - } - // Windows formats - if (*p == AV_PIX_FMT_DXVA2_VLD) { - hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; - return *p; - } - if (*p == AV_PIX_FMT_D3D11) { - hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; - return *p; - } - //Mac format - if (*p == AV_PIX_FMT_QSV) { - hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; - return *p; + switch (*p) { + case AV_PIX_FMT_VAAPI: + hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; + return *p; + break; + case AV_PIX_FMT_CUDA: + hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; + return *p; + break; + case AV_PIX_FMT_DXVA2_VLD: + hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; + return *p; + break; + case AV_PIX_FMT_D3D11: + hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; + return *p; + break; + case AV_PIX_FMT_QSV: + hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; + return *p; + break; } } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - //hw_de_supported = 0; return AV_PIX_FMT_NONE; } @@ -266,6 +264,12 @@ void FFmpegReader::Open() throw InvalidCodec("Hardware device create failed.", path); } } +/* // Check to see if the hardware supports that file (size!) + AVHWFramesConstraints *constraints = NULL; + constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx->device_ref,hwconfig); + if (constraints) + av_hwframe_constraints_free(&constraints); +*/ #endif // Open video codec if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) From 4db2217f0d94dfce07359d6e526efe34389c87af Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 11 Sep 2018 20:18:11 -0700 Subject: [PATCH 022/186] Fallback for hardware accelerated decode to software decode in case the GPU can noy handle the dimensions of the frame. Not yet working, va_config not yet set. --- src/FFmpegReader.cpp | 131 ++++++++++++++++++++++++++++--------------- src/FFmpegWriter.cpp | 6 -- 2 files changed, 86 insertions(+), 51 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 4dabce7e..caa33de1 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -29,6 +29,7 @@ */ #include "../include/FFmpegReader.h" +#include "libavutil/hwcontext_vaapi.h" using namespace openshot; @@ -111,7 +112,6 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 } #if IS_FFMPEG_3_2 -#pragma message "You are compiling with experimental hardware decode" static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { @@ -226,55 +226,96 @@ void FFmpegReader::Open() // Get codec and codec context from stream AVCodec *pCodec = avcodec_find_decoder(codecId); - pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); - #if IS_FFMPEG_3_2 - if (hw_de_on) { - hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); - } - #endif - // Set number of threads equal to number of processors (not to exceed 16) - pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); - - if (pCodec == NULL) { - throw InvalidCodec("A valid video codec could not be found for this file.", path); - } - - // Init options AVDictionary *opts = NULL; - av_dict_set(&opts, "strict", "experimental", 0); + int retry_decode_open = 2; + // If hw accel is selected but hardware connot handle repeat with software decoding + do { + pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); + #if IS_FFMPEG_3_2 + if (hw_de_on && (retry_decode_open==2)) { + // Up to here no decision is made if hardware or software decode + hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); + } + #endif + retry_decode_open = 0; + // Set number of threads equal to number of processors (not to exceed 16) + pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); - #if IS_FFMPEG_3_2 - if (hw_de_on && hw_de_supported) { - // Open Hardware Acceleration - // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set - char *dev_hw = NULL; - dev_hw = getenv( "HW_DE_DEVICE_SET" ); - // Check if it is there and writable - if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { - dev_hw = NULL; // use default - } - hw_device_ctx = NULL; - pCodecCtx->get_format = get_hw_dec_format; - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) { - if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed.", path); + if (pCodec == NULL) { + throw InvalidCodec("A valid video codec could not be found for this file.", path); + } + + // Init options + av_dict_set(&opts, "strict", "experimental", 0); + #if IS_FFMPEG_3_2 + if (hw_de_on && hw_de_supported) { + // Open Hardware Acceleration + // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set + char *dev_hw = NULL; + dev_hw = getenv( "HW_DE_DEVICE_SET" ); + // Check if it is there and writable + if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { + dev_hw = NULL; // use default + } + hw_device_ctx = NULL; + // Here the first hardware initialisations are made + pCodecCtx->get_format = get_hw_dec_format; + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed.", path); + } + } + else { + throw InvalidCodec("Hardware device create failed.", path); } } - else { - throw InvalidCodec("Hardware device create failed.", path); - } - } -/* // Check to see if the hardware supports that file (size!) - AVHWFramesConstraints *constraints = NULL; - constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx->device_ref,hwconfig); - if (constraints) - av_hwframe_constraints_free(&constraints); -*/ - #endif - // Open video codec - if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) - throw InvalidCodec("A video codec was found, but could not be opened.", path); + #endif + // Open video codec + if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) + throw InvalidCodec("A video codec was found, but could not be opened.", path); + #if IS_FFMPEG_3_2 + if (hw_de_on && hw_de_supported) { + AVHWFramesConstraints *constraints = NULL; + // NOT WORKING needs hwconfig config_id !!!!!!!!!!!!!!!!!!!!!!!!!!! + //AVVAAPIHWConfig *hwconfig = NULL; + // void *hwconfig = NULL; + // hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx); + //hwconfig->config_id = ((VAAPIDecodeContext *)pCodecCtx->priv_data)->va_config; + // constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,(void*)hwconfig); + constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,NULL); // No usable information! + if (constraints) { +// constraints->max_height = 1100; // Just for testing +// constraints->max_width = 1950; // Just for testing + if (pCodecCtx->coded_width < constraints->min_width || + pCodecCtx->coded_height < constraints->min_height || + pCodecCtx->coded_width > constraints->max_width || + pCodecCtx->coded_height > constraints->max_height) { + cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; + hw_de_supported = 0; + retry_decode_open = 1; + AV_FREE_CONTEXT(pCodecCtx); + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; + } + } + else { + // All is just peachy + cerr << "MinWidth : " << constraints->min_width << "MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; + cerr << "Frame width :" << pCodecCtx->coded_width << "Frame height :" << pCodecCtx->coded_height << "\n"; + retry_decode_open = 0; + } + av_hwframe_constraints_free(&constraints); + } + else { + cerr << "Constraints could not be found\n"; + } + } // if hw_de_on && hw_de_supported + #else + retry_decode_open = 0; + #endif + } while (retry_decode_open); // retry_decode_open // Free options av_dict_free(&opts); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 924f3490..c16ce7a8 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -71,12 +71,6 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int6 } #endif -#if IS_FFMPEG_3_2 -//#if defined(__linux__) -#pragma message "You are compiling with experimental hardware encode" -//#endif -#endif - FFmpegWriter::FFmpegWriter(string path) : path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), From a1ffa6b13202c8ab2caf85880bc36f924104a134 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 11 Sep 2018 20:30:56 -0700 Subject: [PATCH 023/186] Removed one include --- src/FFmpegReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index caa33de1..e2d5d7bc 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -29,7 +29,7 @@ */ #include "../include/FFmpegReader.h" -#include "libavutil/hwcontext_vaapi.h" +//#include "libavutil/hwcontext_vaapi.h" using namespace openshot; From cfcddd13e5333f1ef0040b26659baba4ecb8ff20 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 13 Sep 2018 12:37:32 -0700 Subject: [PATCH 024/186] Still not able to retreive the maximum dimensions supported by the hardware (line 312 FFmegReader.cpp) Now using defaults of 1950 * 1100 defined in lines 35,36 --- src/FFmpegReader.cpp | 71 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index e2d5d7bc..c89f8cd0 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -29,7 +29,36 @@ */ #include "../include/FFmpegReader.h" -//#include "libavutil/hwcontext_vaapi.h" +#include "libavutil/hwcontext_vaapi.h" + + +#define MAX_SUPPORTED_WIDTH 1950 +#define MAX_SUPPORTED_HEIGHT 1100 + +typedef struct VAAPIDecodeContext { + VAProfile va_profile; + VAEntrypoint va_entrypoint; + VAConfigID va_config; + VAContextID va_context; + + #if FF_API_STRUCT_VAAPI_CONTEXT +// FF_DISABLE_DEPRECATION_WARNINGS + int have_old_context; + struct vaapi_context *old_context; + AVBufferRef *device_ref; +// FF_ENABLE_DEPRECATION_WARNINGS + #endif + + AVHWDeviceContext *device; + AVVAAPIDeviceContext *hwctx; + + AVHWFramesContext *frames; + AVVAAPIFramesContext *hwfc; + + enum AVPixelFormat surface_format; + int surface_count; + } VAAPIDecodeContext; + using namespace openshot; @@ -277,16 +306,12 @@ void FFmpegReader::Open() #if IS_FFMPEG_3_2 if (hw_de_on && hw_de_supported) { AVHWFramesConstraints *constraints = NULL; - // NOT WORKING needs hwconfig config_id !!!!!!!!!!!!!!!!!!!!!!!!!!! - //AVVAAPIHWConfig *hwconfig = NULL; - // void *hwconfig = NULL; - // hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx); - //hwconfig->config_id = ((VAAPIDecodeContext *)pCodecCtx->priv_data)->va_config; - // constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,(void*)hwconfig); - constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,NULL); // No usable information! + void *hwconfig = NULL; + hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx); + // NOT WORKING needs va_config ! + ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config; + constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig); if (constraints) { -// constraints->max_height = 1100; // Just for testing -// constraints->max_width = 1950; // Just for testing if (pCodecCtx->coded_width < constraints->min_width || pCodecCtx->coded_height < constraints->min_height || pCodecCtx->coded_width > constraints->max_width || @@ -302,14 +327,34 @@ void FFmpegReader::Open() } else { // All is just peachy - cerr << "MinWidth : " << constraints->min_width << "MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; - cerr << "Frame width :" << pCodecCtx->coded_width << "Frame height :" << pCodecCtx->coded_height << "\n"; + cerr << "Min width : " << constraints->min_width << " MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; + cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; retry_decode_open = 0; } av_hwframe_constraints_free(&constraints); + if (hwconfig) { + av_freep(&hwconfig); + } } else { - cerr << "Constraints could not be found\n"; + cerr << "Constraints could not be found using default 1k limit\n"; + if (pCodecCtx->coded_width < 0 || + pCodecCtx->coded_height < 0 || + pCodecCtx->coded_width > MAX_SUPPORTED_WIDTH || + pCodecCtx->coded_height > MAX_SUPPORTED_HEIGHT) { + cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; + hw_de_supported = 0; + retry_decode_open = 1; + AV_FREE_CONTEXT(pCodecCtx); + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; + } + } + else { + cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + retry_decode_open = 0; + } } } // if hw_de_on && hw_de_supported #else From 10c8d695957ab184182029d558ffe11ccc0ec9b1 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 13 Sep 2018 14:45:09 -0700 Subject: [PATCH 025/186] Maximum width and height for hardware decode can now be set in preferences --- src/FFmpegReader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index c89f8cd0..725ba524 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -337,11 +337,15 @@ void FFmpegReader::Open() } } else { - cerr << "Constraints could not be found using default 1k limit\n"; + int max_h, max_w; + max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" ))); + max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); + cerr << "Constraints could not be found using default limit\n"; + cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; if (pCodecCtx->coded_width < 0 || pCodecCtx->coded_height < 0 || - pCodecCtx->coded_width > MAX_SUPPORTED_WIDTH || - pCodecCtx->coded_height > MAX_SUPPORTED_HEIGHT) { + pCodecCtx->coded_width > max_w || + pCodecCtx->coded_height > max_h ) { cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; hw_de_supported = 0; retry_decode_open = 1; From 3a2d46826c9fd6249861940181b6b5978e347312 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 13 Sep 2018 18:04:16 -0700 Subject: [PATCH 026/186] Included an if for included files not present in ffmpeg 2 --- src/FFmpegReader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 725ba524..aa3ef4ac 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -29,6 +29,8 @@ */ #include "../include/FFmpegReader.h" + +#if IS_FFMPEG_3_2 #include "libavutil/hwcontext_vaapi.h" @@ -58,6 +60,7 @@ typedef struct VAAPIDecodeContext { enum AVPixelFormat surface_format; int surface_count; } VAAPIDecodeContext; +#endif using namespace openshot; From d97a1bc85057212e83c6e575772c2f91232082f6 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 14 Sep 2018 14:03:03 -0700 Subject: [PATCH 027/186] Commented code that isn't working yet but complicates compilation by needing extra packages. --- src/FFmpegReader.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index aa3ef4ac..f8c5f4af 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -31,12 +31,12 @@ #include "../include/FFmpegReader.h" #if IS_FFMPEG_3_2 -#include "libavutil/hwcontext_vaapi.h" +//#include "libavutil/hwcontext_vaapi.h" #define MAX_SUPPORTED_WIDTH 1950 #define MAX_SUPPORTED_HEIGHT 1100 - +/* typedef struct VAAPIDecodeContext { VAProfile va_profile; VAEntrypoint va_entrypoint; @@ -60,6 +60,7 @@ typedef struct VAAPIDecodeContext { enum AVPixelFormat surface_format; int surface_count; } VAAPIDecodeContext; + */ #endif @@ -312,7 +313,7 @@ void FFmpegReader::Open() void *hwconfig = NULL; hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx); // NOT WORKING needs va_config ! - ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config; + // ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config; constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig); if (constraints) { if (pCodecCtx->coded_width < constraints->min_width || From 08c7f88376fc2e79c265a654fa36ba90a5d19f38 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 14 Sep 2018 14:40:29 -0700 Subject: [PATCH 028/186] The part of the code that should get the config that is used to get the constraints of the GPU is now inside a #if . One can enable it by setting the constant in line 33 of FFmpegReader.cpp to 1. Do not enable that part unless you want to fid a way that works as it also needs the package libva-dev (Ubuntu) to be installed. --- src/FFmpegReader.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index f8c5f4af..3b508f23 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -30,13 +30,15 @@ #include "../include/FFmpegReader.h" +#define PRAYFORAWONDER 0 + #if IS_FFMPEG_3_2 -//#include "libavutil/hwcontext_vaapi.h" - - #define MAX_SUPPORTED_WIDTH 1950 #define MAX_SUPPORTED_HEIGHT 1100 -/* + +#if PRAYFORAWONDER +#include "libavutil/hwcontext_vaapi.h" + typedef struct VAAPIDecodeContext { VAProfile va_profile; VAEntrypoint va_entrypoint; @@ -60,7 +62,8 @@ typedef struct VAAPIDecodeContext { enum AVPixelFormat surface_format; int surface_count; } VAAPIDecodeContext; - */ + + #endif #endif @@ -313,7 +316,9 @@ void FFmpegReader::Open() void *hwconfig = NULL; hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx); // NOT WORKING needs va_config ! - // ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config; + #if PRAYFORAWONDER + ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config; + #endif constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig); if (constraints) { if (pCodecCtx->coded_width < constraints->min_width || From df9d1a57170e387613d30fcd4a2283d73459a450 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 16 Sep 2018 18:14:31 -0700 Subject: [PATCH 029/186] Implement the use of CRF instead od kB/s or MB/s for some formats: VP8, VP9, h264, h265 0 crf with VP9 is lossless 0 crf with VP8, h264, h265 should be lossless --- src/FFmpegWriter.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index c16ce7a8..b1d98a80 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -241,7 +241,9 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i info.pixel_ratio.num = pixel_ratio.num; info.pixel_ratio.den = pixel_ratio.den; } - if (bit_rate >= 1000) + if (bit_rate >= 1000) // bit_rate is the bitrate in b/s + info.video_bit_rate = bit_rate; + if ((bit_rate > 0) && (bit_rate <=63)) // bit_rate is the crf value info.video_bit_rate = bit_rate; info.interlaced_frame = interlaced; @@ -1040,7 +1042,30 @@ AVStream* FFmpegWriter::add_video_stream() #endif /* Init video encoder options */ - c->bit_rate = info.video_bit_rate; + if (info.video_bit_rate > 1000) { + c->bit_rate = info.video_bit_rate; + } +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + else { + switch (c->codec_id) { + case AV_CODEC_ID_VP8 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + break; + case AV_CODEC_ID_VP9 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + if (info.video_bit_rate == 0) { + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + case AV_CODEC_ID_H264 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + break; + case AV_CODEC_ID_H265 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + break; + } + } +#endif //TODO: Implement variable bitrate feature (which actually works). This implementation throws //invalid bitrate errors and rc buffer underflow errors, etc... From 38f4bc6a216a33344c3b0857dd302d1e2bbd96f2 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 18 Sep 2018 11:10:16 -0700 Subject: [PATCH 030/186] Adding aoutput if decode device is not found --- src/FFmpegReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 3b508f23..b9be0b54 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -292,6 +292,7 @@ void FFmpegReader::Open() // Check if it is there and writable if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default + cerr << "\n\n\nDecode Device not present using default\n\n\n"; } hw_device_ctx = NULL; // Here the first hardware initialisations are made From 800dc874592e2451adde09eb39bd09416fac8236 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 18 Sep 2018 11:35:19 -0700 Subject: [PATCH 031/186] Information is printed to the console where openshot was started that shows if hardware decode or siftware decode is being used --- src/FFmpegReader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index b9be0b54..7dbb21d9 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -292,7 +292,7 @@ void FFmpegReader::Open() // Check if it is there and writable if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default - cerr << "\n\n\nDecode Device not present using default\n\n\n"; + cerr << "\n\n\nDecode Device not present using default\n\n\n"; } hw_device_ctx = NULL; // Here the first hardware initialisations are made @@ -337,6 +337,7 @@ void FFmpegReader::Open() } else { // All is just peachy + cerr << "\nDecode hardware acceleration is used\n"; cerr << "Min width : " << constraints->min_width << " MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; retry_decode_open = 0; @@ -351,12 +352,13 @@ void FFmpegReader::Open() max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" ))); max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); cerr << "Constraints could not be found using default limit\n"; - cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; if (pCodecCtx->coded_width < 0 || pCodecCtx->coded_height < 0 || pCodecCtx->coded_width > max_w || pCodecCtx->coded_height > max_h ) { cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; + cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; + cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; hw_de_supported = 0; retry_decode_open = 1; AV_FREE_CONTEXT(pCodecCtx); @@ -366,11 +368,16 @@ void FFmpegReader::Open() } } else { + cerr << "\nDecode hardware acceleration is used\n"; + cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; retry_decode_open = 0; } } } // if hw_de_on && hw_de_supported + else { + cerr << "\nDecode in software is used\n"; + } #else retry_decode_open = 0; #endif From 161acb3d7d5d95284f10f05287465c268bc692f3 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 18 Sep 2018 12:38:53 -0700 Subject: [PATCH 032/186] Include messages in the compile display to make sure the right ffmpeg version is used (>= 3.2) to get hardware acceleration --- src/FFmpegReader.cpp | 6 ++++++ src/FFmpegWriter.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 7dbb21d9..76c0ddd0 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -32,6 +32,12 @@ #define PRAYFORAWONDER 0 +#if IS_FFMPEG_3_2 +#pragma message "You are compiling with experimental hardware decode" +#else +#pragma message "You are compiling only with software decode" +#endif + #if IS_FFMPEG_3_2 #define MAX_SUPPORTED_WIDTH 1950 #define MAX_SUPPORTED_HEIGHT 1100 diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index b1d98a80..0b978d8a 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -32,6 +32,12 @@ using namespace openshot; +#if IS_FFMPEG_3_2 +#pragma message "You are compiling with experimental hardware encode" +#else +#pragma message "You are compiling only with software encode" +#endif + #if IS_FFMPEG_3_2 int hw_en_on = 1; // Is set in UI int hw_en_supported = 0; // Is set by FFmpegWriter From 1f36d122984390b8d0da2d0e2acc0d0adcca2a15 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 18 Sep 2018 14:45:56 -0500 Subject: [PATCH 033/186] Moving delcaration outside of conditional compile logic (so Windows and Mac builds work) --- src/FFmpegWriter.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index b1d98a80..295c7c64 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1235,13 +1235,14 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { + char *dev_hw = NULL; #if defined(__linux__) - // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set - char *dev_hw = getenv( "HW_EN_DEVICE_SET" ); - // Check if it is there and writable - if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { - dev_hw = NULL; // use default - } + // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set + dev_hw = getenv( "HW_EN_DEVICE_SET" ); + // Check if it is there and writable + if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { + dev_hw = NULL; // use default + } #else dev_hw = NULL; // use default #endif From 555eb1f3e2237caa51a7e573cea0cab18177f2f7 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 18 Sep 2018 13:08:42 -0700 Subject: [PATCH 034/186] Use logger for messages about acceleration --- src/FFmpegReader.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 76c0ddd0..aab11460 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -35,7 +35,7 @@ #if IS_FFMPEG_3_2 #pragma message "You are compiling with experimental hardware decode" #else -#pragma message "You are compiling only with software decode" +#pragma message "You are compiling only with software decode" #endif #if IS_FFMPEG_3_2 @@ -298,7 +298,8 @@ void FFmpegReader::Open() // Check if it is there and writable if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { dev_hw = NULL; // use default - cerr << "\n\n\nDecode Device not present using default\n\n\n"; + //cerr << "\n\n\nDecode Device not present using default\n\n\n"; + ZmqLogger::Instance()->AppendDebugMethod("\n\n\nDecode Device not present using default\n\n\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } hw_device_ctx = NULL; // Here the first hardware initialisations are made @@ -332,6 +333,7 @@ void FFmpegReader::Open() pCodecCtx->coded_height < constraints->min_height || pCodecCtx->coded_width > constraints->max_width || pCodecCtx->coded_height > constraints->max_height) { + ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; hw_de_supported = 0; retry_decode_open = 1; @@ -343,6 +345,7 @@ void FFmpegReader::Open() } else { // All is just peachy + ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); cerr << "\nDecode hardware acceleration is used\n"; cerr << "Min width : " << constraints->min_width << " MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; @@ -362,6 +365,7 @@ void FFmpegReader::Open() pCodecCtx->coded_height < 0 || pCodecCtx->coded_width > max_w || pCodecCtx->coded_height > max_h ) { + ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; @@ -374,6 +378,7 @@ void FFmpegReader::Open() } } else { + ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); cerr << "\nDecode hardware acceleration is used\n"; cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; @@ -382,6 +387,7 @@ void FFmpegReader::Open() } } // if hw_de_on && hw_de_supported else { + ZmqLogger::Instance()->AppendDebugMethod("\nDecode in software is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); cerr << "\nDecode in software is used\n"; } #else From 0b260a90879d50a26b22bd8f6640de85bb8023db Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 18 Sep 2018 15:31:34 -0700 Subject: [PATCH 035/186] Code cleanup and move messages regarding hardware acceleration to Debug Logger --- src/FFmpegReader.cpp | 31 ++++++++++++++++--------------- src/FFmpegWriter.cpp | 15 ++++++++++----- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index aab11460..2225e72c 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -334,7 +334,7 @@ void FFmpegReader::Open() pCodecCtx->coded_width > constraints->max_width || pCodecCtx->coded_height > constraints->max_height) { ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; + //cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; hw_de_supported = 0; retry_decode_open = 1; AV_FREE_CONTEXT(pCodecCtx); @@ -345,10 +345,10 @@ void FFmpegReader::Open() } else { // All is just peachy - ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - cerr << "\nDecode hardware acceleration is used\n"; - cerr << "Min width : " << constraints->min_width << " MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; - cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Min width :", constraints->min_width, "Min Height :", constraints->min_height, "MaxWidth :", constraints->max_width, "MaxHeight :", constraints->max_height, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height); + //cerr << "\nDecode hardware acceleration is used\n"; + //cerr << "Min width : " << constraints->min_width << " MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; + //cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; retry_decode_open = 0; } av_hwframe_constraints_free(&constraints); @@ -360,15 +360,16 @@ void FFmpegReader::Open() int max_h, max_w; max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" ))); max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); - cerr << "Constraints could not be found using default limit\n"; + ZmqLogger::Instance()->AppendDebugMethod("Constraints could not be found using default limit\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + //cerr << "Constraints could not be found using default limit\n"; if (pCodecCtx->coded_width < 0 || pCodecCtx->coded_height < 0 || pCodecCtx->coded_width > max_w || pCodecCtx->coded_height > max_h ) { - ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; - cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; - cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height, "", -1, "", -1); + //cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; + //cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; + //cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; hw_de_supported = 0; retry_decode_open = 1; AV_FREE_CONTEXT(pCodecCtx); @@ -378,17 +379,17 @@ void FFmpegReader::Open() } } else { - ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - cerr << "\nDecode hardware acceleration is used\n"; - cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; - cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height, "", -1, "", -1); + //cerr << "\nDecode hardware acceleration is used\n"; + //cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; + //cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; retry_decode_open = 0; } } } // if hw_de_on && hw_de_supported else { ZmqLogger::Instance()->AppendDebugMethod("\nDecode in software is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - cerr << "\nDecode in software is used\n"; + //cerr << "\nDecode in software is used\n"; } #else retry_decode_open = 0; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 840acba1..9791043c 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1254,7 +1254,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #endif if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, dev_hw, NULL, 0) < 0) { - cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video : Codec name: ", info.vcodec.c_str(), -1, " ERROR creating\n", -1, "", -1, "", -1, "", -1, "", -1); + //cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; throw InvalidCodec("Could not create hwdevice", path); } } @@ -1860,10 +1861,12 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra error_code = ret; if (ret < 0 ) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame not sent)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - if (ret == AVERROR(EAGAIN) ) + if (ret == AVERROR(EAGAIN) ) { cerr << "Frame EAGAIN" << "\n"; - if (ret == AVERROR_EOF ) + } + if (ret == AVERROR_EOF ) { cerr << "Frame AVERROR_EOF" << "\n"; + } avcodec_send_frame(video_codec, NULL); } else { @@ -1884,10 +1887,12 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra #if LIBAVFORMAT_VERSION_MAJOR >= 54 // Write video packet (older than FFmpeg 3.2) error_code = avcodec_encode_video2(video_codec, &pkt, frame_final, &got_packet_ptr); - if (error_code != 0 ) + if (error_code != 0 ) { cerr << "Frame AVERROR_EOF" << "\n"; - if (got_packet_ptr == 0 ) + } + if (got_packet_ptr == 0 ) { cerr << "Frame gotpacket error" << "\n"; + } #else // Write video packet (even older versions of FFmpeg) int video_outbuf_size = 200000; From f2323da447b7584f8c7b91d6aca55afe1a3d0ec9 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Wed, 19 Sep 2018 17:51:21 -0700 Subject: [PATCH 036/186] Preparation to choose the graphics card not by name but by number 1, 2, 3. First implementation just for Linux and decode --- src/FFmpegReader.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2225e72c..547169b4 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -294,17 +294,42 @@ void FFmpegReader::Open() // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set char *dev_hw = NULL; + char adapter[256]; + char *adapter_ptr = NULL; + int adapter_num; dev_hw = getenv( "HW_DE_DEVICE_SET" ); + if( dev_hw != NULL) { + adapter_num = atoi(dev_hw); + if (adapter_num < 3 && adapter_num >=0) { + #if defined(__linux__) + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + adapter_ptr = adapter; + #elif defined(_WIN32) + adapter_ptr = NULL; + #elif defined(__APPLE__) + adapter_ptr = NULL; + #endif + } + else { + adapter_ptr = NULL; // Just to be sure + } + } // Check if it is there and writable - if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { - dev_hw = NULL; // use default + #if defined(__linux__) + if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { + #elif defined(_WIN32) + if( adapter_ptr != NULL ) { + #elif defined(__APPLE__) + if( adapter_ptr != NULL ) { + #endif + adapter_ptr = NULL; // use default //cerr << "\n\n\nDecode Device not present using default\n\n\n"; - ZmqLogger::Instance()->AppendDebugMethod("\n\n\nDecode Device not present using default\n\n\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } hw_device_ctx = NULL; // Here the first hardware initialisations are made pCodecCtx->get_format = get_hw_dec_format; - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, dev_hw, NULL, 0) >= 0) { + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); } From 02273973390311edb06cb44a886a5b26cc698d94 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Wed, 19 Sep 2018 21:37:12 -0700 Subject: [PATCH 037/186] Set the graphics card used to decode or encode by setting the environment variable HW_EN_DEVICE_SET for enncoding and HW_DE_DEVICE_SET for decoding. The first card is 0, the second 1 and so on. For now only running on Linux. --- src/FFmpegReader.cpp | 1 + src/FFmpegWriter.cpp | 42 +++++++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 547169b4..912c1e2f 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -303,6 +303,7 @@ void FFmpegReader::Open() if (adapter_num < 3 && adapter_num >=0) { #if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + // Maybe 127 is better because the first card would be 1?! adapter_ptr = adapter; #elif defined(_WIN32) adapter_ptr = NULL; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 9791043c..497538df 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1242,18 +1242,42 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { char *dev_hw = NULL; - #if defined(__linux__) + char adapter[256]; + char *adapter_ptr = NULL; + int adapter_num; // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set dev_hw = getenv( "HW_EN_DEVICE_SET" ); - // Check if it is there and writable - if( dev_hw != NULL && access( dev_hw, W_OK ) == -1 ) { - dev_hw = NULL; // use default - } - #else - dev_hw = NULL; // use default - #endif + if( dev_hw != NULL) { + adapter_num = atoi(dev_hw); + if (adapter_num < 3 && adapter_num >=0) { + #if defined(__linux__) + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + // Maybe 127 is better because the first card would be 1?! + adapter_ptr = adapter; + #elif defined(_WIN32) + adapter_ptr = NULL; + #elif defined(__APPLE__) + adapter_ptr = NULL; + #endif + } + else { + adapter_ptr = NULL; // Just to be sure + } + } +// Check if it is there and writable + #if defined(__linux__) + if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { + #elif defined(_WIN32) + if( adapter_ptr != NULL ) { + #elif defined(__APPLE__) + if( adapter_ptr != NULL ) { + #endif + adapter_ptr = NULL; // use default + //cerr << "\n\n\nEncode Device not present using default\n\n\n"; + ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, - dev_hw, NULL, 0) < 0) { + adapter_ptr, NULL, 0) < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video : Codec name: ", info.vcodec.c_str(), -1, " ERROR creating\n", -1, "", -1, "", -1, "", -1, "", -1); //cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; throw InvalidCodec("Could not create hwdevice", path); From b925a9ba2582833354ff89c9b6928352229b2618 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 23 Sep 2018 09:51:56 -0700 Subject: [PATCH 038/186] protect add_effect with critical --- src/Timeline.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 34dab1d8..fe7c1022 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -281,6 +281,7 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in /* Apply effects to the source frame (if any). If multiple clips are overlapping, only process the * effects on the top clip. */ if (is_top_clip && source_frame) + #pragma omp critical (T_addLayer) source_frame = apply_effects(source_frame, timeline_frame_number, source_clip->Layer()); // Declare an image to hold the source frame's image From 1cd8401a58394bd49f61eb17628e67b5f05c8088 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 23 Sep 2018 10:09:20 -0700 Subject: [PATCH 039/186] Put brackets in the if statement to show that the pragma critical and the followwing command are one block. --- src/Timeline.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index fe7c1022..71805837 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -280,9 +280,10 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in /* Apply effects to the source frame (if any). If multiple clips are overlapping, only process the * effects on the top clip. */ - if (is_top_clip && source_frame) + if (is_top_clip && source_frame) { #pragma omp critical (T_addLayer) source_frame = apply_effects(source_frame, timeline_frame_number, source_clip->Layer()); + } // Declare an image to hold the source frame's image std::shared_ptr source_image; From 53eec32d9eb061f32a26e1c41c4aee73b67ad57c Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 25 Sep 2018 08:04:48 -0700 Subject: [PATCH 040/186] In case CRF is not supported like in hardware accelerated codecs or in mpeg2 a bitrate is calculated that should be close to the one expected with the given CRF value. --- src/FFmpegWriter.cpp | 59 +++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 497538df..207d545f 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1053,23 +1053,48 @@ AVStream* FFmpegWriter::add_video_stream() } #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) else { - switch (c->codec_id) { - case AV_CODEC_ID_VP8 : - av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); - break; - case AV_CODEC_ID_VP9 : - av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); - if (info.video_bit_rate == 0) { - av_opt_set_int(c->priv_data, "lossless", 1, 0); - } - break; - case AV_CODEC_ID_H264 : - av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); - break; - case AV_CODEC_ID_H265 : - av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); - break; - } + if (hw_en_on) { + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); + } + else { + switch (c->codec_id) { + case AV_CODEC_ID_VP8 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + break; + case AV_CODEC_ID_VP9 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + if (info.video_bit_rate == 0) { + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + case AV_CODEC_ID_H264 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + break; + case AV_CODEC_ID_H265 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + break; + default: + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); + } + } } #endif From 325f58f7731c3c58c29f172d69f4ac6a279f97a8 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 15 Nov 2018 22:04:20 -0800 Subject: [PATCH 041/186] Changes to use AV1 if ffmpeg >= 4.0 is used with libaom support --- src/FFmpegWriter.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 207d545f..66befe5c 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1067,6 +1067,12 @@ AVStream* FFmpegWriter::add_video_stream() } else { switch (c->codec_id) { +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + case AV_CODEC_ID_AV1 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + c->bit_rate = 0; + break; +#endif case AV_CODEC_ID_VP8 : av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); break; From 514cb1134014d4604ec4062981e75f6d37fa9660 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 25 Nov 2018 20:28:25 -0800 Subject: [PATCH 042/186] When multiple graphics cards are installed the import with hardware acceleration has to have the card number set or the opening of the device will fail. TODO check multiple formats. Right now only the first is checked which is vaapi. --- src/FFmpegReader.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index d78b7c8f..231d41c7 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -300,21 +300,24 @@ void FFmpegReader::Open() dev_hw = getenv( "HW_DE_DEVICE_SET" ); if( dev_hw != NULL) { adapter_num = atoi(dev_hw); - if (adapter_num < 3 && adapter_num >=0) { - #if defined(__linux__) - snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); - // Maybe 127 is better because the first card would be 1?! - adapter_ptr = adapter; - #elif defined(_WIN32) - adapter_ptr = NULL; - #elif defined(__APPLE__) - adapter_ptr = NULL; - #endif - } - else { - adapter_ptr = NULL; // Just to be sure - } + } else { + adapter_num = 0; } + if (adapter_num < 3 && adapter_num >=0) { + #if defined(__linux__) + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + // Maybe 127 is better because the first card would be 1?! + adapter_ptr = adapter; + #elif defined(_WIN32) + adapter_ptr = NULL; + #elif defined(__APPLE__) + adapter_ptr = NULL; + #endif + } + else { + adapter_ptr = NULL; // Just to be sure + } + //} // Check if it is there and writable #if defined(__linux__) if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { @@ -329,6 +332,8 @@ void FFmpegReader::Open() } hw_device_ctx = NULL; // Here the first hardware initialisations are made + // TODO: check for each format in an extra call + // Now only vaapi the first in the list is found pCodecCtx->get_format = get_hw_dec_format; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { From e7f2494040fb0a17c5f8f0c90789a66140fe8e5d Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 26 Nov 2018 09:36:21 -0800 Subject: [PATCH 043/186] First changes to make hardware accelerated DECODE work with decoders other than vaapi. Encode is already working for nvenc; nvidia driver 396 has to be installed for nvenc to work. On nVidia card turn accelerated decode off in Preferences->Performance for now --- include/FFmpegReader.h | 2 +- src/FFmpegReader.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index f571af73..62437d7a 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -149,7 +149,7 @@ namespace openshot int hw_de_supported = 0; // Is set by FFmpegReader #if IS_FFMPEG_3_2 AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; - AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_NONE; #endif int is_hardware_decode_supported(int codecid); diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 231d41c7..9ed85114 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -79,7 +79,7 @@ int hw_de_on = 1; // Is set in UI //int hw_de_supported = 0; // Is set by FFmpegReader #if IS_FFMPEG_3_2 AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE; -AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; +AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE; #endif FFmpegReader::FFmpegReader(string path) @@ -334,6 +334,7 @@ void FFmpegReader::Open() // Here the first hardware initialisations are made // TODO: check for each format in an extra call // Now only vaapi the first in the list is found + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { From 1713fecc9080f3b68c9b458122e4fe3610b55f59 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 26 Nov 2018 13:31:53 -0800 Subject: [PATCH 044/186] More adjustments to enable hardware decode with nvdec/cuvid --- src/FFmpegReader.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 9ed85114..941435f3 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -155,7 +155,7 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if IS_FFMPEG_3_2 -static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +static enum AVPixelFormat get_hw_dec_format_va(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -166,21 +166,69 @@ static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPi hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; return *p; break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; + } + +static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { case AV_PIX_FMT_CUDA: hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; return *p; break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; + } + +static enum AVPixelFormat get_hw_dec_format_dx(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { case AV_PIX_FMT_DXVA2_VLD: hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; return *p; break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; + } + +static enum AVPixelFormat get_hw_dec_format_d3(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { case AV_PIX_FMT_D3D11: hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; return *p; break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; + } + +static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { case AV_PIX_FMT_QSV: hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; @@ -334,16 +382,54 @@ void FFmpegReader::Open() // Here the first hardware initialisations are made // TODO: check for each format in an extra call // Now only vaapi the first in the list is found + #if defined(__linux__) hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format; + pCodecCtx->get_format = get_hw_dec_format_va; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed.", path); + throw InvalidCodec("Hardware device reference create failed vaapi.", path); } } else { - throw InvalidCodec("Hardware device create failed.", path); + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + pCodecCtx->get_format = get_hw_dec_format_cu; + hw_device_ctx = NULL; + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed cuda.", path); + } + } + else { + throw InvalidCodec("Hardware device create failed.", path); + + } } + #endif + #if defined(_WIN32) + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + pCodecCtx->get_format = get_hw_dec_format_dx; + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed vaapi.", path); + } + } + else { + throw InvalidCodec("Hardware device create failed.", path); + } + #endif + #if defined(__APPLE__) + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed vaapi.", path); + } + } + else { + throw InvalidCodec("Hardware device create failed.", path); + } + #endif + } #endif // Open video codec From 7cadeb364b94226f770fc077b3c759537f452a61 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 26 Nov 2018 18:08:08 -0800 Subject: [PATCH 045/186] More cleanup --- src/FFmpegReader.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 941435f3..2f641ab8 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -155,6 +155,7 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if IS_FFMPEG_3_2 +#if defined(__linux__) static enum AVPixelFormat get_hw_dec_format_va(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -188,7 +189,9 @@ static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum A ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } +#endif +#if defined(_WIN32) static enum AVPixelFormat get_hw_dec_format_dx(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -222,7 +225,9 @@ static enum AVPixelFormat get_hw_dec_format_d3(AVCodecContext *ctx, const enum A ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } +#endif +#if defined(__APPLE__) static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -239,6 +244,7 @@ static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum A ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } +#endif int FFmpegReader::is_hardware_decode_supported(int codecid) { @@ -345,7 +351,7 @@ void FFmpegReader::Open() char adapter[256]; char *adapter_ptr = NULL; int adapter_num; - dev_hw = getenv( "HW_DE_DEVICE_SET" ); + dev_hw = getenv( "HW_DE_DEVICE_SET" ); // The first card is 0 if( dev_hw != NULL) { adapter_num = atoi(dev_hw); } else { @@ -354,7 +360,6 @@ void FFmpegReader::Open() if (adapter_num < 3 && adapter_num >=0) { #if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); - // Maybe 127 is better because the first card would be 1?! adapter_ptr = adapter; #elif defined(_WIN32) adapter_ptr = NULL; @@ -380,8 +385,6 @@ void FFmpegReader::Open() } hw_device_ctx = NULL; // Here the first hardware initialisations are made - // TODO: check for each format in an extra call - // Now only vaapi the first in the list is found #if defined(__linux__) hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; @@ -401,7 +404,6 @@ void FFmpegReader::Open() } else { throw InvalidCodec("Hardware device create failed.", path); - } } #endif @@ -410,19 +412,29 @@ void FFmpegReader::Open() pCodecCtx->get_format = get_hw_dec_format_dx; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed vaapi.", path); + throw InvalidCodec("Hardware device reference create failed dxva2.", path); } } else { - throw InvalidCodec("Hardware device create failed.", path); - } + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11; + pCodecCtx->get_format = get_hw_dec_format_cu; + hw_device_ctx = NULL; + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { + if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { + throw InvalidCodec("Hardware device reference create failed d3d11.", path); + } + } + else { + throw InvalidCodec("Hardware device create failed.", path); + } + } #endif #if defined(__APPLE__) hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed vaapi.", path); + throw InvalidCodec("Hardware device reference create failed qsv.", path); } } else { From d07e8518232f06b4b18ebc0237437670d54b56aa Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Dec 2018 10:34:24 -0800 Subject: [PATCH 046/186] Hardware decode and encode can now be configured completely in Preferences->Performance. The old enable hardware decode is disabled. Now the graphics card can be chosen (0 is the first one) that should be used for encode and/or decode. They needn't be the same! nVidia decode still not working nVidia encode is working with driver 396 Vaapi should be working. mesa-va-drivers must be installed for AMD i965-va-driver must be installed for intel GPUs. Using one card to decode and one to encode an option with laptops with an iGPU and a dedicated GPU (dGPU), as an example. --- src/FFmpegReader.cpp | 72 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2f641ab8..2d7aaafb 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -275,13 +275,29 @@ void FFmpegReader::Open() // Initialize format context pFormatCtx = NULL; - char * val = getenv( "OS2_DECODE_HW" ); + // Old version turn hardware decode on + /*char * val = getenv( "OS2_DECODE_HW" ); if (val == NULL) { hw_de_on = 0; } else{ hw_de_on = (val[0] == '1')? 1 : 0; - } + }*/ + + // New version turn hardware decode on + { + char *decoder_hw = NULL; + decoder_hw = getenv( "HW_DECODER" ); + if(decoder_hw != NULL) { + if( strncmp(decoder_hw,"NONE",4) == 0) { + hw_de_on = 0; + } else { + hw_de_on = 1; + } + } else { + hw_de_on = 0; + } + } // Open video file if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, NULL) != 0) @@ -348,6 +364,7 @@ void FFmpegReader::Open() // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set char *dev_hw = NULL; + char *decoder_hw = NULL; char adapter[256]; char *adapter_ptr = NULL; int adapter_num; @@ -361,6 +378,38 @@ void FFmpegReader::Open() #if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); adapter_ptr = adapter; + decoder_hw = getenv( "HW_DECODER" ); + if(decoder_hw != NULL) { + if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + } + if (strncmp(decoder_hw,"HW_DE_VAAPI",11) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + } + if (strncmp(decoder_hw,"HW_DE_NVDEC",11) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + pCodecCtx->get_format = get_hw_dec_format_cu; + } + } else { + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + } + + /* This is a hack: + my first card is AMD, my second card is nVidia + */ + switch (adapter_num) { + case 1: + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + pCodecCtx->get_format = get_hw_dec_format_cu; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + break; + } #elif defined(_WIN32) adapter_ptr = NULL; #elif defined(__APPLE__) @@ -386,25 +435,16 @@ void FFmpegReader::Open() hw_device_ctx = NULL; // Here the first hardware initialisations are made #if defined(__linux__) - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; + //hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + //pCodecCtx->get_format = get_hw_dec_format_cu; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { + cerr << "\n\n**** HW device create OK ******** \n\n"; if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed vaapi.", path); + throw InvalidCodec("Hardware device reference create failed cuda.", path); } } else { - hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - pCodecCtx->get_format = get_hw_dec_format_cu; - hw_device_ctx = NULL; - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { - if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed cuda.", path); - } - } - else { - throw InvalidCodec("Hardware device create failed.", path); - } + throw InvalidCodec("Hardware device create failed.", path); } #endif #if defined(_WIN32) From 70954f800c0f87cf6199e768586ca99dce017dd2 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Dec 2018 15:54:29 -0800 Subject: [PATCH 047/186] Typo, plus removed hack for my hardware --- src/FFmpegReader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2d7aaafb..a3e247f5 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -400,7 +400,7 @@ void FFmpegReader::Open() /* This is a hack: my first card is AMD, my second card is nVidia */ - switch (adapter_num) { +/* switch (adapter_num) { case 1: hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; pCodecCtx->get_format = get_hw_dec_format_cu; @@ -409,7 +409,7 @@ void FFmpegReader::Open() hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; break; - } + }*/ #elif defined(_WIN32) adapter_ptr = NULL; #elif defined(__APPLE__) @@ -440,7 +440,7 @@ void FFmpegReader::Open() if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { cerr << "\n\n**** HW device create OK ******** \n\n"; if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed cuda.", path); + throw InvalidCodec("Hardware device reference create failed.", path); } } else { From 23e287110d2b6950861a1460a802f310b9fb6f5a Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 8 Dec 2018 18:11:06 -0800 Subject: [PATCH 048/186] Bring Windows and Mac up to date --- src/FFmpegReader.cpp | 84 +++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index a3e247f5..6d5b058a 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -397,23 +397,42 @@ void FFmpegReader::Open() pCodecCtx->get_format = get_hw_dec_format_va; } - /* This is a hack: - my first card is AMD, my second card is nVidia - */ -/* switch (adapter_num) { - case 1: - hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - pCodecCtx->get_format = get_hw_dec_format_cu; - break; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; - break; - }*/ #elif defined(_WIN32) adapter_ptr = NULL; + decoder_hw = getenv( "HW_DECODER" ); + if(decoder_hw != NULL) { + if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + pCodecCtx->get_format = get_hw_dec_format_dx; + } + if (strncmp(decoder_hw,"HW_DE_WINDOWS_DXVA2",19) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + pCodecCtx->get_format = get_hw_dec_format_dx; + } + if (strncmp(decoder_hw,"HW_DE_WINDOWS_D3D11",19) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11; + pCodecCtx->get_format = get_hw_dec_format_d3; + } + } else { + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + pCodecCtx->get_format = get_hw_dec_format_dx; + } #elif defined(__APPLE__) adapter_ptr = NULL; + decoder_hw = getenv( "HW_DECODER" ); + if(decoder_hw != NULL) { + if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + } + if (strncmp(decoder_hw,"HW_DE_MACOS",11) == 0) { //Will never happen + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + } + } else { + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + } #endif } else { @@ -429,14 +448,10 @@ void FFmpegReader::Open() if( adapter_ptr != NULL ) { #endif adapter_ptr = NULL; // use default - //cerr << "\n\n\nDecode Device not present using default\n\n\n"; ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } hw_device_ctx = NULL; // Here the first hardware initialisations are made - #if defined(__linux__) - //hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - //pCodecCtx->get_format = get_hw_dec_format_cu; if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { cerr << "\n\n**** HW device create OK ******** \n\n"; if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { @@ -446,41 +461,6 @@ void FFmpegReader::Open() else { throw InvalidCodec("Hardware device create failed.", path); } - #endif - #if defined(_WIN32) - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; - pCodecCtx->get_format = get_hw_dec_format_dx; - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { - if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed dxva2.", path); - } - } - else { - hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11; - pCodecCtx->get_format = get_hw_dec_format_cu; - hw_device_ctx = NULL; - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { - if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed d3d11.", path); - } - } - else { - throw InvalidCodec("Hardware device create failed.", path); - } - } - #endif - #if defined(__APPLE__) - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { - if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { - throw InvalidCodec("Hardware device reference create failed qsv.", path); - } - } - else { - throw InvalidCodec("Hardware device create failed.", path); - } - #endif } #endif From de1bd4f50647f2a4eb0c971419b711d3957c3654 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 9 Dec 2018 09:02:46 -0800 Subject: [PATCH 049/186] Typos in Windows part --- src/FFmpegReader.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 6d5b058a..f541c295 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -402,19 +402,19 @@ void FFmpegReader::Open() decoder_hw = getenv( "HW_DECODER" ); if(decoder_hw != NULL) { if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; } if (strncmp(decoder_hw,"HW_DE_WINDOWS_DXVA2",19) == 0) { //Will never happen - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; } if (strncmp(decoder_hw,"HW_DE_WINDOWS_D3D11",19) == 0) { //Will never happen - hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11; + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; pCodecCtx->get_format = get_hw_dec_format_d3; } } else { - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2_VLD; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; } #elif defined(__APPLE__) @@ -457,6 +457,14 @@ void FFmpegReader::Open() if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); } + /* + ret = av_hwframe_ctx_init(pCodecCtx->hw_device_ctx); + ret = av_hwframe_ctx_init(ist->hw_frames_ctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error initializing a CUDA frame pool\n"); + return ret; + } + */ } else { throw InvalidCodec("Hardware device create failed.", path); From dac2c9a58c2ebefed4212ec0e49d072b859dc502 Mon Sep 17 00:00:00 2001 From: Jeff Shillitto Date: Sat, 15 Dec 2018 21:55:00 +1100 Subject: [PATCH 050/186] Add a text background colored box option to the text reader --- include/TextReader.h | 7 ++++++- src/TextReader.cpp | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/TextReader.h b/include/TextReader.h index d7d653d2..8e0bc18d 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -90,6 +90,7 @@ namespace openshot double size; string text_color; string background_color; + string text_background_color; std::shared_ptr image; list lines; bool is_open; @@ -110,9 +111,13 @@ namespace openshot /// @param font The font of the text /// @param size The size of the text /// @param text_color The color of the text - /// @param background_color The background color of the text (also supports Transparent) + /// @param background_color The background color of the text frame image (also supports Transparent) TextReader(int width, int height, int x_offset, int y_offset, GravityType gravity, string text, string font, double size, string text_color, string background_color); + /// Draw a box under rendered text using the specified color. + /// @param text_background_color The background color behind the text + void SetTextBackgroundColor(string color); + /// Close Reader void Close(); diff --git a/src/TextReader.cpp b/src/TextReader.cpp index 8234aa5d..245ca6a8 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -45,6 +45,14 @@ TextReader::TextReader(int width, int height, int x_offset, int y_offset, Gravit Close(); } +void TextReader::SetTextBackgroundColor(string color) { + text_background_color = color; + + // Open and Close the reader, to populate it's attributes (such as height, width, etc...) plus the text background color + Open(); + Close(); +} + // Open reader void TextReader::Open() { @@ -97,6 +105,10 @@ void TextReader::Open() lines.push_back(Magick::DrawablePointSize(size)); lines.push_back(Magick::DrawableText(x_offset, y_offset, text)); + if (!text_background_color.empty()) { + lines.push_back(Magick::DrawableTextUnderColor(Magick::Color(text_background_color))); + } + // Draw image image->draw(lines); @@ -190,6 +202,7 @@ Json::Value TextReader::JsonValue() { root["size"] = size; root["text_color"] = text_color; root["background_color"] = background_color; + root["text_background_color"] = text_background_color; root["gravity"] = gravity; // return JsonValue @@ -244,6 +257,8 @@ void TextReader::SetJsonValue(Json::Value root) { text_color = root["text_color"].asString(); if (!root["background_color"].isNull()) background_color = root["background_color"].asString(); + if (!root["text_background_color"].isNull()) + text_background_color = root["text_background_color"].asString(); if (!root["gravity"].isNull()) gravity = (GravityType) root["gravity"].asInt(); From 4dcc72a769f2d2f7c790fe7b769e896c11bb15d4 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Wed, 19 Dec 2018 09:12:15 -0800 Subject: [PATCH 051/186] Fixed bug compiling for older ffmpeg versions < 3.2 --- src/FFmpegReader.cpp | 18 ++++++++++++++++++ src/FFmpegWriter.cpp | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index f541c295..2c181193 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -458,6 +458,24 @@ void FFmpegReader::Open() throw InvalidCodec("Hardware device reference create failed.", path); } /* + av_buffer_unref(&ist->hw_frames_ctx); + ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx); + if (!ist->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "Error creating a CUDA frames context\n"); + return AVERROR(ENOMEM); + } + + frames_ctx = (AVHWFramesContext*)ist->hw_frames_ctx->data; + + frames_ctx->format = AV_PIX_FMT_CUDA; + frames_ctx->sw_format = avctx->sw_pix_fmt; + frames_ctx->width = avctx->width; + frames_ctx->height = avctx->height; + + av_log(avctx, AV_LOG_DEBUG, "Initializing CUDA frames context: sw_format = %s, width = %d, height = %d\n", + av_get_pix_fmt_name(frames_ctx->sw_format), frames_ctx->width, frames_ctx->height); + + ret = av_hwframe_ctx_init(pCodecCtx->hw_device_ctx); ret = av_hwframe_ctx_init(ist->hw_frames_ctx); if (ret < 0) { diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 66befe5c..c4f2ca43 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1053,6 +1053,7 @@ AVStream* FFmpegWriter::add_video_stream() } #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) else { +#if IS_FFMPEG_3_2 if (hw_en_on) { double mbs = 15000000.0; if (info.video_bit_rate > 0) { @@ -1065,7 +1066,9 @@ AVStream* FFmpegWriter::add_video_stream() } c->bit_rate = (int)(mbs); } - else { + else +#endif + { switch (c->codec_id) { #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : From e10695f9d480d917d8f25025e210ad4da025279f Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 20 Dec 2018 09:18:26 -0800 Subject: [PATCH 052/186] Fixed two memory leaks --- src/FFmpegReader.cpp | 1 + src/FFmpegWriter.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2c181193..859f4cf6 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -2426,6 +2426,7 @@ void FFmpegReader::RemoveAVFrame(AVFrame* remove_frame) { // Free memory av_freep(&remove_frame->data[0]); + AV_FREE_FRAME(&remove_frame); } } diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index c4f2ca43..8e29dc59 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1615,8 +1615,8 @@ void FFmpegWriter::write_audio_packets(bool final) } else { // Create a new array - final_samples = new int16_t[audio_input_position * (av_get_bytes_per_sample(audio_codec->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))]; - + //final_samples = new int16_t[audio_input_position * (av_get_bytes_per_sample(audio_codec->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))]; + final_samples = (int16_t*)av_malloc(sizeof(int16_t) * audio_input_position * (av_get_bytes_per_sample(audio_codec->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); // Copy audio into buffer for frame memcpy(final_samples, samples, audio_input_position * av_get_bytes_per_sample(audio_codec->sample_fmt)); From f2db5fdb39bf1de2511857551a9c6d7916ede102 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 26 Jan 2019 11:50:21 -0500 Subject: [PATCH 053/186] FFmpegUtilities: Rename RSHIFT to FF_RSHIFT FFmpeg and Ruby have competing definitions of the RSHIFT macro, so building the Ruby bindings causes warnings to be thrown when it's redefined. This change defines FF_RSHIFT to replace FFmpeg's RSHIFT, which is undef'd --- include/FFmpegUtilities.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 346da541..e16466e3 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -114,6 +114,13 @@ #define PIX_FMT_YUV420P AV_PIX_FMT_YUV420P #endif + // FFmpeg's libavutil/common.h defines an RSHIFT incompatible with Ruby's + // definition in ruby/config.h, so we move it to FF_RSHIFT + #ifdef RSHIFT + #define FF_RSHIFT(a, b) RSHIFT(a, b) + #undef RSHIFT + #endif + #ifdef USE_SW #define SWR_CONVERT(ctx, out, linesize, out_count, in, linesize2, in_count) \ swr_convert(ctx, out, out_count, (const uint8_t **)in, in_count) From bb8efeb72b55d093349d950f533f32b1243d0852 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 26 Jan 2019 11:53:08 -0500 Subject: [PATCH 054/186] Ruby: Rename RSHIFT to RB_RSHIFT, temporarily When Ruby attempts to load the FFmpeg header files, it'll complain that RSHIFT is redefined if the Ruby definition is still in place. So, we define RB_RSHIFT to contain the Ruby definition, undef RSHIFT, load the FFmpeg headers, move its RSHIFT into FF_RSHIFT if necessary, and then restore Ruby's RSHIFT from RB_RSHIFT. --- src/bindings/ruby/openshot.i | 39 +++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index b9a35d41..82925b71 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -57,6 +57,14 @@ namespace std { %{ +/* Ruby and FFmpeg define competing RSHIFT macros, + * so we move Ruby's out of the way for now. We'll + * restore it after dealing with FFmpeg's + */ +#ifdef RSHIFT + #define RB_RSHIFT(a, b) RSHIFT(a, b) + #undef RSHIFT +#endif #include "../../../include/Version.h" #include "../../../include/ReaderBase.h" #include "../../../include/WriterBase.h" @@ -91,7 +99,15 @@ namespace std { #include "../../../include/Settings.h" #include "../../../include/Timeline.h" #include "../../../include/ZmqLogger.h" - +/* Move FFmpeg's RSHIFT to FF_RSHIFT, if present */ +#ifdef RSHIFT + #define FF_RSHIFT(a, b) RSHIFT(a, b) + #undef RSHIFT +#endif +/* And restore Ruby's RSHIFT, if we captured it */ +#ifdef RB_RSHIFT + #define RSHIFT(a, b) RB_RSHIFT(a, b) +#endif %} #ifdef USE_BLACKMAGIC @@ -132,8 +148,29 @@ namespace std { %include "../../../include/EffectInfo.h" %include "../../../include/Enums.h" %include "../../../include/Exceptions.h" + +/* Ruby and FFmpeg define competing RSHIFT macros, + * so we move Ruby's out of the way for now. We'll + * restore it after dealing with FFmpeg's + */ +#ifdef RSHIFT + #define RB_RSHIFT(a, b) RSHIFT(a, b) + #undef RSHIFT +#endif + %include "../../../include/FFmpegReader.h" %include "../../../include/FFmpegWriter.h" + +/* Move FFmpeg's RSHIFT to FF_RSHIFT, if present */ +#ifdef RSHIFT + #define FF_RSHIFT(a, b) RSHIFT(a, b) + #undef RSHIFT +#endif +/* And restore Ruby's RSHIFT, if we captured it */ +#ifdef RB_RSHIFT + #define RSHIFT(a, b) RB_RSHIFT(a, b) +#endif + %include "../../../include/Fraction.h" %include "../../../include/Frame.h" %include "../../../include/FrameMapper.h" From 9aeec7d90ff172539add5c1363d8707fceabe4f1 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 26 Jan 2019 12:22:09 -0800 Subject: [PATCH 055/186] Set the bitrate to 0 if no valid value was given. It is needed for the crf lossless setting --- src/FFmpegReader.cpp | 4 +++- src/FFmpegWriter.cpp | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 011e8fe4..a2a605ad 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -284,6 +284,8 @@ void FFmpegReader::Open() hw_de_on = (val[0] == '1')? 1 : 0; }*/ + //hw_de_on = Settings::Instance()->HARDWARE_DECODE; + // New version turn hardware decode on { char *decoder_hw = NULL; @@ -368,7 +370,7 @@ void FFmpegReader::Open() char adapter[256]; char *adapter_ptr = NULL; int adapter_num; - dev_hw = getenv( "HW_DE_DEVICE_SET" ); // The first card is 0 + dev_hw = getenv( "HW_DE_DEVICE_SET" ); // The first card is 0 if( dev_hw != NULL) { adapter_num = atoi(dev_hw); } else { diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 8b5ee159..55816c23 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -247,8 +247,10 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i info.pixel_ratio.num = pixel_ratio.num; info.pixel_ratio.den = pixel_ratio.den; } - if (bit_rate >= 1000) // bit_rate is the bitrate in b/s + if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; + else + info.video_bit_rate = 0; info.interlaced_frame = interlaced; info.top_field_first = top_field_first; @@ -1083,7 +1085,9 @@ AVStream* FFmpegWriter::add_video_stream() if (info.video_bit_rate > 1000) { c->bit_rate = info.video_bit_rate; } - + else { + c->bit_rate = 0; + } //TODO: Implement variable bitrate feature (which actually works). This implementation throws //invalid bitrate errors and rc buffer underflow errors, etc... //c->rc_min_rate = info.video_bit_rate; From 46051fbba10416ab1c3bd59388b4957c5727f63a Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 27 Jan 2019 10:07:40 -0800 Subject: [PATCH 056/186] Form follows function Moved crf back to SetVideoOptions and adjusted parameters Now h.264 and VP9 have working crf Some small changes in preparation for Settings --- src/FFmpegReader.cpp | 18 ++++----- src/FFmpegWriter.cpp | 91 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index a2a605ad..dd5f063b 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -291,7 +291,7 @@ void FFmpegReader::Open() char *decoder_hw = NULL; decoder_hw = getenv( "HW_DECODER" ); if(decoder_hw != NULL) { - if( strncmp(decoder_hw,"NONE",4) == 0) { + if( strncmp(decoder_hw,"0",4) == 0) { hw_de_on = 0; } else { hw_de_on = 1; @@ -382,15 +382,15 @@ void FFmpegReader::Open() adapter_ptr = adapter; decoder_hw = getenv( "HW_DECODER" ); if(decoder_hw != NULL) { - if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen + if (strncmp(decoder_hw,"0",4) == 0) { //Will never happen hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; } - if (strncmp(decoder_hw,"HW_DE_VAAPI",11) == 0) { //Will never happen + if (strncmp(decoder_hw,"1",11) == 0) { hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; } - if (strncmp(decoder_hw,"HW_DE_NVDEC",11) == 0) { //Will never happen + if (strncmp(decoder_hw,"2",11) == 0) { hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; pCodecCtx->get_format = get_hw_dec_format_cu; } @@ -403,15 +403,15 @@ void FFmpegReader::Open() adapter_ptr = NULL; decoder_hw = getenv( "HW_DECODER" ); if(decoder_hw != NULL) { - if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen + if (strncmp(decoder_hw,"0",4) == 0) { //Will never happen hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; } - if (strncmp(decoder_hw,"HW_DE_WINDOWS_DXVA2",19) == 0) { //Will never happen + if (strncmp(decoder_hw,"3",19) == 0) { hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; } - if (strncmp(decoder_hw,"HW_DE_WINDOWS_D3D11",19) == 0) { //Will never happen + if (strncmp(decoder_hw,"4",19) == 0) { hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; pCodecCtx->get_format = get_hw_dec_format_d3; } @@ -423,11 +423,11 @@ void FFmpegReader::Open() adapter_ptr = NULL; decoder_hw = getenv( "HW_DECODER" ); if(decoder_hw != NULL) { - if (strncmp(decoder_hw,"NONE",4) == 0) { //Will never happen + if (strncmp(decoder_hw,"0",4) == 0) { //Will never happen hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; } - if (strncmp(decoder_hw,"HW_DE_MACOS",11) == 0) { //Will never happen + if (strncmp(decoder_hw,"5",11) == 0) { hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; } diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 55816c23..2c81cf96 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -249,8 +249,10 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i } if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; - else - info.video_bit_rate = 0; + if ((bit_rate >= 0) && (bit_rate < 64) ) // bit_rate is the bitrate in b/s + info.video_bit_rate = bit_rate; + //else + // info.video_bit_rate = 0; info.interlaced_frame = interlaced; info.top_field_first = top_field_first; @@ -392,29 +394,35 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // encode quality and special settings like lossless // This might be better in an extra methods as more options // and way to set quality are possible + int tempi = stoi(value); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) switch (c->codec_id) { case AV_CODEC_ID_VP8 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + av_opt_set_int(c->priv_data, "crf", min(tempi,63), 0); break; case AV_CODEC_ID_VP9 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); - if (stoi(value) == 0) { + av_opt_set_int(c->priv_data, "crf", min(tempi,63), 0); + if (tempi == 0) { av_opt_set_int(c->priv_data, "lossless", 1, 0); + av_opt_set(c->priv_data, "preset", "veryslow", 0); } break; case AV_CODEC_ID_H264 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),51), 0); + av_opt_set_int(c->priv_data, "crf", min(tempi,51), 0); + if (tempi == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + } break; case AV_CODEC_ID_H265 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),51), 0); - if (stoi(value) == 0) { + av_opt_set_int(c->priv_data, "crf", min(tempi,51), 0); + if (tempi == 0) { av_opt_set_int(c->priv_data, "lossless", 1, 0); + av_opt_set(c->priv_data, "preset", "veryslow", 0); } break; #ifdef AV_CODEC_ID_AV1 case AV_CODEC_ID_AV1 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + av_opt_set_int(c->priv_data, "crf", min(tempi,63), 0); break; #endif } @@ -1082,13 +1090,70 @@ AVStream* FFmpegWriter::add_video_stream() #endif /* Init video encoder options */ - if (info.video_bit_rate > 1000) { + if (info.video_bit_rate >= 1000) { c->bit_rate = info.video_bit_rate; } - else { - c->bit_rate = 0; +// else { +// c->bit_rate = 0; +// } + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + else { +#if IS_FFMPEG_3_2 + if (hw_en_on) { + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); + } + else +#endif + { + switch (c->codec_id) { +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + case AV_CODEC_ID_AV1 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + c->bit_rate = 0; + break; +#endif + case AV_CODEC_ID_VP8 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + break; + case AV_CODEC_ID_VP9 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + c->bit_rate = 0; + if (info.video_bit_rate == 0) { + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + case AV_CODEC_ID_H264 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + break; + case AV_CODEC_ID_H265 : + av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + break; + default: + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); + } + } } - //TODO: Implement variable bitrate feature (which actually works). This implementation throws +#endif + +//TODO: Implement variable bitrate feature (which actually works). This implementation throws //invalid bitrate errors and rc buffer underflow errors, etc... //c->rc_min_rate = info.video_bit_rate; //c->rc_max_rate = info.video_bit_rate; From 1a44bd789cf307937d712c89047251bd3a1351b5 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 27 Jan 2019 10:26:20 -0800 Subject: [PATCH 057/186] Make sure that crf is not set in SetOptions --- src/FFmpegWriter.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 2c81cf96..c5c40685 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -390,7 +390,7 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // Buffer size convert >> c->rc_buffer_size; - else if (name == "crf") { +/* else if (name == "crf") { // encode quality and special settings like lossless // This might be better in an extra methods as more options // and way to set quality are possible @@ -428,7 +428,7 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) } #endif } - +*/ else // Set AVOption AV_OPTION_SET(st, c->priv_data, name.c_str(), value.c_str(), c); @@ -1128,7 +1128,8 @@ AVStream* FFmpegWriter::add_video_stream() av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); c->bit_rate = 0; if (info.video_bit_rate == 0) { - av_opt_set_int(c->priv_data, "lossless", 1, 0); + av_opt_set(c->priv_data, "preset", "veryslow", 0); + av_opt_set_int(c->priv_data, "lossless", 1, 0); } break; case AV_CODEC_ID_H264 : From 39bf06b3d3ab7469583064362565fb6f1be7fb48 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 27 Jan 2019 10:50:23 -0800 Subject: [PATCH 058/186] Now VP8, VP9, h.264, h.265 have working crf --- src/FFmpegWriter.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index c5c40685..778c352e 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1123,6 +1123,11 @@ AVStream* FFmpegWriter::add_video_stream() #endif case AV_CODEC_ID_VP8 : av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); + c->bit_rate = 10000000; + if (info.video_bit_rate == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + c->bit_rate = 30000000; + } break; case AV_CODEC_ID_VP9 : av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,63), 0); @@ -1137,6 +1142,10 @@ AVStream* FFmpegWriter::add_video_stream() break; case AV_CODEC_ID_H265 : av_opt_set_int(c->priv_data, "crf", min(info.video_bit_rate,51), 0); + if (info.video_bit_rate == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } break; default: double mbs = 15000000.0; From 05fb797776086103d82c9a448dc5928b18de5bab Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 29 Jan 2019 10:26:10 -0800 Subject: [PATCH 059/186] Move the check if hw accell ecoding is used with crf to the right place --- src/FFmpegWriter.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 3ae1dd24..d98d88d3 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -400,7 +400,24 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // encode quality and special settings like lossless // This might be better in an extra methods as more options // and way to set quality are possible - #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + #if IS_FFMPEG_3_2 + if (hw_en_on) { + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380000.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); + } else + #endif +// #endif +// #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + { switch (c->codec_id) { #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : @@ -447,6 +464,7 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) } c->bit_rate = (int)(mbs); } + } #endif } @@ -1108,24 +1126,6 @@ AVStream* FFmpegWriter::add_video_stream() if (info.video_bit_rate >= 1000) { c->bit_rate = info.video_bit_rate; } - #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) - else { - #if IS_FFMPEG_3_2 - if (hw_en_on) { - double mbs = 15000000.0; - if (info.video_bit_rate > 0) { - if (info.video_bit_rate > 42) { - mbs = 380000.0; - } - else { - mbs *= pow(0.912,info.video_bit_rate); - } - } - c->bit_rate = (int)(mbs); - } - #endif - } - #endif //TODO: Implement variable bitrate feature (which actually works). This implementation throws //invalid bitrate errors and rc buffer underflow errors, etc... From 7e3669b620d96af79a98892eb9b7a11e2114853e Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 29 Jan 2019 12:38:52 -0800 Subject: [PATCH 060/186] Formating --- src/FFmpegWriter.cpp | 459 +++++++++++++++++++++---------------------- 1 file changed, 228 insertions(+), 231 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d98d88d3..6b8f240f 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -48,32 +48,32 @@ AVFrame *hw_frame = NULL; static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int64_t width, int64_t height) { - AVBufferRef *hw_frames_ref; - AVHWFramesContext *frames_ctx = NULL; - int err = 0; + AVBufferRef *hw_frames_ref; + AVHWFramesContext *frames_ctx = NULL; + int err = 0; - if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { - fprintf(stderr, "Failed to create HW frame context.\n"); - return -1; - } - frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); - frames_ctx->format = hw_en_av_pix_fmt; - frames_ctx->sw_format = AV_PIX_FMT_NV12; - frames_ctx->width = width; - frames_ctx->height = height; - frames_ctx->initial_pool_size = 20; - if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { - fprintf(stderr, "Failed to initialize HW frame context." - "Error code: %s\n",av_err2str(err)); - av_buffer_unref(&hw_frames_ref); - return err; - } - ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref); - if (!ctx->hw_frames_ctx) - err = AVERROR(ENOMEM); + if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { + fprintf(stderr, "Failed to create HW frame context.\n"); + return -1; + } + frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + frames_ctx->format = hw_en_av_pix_fmt; + frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->width = width; + frames_ctx->height = height; + frames_ctx->initial_pool_size = 20; + if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { + fprintf(stderr, "Failed to initialize HW frame context." + "Error code: %s\n",av_err2str(err)); + av_buffer_unref(&hw_frames_ref); + return err; + } + ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref); + if (!ctx->hw_frames_ctx) + err = AVERROR(ENOMEM); - av_buffer_unref(&hw_frames_ref); - return err; + av_buffer_unref(&hw_frames_ref); + return err; } #endif @@ -176,49 +176,49 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i if ( (strcmp(codec.c_str(),"h264_vaapi") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; - hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_VAAPI; - hw_en_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_VAAPI; + hw_en_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + } + else { + if ( (strcmp(codec.c_str(),"h264_nvenc") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; + hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; + } } - else { - if ( (strcmp(codec.c_str(),"h264_nvenc") == 0)) { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 1; - hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; - hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; - } - else { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 0; - hw_en_supported = 0; - } - } #elif defined(_WIN32) if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; - hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; - hw_en_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_DXVA2_VLD; + hw_en_av_device_type = AV_HWDEVICE_TYPE_DXVA2; } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 0; - hw_en_supported = 0; + hw_en_supported = 0; } - #elif defined(__APPLE__) + #elif defined(__APPLE__) if ( (strcmp(codec.c_str(),"h264_qsv") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; - hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_QSV; - hw_en_av_device_type = AV_HWDEVICE_TYPE_QSV; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_QSV; + hw_en_av_device_type = AV_HWDEVICE_TYPE_QSV; } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 0; - hw_en_supported = 0; + hw_en_supported = 0; } #else // is FFmpeg 3 but not linux new_codec = avcodec_find_encoder_by_name(codec.c_str()); @@ -255,7 +255,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i info.pixel_ratio.num = pixel_ratio.num; info.pixel_ratio.den = pixel_ratio.den; } - if (bit_rate >= 1000) // bit_rate is the bitrate in b/s + if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; if ((bit_rate >= 0) && (bit_rate < 64) ) // bit_rate is the bitrate in crf info.video_bit_rate = bit_rate; @@ -348,8 +348,8 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // Was option found? if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" || - name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || - name == "crf")) + name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || + name == "crf")) { // Check for specific named options if (name == "g") @@ -396,28 +396,26 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // Buffer size convert >> c->rc_buffer_size; - else if (name == "crf") { + else if (name == "crf") { // encode quality and special settings like lossless // This might be better in an extra methods as more options // and way to set quality are possible - #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) - #if IS_FFMPEG_3_2 - if (hw_en_on) { - double mbs = 15000000.0; - if (info.video_bit_rate > 0) { - if (info.video_bit_rate > 42) { - mbs = 380000.0; - } - else { - mbs *= pow(0.912,info.video_bit_rate); - } - } - c->bit_rate = (int)(mbs); - } else - #endif -// #endif -// #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) - { + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) + #if IS_FFMPEG_3_2 + if (hw_en_on) { + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380000.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); + } else + #endif + { switch (c->codec_id) { #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : @@ -519,7 +517,7 @@ void FFmpegWriter::WriteHeader() throw InvalidFile("Could not open or write file.", path); } - // Force the output filename (which doesn't always happen for some reason) + // Force the output filename (which doesn't always happen for some reason) snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", path.c_str()); // Write the stream header, if any @@ -743,11 +741,11 @@ void FFmpegWriter::flush_encoders() return; #endif - int error_code = 0; - int stop_encoding = 1; + int error_code = 0; + int stop_encoding = 1; - // FLUSH VIDEO ENCODER - if (info.has_video) + // FLUSH VIDEO ENCODER + if (info.has_video) for (;;) { // Increment PTS (in frames and scaled to the codec's timebase) @@ -846,8 +844,8 @@ void FFmpegWriter::flush_encoders() av_freep(&video_outbuf); } - // FLUSH AUDIO ENCODER - if (info.has_audio) + // FLUSH AUDIO ENCODER + if (info.has_audio) for (;;) { // Increment PTS (in samples and scaled to the codec's timebase) @@ -914,16 +912,16 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { AV_FREE_CONTEXT(video_codec); video_codec = NULL; - #if IS_FFMPEG_3_2 + #if IS_FFMPEG_3_2 // #if defined(__linux__) - if (hw_en_on && hw_en_supported) { - if (hw_device_ctx) { - av_buffer_unref(&hw_device_ctx); - hw_device_ctx = NULL; - } - } + if (hw_en_on && hw_en_supported) { + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; + } + } // #endif - #endif + #endif } // Close the audio codec @@ -1042,15 +1040,15 @@ AVStream* FFmpegWriter::add_audio_stream() // Set valid sample rate (or throw error) if (codec->supported_samplerates) { int i; - for (i = 0; codec->supported_samplerates[i] != 0; i++) - if (info.sample_rate == codec->supported_samplerates[i]) - { - // Set the valid sample rate - c->sample_rate = info.sample_rate; - break; - } - if (codec->supported_samplerates[i] == 0) - throw InvalidSampleRate("An invalid sample rate was detected for this codec.", path); + for (i = 0; codec->supported_samplerates[i] != 0; i++) + if (info.sample_rate == codec->supported_samplerates[i]) + { + // Set the valid sample rate + c->sample_rate = info.sample_rate; + break; + } + if (codec->supported_samplerates[i] == 0) + throw InvalidSampleRate("An invalid sample rate was detected for this codec.", path); } else // Set sample rate c->sample_rate = info.sample_rate; @@ -1174,31 +1172,31 @@ AVStream* FFmpegWriter::add_video_stream() #endif // Find all supported pixel formats for this codec - const PixelFormat* supported_pixel_formats = codec->pix_fmts; - while (supported_pixel_formats != NULL && *supported_pixel_formats != PIX_FMT_NONE) { - // Assign the 1st valid pixel format (if one is missing) - if (c->pix_fmt == PIX_FMT_NONE) - c->pix_fmt = *supported_pixel_formats; - ++supported_pixel_formats; - } + const PixelFormat* supported_pixel_formats = codec->pix_fmts; + while (supported_pixel_formats != NULL && *supported_pixel_formats != PIX_FMT_NONE) { + // Assign the 1st valid pixel format (if one is missing) + if (c->pix_fmt == PIX_FMT_NONE) + c->pix_fmt = *supported_pixel_formats; + ++supported_pixel_formats; + } - // Codec doesn't have any pix formats? - if (c->pix_fmt == PIX_FMT_NONE) { - if(fmt->video_codec == AV_CODEC_ID_RAWVIDEO) { - // Raw video should use RGB24 - c->pix_fmt = PIX_FMT_RGB24; + // Codec doesn't have any pix formats? + if (c->pix_fmt == PIX_FMT_NONE) { + if(fmt->video_codec == AV_CODEC_ID_RAWVIDEO) { + // Raw video should use RGB24 + c->pix_fmt = PIX_FMT_RGB24; #if (LIBAVFORMAT_VERSION_MAJOR < 58) - if (strcmp(fmt->name, "gif") != 0) - // If not GIF format, skip the encoding process - // Set raw picture flag (so we don't encode this video) - oc->oformat->flags |= AVFMT_RAWPICTURE; + if (strcmp(fmt->name, "gif") != 0) + // If not GIF format, skip the encoding process + // Set raw picture flag (so we don't encode this video) + oc->oformat->flags |= AVFMT_RAWPICTURE; #endif - } else { - // Set the default codec - c->pix_fmt = PIX_FMT_YUV420P; - } - } + } else { + // Set the default codec + c->pix_fmt = PIX_FMT_YUV420P; + } + } AV_COPY_PARAMS_FROM_CONTEXT(st, c); #if (LIBAVFORMAT_VERSION_MAJOR < 58) @@ -1293,51 +1291,50 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) // Set number of threads equal to number of processors (not to exceed 16) video_codec->thread_count = min(FF_NUM_PROCESSORS, 16); - #if IS_FFMPEG_3_2 - if (hw_en_on && hw_en_supported) { - char *dev_hw = NULL; - char adapter[256]; - char *adapter_ptr = NULL; - int adapter_num; + #if IS_FFMPEG_3_2 + if (hw_en_on && hw_en_supported) { + char *dev_hw = NULL; + char adapter[256]; + char *adapter_ptr = NULL; + int adapter_num; // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set dev_hw = getenv( "HW_EN_DEVICE_SET" ); - if( dev_hw != NULL) { - adapter_num = atoi(dev_hw); - if (adapter_num < 3 && adapter_num >=0) { - #if defined(__linux__) - snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); - // Maybe 127 is better because the first card would be 1?! - adapter_ptr = adapter; - #elif defined(_WIN32) - adapter_ptr = NULL; - #elif defined(__APPLE__) - adapter_ptr = NULL; - #endif - } - else { - adapter_ptr = NULL; // Just to be sure - } - } + if( dev_hw != NULL) { + adapter_num = atoi(dev_hw); + if (adapter_num < 3 && adapter_num >=0) { + #if defined(__linux__) + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + // Maybe 127 is better because the first card would be 1?! + adapter_ptr = adapter; + #elif defined(_WIN32) + adapter_ptr = NULL; + #elif defined(__APPLE__) + adapter_ptr = NULL; + #endif + } + else { + adapter_ptr = NULL; // Just to be sure + } + } // Check if it is there and writable - #if defined(__linux__) - if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { - #elif defined(_WIN32) - if( adapter_ptr != NULL ) { - #elif defined(__APPLE__) - if( adapter_ptr != NULL ) { - #endif - adapter_ptr = NULL; // use default - //cerr << "\n\n\nEncode Device not present using default\n\n\n"; - ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - } - if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, - adapter_ptr, NULL, 0) < 0) { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video : Codec name: ", info.vcodec.c_str(), -1, " ERROR creating\n", -1, "", -1, "", -1, "", -1, "", -1); - //cerr << "FFmpegWriter::open_video : Codec name: " << info.vcodec.c_str() << " ERROR creating\n"; - throw InvalidCodec("Could not create hwdevice", path); - } - } - #endif + #if defined(__linux__) + if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { + #elif defined(_WIN32) + if( adapter_ptr != NULL ) { + #elif defined(__APPLE__) + if( adapter_ptr != NULL ) { + #endif + adapter_ptr = NULL; // use default + //cerr << "\n\n\nEncode Device not present using default\n\n\n"; + ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, + adapter_ptr, NULL, 0) < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_video : Codec name: ", info.vcodec.c_str(), -1, " ERROR creating\n", -1, "", -1, "", -1, "", -1, "", -1); + throw InvalidCodec("Could not create hwdevice", path); + } + } + #endif /* find the video encoder */ codec = avcodec_find_encoder_by_name(info.vcodec.c_str()); if (!codec) @@ -1345,29 +1342,29 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) if (!codec) throw InvalidCodec("Could not find codec", path); - /* Force max_b_frames to 0 in some cases (i.e. for mjpeg image sequences */ - if(video_codec->max_b_frames && video_codec->codec_id != AV_CODEC_ID_MPEG4 && video_codec->codec_id != AV_CODEC_ID_MPEG1VIDEO && video_codec->codec_id != AV_CODEC_ID_MPEG2VIDEO) - video_codec->max_b_frames = 0; + /* Force max_b_frames to 0 in some cases (i.e. for mjpeg image sequences */ + if(video_codec->max_b_frames && video_codec->codec_id != AV_CODEC_ID_MPEG4 && video_codec->codec_id != AV_CODEC_ID_MPEG1VIDEO && video_codec->codec_id != AV_CODEC_ID_MPEG2VIDEO) + video_codec->max_b_frames = 0; // Init options AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "experimental", 0); - #if IS_FFMPEG_3_2 - if (hw_en_on && hw_en_supported) { - video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames - video_codec->pix_fmt = hw_en_av_pix_fmt; - video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; - av_opt_set(video_codec->priv_data,"preset","slow",0); - av_opt_set(video_codec->priv_data,"tune","zerolatency",0); - av_opt_set(video_codec->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); - // set hw_frames_ctx for encoder's AVCodecContext - int err; - if ((err = set_hwframe_ctx(video_codec, hw_device_ctx, info.width, info.height)) < 0) { - fprintf(stderr, "Failed to set hwframe context.\n"); - } - } - #endif + #if IS_FFMPEG_3_2 + if (hw_en_on && hw_en_supported) { + video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames + video_codec->pix_fmt = hw_en_av_pix_fmt; + video_codec->profile = FF_PROFILE_H264_BASELINE | FF_PROFILE_H264_CONSTRAINED; + av_opt_set(video_codec->priv_data,"preset","slow",0); + av_opt_set(video_codec->priv_data,"tune","zerolatency",0); + av_opt_set(video_codec->priv_data, "vprofile", "baseline", AV_OPT_SEARCH_CHILDREN); + // set hw_frames_ctx for encoder's AVCodecContext + int err; + if ((err = set_hwframe_ctx(video_codec, hw_device_ctx, info.width, info.height)) < 0) { + fprintf(stderr, "Failed to set hwframe context.\n"); + } + } + #endif /* open the codec */ if (avcodec_open2(video_codec, codec, &opts) < 0) @@ -1627,9 +1624,9 @@ void FFmpegWriter::write_audio_packets(bool final) memcpy(samples, frame_final->data[0], nb_samples * av_get_bytes_per_sample(audio_codec->sample_fmt) * info.channels); // deallocate AVFrame - av_freep(&(audio_frame->data[0])); - AV_FREE_FRAME(&audio_frame); - all_queued_samples = NULL; // this array cleared with above call + av_freep(&(audio_frame->data[0])); + AV_FREE_FRAME(&audio_frame); + all_queued_samples = NULL; // this array cleared with above call ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets (Successfully completed 2nd resampling for Planar formats)", "nb_samples", nb_samples, "", -1, "", -1, "", -1, "", -1, "", -1); @@ -1730,7 +1727,7 @@ void FFmpegWriter::write_audio_packets(bool final) // deallocate AVFrame av_freep(&(frame_final->data[0])); - AV_FREE_FRAME(&frame_final); + AV_FREE_FRAME(&frame_final); // deallocate memory for packet AV_FREE_PACKET(&pkt); @@ -1820,19 +1817,19 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) #if IS_FFMPEG_3_2 AVFrame *frame_final; // #if defined(__linux__) - if (hw_en_on && hw_en_supported) { - frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); - } else + if (hw_en_on && hw_en_supported) { + frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); + } else // #endif - { - frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); - } + { + frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); + } #else AVFrame *frame_final = allocate_avframe(video_codec->pix_fmt, info.width, info.height, &bytes_final, NULL); #endif // Fill with data - AV_COPY_PICTURE_DATA(frame_source, (uint8_t*)pixels, PIX_FMT_RGBA, source_image_width, source_image_height); + AV_COPY_PICTURE_DATA(frame_source, (uint8_t*)pixels, PIX_FMT_RGBA, source_image_width, source_image_height); ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::process_video_packet", "frame->number", frame->number, "bytes_source", bytes_source, "bytes_final", bytes_final, "", -1, "", -1, "", -1); // Resize & convert pixel format @@ -1901,50 +1898,50 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; - #if IS_FFMPEG_3_2 + #if IS_FFMPEG_3_2 // #if defined(__linux__) - if (hw_en_on && hw_en_supported) { - if (!(hw_frame = av_frame_alloc())) { - fprintf(stderr, "Error code: av_hwframe_alloc\n"); - } - if (av_hwframe_get_buffer(video_codec->hw_frames_ctx, hw_frame, 0) < 0) { - fprintf(stderr, "Error code: av_hwframe_get_buffer\n"); - } - if (!hw_frame->hw_frames_ctx) { - fprintf(stderr, "Error hw_frames_ctx.\n"); - } - hw_frame->format = AV_PIX_FMT_NV12; - if ( av_hwframe_transfer_data(hw_frame, frame_final, 0) < 0) { - fprintf(stderr, "Error while transferring frame data to surface.\n"); - } - av_frame_copy_props(hw_frame, frame_final); - } + if (hw_en_on && hw_en_supported) { + if (!(hw_frame = av_frame_alloc())) { + fprintf(stderr, "Error code: av_hwframe_alloc\n"); + } + if (av_hwframe_get_buffer(video_codec->hw_frames_ctx, hw_frame, 0) < 0) { + fprintf(stderr, "Error code: av_hwframe_get_buffer\n"); + } + if (!hw_frame->hw_frames_ctx) { + fprintf(stderr, "Error hw_frames_ctx.\n"); + } + hw_frame->format = AV_PIX_FMT_NV12; + if ( av_hwframe_transfer_data(hw_frame, frame_final, 0) < 0) { + fprintf(stderr, "Error while transferring frame data to surface.\n"); + } + av_frame_copy_props(hw_frame, frame_final); + } // #endif - #endif + #endif /* encode the image */ int got_packet_ptr = 0; int error_code = 0; #if IS_FFMPEG_3_2 // Write video packet (latest version of FFmpeg) int frameFinished = 0; - int ret; + int ret; // #if defined(__linux__) - #if IS_FFMPEG_3_2 - if (hw_en_on && hw_en_supported) { - ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! - } else - #endif + #if IS_FFMPEG_3_2 + if (hw_en_on && hw_en_supported) { + ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! + } else + #endif // #endif - ret = avcodec_send_frame(video_codec, frame_final); + ret = avcodec_send_frame(video_codec, frame_final); error_code = ret; if (ret < 0 ) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame not sent)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); if (ret == AVERROR(EAGAIN) ) { cerr << "Frame EAGAIN" << "\n"; - } + } if (ret == AVERROR_EOF ) { cerr << "Frame AVERROR_EOF" << "\n"; - } + } avcodec_send_frame(video_codec, NULL); } else { @@ -1967,10 +1964,10 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra error_code = avcodec_encode_video2(video_codec, &pkt, frame_final, &got_packet_ptr); if (error_code != 0 ) { cerr << "Frame AVERROR_EOF" << "\n"; - } + } if (got_packet_ptr == 0 ) { cerr << "Frame gotpacket error" << "\n"; - } + } #else // Write video packet (even older versions of FFmpeg) int video_outbuf_size = 200000; @@ -2026,14 +2023,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra AV_FREE_PACKET(&pkt); #if IS_FFMPEG_3_2 // #if defined(__linux__) - if (hw_en_on && hw_en_supported) { - if (hw_frame) { - av_frame_free(&hw_frame); - hw_frame = NULL; - } - } + if (hw_en_on && hw_en_supported) { + if (hw_frame) { + av_frame_free(&hw_frame); + hw_frame = NULL; + } + } // #endif - #endif + #endif } // Success @@ -2061,14 +2058,14 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) // Init the software scaler from FFMpeg #if IS_FFMPEG_3_2 // #if defined(__linux__) - if (hw_en_on && hw_en_supported) { - img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); - } else + if (hw_en_on && hw_en_supported) { + img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); + } else // #endif - #endif - { - img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL); - } + #endif + { + img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL); + } // Add rescaler to vector image_rescalers.push_back(img_convert_ctx); From 2ca84217bc18d7746183db4c76a32819af5f34d2 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Wed, 30 Jan 2019 09:58:54 -0800 Subject: [PATCH 061/186] First changes to use Settings instead of GetEnv --- include/Settings.h | 21 +++++++++++++ src/FFmpegReader.cpp | 75 +++++++++++++++++++++++++------------------- src/Settings.cpp | 8 +++++ 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/include/Settings.h b/include/Settings.h index ec26338b..0102479a 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -79,6 +79,9 @@ namespace openshot { /// Use video card for faster video decoding (if supported) bool HARDWARE_DECODE = false; + /// Use video codec for faster video decoding (if supported) + int HARDWARE_DECODER = 0; + /// Use video card for faster video encoding (if supported) bool HARDWARE_ENCODE = false; @@ -94,6 +97,24 @@ namespace openshot { /// Wait for OpenMP task to finish before continuing (used to limit threads on slower systems) bool WAIT_FOR_VIDEO_PROCESSING_TASK = false; + /// Number of threads of OpenMP + int OMP_THREADS = 6;//OPEN_MP_NUM_PROCESSORS + + /// Number of threads that ffmpeg uses + int FF_THREADS = 8;//FF_NUM_PROCESSORS + + /// Maximum rows that hardware decode can handle + int DE_LIMIT_HEIGHT_MAX = 1100; + + /// Maximum columns that hardware decode can handle + int DE_LIMIT_WIDTH_MAX = 1950; + + /// Which GPU to use to decode (0 is the first) + int HW_DE_DEVICE_SET = 0; + + /// Which GPU to use to encode (0 is the first) + int HW_EN_DEVICE_SET = 0; + /// Create or get an instance of this logger singleton (invoke the class with this method) static Settings * Instance(); }; diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index dd5f063b..03063d11 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -287,7 +287,7 @@ void FFmpegReader::Open() //hw_de_on = Settings::Instance()->HARDWARE_DECODE; // New version turn hardware decode on - { + /* { char *decoder_hw = NULL; decoder_hw = getenv( "HW_DECODER" ); if(decoder_hw != NULL) { @@ -299,7 +299,11 @@ void FFmpegReader::Open() } else { hw_de_on = 0; } - } + }*/ + // Newest versions + { + hw_de_on = (Settings::Instance()->HARDWARE_DECODER == 0 ? 0 : 1); + } // Open video file if (avformat_open_input(&pFormatCtx, path.c_str(), NULL, NULL) != 0) @@ -366,7 +370,8 @@ void FFmpegReader::Open() // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set char *dev_hw = NULL; - char *decoder_hw = NULL; + //char *decoder_hw = NULL; + int i_decoder_hw = 0; char adapter[256]; char *adapter_ptr = NULL; int adapter_num; @@ -380,60 +385,62 @@ void FFmpegReader::Open() #if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); adapter_ptr = adapter; - decoder_hw = getenv( "HW_DECODER" ); - if(decoder_hw != NULL) { - if (strncmp(decoder_hw,"0",4) == 0) { //Will never happen + i_decoder_hw = Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 0: hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; - } - if (strncmp(decoder_hw,"1",11) == 0) { + break; + case 1: hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; - } - if (strncmp(decoder_hw,"2",11) == 0) { + break; + case 2: hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; pCodecCtx->get_format = get_hw_dec_format_cu; - } - } else { - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; - } + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + break; + } #elif defined(_WIN32) adapter_ptr = NULL; - decoder_hw = getenv( "HW_DECODER" ); - if(decoder_hw != NULL) { - if (strncmp(decoder_hw,"0",4) == 0) { //Will never happen + i_decoder_hw = Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 0: hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; - } - if (strncmp(decoder_hw,"3",19) == 0) { + break; + case 3: hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; - } - if (strncmp(decoder_hw,"4",19) == 0) { + break; + case 4: hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; pCodecCtx->get_format = get_hw_dec_format_d3; - } - } else { + default: hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; + break; } #elif defined(__APPLE__) adapter_ptr = NULL; - decoder_hw = getenv( "HW_DECODER" ); - if(decoder_hw != NULL) { - if (strncmp(decoder_hw,"0",4) == 0) { //Will never happen + i_decoder_hw = Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 0: hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; - } - if (strncmp(decoder_hw,"5",11) == 0) { + break; + case 5: hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; - } - } else { + break; + default: hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; + break; } #endif } @@ -536,8 +543,10 @@ void FFmpegReader::Open() } else { int max_h, max_w; - max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" ))); - max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); + //max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" ))); + max_h = Settings::Instance()->DE_LIMIT_HEIGHT_MAX; + //max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); + max_w = Settings::Instance()->DE_LIMIT_WIDTH_MAX; ZmqLogger::Instance()->AppendDebugMethod("Constraints could not be found using default limit\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); //cerr << "Constraints could not be found using default limit\n"; if (pCodecCtx->coded_width < 0 || diff --git a/src/Settings.cpp b/src/Settings.cpp index b13f0f5a..961e3682 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -41,11 +41,19 @@ Settings *Settings::Instance() // Create the actual instance of logger only once m_pInstance = new Settings; m_pInstance->HARDWARE_DECODE = false; + m_pInstance->HARDWARE_DECODER = 0; m_pInstance->HARDWARE_ENCODE = false; m_pInstance->HIGH_QUALITY_SCALING = false; m_pInstance->MAX_WIDTH = 0; m_pInstance->MAX_HEIGHT = 0; m_pInstance->WAIT_FOR_VIDEO_PROCESSING_TASK = false; + m_pInstance->OMP_THREADS = 6;//OPEN_MP_NUM_PROCESSORS + m_pInstance->FF_THREADS = 8;//FF_NUM_PROCESSORS + m_pInstance->DE_LIMIT_HEIGHT_MAX = 1100; + m_pInstance->DE_LIMIT_WIDTH_MAX = 1950; + m_pInstance->HW_DE_DEVICE_SET = 0; + m_pInstance->HW_EN_DEVICE_SET = 0; + } return m_pInstance; From 596ae0efac24144aa85ceb5a8cd10b6b1e8d8a48 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Wed, 30 Jan 2019 20:44:36 -0800 Subject: [PATCH 062/186] More changes to move to Settings, still needs work --- include/OpenMPUtilities.h | 11 +++++++++-- include/Settings.h | 2 +- src/FFmpegReader.cpp | 29 +++++++++++++++++------------ src/FFmpegWriter.cpp | 17 +++++++++++------ src/Settings.cpp | 2 +- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index 9af58150..f0adfd4b 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -32,9 +32,16 @@ #include #include +#include "../include/Settings.h" + +using namespace std; +using namespace openshot; + // Calculate the # of OpenMP Threads to allow -#define OPEN_MP_NUM_PROCESSORS ((getenv( "LIMIT_OMP_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_OMP_THREADS" ))) ))) -#define FF_NUM_PROCESSORS ((getenv( "LIMIT_FF_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_FF_THREADS" ))) ))) +//#define OPEN_MP_NUM_PROCESSORS ((getenv( "LIMIT_OMP_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_OMP_THREADS" ))) ))) +//#define FF_NUM_PROCESSORS ((getenv( "LIMIT_FF_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_FF_THREADS" ))) ))) +#define OPEN_MP_NUM_PROCESSORS (min(omp_get_num_procs(), max(2, openshot::Settings::Instance()->OMP_THREADS) )) +#define FF_NUM_PROCESSORS (min(omp_get_num_procs(), max(2, openshot::Settings::Instance()->FF_THREADS) )) diff --git a/include/Settings.h b/include/Settings.h index 0102479a..15ff5fa3 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -98,7 +98,7 @@ namespace openshot { bool WAIT_FOR_VIDEO_PROCESSING_TASK = false; /// Number of threads of OpenMP - int OMP_THREADS = 6;//OPEN_MP_NUM_PROCESSORS + int OMP_THREADS = 12;//OPEN_MP_NUM_PROCESSORS /// Number of threads that ffmpeg uses int FF_THREADS = 8;//FF_NUM_PROCESSORS diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 03063d11..b45145b7 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -284,7 +284,7 @@ void FFmpegReader::Open() hw_de_on = (val[0] == '1')? 1 : 0; }*/ - //hw_de_on = Settings::Instance()->HARDWARE_DECODE; + //hw_de_on = openshot::Settings::Instance()->HARDWARE_DECODE; // New version turn hardware decode on /* { @@ -302,7 +302,7 @@ void FFmpegReader::Open() }*/ // Newest versions { - hw_de_on = (Settings::Instance()->HARDWARE_DECODER == 0 ? 0 : 1); + hw_de_on = (openshot::Settings::Instance()->HARDWARE_DECODER == 0 ? 0 : 1); } // Open video file @@ -369,23 +369,25 @@ void FFmpegReader::Open() if (hw_de_on && hw_de_supported) { // Open Hardware Acceleration // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set - char *dev_hw = NULL; + //char *dev_hw = NULL; //char *decoder_hw = NULL; int i_decoder_hw = 0; char adapter[256]; char *adapter_ptr = NULL; int adapter_num; - dev_hw = getenv( "HW_DE_DEVICE_SET" ); // The first card is 0 +/* dev_hw = getenv( "HW_DE_DEVICE_SET" ); // The first card is 0 if( dev_hw != NULL) { adapter_num = atoi(dev_hw); } else { adapter_num = 0; - } + }*/ + adapter_num = openshot::Settings::Instance()->HW_DE_DEVICE_SET; + fprintf(stderr, "\n\nDecodiing Device Nr: %d\n", adapter_num); if (adapter_num < 3 && adapter_num >=0) { #if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); adapter_ptr = adapter; - i_decoder_hw = Settings::Instance()->HARDWARE_DECODER; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; @@ -407,7 +409,7 @@ void FFmpegReader::Open() #elif defined(_WIN32) adapter_ptr = NULL; - i_decoder_hw = Settings::Instance()->HARDWARE_DECODER; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; @@ -427,7 +429,7 @@ void FFmpegReader::Open() } #elif defined(__APPLE__) adapter_ptr = NULL; - i_decoder_hw = Settings::Instance()->HARDWARE_DECODER; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; @@ -456,6 +458,9 @@ void FFmpegReader::Open() #elif defined(__APPLE__) if( adapter_ptr != NULL ) { #endif + ZmqLogger::Instance()->AppendDebugMethod("Decode Device present using device", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + else { adapter_ptr = NULL; // use default ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } @@ -544,9 +549,9 @@ void FFmpegReader::Open() else { int max_h, max_w; //max_h = ((getenv( "LIMIT_HEIGHT_MAX" )==NULL) ? MAX_SUPPORTED_HEIGHT : atoi(getenv( "LIMIT_HEIGHT_MAX" ))); - max_h = Settings::Instance()->DE_LIMIT_HEIGHT_MAX; + max_h = openshot::Settings::Instance()->DE_LIMIT_HEIGHT_MAX; //max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); - max_w = Settings::Instance()->DE_LIMIT_WIDTH_MAX; + max_w = openshot::Settings::Instance()->DE_LIMIT_WIDTH_MAX; ZmqLogger::Instance()->AppendDebugMethod("Constraints could not be found using default limit\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); //cerr << "Constraints could not be found using default limit\n"; if (pCodecCtx->coded_width < 0 || @@ -1354,10 +1359,10 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) // without losing quality. NOTE: We cannot go smaller than the timeline itself, or the add_layer timeline // method will scale it back to timeline size before scaling it smaller again. This needs to be fixed in // the future. - int max_width = Settings::Instance()->MAX_WIDTH; + int max_width = openshot::Settings::Instance()->MAX_WIDTH; if (max_width <= 0) max_width = info.width; - int max_height = Settings::Instance()->MAX_HEIGHT; + int max_height = openshot::Settings::Instance()->MAX_HEIGHT; if (max_height <= 0) max_height = info.height; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 6b8f240f..6a947d4c 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1293,15 +1293,17 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { - char *dev_hw = NULL; + //char *dev_hw = NULL; char adapter[256]; char *adapter_ptr = NULL; int adapter_num; // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set - dev_hw = getenv( "HW_EN_DEVICE_SET" ); - if( dev_hw != NULL) { - adapter_num = atoi(dev_hw); - if (adapter_num < 3 && adapter_num >=0) { + //dev_hw = getenv( "HW_EN_DEVICE_SET" ); + //if( dev_hw != NULL) { + // adapter_num = atoi(dev_hw); + adapter_num = openshot::Settings::Instance()->HW_EN_DEVICE_SET; + fprintf(stderr, "\n\nEncodiing Device Nr: %d\n", adapter_num); + if (adapter_num < 3 && adapter_num >=0) { #if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); // Maybe 127 is better because the first card would be 1?! @@ -1315,7 +1317,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) else { adapter_ptr = NULL; // Just to be sure } - } +// } // Check if it is there and writable #if defined(__linux__) if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { @@ -1324,6 +1326,9 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) #elif defined(__APPLE__) if( adapter_ptr != NULL ) { #endif + ZmqLogger::Instance()->AppendDebugMethod("Encode Device present using device", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + else { adapter_ptr = NULL; // use default //cerr << "\n\n\nEncode Device not present using default\n\n\n"; ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); diff --git a/src/Settings.cpp b/src/Settings.cpp index 961e3682..4f502341 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -47,7 +47,7 @@ Settings *Settings::Instance() m_pInstance->MAX_WIDTH = 0; m_pInstance->MAX_HEIGHT = 0; m_pInstance->WAIT_FOR_VIDEO_PROCESSING_TASK = false; - m_pInstance->OMP_THREADS = 6;//OPEN_MP_NUM_PROCESSORS + m_pInstance->OMP_THREADS = 12;//OPEN_MP_NUM_PROCESSORS m_pInstance->FF_THREADS = 8;//FF_NUM_PROCESSORS m_pInstance->DE_LIMIT_HEIGHT_MAX = 1100; m_pInstance->DE_LIMIT_WIDTH_MAX = 1950; From 2e635e3d87a4ef2f902b097bd9914f77a9ce87cf Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 31 Jan 2019 09:42:26 -0800 Subject: [PATCH 063/186] Formating and Cleanup Fix forgotten break in switch --- include/OpenMPUtilities.h | 2 - include/Settings.h | 4 +- src/FFmpegReader.cpp | 317 ++++++++++++++++---------------------- src/FFmpegWriter.cpp | 27 +--- src/Settings.cpp | 4 +- 5 files changed, 144 insertions(+), 210 deletions(-) diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index f0adfd4b..0411b6ba 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -38,8 +38,6 @@ using namespace std; using namespace openshot; // Calculate the # of OpenMP Threads to allow -//#define OPEN_MP_NUM_PROCESSORS ((getenv( "LIMIT_OMP_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_OMP_THREADS" ))) ))) -//#define FF_NUM_PROCESSORS ((getenv( "LIMIT_FF_THREADS" )==NULL) ? omp_get_num_procs() : (min(omp_get_num_procs(), max(2, atoi(getenv( "LIMIT_FF_THREADS" ))) ))) #define OPEN_MP_NUM_PROCESSORS (min(omp_get_num_procs(), max(2, openshot::Settings::Instance()->OMP_THREADS) )) #define FF_NUM_PROCESSORS (min(omp_get_num_procs(), max(2, openshot::Settings::Instance()->FF_THREADS) )) diff --git a/include/Settings.h b/include/Settings.h index 15ff5fa3..b01d9590 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -98,10 +98,10 @@ namespace openshot { bool WAIT_FOR_VIDEO_PROCESSING_TASK = false; /// Number of threads of OpenMP - int OMP_THREADS = 12;//OPEN_MP_NUM_PROCESSORS + int OMP_THREADS = 12; /// Number of threads that ffmpeg uses - int FF_THREADS = 8;//FF_NUM_PROCESSORS + int FF_THREADS = 8; /// Maximum rows that hardware decode can handle int DE_LIMIT_HEIGHT_MAX = 1100; diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index b45145b7..2e938f35 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -76,7 +76,6 @@ typedef struct VAAPIDecodeContext { using namespace openshot; int hw_de_on = 1; // Is set in UI -//int hw_de_supported = 0; // Is set by FFmpegReader #if IS_FFMPEG_3_2 AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE; AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE; @@ -158,91 +157,91 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if defined(__linux__) static enum AVPixelFormat get_hw_dec_format_va(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { - const enum AVPixelFormat *p; + const enum AVPixelFormat *p; - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { case AV_PIX_FMT_VAAPI: hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; - return *p; + return *p; break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; - } + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { - const enum AVPixelFormat *p; + const enum AVPixelFormat *p; - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { case AV_PIX_FMT_CUDA: hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; - return *p; + return *p; break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; - } + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} #endif #if defined(_WIN32) static enum AVPixelFormat get_hw_dec_format_dx(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { - const enum AVPixelFormat *p; + const enum AVPixelFormat *p; - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { case AV_PIX_FMT_DXVA2_VLD: hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; - return *p; + return *p; break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; - } + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} static enum AVPixelFormat get_hw_dec_format_d3(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { - const enum AVPixelFormat *p; + const enum AVPixelFormat *p; - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { case AV_PIX_FMT_D3D11: hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; - return *p; + return *p; break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; - } + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} #endif #if defined(__APPLE__) static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { - const enum AVPixelFormat *p; + const enum AVPixelFormat *p; - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { case AV_PIX_FMT_QSV: hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; - return *p; + return *p; break; } - } + } ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; + return AV_PIX_FMT_NONE; } #endif @@ -274,33 +273,6 @@ void FFmpegReader::Open() { // Initialize format context pFormatCtx = NULL; - - // Old version turn hardware decode on - /*char * val = getenv( "OS2_DECODE_HW" ); - if (val == NULL) { - hw_de_on = 0; - } - else{ - hw_de_on = (val[0] == '1')? 1 : 0; - }*/ - - //hw_de_on = openshot::Settings::Instance()->HARDWARE_DECODE; - - // New version turn hardware decode on - /* { - char *decoder_hw = NULL; - decoder_hw = getenv( "HW_DECODER" ); - if(decoder_hw != NULL) { - if( strncmp(decoder_hw,"0",4) == 0) { - hw_de_on = 0; - } else { - hw_de_on = 1; - } - } else { - hw_de_on = 0; - } - }*/ - // Newest versions { hw_de_on = (openshot::Settings::Instance()->HARDWARE_DECODER == 0 ? 0 : 1); } @@ -368,106 +340,96 @@ void FFmpegReader::Open() #if IS_FFMPEG_3_2 if (hw_de_on && hw_de_supported) { // Open Hardware Acceleration - // Use the hw device given in the environment variable HW_DE_DEVICE_SET or the default if not set - //char *dev_hw = NULL; - //char *decoder_hw = NULL; int i_decoder_hw = 0; - char adapter[256]; - char *adapter_ptr = NULL; - int adapter_num; -/* dev_hw = getenv( "HW_DE_DEVICE_SET" ); // The first card is 0 - if( dev_hw != NULL) { - adapter_num = atoi(dev_hw); - } else { - adapter_num = 0; - }*/ + char adapter[256]; + char *adapter_ptr = NULL; + int adapter_num; adapter_num = openshot::Settings::Instance()->HW_DE_DEVICE_SET; fprintf(stderr, "\n\nDecodiing Device Nr: %d\n", adapter_num); - if (adapter_num < 3 && adapter_num >=0) { - #if defined(__linux__) - snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); - adapter_ptr = adapter; + if (adapter_num < 3 && adapter_num >=0) { + #if defined(__linux__) + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + adapter_ptr = adapter; i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; break; case 1: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; break; case 2: - hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - pCodecCtx->get_format = get_hw_dec_format_cu; + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + pCodecCtx->get_format = get_hw_dec_format_cu; break; default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; break; } - #elif defined(_WIN32) - adapter_ptr = NULL; + #elif defined(_WIN32) + adapter_ptr = NULL; i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + pCodecCtx->get_format = get_hw_dec_format_dx; + break; case 3: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; - case 4: - hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; - pCodecCtx->get_format = get_hw_dec_format_d3; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + pCodecCtx->get_format = get_hw_dec_format_dx; break; - } - #elif defined(__APPLE__) - adapter_ptr = NULL; + case 4: + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; + pCodecCtx->get_format = get_hw_dec_format_d3; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + pCodecCtx->get_format = get_hw_dec_format_dx; + break; + } + #elif defined(__APPLE__) + adapter_ptr = NULL; i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - case 5: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; break; - } - #endif - } - else { - adapter_ptr = NULL; // Just to be sure - } - //} - // Check if it is there and writable - #if defined(__linux__) - if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { - #elif defined(_WIN32) - if( adapter_ptr != NULL ) { - #elif defined(__APPLE__) - if( adapter_ptr != NULL ) { - #endif + case 5: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; + } + #endif + } + else { + adapter_ptr = NULL; // Just to be sure + } + // Check if it is there and writable + #if defined(__linux__) + if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { + #elif defined(_WIN32) + if( adapter_ptr != NULL ) { + #elif defined(__APPLE__) + if( adapter_ptr != NULL ) { + #endif ZmqLogger::Instance()->AppendDebugMethod("Decode Device present using device", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } else { - adapter_ptr = NULL; // use default - ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - } + adapter_ptr = NULL; // use default + ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } hw_device_ctx = NULL; // Here the first hardware initialisations are made if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { - cerr << "\n\n**** HW device create OK ******** \n\n"; if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); } @@ -523,8 +485,7 @@ void FFmpegReader::Open() pCodecCtx->coded_height < constraints->min_height || pCodecCtx->coded_width > constraints->max_width || pCodecCtx->coded_height > constraints->max_height) { - ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - //cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; + ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); hw_de_supported = 0; retry_decode_open = 1; AV_FREE_CONTEXT(pCodecCtx); @@ -535,10 +496,7 @@ void FFmpegReader::Open() } else { // All is just peachy - ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Min width :", constraints->min_width, "Min Height :", constraints->min_height, "MaxWidth :", constraints->max_width, "MaxHeight :", constraints->max_height, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height); - //cerr << "\nDecode hardware acceleration is used\n"; - //cerr << "Min width : " << constraints->min_width << " MinHeight : " << constraints->min_height << "MaxWidth : " << constraints->max_width << "MaxHeight : " << constraints->max_height << "\n"; - //cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Min width :", constraints->min_width, "Min Height :", constraints->min_height, "MaxWidth :", constraints->max_width, "MaxHeight :", constraints->max_height, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height); retry_decode_open = 0; } av_hwframe_constraints_free(&constraints); @@ -552,16 +510,13 @@ void FFmpegReader::Open() max_h = openshot::Settings::Instance()->DE_LIMIT_HEIGHT_MAX; //max_w = ((getenv( "LIMIT_WIDTH_MAX" )==NULL) ? MAX_SUPPORTED_WIDTH : atoi(getenv( "LIMIT_WIDTH_MAX" ))); max_w = openshot::Settings::Instance()->DE_LIMIT_WIDTH_MAX; - ZmqLogger::Instance()->AppendDebugMethod("Constraints could not be found using default limit\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("Constraints could not be found using default limit\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); //cerr << "Constraints could not be found using default limit\n"; if (pCodecCtx->coded_width < 0 || pCodecCtx->coded_height < 0 || pCodecCtx->coded_width > max_w || pCodecCtx->coded_height > max_h ) { - ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height, "", -1, "", -1); - //cerr << "DIMENSIONS ARE TOO LARGE for hardware acceleration\n"; - //cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; - //cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + ZmqLogger::Instance()->AppendDebugMethod("DIMENSIONS ARE TOO LARGE for hardware acceleration\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height, "", -1, "", -1); hw_de_supported = 0; retry_decode_open = 1; AV_FREE_CONTEXT(pCodecCtx); @@ -571,18 +526,14 @@ void FFmpegReader::Open() } } else { - ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height, "", -1, "", -1); - //cerr << "\nDecode hardware acceleration is used\n"; - //cerr << " Max Width : " << max_w << " Height : " << max_h << "\n"; - //cerr << "Frame width : " << pCodecCtx->coded_width << " Frame height : " << pCodecCtx->coded_height << "\n"; + ZmqLogger::Instance()->AppendDebugMethod("\nDecode hardware acceleration is used\n", "Max Width :", max_w, "Max Height :", max_h, "Frame width :", pCodecCtx->coded_width, "Frame height :", pCodecCtx->coded_height, "", -1, "", -1); retry_decode_open = 0; } } } // if hw_de_on && hw_de_supported - else { - ZmqLogger::Instance()->AppendDebugMethod("\nDecode in software is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - //cerr << "\nDecode in software is used\n"; - } + else { + ZmqLogger::Instance()->AppendDebugMethod("\nDecode in software is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } #else retry_decode_open = 0; #endif @@ -897,8 +848,8 @@ std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) } else { - #pragma omp critical (ReadStream) - { + #pragma omp critical (ReadStream) + { // Check the cache a 2nd time (due to a potential previous lock) if (has_missing_frames) CheckMissingFrame(requested_frame); @@ -944,8 +895,8 @@ std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) frame = ReadStream(requested_frame); } } - } //omp critical - return frame; + } //omp critical + return frame; } } @@ -1141,11 +1092,11 @@ int FFmpegReader::GetNextPacket() found_packet = av_read_frame(pFormatCtx, next_packet); - if (packet) { - // Remove previous packet before getting next one - RemoveAVPacket(packet); - packet = NULL; - } + if (packet) { + // Remove previous packet before getting next one + RemoveAVPacket(packet); + packet = NULL; + } if (found_packet >= 0) { @@ -1191,15 +1142,15 @@ bool FFmpegReader::GetAVFrame() pFrame = new AVFrame(); while (ret >= 0) { ret = avcodec_receive_frame(pCodecCtx, next_frame2); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { - break; + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; } if (ret != 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } if (hw_de_on && hw_de_supported) { int err; - if (next_frame2->format == hw_de_av_pix_fmt) { + if (next_frame2->format == hw_de_av_pix_fmt) { next_frame->format = AV_PIX_FMT_YUV420P; if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); @@ -1437,7 +1388,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) // Resize / Convert to RGB sws_scale(img_convert_ctx, my_frame->data, my_frame->linesize, 0, - original_height, pFrameRGB->data, pFrameRGB->linesize); + original_height, pFrameRGB->data, pFrameRGB->linesize); // Create or get the existing frame object std::shared_ptr f = CreateFrame(current_frame); @@ -2257,8 +2208,8 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_frame) { // Loop through all working queue frames - bool checked_count_tripped = false; - int max_checked_count = 80; + bool checked_count_tripped = false; + int max_checked_count = 80; while (true) { @@ -2291,11 +2242,11 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram // Get check count for this frame checked_frames_size = checked_frames.size(); - if (!checked_count_tripped || f->number >= requested_frame) - checked_count = checked_frames[f->number]; - else - // Force checked count over the limit - checked_count = max_checked_count; + if (!checked_count_tripped || f->number >= requested_frame) + checked_count = checked_frames[f->number]; + else + // Force checked count over the limit + checked_count = max_checked_count; } if (previous_packet_location.frame == f->number && !end_of_stream) @@ -2311,8 +2262,8 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames (exceeded checked_count)", "requested_frame", requested_frame, "frame_number", f->number, "is_video_ready", is_video_ready, "is_audio_ready", is_audio_ready, "checked_count", checked_count, "checked_frames_size", checked_frames_size); - // Trigger checked count tripped mode (clear out all frames before requested frame) - checked_count_tripped = true; + // Trigger checked count tripped mode (clear out all frames before requested frame) + checked_count_tripped = true; if (info.has_video && !is_video_ready && last_video_frame) { // Copy image from last frame @@ -2357,8 +2308,8 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram missing_frames.Add(f); } - // Remove from 'checked' count - checked_frames.erase(f->number); + // Remove from 'checked' count + checked_frames.erase(f->number); } // Remove frame from working cache @@ -2482,10 +2433,10 @@ void FFmpegReader::CheckFPS() // Remove AVFrame from cache (and deallocate it's memory) void FFmpegReader::RemoveAVFrame(AVFrame* remove_frame) { - // Remove pFrame (if exists) - if (remove_frame) - { - // Free memory + // Remove pFrame (if exists) + if (remove_frame) + { + // Free memory #pragma omp critical (packet_cache) { av_freep(&remove_frame->data[0]); @@ -2500,7 +2451,7 @@ void FFmpegReader::RemoveAVFrame(AVFrame* remove_frame) void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet) { // deallocate memory for packet - AV_FREE_PACKET(remove_packet); + AV_FREE_PACKET(remove_packet); // Delete the object delete remove_packet; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 6a947d4c..14171894 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -462,7 +462,7 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) } c->bit_rate = (int)(mbs); } - } + } #endif } @@ -1298,9 +1298,6 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) char *adapter_ptr = NULL; int adapter_num; // Use the hw device given in the environment variable HW_EN_DEVICE_SET or the default if not set - //dev_hw = getenv( "HW_EN_DEVICE_SET" ); - //if( dev_hw != NULL) { - // adapter_num = atoi(dev_hw); adapter_num = openshot::Settings::Instance()->HW_EN_DEVICE_SET; fprintf(stderr, "\n\nEncodiing Device Nr: %d\n", adapter_num); if (adapter_num < 3 && adapter_num >=0) { @@ -1317,7 +1314,6 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) else { adapter_ptr = NULL; // Just to be sure } -// } // Check if it is there and writable #if defined(__linux__) if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { @@ -1539,9 +1535,9 @@ void FFmpegWriter::write_audio_packets(bool final) // Remove converted audio av_freep(&(audio_frame->data[0])); - AV_FREE_FRAME(&audio_frame); + AV_FREE_FRAME(&audio_frame); av_freep(&audio_converted->data[0]); - AV_FREE_FRAME(&audio_converted); + AV_FREE_FRAME(&audio_converted); all_queued_samples = NULL; // this array cleared with above call ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets (Successfully completed 1st resampling)", "nb_samples", nb_samples, "remaining_frame_samples", remaining_frame_samples, "", -1, "", -1, "", -1, "", -1); @@ -1732,7 +1728,7 @@ void FFmpegWriter::write_audio_packets(bool final) // deallocate AVFrame av_freep(&(frame_final->data[0])); - AV_FREE_FRAME(&frame_final); + AV_FREE_FRAME(&frame_final); // deallocate memory for packet AV_FREE_PACKET(&pkt); @@ -1821,11 +1817,9 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t*) pixels); #if IS_FFMPEG_3_2 AVFrame *frame_final; -// #if defined(__linux__) if (hw_en_on && hw_en_supported) { frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); } else -// #endif { frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); } @@ -1887,7 +1881,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } else #endif - { + { AVPacket pkt; av_init_packet(&pkt); @@ -1904,7 +1898,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; #if IS_FFMPEG_3_2 -// #if defined(__linux__) if (hw_en_on && hw_en_supported) { if (!(hw_frame = av_frame_alloc())) { fprintf(stderr, "Error code: av_hwframe_alloc\n"); @@ -1921,7 +1914,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } av_frame_copy_props(hw_frame, frame_final); } -// #endif #endif /* encode the image */ int got_packet_ptr = 0; @@ -1930,13 +1922,11 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Write video packet (latest version of FFmpeg) int frameFinished = 0; int ret; -// #if defined(__linux__) #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! } else #endif -// #endif ret = avcodec_send_frame(video_codec, frame_final); error_code = ret; if (ret < 0 ) { @@ -2002,7 +1992,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra //pkt.pts = pkt.dts = write_video_count; // set the timestamp -// av_packet_rescale_ts(&pkt, video_st->time_base,video_codec->time_base); if (pkt.pts != AV_NOPTS_VALUE) pkt.pts = av_rescale_q(pkt.pts, video_codec->time_base, video_st->time_base); if (pkt.dts != AV_NOPTS_VALUE) @@ -2026,15 +2015,13 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Deallocate packet AV_FREE_PACKET(&pkt); - #if IS_FFMPEG_3_2 -// #if defined(__linux__) + #if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { if (hw_frame) { av_frame_free(&hw_frame); hw_frame = NULL; } } -// #endif #endif } @@ -2062,11 +2049,9 @@ void FFmpegWriter::InitScalers(int source_width, int source_height) { // Init the software scaler from FFMpeg #if IS_FFMPEG_3_2 -// #if defined(__linux__) if (hw_en_on && hw_en_supported) { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); } else -// #endif #endif { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL); diff --git a/src/Settings.cpp b/src/Settings.cpp index 4f502341..461f9183 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -47,8 +47,8 @@ Settings *Settings::Instance() m_pInstance->MAX_WIDTH = 0; m_pInstance->MAX_HEIGHT = 0; m_pInstance->WAIT_FOR_VIDEO_PROCESSING_TASK = false; - m_pInstance->OMP_THREADS = 12;//OPEN_MP_NUM_PROCESSORS - m_pInstance->FF_THREADS = 8;//FF_NUM_PROCESSORS + m_pInstance->OMP_THREADS = 12; + m_pInstance->FF_THREADS = 8; m_pInstance->DE_LIMIT_HEIGHT_MAX = 1100; m_pInstance->DE_LIMIT_WIDTH_MAX = 1950; m_pInstance->HW_DE_DEVICE_SET = 0; From 334a46cc5de5a0331bf376a02188d5dba50987fa Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 1 Feb 2019 03:38:44 -0800 Subject: [PATCH 064/186] Fix check if GPU can be used for encoding and decoding --- src/FFmpegReader.cpp | 2 +- src/FFmpegWriter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2e938f35..7439db4d 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -415,7 +415,7 @@ void FFmpegReader::Open() } // Check if it is there and writable #if defined(__linux__) - if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { + if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) { #elif defined(_WIN32) if( adapter_ptr != NULL ) { #elif defined(__APPLE__) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 14171894..41285314 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1316,7 +1316,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) } // Check if it is there and writable #if defined(__linux__) - if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == -1 ) { + if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) { #elif defined(_WIN32) if( adapter_ptr != NULL ) { #elif defined(__APPLE__) From a2b8eaff37896d0b5e97a203d611ca000f2bcbee Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 15 Feb 2019 10:11:45 -0800 Subject: [PATCH 065/186] Allow to use nvenc and nvdec in Windows for nVidia cards. nVidia card don't use the DX API like intel or AMD cards. If ffmpeg and the libraries are compiled with nvenc and nvdec support on WIndows this should(!) now work. --- src/FFmpegReader.cpp | 21 +++++++++++++++++++++ src/FFmpegWriter.cpp | 15 ++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 7439db4d..1c80bb84 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -224,6 +224,23 @@ static enum AVPixelFormat get_hw_dec_format_d3(AVCodecContext *ctx, const enum A ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } + +static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { + case AV_PIX_FMT_CUDA: + hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; + return *p; + break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} #endif #if defined(__APPLE__) @@ -378,6 +395,10 @@ void FFmpegReader::Open() hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; break; + case 2: + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + pCodecCtx->get_format = get_hw_dec_format_cu; + break; case 3: hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 41285314..fb8040a8 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -203,9 +203,18 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i hw_en_av_device_type = AV_HWDEVICE_TYPE_DXVA2; } else { - new_codec = avcodec_find_encoder_by_name(codec.c_str()); - hw_en_on = 0; - hw_en_supported = 0; + if ( (strcmp(codec.c_str(),"h264_nvenc") == 0)) { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 1; + hw_en_supported = 1; + hw_en_av_pix_fmt = AV_PIX_FMT_CUDA; + hw_en_av_device_type = AV_HWDEVICE_TYPE_CUDA; + } + else { + new_codec = avcodec_find_encoder_by_name(codec.c_str()); + hw_en_on = 0; + hw_en_supported = 0; + } } #elif defined(__APPLE__) if ( (strcmp(codec.c_str(),"h264_qsv") == 0)) { From 48a2656080931cde020d1fbe61fb95cca25b5222 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 1 Mar 2019 16:32:52 -0800 Subject: [PATCH 066/186] AVoid crashes with mp3 that are tagged by removing AV_ALLOCATE_IMAGE(pFrame, AV_GET_CODEC_PIXEL_FORMAT( ... --- src/FFmpegReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index dae538f2..1b2c6b82 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -2369,7 +2369,7 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram void FFmpegReader::CheckFPS() { check_fps = true; - AV_ALLOCATE_IMAGE(pFrame, AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx), info.width, info.height); + int first_second_counter = 0; int second_second_counter = 0; From 16c3d53d038b72002d51a7d0605d1223c521ecdb Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 8 Mar 2019 14:26:14 -0800 Subject: [PATCH 067/186] Fix problem with q values for crf quality setting. DOTO adjust q values according to desired quality --- src/FFmpegWriter.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index fb8040a8..90266ffa 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1132,6 +1132,12 @@ AVStream* FFmpegWriter::add_video_stream() /* Init video encoder options */ if (info.video_bit_rate >= 1000) { c->bit_rate = info.video_bit_rate; + c->qmin = 2; + c->qmax = 30; + } + else { + c->qmin = 0; + c->qmax = 63; } //TODO: Implement variable bitrate feature (which actually works). This implementation throws @@ -1141,8 +1147,8 @@ AVStream* FFmpegWriter::add_video_stream() //c->rc_buffer_size = FFMAX(c->rc_max_rate, 15000000) * 112L / 15000000 * 16384; //if ( !c->rc_initial_buffer_occupancy ) // c->rc_initial_buffer_occupancy = c->rc_buffer_size * 3/4; - c->qmin = 2; - c->qmax = 30; +// c->qmin = 2; +// c->qmax = 30; /* resolution must be a multiple of two */ // TODO: require /2 height and width From 6a21c984e9898e84b6d58a6ef936c7ce9dca7b26 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 8 Mar 2019 14:41:40 -0800 Subject: [PATCH 068/186] Fixed q values for low fixed bitrates. Low bitrates should now be produced if desired. DOTO fine tune the q values --- src/FFmpegWriter.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 90266ffa..17290bce 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1132,8 +1132,14 @@ AVStream* FFmpegWriter::add_video_stream() /* Init video encoder options */ if (info.video_bit_rate >= 1000) { c->bit_rate = info.video_bit_rate; - c->qmin = 2; - c->qmax = 30; + if (info.video_bit_rate >= 1500000) { + c->qmin = 2; + c->qmax = 30; + } + else { + c->qmin = 0; + c->qmax = 63; + } } else { c->qmin = 0; From 6b9a9ca6ff1022ad60956d8643ca09decc839d38 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 8 Mar 2019 16:52:34 -0800 Subject: [PATCH 069/186] Removed the branch for low fixed bitrate q values as it did not work with mpeg2 export. Now for low fixed bitrates no presets for the q values are set. TODO find the optimum q values for each codec for low and high bitrates --- src/FFmpegWriter.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 17290bce..cf4004c4 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1136,10 +1136,8 @@ AVStream* FFmpegWriter::add_video_stream() c->qmin = 2; c->qmax = 30; } - else { - c->qmin = 0; - c->qmax = 63; - } + // Here should be the setting for low fixed bitrate + // Defaults are used because mpeg2 otherwise had problems } else { c->qmin = 0; @@ -1153,8 +1151,6 @@ AVStream* FFmpegWriter::add_video_stream() //c->rc_buffer_size = FFMAX(c->rc_max_rate, 15000000) * 112L / 15000000 * 16384; //if ( !c->rc_initial_buffer_occupancy ) // c->rc_initial_buffer_occupancy = c->rc_buffer_size * 3/4; -// c->qmin = 2; -// c->qmax = 30; /* resolution must be a multiple of two */ // TODO: require /2 height and width From b5ebc996eefde4aace92bf287a8a3297488cdd75 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 10 Mar 2019 10:42:48 -0700 Subject: [PATCH 070/186] Adjust the q values for low quality crf settings --- src/FFmpegWriter.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index cf4004c4..b1eb7ec3 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1140,8 +1140,14 @@ AVStream* FFmpegWriter::add_video_stream() // Defaults are used because mpeg2 otherwise had problems } else { - c->qmin = 0; - c->qmax = 63; + if (info.video_bit_rate < 40) { + c->qmin = 0; + c->qmax = 63; + } + else { + c->qmin = info.video_bit_rate - 5; + c->qmax = 63; + } } //TODO: Implement variable bitrate feature (which actually works). This implementation throws From a170d7db38f6a3798bec89bb8dd77ee3c8c5f384 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 10 Mar 2019 13:09:47 -0700 Subject: [PATCH 071/186] Check if the codec supports CRF when setting q values --- src/FFmpegWriter.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index b1eb7ec3..12bfda54 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1140,13 +1140,28 @@ AVStream* FFmpegWriter::add_video_stream() // Defaults are used because mpeg2 otherwise had problems } else { - if (info.video_bit_rate < 40) { - c->qmin = 0; - c->qmax = 63; - } - else { - c->qmin = info.video_bit_rate - 5; - c->qmax = 63; + // Check if codec supports crf + switch (c->codec_id) { + #if (LIBAVCODEC_VERSION_MAJOR >= 58) + case AV_CODEC_ID_AV1 : + #endif + case AV_CODEC_ID_VP8 : + case AV_CODEC_ID_VP9 : + case AV_CODEC_ID_H264 : + case AV_CODEC_ID_H265 : + if (info.video_bit_rate < 40) { + c->qmin = 0; + c->qmax = 63; + } + else { + c->qmin = info.video_bit_rate - 5; + c->qmax = 63; + } + break; + default: + // Here should be the setting for codecs that don't support crf + // For now defaults are used + break; } } From cd4e25ea6782748b18bbf5ba9709b727b029ac9b Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 10 Mar 2019 13:28:56 -0700 Subject: [PATCH 072/186] Fix for FFmpeg 2.x --- src/FFmpegWriter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 12bfda54..1c9094a6 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -1142,13 +1142,15 @@ AVStream* FFmpegWriter::add_video_stream() else { // Check if codec supports crf switch (c->codec_id) { + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) #if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : #endif - case AV_CODEC_ID_VP8 : case AV_CODEC_ID_VP9 : - case AV_CODEC_ID_H264 : case AV_CODEC_ID_H265 : + #endif + case AV_CODEC_ID_VP8 : + case AV_CODEC_ID_H264 : if (info.video_bit_rate < 40) { c->qmin = 0; c->qmax = 63; From abe44ade73f1f10850985c62f8114c2f46224e43 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 15 Mar 2019 13:14:52 -0500 Subject: [PATCH 073/186] Bumping version to 0.2.3 (SO 17) --- include/Version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Version.h b/include/Version.h index 4ff2c36c..6077cde5 100644 --- a/include/Version.h +++ b/include/Version.h @@ -36,8 +36,8 @@ #define OPENSHOT_VERSION_MAJOR 0; /// Major version number is incremented when huge features are added or improved. #define OPENSHOT_VERSION_MINOR 2; /// Minor version is incremented when smaller (but still very important) improvements are added. -#define OPENSHOT_VERSION_BUILD 2; /// Build number is incremented when minor bug fixes and less important improvements are added. -#define OPENSHOT_VERSION_SO 16; /// Shared object version number. This increments any time the API and ABI changes (so old apps will no longer link) +#define OPENSHOT_VERSION_BUILD 3; /// Build number is incremented when minor bug fixes and less important improvements are added. +#define OPENSHOT_VERSION_SO 17; /// Shared object version number. This increments any time the API and ABI changes (so old apps will no longer link) #define OPENSHOT_VERSION_MAJOR_MINOR STRINGIZE(OPENSHOT_VERSION_MAJOR) "." STRINGIZE(OPENSHOT_VERSION_MINOR); /// A string of the "Major.Minor" version #define OPENSHOT_VERSION_ALL STRINGIZE(OPENSHOT_VERSION_MAJOR) "." STRINGIZE(OPENSHOT_VERSION_MINOR) "." STRINGIZE(OPENSHOT_VERSION_BUILD); /// A string of the entire version "Major.Minor.Build" From 3e5dc1d7278504eae20427f0b5f0bcce7a4a97e5 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 29 Mar 2019 08:10:31 -0400 Subject: [PATCH 074/186] Streamline libopenshot-audio discovery --- cmake/Modules/FindOpenShotAudio.cmake | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/cmake/Modules/FindOpenShotAudio.cmake b/cmake/Modules/FindOpenShotAudio.cmake index 1de4529b..0aeb0e1f 100644 --- a/cmake/Modules/FindOpenShotAudio.cmake +++ b/cmake/Modules/FindOpenShotAudio.cmake @@ -7,31 +7,12 @@ message("$ENV{LIBOPENSHOT_AUDIO_DIR}") -# Find the base directory of juce includes -find_path(LIBOPENSHOT_AUDIO_BASE_DIR JuceHeader.h +# Find the libopenshot-audio header files +find_path(LIBOPENSHOT_AUDIO_INCLUDE_DIR JuceHeader.h PATHS $ENV{LIBOPENSHOT_AUDIO_DIR}/include/libopenshot-audio/ /usr/include/libopenshot-audio/ /usr/local/include/libopenshot-audio/ ) -# Get a list of all header file paths -FILE(GLOB_RECURSE JUCE_HEADER_FILES - ${LIBOPENSHOT_AUDIO_BASE_DIR}/*.h -) - -# Loop through each header file -FOREACH(HEADER_PATH ${JUCE_HEADER_FILES}) - # Get the directory of each header file - get_filename_component(HEADER_DIRECTORY ${HEADER_PATH} - PATH - ) - - # Append each directory into the HEADER_DIRECTORIES list - LIST(APPEND HEADER_DIRECTORIES ${HEADER_DIRECTORY}) -ENDFOREACH(HEADER_PATH) - -# Remove duplicates from the header directories list -LIST(REMOVE_DUPLICATES HEADER_DIRECTORIES) - # Find the libopenshot-audio.so (check env var first) find_library(LIBOPENSHOT_AUDIO_LIBRARY NAMES libopenshot-audio openshot-audio @@ -48,9 +29,7 @@ find_library(LIBOPENSHOT_AUDIO_LIBRARY set(LIBOPENSHOT_AUDIO_LIBRARIES ${LIBOPENSHOT_AUDIO_LIBRARY}) set(LIBOPENSHOT_AUDIO_LIBRARY ${LIBOPENSHOT_AUDIO_LIBRARIES}) -# Seems to work fine with just the base dir (rather than all the actual include folders) -set(LIBOPENSHOT_AUDIO_INCLUDE_DIR ${LIBOPENSHOT_AUDIO_BASE_DIR} ) -set(LIBOPENSHOT_AUDIO_INCLUDE_DIRS ${LIBOPENSHOT_AUDIO_BASE_DIR} ) +set(LIBOPENSHOT_AUDIO_INCLUDE_DIRS ${LIBOPENSHOT_AUDIO_INCLUDE_DIR} ) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBOPENSHOT_AUDIO_FOUND to TRUE From 7e7f5c341ac1e1bf5342eaaed72abcf8864bfb18 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 29 Mar 2019 08:11:19 -0400 Subject: [PATCH 075/186] Use new Juce header file location --- include/AudioBufferSource.h | 2 +- include/AudioReaderSource.h | 2 +- include/AudioResampler.h | 2 +- include/Clip.h | 2 +- include/Frame.h | 2 +- include/Settings.h | 2 +- include/ZmqLogger.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h index 57826f66..b1571c8d 100644 --- a/include/AudioBufferSource.h +++ b/include/AudioBufferSource.h @@ -37,7 +37,7 @@ #endif #include -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" using namespace std; diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index 31b17d80..3c82e7ad 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -37,7 +37,7 @@ #endif #include -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" #include "ReaderBase.h" using namespace std; diff --git a/include/AudioResampler.h b/include/AudioResampler.h index 412d49b1..f084329c 100644 --- a/include/AudioResampler.h +++ b/include/AudioResampler.h @@ -38,7 +38,7 @@ #define _NDEBUG #endif -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" #include "AudioBufferSource.h" #include "Exceptions.h" diff --git a/include/Clip.h b/include/Clip.h index 3cd33b3a..c9b914b8 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -36,7 +36,7 @@ #include #include #include -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" #include "AudioResampler.h" #include "ClipBase.h" #include "Color.h" diff --git a/include/Frame.h b/include/Frame.h index eba7f8bb..67c5ca02 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -56,7 +56,7 @@ #ifdef USE_IMAGEMAGICK #include "Magick++.h" #endif -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" #include "ChannelLayouts.h" #include "AudioBufferSource.h" #include "AudioResampler.h" diff --git a/include/Settings.h b/include/Settings.h index ec26338b..0629cc4f 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -29,7 +29,7 @@ #define OPENSHOT_SETTINGS_H -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" #include #include #include diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index 62773e68..112b2327 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -29,7 +29,7 @@ #define OPENSHOT_LOGGER_H -#include "JuceLibraryCode/JuceHeader.h" +#include "JuceHeader.h" #include #include #include From 13ab8b48bd99c9e76fbc835a0ed592e1ce565a85 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 30 Mar 2019 01:47:49 -0500 Subject: [PATCH 076/186] Moving JuceHeader.h in ZmqLogger.h, to come after system libraries (to prevent error on Mac related to Point declaration) --- include/ZmqLogger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index 112b2327..8ababac0 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -29,7 +29,6 @@ #define OPENSHOT_LOGGER_H -#include "JuceHeader.h" #include #include #include @@ -40,6 +39,7 @@ #include #include #include +#include "JuceHeader.h" using namespace std; From 6e2600dcd4e949b8208bf9571b7d1811e84729a6 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 30 Mar 2019 14:23:50 -0500 Subject: [PATCH 077/186] Moving JuceHeader.h below other includes, to be sure it is always included after system libraries (for Mac Point build failure) --- include/AudioReaderSource.h | 2 +- include/AudioResampler.h | 2 +- include/Clip.h | 2 +- include/EffectBase.h | 2 +- include/Frame.h | 2 +- include/Settings.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index 3c82e7ad..76c3dc7d 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -37,8 +37,8 @@ #endif #include -#include "JuceHeader.h" #include "ReaderBase.h" +#include "JuceHeader.h" using namespace std; diff --git a/include/AudioResampler.h b/include/AudioResampler.h index f084329c..b81bfc3e 100644 --- a/include/AudioResampler.h +++ b/include/AudioResampler.h @@ -38,9 +38,9 @@ #define _NDEBUG #endif -#include "JuceHeader.h" #include "AudioBufferSource.h" #include "Exceptions.h" +#include "JuceHeader.h" namespace openshot { diff --git a/include/Clip.h b/include/Clip.h index c9b914b8..346629e4 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -36,7 +36,6 @@ #include #include #include -#include "JuceHeader.h" #include "AudioResampler.h" #include "ClipBase.h" #include "Color.h" @@ -47,6 +46,7 @@ #include "Fraction.h" #include "KeyFrame.h" #include "ReaderBase.h" +#include "JuceHeader.h" using namespace std; using namespace openshot; diff --git a/include/EffectBase.h b/include/EffectBase.h index 209369a8..d38e3f45 100644 --- a/include/EffectBase.h +++ b/include/EffectBase.h @@ -32,8 +32,8 @@ #include #include #include "ClipBase.h" -#include "Frame.h" #include "Json.h" +#include "Frame.h" using namespace std; diff --git a/include/Frame.h b/include/Frame.h index 67c5ca02..66d8ccfa 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -56,11 +56,11 @@ #ifdef USE_IMAGEMAGICK #include "Magick++.h" #endif -#include "JuceHeader.h" #include "ChannelLayouts.h" #include "AudioBufferSource.h" #include "AudioResampler.h" #include "Fraction.h" +#include "JuceHeader.h" #pragma SWIG nowarn=362 using namespace std; diff --git a/include/Settings.h b/include/Settings.h index 0629cc4f..e46f12e0 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -29,7 +29,6 @@ #define OPENSHOT_SETTINGS_H -#include "JuceHeader.h" #include #include #include @@ -40,6 +39,7 @@ #include #include #include +#include "JuceHeader.h" using namespace std; From 76e87e6145a71f58839f7527de406669a68cbfb9 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Wed, 3 Apr 2019 23:07:47 -0500 Subject: [PATCH 078/186] Reorder x64 windows build before x86 build --- .gitlab-ci.yml | 60 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f8b13908..f0f868c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,6 +56,36 @@ mac-builder: tags: - mac +windows-builder-x64: + stage: build-libopenshot + artifacts: + expire_in: 6 months + paths: + - build\install-x64\* + script: + - try { Invoke-WebRequest -Uri "http://gitlab.openshot.org/OpenShot/libopenshot-audio/-/jobs/artifacts/$CI_COMMIT_REF_NAME/download?job=windows-builder-x64" -Headers @{"PRIVATE-TOKEN"="$ACCESS_TOKEN"} -OutFile "artifacts.zip" } catch { $_.Exception.Response.StatusCode.Value__ } + - if (-not (Test-Path "artifacts.zip")) { Invoke-WebRequest -Uri "http://gitlab.openshot.org/OpenShot/libopenshot-audio/-/jobs/artifacts/develop/download?job=windows-builder-x64" -Headers @{"PRIVATE-TOKEN"="$ACCESS_TOKEN"} -OutFile "artifacts.zip" } + - Expand-Archive -Path artifacts.zip -DestinationPath . + - $env:LIBOPENSHOT_AUDIO_DIR = "$CI_PROJECT_DIR\build\install-x64" + - $env:UNITTEST_DIR = "C:\msys64\usr" + - $env:ZMQDIR = "C:\msys64\usr" + - $env:Path = "C:\msys64\mingw64\bin;C:\msys64\mingw64\lib;C:\msys64\usr\lib\cmake\UnitTest++;C:\msys64\home\jonathan\depot_tools;C:\msys64\usr;C:\msys64\usr\lib;" + $env:Path; + - New-Item -ItemType Directory -Force -Path build + - New-Item -ItemType Directory -Force -Path build\install-x64\python + - cd build + - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -G "MinGW Makefiles" -D"CMAKE_BUILD_TYPE:STRING=Release" ../ + - mingw32-make install + - Move-Item -Force -path "C:\msys64\mingw64\lib\python3.6\site-packages\*openshot*" -destination "install-x64\python\" + - cp src\libopenshot.dll install-x64\lib + - New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force + - $PREV_GIT_LABEL=(git describe --tags --abbrev=0) + - git log "$PREV_GIT_LABEL..HEAD" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" + when: always + except: + - tags + tags: + - windows + windows-builder-x86: stage: build-libopenshot artifacts: @@ -87,36 +117,6 @@ windows-builder-x86: tags: - windows -windows-builder-x64: - stage: build-libopenshot - artifacts: - expire_in: 6 months - paths: - - build\install-x64\* - script: - - try { Invoke-WebRequest -Uri "http://gitlab.openshot.org/OpenShot/libopenshot-audio/-/jobs/artifacts/$CI_COMMIT_REF_NAME/download?job=windows-builder-x64" -Headers @{"PRIVATE-TOKEN"="$ACCESS_TOKEN"} -OutFile "artifacts.zip" } catch { $_.Exception.Response.StatusCode.Value__ } - - if (-not (Test-Path "artifacts.zip")) { Invoke-WebRequest -Uri "http://gitlab.openshot.org/OpenShot/libopenshot-audio/-/jobs/artifacts/develop/download?job=windows-builder-x64" -Headers @{"PRIVATE-TOKEN"="$ACCESS_TOKEN"} -OutFile "artifacts.zip" } - - Expand-Archive -Path artifacts.zip -DestinationPath . - - $env:LIBOPENSHOT_AUDIO_DIR = "$CI_PROJECT_DIR\build\install-x64" - - $env:UNITTEST_DIR = "C:\msys64\usr" - - $env:ZMQDIR = "C:\msys64\usr" - - $env:Path = "C:\msys64\mingw64\bin;C:\msys64\mingw64\lib;C:\msys64\usr\lib\cmake\UnitTest++;C:\msys64\home\jonathan\depot_tools;C:\msys64\usr;C:\msys64\usr\lib;" + $env:Path; - - New-Item -ItemType Directory -Force -Path build - - New-Item -ItemType Directory -Force -Path build\install-x64\python - - cd build - - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -G "MinGW Makefiles" -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - - mingw32-make install - - Move-Item -Force -path "C:\msys64\mingw64\lib\python3.6\site-packages\*openshot*" -destination "install-x64\python\" - - cp src\libopenshot.dll install-x64\lib - - New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - - $PREV_GIT_LABEL=(git describe --tags --abbrev=0) - - git log "$PREV_GIT_LABEL..HEAD" --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" - when: always - except: - - tags - tags: - - windows - trigger-pipeline: stage: trigger-openshot-qt script: From 9dbb063dedd3a759f11e9abd14ab4f89ffddfc40 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 4 Apr 2019 00:55:47 -0500 Subject: [PATCH 079/186] Persist any error returned by JUCE during initialise() method, such as sample rate issues on Windows (when playback and recording sample rates do not match, which breaks WASAPI) --- include/Qt/AudioPlaybackThread.h | 82 +++++++++++++++++--------------- include/QtPlayer.h | 3 ++ src/Frame.cpp | 8 +++- src/Qt/AudioPlaybackThread.cpp | 9 +++- src/QtPlayer.cpp | 14 ++++-- 5 files changed, 71 insertions(+), 45 deletions(-) diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index 68a2be3b..1d654756 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -57,12 +57,15 @@ namespace openshot class AudioDeviceManagerSingleton { private: /// Default constructor (Don't allow user to create an instance of this singleton) - AudioDeviceManagerSingleton(){}; + AudioDeviceManagerSingleton(){ initialise_error=""; }; /// Private variable to keep track of singleton instance static AudioDeviceManagerSingleton * m_pInstance; public: + /// Error found during JUCE initialise method + string initialise_error; + /// Create or get an instance of this singleton (invoke the class with this method) static AudioDeviceManagerSingleton * Instance(int numChannels); @@ -78,52 +81,55 @@ namespace openshot */ class AudioPlaybackThread : Thread { - AudioSourcePlayer player; - AudioTransportSource transport; - MixerAudioSource mixer; - AudioReaderSource *source; - double sampleRate; - int numChannels; - WaitableEvent play; - WaitableEvent played; - int buffer_size; - bool is_playing; - SafeTimeSliceThread time_thread; - - /// Constructor - AudioPlaybackThread(); - /// Destructor - ~AudioPlaybackThread(); + AudioSourcePlayer player; + AudioTransportSource transport; + MixerAudioSource mixer; + AudioReaderSource *source; + double sampleRate; + int numChannels; + WaitableEvent play; + WaitableEvent played; + int buffer_size; + bool is_playing; + SafeTimeSliceThread time_thread; - /// Set the current thread's reader - void Reader(ReaderBase *reader); + /// Constructor + AudioPlaybackThread(); + /// Destructor + ~AudioPlaybackThread(); - /// Get the current frame object (which is filling the buffer) - std::shared_ptr getFrame(); + /// Set the current thread's reader + void Reader(ReaderBase *reader); - /// Get the current frame number being played - int64_t getCurrentFramePosition(); + /// Get the current frame object (which is filling the buffer) + std::shared_ptr getFrame(); - /// Play the audio - void Play(); + /// Get the current frame number being played + int64_t getCurrentFramePosition(); - /// Seek the audio thread - void Seek(int64_t new_position); + /// Play the audio + void Play(); - /// Stop the audio playback - void Stop(); + /// Seek the audio thread + void Seek(int64_t new_position); - /// Start thread - void run(); - - /// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) - void setSpeed(int new_speed) { if (source) source->setSpeed(new_speed); } + /// Stop the audio playback + void Stop(); - /// Get Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) - int getSpeed() const { if (source) return source->getSpeed(); else return 1; } + /// Start thread + void run(); - friend class PlayerPrivate; - friend class QtPlayer; + /// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) + void setSpeed(int new_speed) { if (source) source->setSpeed(new_speed); } + + /// Get Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) + int getSpeed() const { if (source) return source->getSpeed(); else return 1; } + + /// Get Audio Error (if any) + string getError() { return AudioDeviceManagerSingleton::Instance(numChannels)->initialise_error; } + + friend class PlayerPrivate; + friend class QtPlayer; }; } diff --git a/include/QtPlayer.h b/include/QtPlayer.h index 354bbfc8..a1a7ee0c 100644 --- a/include/QtPlayer.h +++ b/include/QtPlayer.h @@ -59,6 +59,9 @@ namespace openshot /// Close audio device void CloseAudioDevice(); + /// Get Error (if any) + string GetError(); + /// Play the video void Play(); diff --git a/src/Frame.cpp b/src/Frame.cpp index a00fc232..24b653a9 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -953,11 +953,15 @@ void Frame::Play() return; AudioDeviceManager deviceManager; - deviceManager.initialise (0, /* number of input channels */ + String error = deviceManager.initialise (0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ true /* select default device on failure */); - //deviceManager.playTestSound(); + + // Output error (if any) + if (error.isNotEmpty()) { + cout << "Error on initialise(): " << error.toStdString() << endl; + } AudioSourcePlayer audioSourcePlayer; deviceManager.addAudioCallback (&audioSourcePlayer); diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index fac2e3fc..c64bd688 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -42,11 +42,18 @@ namespace openshot m_pInstance = new AudioDeviceManagerSingleton; // Initialize audio device only 1 time - m_pInstance->audioDeviceManager.initialise ( + String error = m_pInstance->audioDeviceManager.initialise ( 0, /* number of input channels */ numChannels, /* number of output channels */ 0, /* no XML settings.. */ true /* select default device on failure */); + + // Persist any errors detected + if (error.isNotEmpty()) { + m_pInstance->initialise_error = error.toStdString(); + } else { + m_pInstance->initialise_error = ""; + } } return m_pInstance; diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp index 028a9b70..4f53c7ca 100644 --- a/src/QtPlayer.cpp +++ b/src/QtPlayer.cpp @@ -59,12 +59,21 @@ void QtPlayer::CloseAudioDevice() AudioDeviceManagerSingleton::Instance(0)->CloseAudioDevice(); } +// Return any error string during initialization +string QtPlayer::GetError() { + if (reader && threads_started) { + // Get error from audio thread (if any) + return p->audioPlayback->getError(); + } else { + return ""; + } +} + void QtPlayer::SetSource(const std::string &source) { FFmpegReader *ffreader = new FFmpegReader(source); ffreader->DisplayInfo(); - //reader = new FrameMapper(ffreader, ffreader->info.fps, PULLDOWN_NONE, ffreader->info.sample_rate, ffreader->info.channels, ffreader->info.channel_layout); reader = new Timeline(ffreader->info.width, ffreader->info.height, ffreader->info.fps, ffreader->info.sample_rate, ffreader->info.channels, ffreader->info.channel_layout); Clip *c = new Clip(source); @@ -72,9 +81,6 @@ void QtPlayer::SetSource(const std::string &source) tm->AddClip(c); tm->Open(); -// ZmqLogger::Instance()->Path("/home/jonathan/.openshot_qt/libopenshot.log"); -// ZmqLogger::Instance()->Enable(true); - // Set the reader Reader(reader); } From 4c532fe1016a33c7262f565c511ac3ac1e888c7e Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 4 Apr 2019 20:30:15 -0500 Subject: [PATCH 080/186] Change travis ci to use xenial dist (instead of trusty) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fa191b2b..6954814f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -dist: trusty +dist: xenial matrix: include: From 6fb49710a3056e228722c9a4215f2179c8f5377a Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 4 Apr 2019 20:33:58 -0500 Subject: [PATCH 081/186] Requiring sudo for Travis ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6954814f..06d0a39e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ dist: xenial +sudo: required matrix: include: From 85a10291f61d6956028bc170c50b6a2c6dfd714f Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 4 Apr 2019 20:38:39 -0500 Subject: [PATCH 082/186] Updating Qt apt repository for xenial --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06d0a39e..879a8190 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: name: "FFmpeg 2" before_script: - sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y - - sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y + - sudo add-apt-repository ppa:beineri/opt-qt-5.10.0-xenial -y - sudo apt-get update -qq - sudo apt-get install gcc-4.8 cmake libavcodec-dev libavformat-dev libswscale-dev libavresample-dev libavutil-dev libopenshot-audio-dev libopenshot-dev libfdk-aac-dev libfdk-aac-dev libjsoncpp-dev libmagick++-dev libopenshot-audio-dev libunittest++-dev libzmq3-dev pkg-config python3-dev qtbase5-dev qtmultimedia5-dev swig -y - sudo apt autoremove -y @@ -21,7 +21,7 @@ matrix: name: "FFmpeg 3" before_script: - sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y - - sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y + - sudo add-apt-repository ppa:beineri/opt-qt-5.10.0-xenial -y - sudo add-apt-repository ppa:jonathonf/ffmpeg-3 -y - sudo apt-get update -qq - sudo apt-get install gcc-4.8 cmake libavcodec-dev libavformat-dev libswscale-dev libavresample-dev libavutil-dev libopenshot-audio-dev libopenshot-dev libfdk-aac-dev libfdk-aac-dev libjsoncpp-dev libmagick++-dev libopenshot-audio-dev libunittest++-dev libzmq3-dev pkg-config python3-dev qtbase5-dev qtmultimedia5-dev swig -y @@ -36,7 +36,7 @@ matrix: name: "FFmpeg 4" before_script: - sudo add-apt-repository ppa:openshot.developers/libopenshot-daily -y - - sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y + - sudo add-apt-repository ppa:beineri/opt-qt-5.10.0-xenial -y - sudo add-apt-repository ppa:jonathonf/ffmpeg -y - sudo add-apt-repository ppa:jonathonf/ffmpeg-4 -y - sudo add-apt-repository ppa:jonathonf/backports -y From 6ee1ab17a497993f207a6d08eb035b3b18bb2216 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 5 Jul 2018 15:49:45 -0400 Subject: [PATCH 083/186] Use updated, improved UseDoxygen.cmake --- cmake/Modules/UseDoxygen.cmake | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/UseDoxygen.cmake b/cmake/Modules/UseDoxygen.cmake index 48480e4d..b261d431 100644 --- a/cmake/Modules/UseDoxygen.cmake +++ b/cmake/Modules/UseDoxygen.cmake @@ -1,4 +1,30 @@ -# - Run Doxygen +# Redistribution and use is allowed according to the terms of the New +# BSD license: +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# - Run Doxygen # # Adds a doxygen target that runs doxygen to generate the html # and optionally the LaTeX API documentation. @@ -48,7 +74,6 @@ # # Redistribution and use is allowed according to the terms of the New # BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. # macro(usedoxygen_set_default name value type docstring) @@ -134,7 +159,9 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND) configure_file("${DOXYFILE_IN}" "${DOXYFILE}" @ONLY) - get_target_property(DOC_TARGET doc TYPE) + if(TARGET doc) + get_target_property(DOC_TARGET doc TYPE) + endif() if(NOT DOC_TARGET) add_custom_target(doc) endif() From 708f3254ca42aaa9a5f12178c0d5a59f87cc37aa Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 4 Apr 2019 23:09:44 -0400 Subject: [PATCH 084/186] Modernize project for CMake 3.1+ --- CMakeLists.txt | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eaf7d65f..cf1ae4ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ # # Copyright (c) 2008-2014 OpenShot Studios, LLC # . This file is part of -# OpenShot Library (libopenshot), an open-source project dedicated to -# delivering high quality video editing and animation solutions to the +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the # world. For more information visit . # # OpenShot Library (libopenshot) is free software: you can redistribute it @@ -24,24 +24,29 @@ # along with OpenShot Library. If not, see . ################################################################################ -cmake_minimum_required(VERSION 2.8.11) +cmake_minimum_required(VERSION 3.1...3.14 FATAL_ERROR) -MESSAGE("--------------------------------------------------------------") -MESSAGE("Welcome to the OpenShot Build System! CMake will now check for all required build") -MESSAGE("dependencies and notify you of any missing files or other issues. If you have any") -MESSAGE("questions or issues, please visit .") +message("\ +----------------------------------------------------------------- + Welcome to the OpenShot Build System! + +CMake will now check libopenshot's build dependencies and inform +you of any missing files or other issues. + +For more information, please visit . +-----------------------------------------------------------------") ################ ADD CMAKE MODULES ################## set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules") ################ GET VERSION INFORMATION FROM VERSION.H ################## -MESSAGE("--------------------------------------------------------------") -MESSAGE("Determining Version Number (from Version.h file)") +message(STATUS "Determining Version Number (from Version.h file)") #### Get the lines related to libopenshot version from the Version.h header -file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/include/Version.h OPENSHOT_VERSION_LINES - REGEX "#define[ ]+OPENSHOT_VERSION_.*[0-9]+;.*") - +file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/include/Version.h + OPENSHOT_VERSION_LINES + REGEX "#define[ ]+OPENSHOT_VERSION_.*[0-9]+;.*") + #### Set each line into it's own variable list (GET OPENSHOT_VERSION_LINES 0 LINE_MAJOR) list (GET OPENSHOT_VERSION_LINES 1 LINE_MINOR) @@ -53,22 +58,23 @@ STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_MAJOR[ ]+([0-9]+);(.*)" "\\1" STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_MINOR[ ]+([0-9]+);(.*)" "\\1" MINOR_VERSION "${LINE_MINOR}") STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_BUILD[ ]+([0-9]+);(.*)" "\\1" BUILD_VERSION "${LINE_BUILD}") STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_SO[ ]+([0-9]+);(.*)" "\\1" SO_VERSION "${LINE_SO}") -set(PROJECT_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_VERSION}") -MESSAGE("--> MAJOR Version: ${MAJOR_VERSION}") -MESSAGE("--> MINOR Version: ${MINOR_VERSION}") -MESSAGE("--> BUILD Version: ${BUILD_VERSION}") -MESSAGE("--> SO/API/ABI Version: ${SO_VERSION}") -MESSAGE("--> VERSION: ${PROJECT_VERSION}") -MESSAGE("") +message(STATUS "Determining Version Number - done") ################### SETUP PROJECT ################### -PROJECT(openshot) -MESSAGE("--------------------------------------------------------------") -MESSAGE("Generating build files for ${PROJECT_NAME} (${PROJECT_VERSION})") +PROJECT(libopenshot LANGUAGES CXX + VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_VERSION}) + +message("\ +Generating build files for OpenShot + Building ${PROJECT_NAME} (version ${PROJECT_VERSION}) + SO/API/ABI Version: ${SO_VERSION} +") #### Enable C++11 (for std::shared_ptr support) -set(CMAKE_CXX_FLAGS "-std=c++11") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) IF (WIN32) SET_PROPERTY(GLOBAL PROPERTY WIN32 "WIN32") From 3d8c2412f0b42471437d9ab7af44db1c2a790f55 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 4 Apr 2019 23:10:53 -0400 Subject: [PATCH 085/186] Bindings build in CMake 3.1-3.14+ --- src/bindings/python/CMakeLists.txt | 77 +++++++++++++++++++----------- src/bindings/ruby/CMakeLists.txt | 40 +++++++++++----- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 80f012ee..96dbf13f 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -6,8 +6,8 @@ # # Copyright (c) 2008-2014 OpenShot Studios, LLC # . This file is part of -# OpenShot Library (libopenshot), an open-source project dedicated to -# delivering high quality video editing and animation solutions to the +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the # world. For more information visit . # # OpenShot Library (libopenshot) is free software: you can redistribute it @@ -29,37 +29,56 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) +### Enable some legacy SWIG behaviors, in newer CMAKE +cmake_policy(SET CMP0078 OLD) +cmake_policy(SET CMP0086 OLD) + FIND_PACKAGE(PythonLibs 3) FIND_PACKAGE(PythonInterp 3) -IF (PYTHONLIBS_FOUND) - IF (PYTHONINTERP_FOUND) +if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) - ### Include Python header files - INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - - ### Enable C++ support in SWIG - SET_SOURCE_FILES_PROPERTIES(openshot.i PROPERTIES CPLUSPLUS ON) - SET(CMAKE_SWIG_FLAGS "") - - ### Add the SWIG interface file (which defines all the SWIG methods) - SWIG_ADD_MODULE(openshot python openshot.i) + ### Include Python header files + INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - ### Link the new python wrapper library with libopenshot - SWIG_LINK_LIBRARIES(openshot ${PYTHON_LIBRARIES} openshot) + ### Enable C++ support in SWIG + set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) + set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + SET(CMAKE_SWIG_FLAGS "") - ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - EXECUTE_PROCESS ( COMMAND ${PYTHON_EXECUTABLE} -c "import site; print(site.getsitepackages()[0])" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH}) + ### Add the SWIG interface file (which defines all the SWIG methods) + if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(pyopenshot python openshot.i) + else() + swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) + endif() - ############### INSTALL HEADERS & LIBRARY ################ - ### Install Python bindings - INSTALL(TARGETS _openshot DESTINATION ${PYTHON_MODULE_PATH} ) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py DESTINATION ${PYTHON_MODULE_PATH} ) + ### Set output name of target + set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES + PREFIX "_" OUTPUT_NAME "openshot") - ENDIF(PYTHONINTERP_FOUND) -ENDIF (PYTHONLIBS_FOUND) + ### Link the new python wrapper library with libopenshot + target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} + ${PYTHON_LIBRARIES} openshot) + + ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ +from distutils.sysconfig import get_python_lib; \ +print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH}) + + ############### INSTALL HEADERS & LIBRARY ################ + ### Install Python bindings + INSTALL(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} + LIBRARY DESTINATION ${PYTHON_MODULE_PATH} ) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py + DESTINATION ${PYTHON_MODULE_PATH} ) + +endif () diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 75cee048..7ae8440b 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -6,8 +6,8 @@ # # Copyright (c) 2008-2014 OpenShot Studios, LLC # . This file is part of -# OpenShot Library (libopenshot), an open-source project dedicated to -# delivering high quality video editing and animation solutions to the +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the # world. For more information visit . # # OpenShot Library (libopenshot) is free software: you can redistribute it @@ -29,35 +29,49 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) +### Enable some legacy SWIG behaviors, in newer CMAKE +cmake_policy(SET CMP0078 OLD) +cmake_policy(SET CMP0086 OLD) + FIND_PACKAGE(Ruby) IF (RUBY_FOUND) ### Include the Ruby header files INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - + ### Enable C++ in SWIG - SET_SOURCE_FILES_PROPERTIES(openshot.i PROPERTIES CPLUSPLUS ON) + set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) + set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + SET(CMAKE_SWIG_FLAGS "") ### Add the SWIG interface file (which defines all the SWIG methods) - SWIG_ADD_MODULE(rbopenshot ruby openshot.i) - + if (CMAKE_VERSION VERSION_LESS 3.8.0) + swig_add_module(rbopenshot ruby openshot.i) + else() + swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) + endif() + ### Set name of target (with no prefix, since Ruby does not like that) - SET_TARGET_PROPERTIES(rbopenshot PROPERTIES PREFIX "" OUTPUT_NAME "openshot") + SET_TARGET_PROPERTIES(${SWIG_MODULE_rbopenshot_REAL_NAME} PROPERTIES + PREFIX "" OUTPUT_NAME "openshot") ### Link the new Ruby wrapper library with libopenshot - SWIG_LINK_LIBRARIES(rbopenshot ${RUBY_LIBRARY} openshot) - + target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} + ${RUBY_LIBRARY} openshot) + ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" OUTPUT_VARIABLE RUBY_VENDOR_ARCH_DIR) + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} + -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" + OUTPUT_VARIABLE RUBY_VENDOR_ARCH_DIR) MESSAGE(STATUS "Ruby executable: ${RUBY_EXECUTABLE}") MESSAGE(STATUS "Ruby vendor arch dir: ${RUBY_VENDOR_ARCH_DIR}") MESSAGE(STATUS "Ruby include path: ${RUBY_INCLUDE_PATH}") - ############### INSTALL HEADERS & LIBRARY ################ # Install Ruby bindings - INSTALL(TARGETS rbopenshot LIBRARY DESTINATION ${RUBY_VENDOR_ARCH_DIR}) - + install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} + LIBRARY DESTINATION ${RUBY_VENDOR_ARCH_DIR} ) + ENDIF (RUBY_FOUND) From 268e72aaf3383b72792c27b9c6945032d086a043 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 4 Apr 2019 23:30:28 -0400 Subject: [PATCH 086/186] Update copyright and cmake output --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf1ae4ff..71c56f37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the @@ -59,13 +59,17 @@ STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_MINOR[ ]+([0-9]+);(.*)" "\\1" STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_BUILD[ ]+([0-9]+);(.*)" "\\1" BUILD_VERSION "${LINE_BUILD}") STRING(REGEX REPLACE "#define[ ]+OPENSHOT_VERSION_SO[ ]+([0-9]+);(.*)" "\\1" SO_VERSION "${LINE_SO}") +message(STATUS "MAJOR Version: ${MAJOR_VERSION}") +message(STATUS "MINOR Version: ${MINOR_VERSION}") +message(STATUS "BUILD Version: ${BUILD_VERSION}") +message(STATUS "SO/API/ABI Version: ${SO_VERSION}") message(STATUS "Determining Version Number - done") ################### SETUP PROJECT ################### PROJECT(libopenshot LANGUAGES CXX VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_VERSION}) -message("\ +message(" Generating build files for OpenShot Building ${PROJECT_NAME} (version ${PROJECT_VERSION}) SO/API/ABI Version: ${SO_VERSION} From f3c35da5c80a77fadeb8298a07d179fbb2bc189a Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 5 Apr 2019 00:49:27 -0400 Subject: [PATCH 087/186] Don't break older cmake with new policy --- src/bindings/python/CMakeLists.txt | 10 ++-- src/bindings/python/CMakeLists.txt~ | 72 +++++++++++++++++++++++++++++ src/bindings/ruby/CMakeLists.txt | 10 ++-- src/bindings/ruby/CMakeLists.txt~ | 66 ++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 src/bindings/python/CMakeLists.txt~ create mode 100644 src/bindings/ruby/CMakeLists.txt~ diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 96dbf13f..93ae9360 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -29,9 +29,13 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) -### Enable some legacy SWIG behaviors, in newer CMAKE -cmake_policy(SET CMP0078 OLD) -cmake_policy(SET CMP0086 OLD) +### Enable some legacy SWIG behaviors, in newer CMAKEs +if (CMAKE_VERSION VERSION_GREATER 3.13) + cmake_policy(SET CMP0078 OLD) +endif() +if (CMAKE_VERSION VERSION_GREATER 3.14) + cmake_policy(SET CMP0086 OLD) +endif() FIND_PACKAGE(PythonLibs 3) FIND_PACKAGE(PythonInterp 3) diff --git a/src/bindings/python/CMakeLists.txt~ b/src/bindings/python/CMakeLists.txt~ new file mode 100644 index 00000000..43c30a0e --- /dev/null +++ b/src/bindings/python/CMakeLists.txt~ @@ -0,0 +1,72 @@ +####################### CMakeLists.txt (libopenshot) ######################### +# @brief CMake build file for libopenshot (used to generate Python SWIG bindings) +# @author Jonathan Thomas +# +# @section LICENSE +# +# Copyright (c) 2008-2014 OpenShot Studios, LLC +# . This file is part of +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the +# world. For more information visit . +# +# OpenShot Library (libopenshot) 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 3 of the +# License, or (at your option) any later version. +# +# OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . +################################################################################ + + +############### SWIG PYTHON BINDINGS ################ +FIND_PACKAGE(SWIG 2.0 REQUIRED) +INCLUDE(${SWIG_USE_FILE}) + +FIND_PACKAGE(PythonLibs 3) +FIND_PACKAGE(PythonInterp 3) +if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) + + ### Include Python header files + INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + + ### Enable C++ support in SWIG + set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) + set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + SET(CMAKE_SWIG_FLAGS "") + + ### Add the SWIG interface file (which defines all the SWIG methods) + swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) + + ### Set output name of target + set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES + PREFIX "_" OUTPUT_NAME "openshot") + + ### Link the new python wrapper library with libopenshot + target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} ${PYTHON_LIBRARIES} openshot) + + ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c + "from distutils.sysconfig import get_python_lib; print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH}) + + ############### INSTALL HEADERS & LIBRARY ################ + ### Install Python bindings + INSTALL(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} + LIBRARY DESTINATION ${PYTHON_MODULE_PATH} ) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py + DESTINATION ${PYTHON_MODULE_PATH} ) + +endif () diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 7ae8440b..82c9d5d5 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -29,9 +29,13 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) -### Enable some legacy SWIG behaviors, in newer CMAKE -cmake_policy(SET CMP0078 OLD) -cmake_policy(SET CMP0086 OLD) +### Enable some legacy SWIG behaviors, in newer CMAKEs +if (CMAKE_VERSION VERSION_GREATER 3.13) + cmake_policy(SET CMP0078 OLD) +endif() +if (CMAKE_VERSION VERSION_GREATER 3.14) + cmake_policy(SET CMP0086 OLD) +endif() FIND_PACKAGE(Ruby) IF (RUBY_FOUND) diff --git a/src/bindings/ruby/CMakeLists.txt~ b/src/bindings/ruby/CMakeLists.txt~ new file mode 100644 index 00000000..e1b36449 --- /dev/null +++ b/src/bindings/ruby/CMakeLists.txt~ @@ -0,0 +1,66 @@ +####################### CMakeLists.txt (libopenshot) ######################### +# @brief CMake build file for libopenshot (used to generate Ruby SWIG bindings) +# @author Jonathan Thomas +# +# @section LICENSE +# +# Copyright (c) 2008-2014 OpenShot Studios, LLC +# . This file is part of +# OpenShot Library (libopenshot), an open-source project dedicated to +# delivering high quality video editing and animation solutions to the +# world. For more information visit . +# +# OpenShot Library (libopenshot) 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 3 of the +# License, or (at your option) any later version. +# +# OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . +################################################################################ + + +############### RUBY BINDINGS ################ +FIND_PACKAGE(SWIG 2.0 REQUIRED) +INCLUDE(${SWIG_USE_FILE}) + +FIND_PACKAGE(Ruby) +IF (RUBY_FOUND) + + ### Include the Ruby header files + INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + + ### Enable C++ in SWIG + set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) + set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) + + SET(CMAKE_SWIG_FLAGS "") + + ### Add the SWIG interface file (which defines all the SWIG methods) + swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) + + ### Set name of target (with no prefix, since Ruby does not like that) + SET_TARGET_PROPERTIES(${SWIG_MODULE_rbopenshot_REAL_NAME} + PROPERTIES PREFIX "" OUTPUT_NAME "openshot") + + ### Link the new Ruby wrapper library with libopenshot + target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} ${RUBY_LIBRARY} openshot) + + ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) + EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" OUTPUT_VARIABLE RUBY_VENDOR_ARCH_DIR) + MESSAGE(STATUS "Ruby executable: ${RUBY_EXECUTABLE}") + MESSAGE(STATUS "Ruby vendor arch dir: ${RUBY_VENDOR_ARCH_DIR}") + MESSAGE(STATUS "Ruby include path: ${RUBY_INCLUDE_PATH}") + + + ############### INSTALL HEADERS & LIBRARY ################ + # Install Ruby bindings + install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} LIBRARY DESTINATION ${RUBY_VENDOR_ARCH_DIR} ) + +ENDIF (RUBY_FOUND) From f26978d889932f9db8b4ef15b19980111b011923 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 5 Apr 2019 01:08:38 -0400 Subject: [PATCH 088/186] tests/CMakeLists.txt: Use generic PROJECT_SOURCE_DIR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Previously it was using the variable `${openshot_SOURCE_DIR}` which assumes the project name is "openshot" — but it changed.) --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f2ae9377..2d2a0122 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,7 +24,7 @@ # along with OpenShot Library. If not, see . ################################################################################ -SET(TEST_MEDIA_PATH "${openshot_SOURCE_DIR}/src/examples/") +SET(TEST_MEDIA_PATH "${PROJECT_SOURCE_DIR}/src/examples/") ################ WINDOWS ################## # Set some compiler options for Windows From 42e2c9912b572d3d62f2424a17980aff5b669557 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Fri, 5 Apr 2019 17:32:34 -0400 Subject: [PATCH 089/186] Re-enable C lang for old CMake --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c56f37..2e3a49c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ message(STATUS "SO/API/ABI Version: ${SO_VERSION}") message(STATUS "Determining Version Number - done") ################### SETUP PROJECT ################### -PROJECT(libopenshot LANGUAGES CXX +PROJECT(libopenshot LANGUAGES C CXX VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${BUILD_VERSION}) message(" From b1f1df7dcd0ab45b30741303d4b99f0511399723 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 5 Apr 2019 17:10:29 -0500 Subject: [PATCH 090/186] Attempt to fix cmake "test" reserved word error --- tests/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2d2a0122..02c8f9b4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -224,8 +224,8 @@ IF (NOT DISABLE_TESTS) # Link libraries to the new executable target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) - #################### MAKE TEST ###################### # Hook up the 'make test' target to the 'openshot-test' executable - ADD_CUSTOM_TARGET(test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) + ADD_TEST(NAME openshot-test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) ENDIF (NOT DISABLE_TESTS) From dbc6e8ec61d2bb67cdf1d8d1b58a14484bb151ff Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 5 Apr 2019 17:40:38 -0500 Subject: [PATCH 091/186] Attempt to fix cmake "test" reserved word error --- tests/CMakeLists.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 02c8f9b4..4b3e4cfb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -224,8 +224,16 @@ IF (NOT DISABLE_TESTS) # Link libraries to the new executable target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) + # Add cmake policy + cmake_policy(PUSH) + if(POLICY CMP0037) + cmake_policy(SET CMP0037 OLD) + endif() + #################### MAKE TEST ###################### # Hook up the 'make test' target to the 'openshot-test' executable - ADD_TEST(NAME openshot-test - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) + ADD_CUSTOM_TARGET(test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) + + # Remove cmake policy + cmake_policy(POP) ENDIF (NOT DISABLE_TESTS) From ab46eea1c42c64c05a79ebc1fa78c31df002bd0a Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 6 Apr 2019 06:17:44 -0400 Subject: [PATCH 092/186] Remove accidentally-committed tilde files I snuck `src/bindings/*/CMakeLists.txt~` files into one of my recent commits somehow. This commit removes them, and adds an explicit `*~` to `.gitignore` to help prevent a repeat occurrence. --- .gitignore | 1 + src/bindings/python/CMakeLists.txt~ | 72 ----------------------------- src/bindings/ruby/CMakeLists.txt~ | 66 -------------------------- 3 files changed, 1 insertion(+), 138 deletions(-) delete mode 100644 src/bindings/python/CMakeLists.txt~ delete mode 100644 src/bindings/ruby/CMakeLists.txt~ diff --git a/.gitignore b/.gitignore index a11656cf..022991be 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build/* .project .cproject /.metadata/ +*~ diff --git a/src/bindings/python/CMakeLists.txt~ b/src/bindings/python/CMakeLists.txt~ deleted file mode 100644 index 43c30a0e..00000000 --- a/src/bindings/python/CMakeLists.txt~ +++ /dev/null @@ -1,72 +0,0 @@ -####################### CMakeLists.txt (libopenshot) ######################### -# @brief CMake build file for libopenshot (used to generate Python SWIG bindings) -# @author Jonathan Thomas -# -# @section LICENSE -# -# Copyright (c) 2008-2014 OpenShot Studios, LLC -# . This file is part of -# OpenShot Library (libopenshot), an open-source project dedicated to -# delivering high quality video editing and animation solutions to the -# world. For more information visit . -# -# OpenShot Library (libopenshot) 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 3 of the -# License, or (at your option) any later version. -# -# OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . -################################################################################ - - -############### SWIG PYTHON BINDINGS ################ -FIND_PACKAGE(SWIG 2.0 REQUIRED) -INCLUDE(${SWIG_USE_FILE}) - -FIND_PACKAGE(PythonLibs 3) -FIND_PACKAGE(PythonInterp 3) -if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) - - ### Include Python header files - INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - - ### Enable C++ support in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - SET(CMAKE_SWIG_FLAGS "") - - ### Add the SWIG interface file (which defines all the SWIG methods) - swig_add_library(pyopenshot LANGUAGE python SOURCES openshot.i) - - ### Set output name of target - set_target_properties(${SWIG_MODULE_pyopenshot_REAL_NAME} PROPERTIES - PREFIX "_" OUTPUT_NAME "openshot") - - ### Link the new python wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} ${PYTHON_LIBRARIES} openshot) - - ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c - "from distutils.sysconfig import get_python_lib; print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH}) - - ############### INSTALL HEADERS & LIBRARY ################ - ### Install Python bindings - INSTALL(TARGETS ${SWIG_MODULE_pyopenshot_REAL_NAME} - LIBRARY DESTINATION ${PYTHON_MODULE_PATH} ) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/openshot.py - DESTINATION ${PYTHON_MODULE_PATH} ) - -endif () diff --git a/src/bindings/ruby/CMakeLists.txt~ b/src/bindings/ruby/CMakeLists.txt~ deleted file mode 100644 index e1b36449..00000000 --- a/src/bindings/ruby/CMakeLists.txt~ +++ /dev/null @@ -1,66 +0,0 @@ -####################### CMakeLists.txt (libopenshot) ######################### -# @brief CMake build file for libopenshot (used to generate Ruby SWIG bindings) -# @author Jonathan Thomas -# -# @section LICENSE -# -# Copyright (c) 2008-2014 OpenShot Studios, LLC -# . This file is part of -# OpenShot Library (libopenshot), an open-source project dedicated to -# delivering high quality video editing and animation solutions to the -# world. For more information visit . -# -# OpenShot Library (libopenshot) 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 3 of the -# License, or (at your option) any later version. -# -# OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . -################################################################################ - - -############### RUBY BINDINGS ################ -FIND_PACKAGE(SWIG 2.0 REQUIRED) -INCLUDE(${SWIG_USE_FILE}) - -FIND_PACKAGE(Ruby) -IF (RUBY_FOUND) - - ### Include the Ruby header files - INCLUDE_DIRECTORIES(${RUBY_INCLUDE_DIRS}) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - - ### Enable C++ in SWIG - set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON) - set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot) - - SET(CMAKE_SWIG_FLAGS "") - - ### Add the SWIG interface file (which defines all the SWIG methods) - swig_add_library(rbopenshot LANGUAGE ruby SOURCES openshot.i) - - ### Set name of target (with no prefix, since Ruby does not like that) - SET_TARGET_PROPERTIES(${SWIG_MODULE_rbopenshot_REAL_NAME} - PROPERTIES PREFIX "" OUTPUT_NAME "openshot") - - ### Link the new Ruby wrapper library with libopenshot - target_link_libraries(${SWIG_MODULE_rbopenshot_REAL_NAME} ${RUBY_LIBRARY} openshot) - - ### FIND THE RUBY INTERPRETER (AND THE LOAD_PATH FOLDER) - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" OUTPUT_VARIABLE RUBY_VENDOR_ARCH_DIR) - MESSAGE(STATUS "Ruby executable: ${RUBY_EXECUTABLE}") - MESSAGE(STATUS "Ruby vendor arch dir: ${RUBY_VENDOR_ARCH_DIR}") - MESSAGE(STATUS "Ruby include path: ${RUBY_INCLUDE_PATH}") - - - ############### INSTALL HEADERS & LIBRARY ################ - # Install Ruby bindings - install(TARGETS ${SWIG_MODULE_rbopenshot_REAL_NAME} LIBRARY DESTINATION ${RUBY_VENDOR_ARCH_DIR} ) - -ENDIF (RUBY_FOUND) From 496183ce90aac265aba6e86416ddb7bbc3207e54 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 6 Apr 2019 11:05:59 -0500 Subject: [PATCH 093/186] change `make test` to `make os_test` (due to changes in cmake 3) --- .travis.yml | 6 +++--- tests/CMakeLists.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 879a8190..4afd8467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ matrix: - mkdir -p build; cd build; - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - - make test + - make os_test - language: cpp name: "FFmpeg 3" @@ -30,7 +30,7 @@ matrix: - mkdir -p build; cd build; - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - - make test + - make os_test - language: cpp name: "FFmpeg 4" @@ -47,4 +47,4 @@ matrix: - mkdir -p build; cd build; - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - - make test + - make os_test diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4b3e4cfb..18a5d26e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -231,8 +231,8 @@ IF (NOT DISABLE_TESTS) endif() #################### MAKE TEST ###################### - # Hook up the 'make test' target to the 'openshot-test' executable - ADD_CUSTOM_TARGET(test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) + # Hook up the 'make os_test' target to the 'openshot-test' executable + ADD_CUSTOM_TARGET(os_test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) # Remove cmake policy cmake_policy(POP) From 999d2021cfc88156ab99e8aa6607fcbd9587f200 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 6 Apr 2019 09:54:58 -0700 Subject: [PATCH 094/186] cmake target test renamed to os_test (test is predefined in cmake 3) --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2d2a0122..07bb23c3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -227,5 +227,5 @@ IF (NOT DISABLE_TESTS) #################### MAKE TEST ###################### # Hook up the 'make test' target to the 'openshot-test' executable - ADD_CUSTOM_TARGET(test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) + ADD_CUSTOM_TARGET(os_test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) ENDIF (NOT DISABLE_TESTS) From 9a7a720e3c3fe961698de779787ac83b5b71c53b Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 6 Apr 2019 10:26:04 -0700 Subject: [PATCH 095/186] change target of test to os_test in travis --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 879a8190..4afd8467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ matrix: - mkdir -p build; cd build; - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - - make test + - make os_test - language: cpp name: "FFmpeg 3" @@ -30,7 +30,7 @@ matrix: - mkdir -p build; cd build; - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - - make test + - make os_test - language: cpp name: "FFmpeg 4" @@ -47,4 +47,4 @@ matrix: - mkdir -p build; cd build; - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - - make test + - make os_test From 6e7b989b93960529e2700ba276fd947fa230d8d9 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 6 Apr 2019 12:34:29 -0500 Subject: [PATCH 096/186] Removing policy experiment --- tests/CMakeLists.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 18a5d26e..1ec36460 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -224,16 +224,7 @@ IF (NOT DISABLE_TESTS) # Link libraries to the new executable target_link_libraries(openshot-test openshot ${UNITTEST++_LIBRARY}) - # Add cmake policy - cmake_policy(PUSH) - if(POLICY CMP0037) - cmake_policy(SET CMP0037 OLD) - endif() - #################### MAKE TEST ###################### # Hook up the 'make os_test' target to the 'openshot-test' executable ADD_CUSTOM_TARGET(os_test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) - - # Remove cmake policy - cmake_policy(POP) ENDIF (NOT DISABLE_TESTS) From 62a68aac13ca7f510192fd320f7b33e3f561d7cd Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 6 Apr 2019 13:19:06 -0500 Subject: [PATCH 097/186] Fixing python install logic in gitlab (since we've changed the prefix of where it's installed) --- .gitlab-ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f0f868c9..42656302 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ linux-builder: - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - make - make install - - mv /usr/local/lib/python3.4/dist-packages/*openshot* install-x64/python + - mv install-x64/lib/python3.4/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" when: always @@ -47,7 +47,7 @@ mac-builder: - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=/usr/local/opt/gcc48/bin/g++-4.8 -DCMAKE_C_COMPILER=/usr/local/opt/gcc48/bin/gcc-4.8 -DCMAKE_PREFIX_PATH=/usr/local/qt5/5.5/clang_64 -DPYTHON_INCLUDE_DIR=/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -DPYTHON_LIBRARY=/Library/Frameworks/Python.framework/Versions/3.6/lib/libpython3.6.dylib -DPython_FRAMEWORKS=/Library/Frameworks/Python.framework/ -D"CMAKE_BUILD_TYPE:STRING=Debug" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../ - make - make install - - mv /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/*openshot* install-x64/python + - mv install-x64/lib/python3.6/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" when: always @@ -75,7 +75,7 @@ windows-builder-x64: - cd build - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x64" -G "MinGW Makefiles" -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - mingw32-make install - - Move-Item -Force -path "C:\msys64\mingw64\lib\python3.6\site-packages\*openshot*" -destination "install-x64\python\" + - Move-Item -Force -path "install-x64\lib\python3.6\site-packages\*openshot*" -destination "install-x64\python\" - cp src\libopenshot.dll install-x64\lib - New-Item -path "install-x64/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - $PREV_GIT_LABEL=(git describe --tags --abbrev=0) @@ -106,7 +106,7 @@ windows-builder-x86: - cd build - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR\build\install-x86" -G "MinGW Makefiles" -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_CXX_FLAGS=-m32" -D"CMAKE_EXE_LINKER_FLAGS=-Wl,--large-address-aware" -D"CMAKE_C_FLAGS=-m32" ../ - mingw32-make install - - Move-Item -Force -path "C:\msys32\mingw32\lib\python3.6\site-packages\*openshot*" -destination "install-x86\python\" + - Move-Item -Force -path "install-x86\lib\python3.6\site-packages\*openshot*" -destination "install-x86\python\" - cp src\libopenshot.dll install-x86\lib - New-Item -path "install-x86/share/" -Name "$CI_PROJECT_NAME" -Value "CI_PROJECT_NAME:$CI_PROJECT_NAME`nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME`nCI_COMMIT_SHA:$CI_COMMIT_SHA`nCI_JOB_ID:$CI_JOB_ID" -ItemType file -force - $PREV_GIT_LABEL=(git describe --tags --abbrev=0) From 2748e9a2a285f11639e71c1502e88bbead733cf7 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 6 Apr 2019 19:24:32 -0400 Subject: [PATCH 098/186] Use if(POLICY) I somehow missed that `if(POLICY CMPxxxx)` exists to wrap `cmp_policy()` calls so only CMake versions that understand that policy attempt to set it. Which is way smarter than the version-based logic I was using. --- src/bindings/python/CMakeLists.txt | 4 ++-- src/bindings/ruby/CMakeLists.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 93ae9360..3418d2de 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -30,10 +30,10 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs -if (CMAKE_VERSION VERSION_GREATER 3.13) +if (POLICY CMP0078) cmake_policy(SET CMP0078 OLD) endif() -if (CMAKE_VERSION VERSION_GREATER 3.14) +if (POLICY CMP0086) cmake_policy(SET CMP0086 OLD) endif() diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 82c9d5d5..7e3bce99 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -30,10 +30,10 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs -if (CMAKE_VERSION VERSION_GREATER 3.13) +if (POLICY CMP0078) cmake_policy(SET CMP0078 OLD) endif() -if (CMAKE_VERSION VERSION_GREATER 3.14) +if (POLICY CMP0086) cmake_policy(SET CMP0086 OLD) endif() From 04b3d2f6b1c61e99884efc6a363a8d24857f1304 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 6 Apr 2019 19:38:44 -0400 Subject: [PATCH 099/186] Fix up JsonCPP discovery messages The JsonCPP discovery previously claimed it "Could NOT find" the system JsonCPP, even when it never checked because USE_SYSTEM_JSONCPP was not enabled. With this change it correctly reports whether it's looking for the system install or just using the built-in copy. For convenience, the message includes the name of the option that controls this behavior. --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 71541432..d793ffa2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -199,10 +199,12 @@ endif(RESVG_FOUND) ################### JSONCPP ##################### # Include jsoncpp headers (needed for JSON parsing) if (USE_SYSTEM_JSONCPP) + message(STATUS "Discovering system JsonCPP (USE_SYSTEM_JSONCPP enabled)") find_package(JsonCpp REQUIRED) include_directories(${JSONCPP_INCLUDE_DIRS}) + message(STATUS "Discovering system JsonCPP - done") else() - message("-- Could NOT find JsonCpp library (Using embedded JsonCpp instead)") + message(STATUS "Using embedded JsonCpp (USE_SYSTEM_JSONCPP not enabled)") include_directories("../thirdparty/jsoncpp/include") endif(USE_SYSTEM_JSONCPP) From 195b5762eed0760c512ede22582e1ea21504d7bb Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sat, 6 Apr 2019 20:09:20 -0400 Subject: [PATCH 100/186] Make os_test use openshot-test target By specifying `COMMAND openshot-test` for the custom target, the path to the compiled executable is automatically used and the openshot-test target is automatically made a dependency. --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1ec36460..72884f1f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -226,5 +226,5 @@ IF (NOT DISABLE_TESTS) #################### MAKE TEST ###################### # Hook up the 'make os_test' target to the 'openshot-test' executable - ADD_CUSTOM_TARGET(os_test ${CMAKE_CURRENT_BINARY_DIR}/openshot-test) + ADD_CUSTOM_TARGET(os_test COMMAND openshot-test) ENDIF (NOT DISABLE_TESTS) From f61d054a74ff8124c77d263b933d5e7d24fd4245 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 11 Apr 2019 07:39:01 -0700 Subject: [PATCH 101/186] cmake hack Find the right install directory. I hope someone will come up with a more elegant way. --- src/bindings/python/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 93ae9360..d4358b5e 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -67,8 +67,8 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ -from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" +import site; from distutils.sysconfig import get_python_lib; \ +print( get_python_lib( plat_specific=True, standard_lib=True, prefix='${CMAKE_INSTALL_PREFIX}' ) + '/' + site.getsitepackages()[0].split('/')[-1] )" OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE ) From 94d4de48db00921c09bc6caa5c4cff316bed5eca Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 11 Apr 2019 08:06:11 -0700 Subject: [PATCH 102/186] 2nd attempt --- src/bindings/python/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index d4358b5e..0e2f6eee 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -68,7 +68,7 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ import site; from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, standard_lib=True, prefix='${CMAKE_INSTALL_PREFIX}' ) + '/' + site.getsitepackages()[0].split('/')[-1] )" +print( get_python_lib( plat_specific=True, standard_lib=True, prefix='${CMAKE_INSTALL_PREFIX}' ) + '/' + get_python_lib( plat_specific=False, standard_lib=False, prefix='${CMAKE_INSTALL_PREFIX}' ).split('/')[-1] )" OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE ) From 2dd19696000243ce7335dffc44f9924b97f0b280 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 11 Apr 2019 15:42:03 -0700 Subject: [PATCH 103/186] Alternate version --- src/bindings/python/CMakeLists.txt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 0e2f6eee..da8c1afa 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -66,11 +66,18 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ${PYTHON_LIBRARIES} openshot) ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ -import site; from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, standard_lib=True, prefix='${CMAKE_INSTALL_PREFIX}' ) + '/' + get_python_lib( plat_specific=False, standard_lib=False, prefix='${CMAKE_INSTALL_PREFIX}' ).split('/')[-1] )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) + if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + # If not prefix found, detect python site package folder + EXECUTE_PROCESS ( COMMAND ${PYTHON_EXECUTABLE} -c "import site; print(site.getsitepackages()[0])" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + else() + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + from distutils.sysconfig import get_python_lib; \ + print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + endif() GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) From dcff7245b3a651e4e8293fb8da6e9484c387c8f9 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 11 Apr 2019 16:01:26 -0700 Subject: [PATCH 104/186] Revert to older version plus add slash --- src/bindings/python/CMakeLists.txt | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index da8c1afa..c8686097 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -66,18 +66,13 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ${PYTHON_LIBRARIES} openshot) ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - # If not prefix found, detect python site package folder - EXECUTE_PROCESS ( COMMAND ${PYTHON_EXECUTABLE} -c "import site; print(site.getsitepackages()[0])" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - else() - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ - from distutils.sysconfig import get_python_lib; \ - print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - endif() + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ +import site; from distutils.sysconfig import get_python_lib; \ +print( get_python_lib( plat_specific=True, standard_lib=True, prefix='${CMAKE_INSTALL_PREFIX}' ) \ + + '/' + get_python_lib( plat_specific=False, standard_lib=False, prefix='${CMAKE_INSTALL_PREFIX}' ).split('/')[-1] \ + + '/' )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) From 893b91b528b6c0447df8f3931b452a352f234b4c Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 18 Apr 2019 01:07:57 -0500 Subject: [PATCH 105/186] Adding doc/HW-ACCEL.md document, code reformatting, some variable renaming --- README.md | 7 + doc/HW-ACCEL.md | 84 +++++ include/FFmpegReader.h | 30 +- include/FFmpegWriter.h | 89 +++-- src/FFmpegReader.cpp | 778 ++++++++++++++++++----------------------- 5 files changed, 493 insertions(+), 495 deletions(-) create mode 100644 doc/HW-ACCEL.md diff --git a/README.md b/README.md index 8deb86a1..cf69c1cf 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,13 @@ are also available in the /docs/ source folder. * [Mac](https://github.com/OpenShot/libopenshot/wiki/Mac-Build-Instructions) * [Windows](https://github.com/OpenShot/libopenshot/wiki/Windows-Build-Instructions) +## Hardware Acceleration + +OpenShot now supports experimental hardware acceleration, both for encoding and +decoding videos. When enabled, this can either speed up those operations or slow +them down, depending on the power and features supported by your graphics card. +Please see [doc/HW-ACCELL.md](doc/HW-ACCEL.md) for more information. + ## Documentation Beautiful HTML documentation can be generated using Doxygen. diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md new file mode 100644 index 00000000..edbe85b4 --- /dev/null +++ b/doc/HW-ACCEL.md @@ -0,0 +1,84 @@ +## Hardware Acceleration + +Observations for developers wanting to make hardware acceleration work. + +*All observations are for Linux (but contributions welcome).* + +## Supported FFmpeg Versions + +* HW accel is supported from ffmpeg version 3.2 (3.3 for nVidia drivers) +* HW accel was removed for nVidia drivers in Ubuntu for ffmpeg 4+ +* I could not manage to build a version of ffmpeg 4.1 with the nVidia SDK +that worked with nVidia cards. There might be a problem in ffmpeg 4+ +that prohibits this. + +**Notice:** The ffmpeg versions of Ubuntu and PPAs for Ubuntu show the +same behaviour. ffmpeg 3 has working nVidia hardware acceleration while +ffmpeg 4+ has no support for nVidia hardware acceleration +included. + +## OpenShot Settings + +The following settings are use by libopenshot to enable, disable, and control +the various hardware acceleration features. + +``` +/// Use video card for faster video decoding (if supported) +bool HARDWARE_DECODE = false; + +/// Use video codec for faster video decoding (if supported) +int HARDWARE_DECODER = 0; + +/// Use video card for faster video encoding (if supported) +bool HARDWARE_ENCODE = false; + +/// Number of threads of OpenMP +int OMP_THREADS = 12; + +/// Number of threads that ffmpeg uses +int FF_THREADS = 8; + +/// Maximum rows that hardware decode can handle +int DE_LIMIT_HEIGHT_MAX = 1100; + +/// Maximum columns that hardware decode can handle +int DE_LIMIT_WIDTH_MAX = 1950; + +/// Which GPU to use to decode (0 is the first) +int HW_DE_DEVICE_SET = 0; + +/// Which GPU to use to encode (0 is the first) +int HW_EN_DEVICE_SET = 0; +``` + +## Libva / VA-API (Video Acceleration API) + +The correct version of libva is needed (libva in Ubuntu 16.04 or libva2 +in Ubuntu 18.04) for the AppImage to work with hardware acceleration. +An AppImage that works on both systems (supporting libva and libva2), +might be possible when no libva is included in the AppImage. + +* vaapi is working for intel and AMD +* vaapi is working for decode only for nouveau +* nVidia driver is working for export only + +## AMD Graphics Cards (RadeonOpenCompute/ROCm) + +Decoding and encoding on the (AMD) GPU can be done on systems where ROCm +is installed and run. Possible future use for GPU acceleration of effects (contributions +welcome). + +## Multiple Graphics Cards + +If the computer has multiple graphics cards installed, you can choose which +should be used by libopenshot. Also, you can optionally use one card for +decoding and the other for encoding (if both cards support acceleration). + +## Help Us Improve Hardware Support + +This information might be wrong, and we would love to continue improving +our support for hardware acceleration in OpenShot. Please help us update +this document if you find an error or discover some new information. + +**Desperately Needed:** a way to compile ffmpeg 4.0 and up with working nVidia +hardware acceleration support on Ubuntu Linux! diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index acbec206..abf1af57 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -50,18 +50,17 @@ using namespace std; -namespace openshot -{ +namespace openshot { /** * @brief This struct holds the associated video frame and starting sample # for an audio packet. * * Because audio packets do not match up with video frames, this helps determine exactly * where the audio packet's samples belong. */ - struct AudioLocation - { + struct AudioLocation { int64_t frame; int sample_start; + bool is_near(AudioLocation location, int samples_per_frame, int64_t amount); }; @@ -91,17 +90,16 @@ namespace openshot * r.Close(); * @endcode */ - class FFmpegReader : public ReaderBase - { + class FFmpegReader : public ReaderBase { private: string path; AVFormatContext *pFormatCtx; int i, videoStream, audioStream; AVCodecContext *pCodecCtx, *aCodecCtx; - #if (LIBAVFORMAT_VERSION_MAJOR >= 57) +#if (LIBAVFORMAT_VERSION_MAJOR >= 57) AVBufferRef *hw_device_ctx = NULL; //PM - #endif +#endif AVStream *pStream, *aStream; AVPacket *packet; AVFrame *pFrame; @@ -145,15 +143,15 @@ namespace openshot int64_t video_pts_offset; int64_t last_frame; int64_t largest_frame_processed; - int64_t current_video_frame; // can't reliably use PTS of video to determine this + int64_t current_video_frame; // can't reliably use PTS of video to determine this - int hw_de_supported = 0; // Is set by FFmpegReader - #if IS_FFMPEG_3_2 + int hw_de_supported = 0; // Is set by FFmpegReader +#if IS_FFMPEG_3_2 AVPixelFormat hw_de_av_pix_fmt = AV_PIX_FMT_NONE; AVHWDeviceType hw_de_av_device_type = AV_HWDEVICE_TYPE_NONE; - #endif +#endif - int is_hardware_decode_supported(int codecid); + int IsHardwareDecodeSupported(int codecid); /// Check for the correct frames per second value by scanning the 1st few seconds of video packets. void CheckFPS(); @@ -210,10 +208,10 @@ namespace openshot std::shared_ptr ReadStream(int64_t requested_frame); /// Remove AVFrame from cache (and deallocate it's memory) - void RemoveAVFrame(AVFrame*); + void RemoveAVFrame(AVFrame *); /// Remove AVPacket from cache (and deallocate it's memory) - void RemoveAVPacket(AVPacket*); + void RemoveAVPacket(AVPacket *); /// Seek to a specific Frame. This is not always frame accurate, it's more of an estimation on many codecs. void Seek(int64_t requested_frame); @@ -251,7 +249,7 @@ namespace openshot void Close(); /// Get the cache object used by this reader - CacheMemory* GetCache() { return &final_cache; }; + CacheMemory *GetCache() { return &final_cache; }; /// Get a shared pointer to a openshot::Frame object for a specific frame number of this reader. /// diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index e219f72c..b93ef7b3 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -56,14 +56,12 @@ using namespace std; -namespace openshot -{ +namespace openshot { /// This enumeration designates the type of stream when encoding (video or audio) - enum StreamType - { - VIDEO_STREAM, ///< A video stream (used to determine which type of stream) - AUDIO_STREAM ///< An audio stream (used to determine which type of stream) + enum StreamType { + VIDEO_STREAM, ///< A video stream (used to determine which type of stream) + AUDIO_STREAM ///< An audio stream (used to determine which type of stream) }; /** @@ -141,8 +139,7 @@ namespace openshot * r.Close(); * @endcode */ - class FFmpegWriter : public WriterBase - { + class FFmpegWriter : public WriterBase { private: string path; int cache_size; @@ -155,56 +152,56 @@ namespace openshot bool write_header; bool write_trailer; - AVOutputFormat *fmt; - AVFormatContext *oc; - AVStream *audio_st, *video_st; - AVCodecContext *video_codec; - AVCodecContext *audio_codec; - SwsContext *img_convert_ctx; - double audio_pts, video_pts; - int16_t *samples; - uint8_t *audio_outbuf; - uint8_t *audio_encoder_buffer; + AVOutputFormat *fmt; + AVFormatContext *oc; + AVStream *audio_st, *video_st; + AVCodecContext *video_codec; + AVCodecContext *audio_codec; + SwsContext *img_convert_ctx; + double audio_pts, video_pts; + int16_t *samples; + uint8_t *audio_outbuf; + uint8_t *audio_encoder_buffer; - int num_of_rescalers; + int num_of_rescalers; int rescaler_position; - vector image_rescalers; + vector image_rescalers; - int audio_outbuf_size; - int audio_input_frame_size; - int initial_audio_input_frame_size; - int audio_input_position; - int audio_encoder_buffer_size; - SWRCONTEXT *avr; - SWRCONTEXT *avr_planar; + int audio_outbuf_size; + int audio_input_frame_size; + int initial_audio_input_frame_size; + int audio_input_position; + int audio_encoder_buffer_size; + SWRCONTEXT *avr; + SWRCONTEXT *avr_planar; - /* Resample options */ - int original_sample_rate; - int original_channels; + /* Resample options */ + int original_sample_rate; + int original_channels; - std::shared_ptr last_frame; - deque > spooled_audio_frames; - deque > spooled_video_frames; + std::shared_ptr last_frame; + deque > spooled_audio_frames; + deque > spooled_video_frames; - deque > queued_audio_frames; - deque > queued_video_frames; + deque > queued_audio_frames; + deque > queued_video_frames; - deque > processed_frames; - deque > deallocate_frames; + deque > processed_frames; + deque > deallocate_frames; - map, AVFrame*> av_frames; + map, AVFrame *> av_frames; - /// Add an AVFrame to the cache - void add_avframe(std::shared_ptr frame, AVFrame* av_frame); + /// Add an AVFrame to the cache + void add_avframe(std::shared_ptr frame, AVFrame *av_frame); /// Add an audio output stream - AVStream* add_audio_stream(); + AVStream *add_audio_stream(); /// Add a video output stream - AVStream* add_video_stream(); + AVStream *add_video_stream(); /// Allocate an AVFrame object - AVFrame* allocate_avframe(PixelFormat pix_fmt, int width, int height, int *buffer_size, uint8_t *new_buffer); + AVFrame *allocate_avframe(PixelFormat pix_fmt, int width, int height, int *buffer_size, uint8_t *new_buffer); /// Auto detect format (from path) void auto_detect_format(); @@ -239,7 +236,7 @@ namespace openshot void write_audio_packets(bool final); /// write video frame - bool write_video_packet(std::shared_ptr frame, AVFrame* frame_final); + bool write_video_packet(std::shared_ptr frame, AVFrame *frame_final); /// write all queued frames void write_queued_frames(); @@ -303,7 +300,7 @@ namespace openshot /// @param interlaced Does this video need to be interlaced? /// @param top_field_first Which frame should be used as the top field? /// @param bit_rate The video bit rate used during encoding - void SetVideoOptions(bool has_video, string codec, Fraction fps, int width, int height,Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate); + void SetVideoOptions(bool has_video, string codec, Fraction fps, int width, int height, Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate); /// @brief Set custom options (some codecs accept additional params). This must be called after the /// PrepareStreams() method, otherwise the streams have not been initialized yet. @@ -324,7 +321,7 @@ namespace openshot /// @param reader A openshot::ReaderBase object which will provide frames to be written /// @param start The starting frame number of the reader /// @param length The number of frames to write - void WriteFrame(ReaderBase* reader, int64_t start, int64_t length); + void WriteFrame(ReaderBase *reader, int64_t start, int64_t length); /// @brief Write the file trailer (after all frames are written). This is called automatically /// by the Close() method if this method has not yet been called. diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 1b2c6b82..3af851e1 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -30,7 +30,7 @@ #include "../include/FFmpegReader.h" -#define PRAYFORAWONDER 0 +#define ENABLE_VAAPI 0 #if IS_FFMPEG_3_2 #pragma message "You are compiling with experimental hardware decode" @@ -42,52 +42,51 @@ #define MAX_SUPPORTED_WIDTH 1950 #define MAX_SUPPORTED_HEIGHT 1100 -#if PRAYFORAWONDER +#if ENABLE_VAAPI #include "libavutil/hwcontext_vaapi.h" typedef struct VAAPIDecodeContext { - VAProfile va_profile; - VAEntrypoint va_entrypoint; - VAConfigID va_config; - VAContextID va_context; + VAProfile va_profile; + VAEntrypoint va_entrypoint; + VAConfigID va_config; + VAContextID va_context; - #if FF_API_STRUCT_VAAPI_CONTEXT -// FF_DISABLE_DEPRECATION_WARNINGS - int have_old_context; - struct vaapi_context *old_context; - AVBufferRef *device_ref; -// FF_ENABLE_DEPRECATION_WARNINGS - #endif +#if FF_API_STRUCT_VAAPI_CONTEXT + // FF_DISABLE_DEPRECATION_WARNINGS + int have_old_context; + struct vaapi_context *old_context; + AVBufferRef *device_ref; + // FF_ENABLE_DEPRECATION_WARNINGS +#endif - AVHWDeviceContext *device; - AVVAAPIDeviceContext *hwctx; + AVHWDeviceContext *device; + AVVAAPIDeviceContext *hwctx; - AVHWFramesContext *frames; - AVVAAPIFramesContext *hwfc; + AVHWFramesContext *frames; + AVVAAPIFramesContext *hwfc; - enum AVPixelFormat surface_format; - int surface_count; + enum AVPixelFormat surface_format; + int surface_count; } VAAPIDecodeContext; - - #endif +#endif #endif using namespace openshot; -int hw_de_on = 1; // Is set in UI +int hw_de_on = 0; #if IS_FFMPEG_3_2 AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE; -AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE; + AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE; #endif FFmpegReader::FFmpegReader(string path) - : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), - audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), - check_fps(false), enable_seek(true), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0), - prev_samples(0), prev_pts(0), pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0), - current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), - packet(NULL) { + : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), + audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), + check_fps(false), enable_seek(true), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0), + prev_samples(0), prev_pts(0), pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0), + current_video_frame(0), has_missing_frames(false), num_packets_since_video_frame(0), num_checks_since_final(0), + packet(NULL) { // Initialize FFMpeg, and register all formats and codecs AV_REGISTER_ALL @@ -134,8 +133,7 @@ FFmpegReader::~FFmpegReader() { } // This struct holds the associated video frame and starting sample # for an audio packet. -bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64_t amount) -{ +bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64_t amount) { // Is frame even close to this one? if (abs(location.frame - frame) >= 2) // This is too far away to be considered @@ -168,7 +166,7 @@ static enum AVPixelFormat get_hw_dec_format_va(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_va (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } @@ -185,7 +183,7 @@ static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_cu (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } #endif @@ -204,7 +202,7 @@ static enum AVPixelFormat get_hw_dec_format_dx(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_dx (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } @@ -221,7 +219,7 @@ static enum AVPixelFormat get_hw_dec_format_d3(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_d3 (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } @@ -238,7 +236,7 @@ static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_cu (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } #endif @@ -257,12 +255,12 @@ static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_qs (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } #endif -int FFmpegReader::is_hardware_decode_supported(int codecid) +int FFmpegReader::IsHardwareDecodeSupported(int codecid) { int ret; switch (codecid) { @@ -283,15 +281,13 @@ int FFmpegReader::is_hardware_decode_supported(int codecid) #endif -void FFmpegReader::Open() -{ +void FFmpegReader::Open() { // Open reader if not already open - if (!is_open) - { + if (!is_open) { // Initialize format context pFormatCtx = NULL; { - hw_de_on = (openshot::Settings::Instance()->HARDWARE_DECODER == 0 ? 0 : 1); + hw_de_on = (openshot::Settings::Instance()->HARDWARE_DECODER == 0 ? 0 : 1); } // Open video file @@ -305,8 +301,7 @@ void FFmpegReader::Open() videoStream = -1; audioStream = -1; // Loop through each stream, and identify the video and audio stream index - for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) - { + for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) { // Is this a video stream? if (AV_GET_CODEC_TYPE(pFormatCtx->streams[i]) == AVMEDIA_TYPE_VIDEO && videoStream < 0) { videoStream = i; @@ -320,8 +315,7 @@ void FFmpegReader::Open() throw NoStreamsFound("No video or audio streams found in this file.", path); // Is there a video stream? - if (videoStream != -1) - { + if (videoStream != -1) { // Set the stream index info.video_stream_index = videoStream; @@ -335,16 +329,17 @@ void FFmpegReader::Open() AVCodec *pCodec = avcodec_find_decoder(codecId); AVDictionary *opts = NULL; int retry_decode_open = 2; - // If hw accel is selected but hardware connot handle repeat with software decoding + // If hw accel is selected but hardware cannot handle repeat with software decoding do { pCodecCtx = AV_GET_CODEC_CONTEXT(pStream, pCodec); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_de_on && (retry_decode_open==2)) { // Up to here no decision is made if hardware or software decode - hw_de_supported = is_hardware_decode_supported(pCodecCtx->codec_id); + hw_de_supported = IsHardwareDecodeSupported(pCodecCtx->codec_id); } - #endif +#endif retry_decode_open = 0; + // Set number of threads equal to number of processors (not to exceed 16) pCodecCtx->thread_count = min(FF_NUM_PROCESSORS, 16); @@ -354,7 +349,7 @@ void FFmpegReader::Open() // Init options av_dict_set(&opts, "strict", "experimental", 0); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_de_on && hw_de_supported) { // Open Hardware Acceleration int i_decoder_hw = 0; @@ -363,143 +358,148 @@ void FFmpegReader::Open() int adapter_num; adapter_num = openshot::Settings::Instance()->HW_DE_DEVICE_SET; fprintf(stderr, "\n\nDecodiing Device Nr: %d\n", adapter_num); + if (adapter_num < 3 && adapter_num >=0) { - #if defined(__linux__) - snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); - adapter_ptr = adapter; - i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; - switch (i_decoder_hw) { +#if defined(__linux__) + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + adapter_ptr = adapter; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 0: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + break; + case 1: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + break; + case 2: + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + pCodecCtx->get_format = get_hw_dec_format_cu; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + pCodecCtx->get_format = get_hw_dec_format_va; + break; + } + +#elif defined(_WIN32) + adapter_ptr = NULL; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; - break; - case 1: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + pCodecCtx->get_format = get_hw_dec_format_dx; break; case 2: hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; pCodecCtx->get_format = get_hw_dec_format_cu; break; + case 3: + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + pCodecCtx->get_format = get_hw_dec_format_dx; + break; + case 4: + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; + pCodecCtx->get_format = get_hw_dec_format_d3; + break; default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + pCodecCtx->get_format = get_hw_dec_format_dx; break; } +#elif defined(__APPLE__) + adapter_ptr = NULL; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 0: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; + case 5: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; + } +#endif - #elif defined(_WIN32) - adapter_ptr = NULL; - i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; - switch (i_decoder_hw) { - case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; - case 2: - hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - pCodecCtx->get_format = get_hw_dec_format_cu; - break; - case 3: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; - case 4: - hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; - pCodecCtx->get_format = get_hw_dec_format_d3; - break; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; - } - #elif defined(__APPLE__) - adapter_ptr = NULL; - i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; - switch (i_decoder_hw) { - case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - case 5: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - } - #endif - } - else { + } else { adapter_ptr = NULL; // Just to be sure } + // Check if it is there and writable - #if defined(__linux__) +#if defined(__linux__) if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) { - #elif defined(_WIN32) +#elif defined(_WIN32) if( adapter_ptr != NULL ) { - #elif defined(__APPLE__) +#elif defined(__APPLE__) if( adapter_ptr != NULL ) { - #endif +#endif ZmqLogger::Instance()->AppendDebugMethod("Decode Device present using device", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } else { adapter_ptr = NULL; // use default ZmqLogger::Instance()->AppendDebugMethod("Decode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } + hw_device_ctx = NULL; // Here the first hardware initialisations are made if (av_hwdevice_ctx_create(&hw_device_ctx, hw_de_av_device_type, adapter_ptr, NULL, 0) >= 0) { if (!(pCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx))) { throw InvalidCodec("Hardware device reference create failed.", path); } - /* - av_buffer_unref(&ist->hw_frames_ctx); - ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx); - if (!ist->hw_frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "Error creating a CUDA frames context\n"); - return AVERROR(ENOMEM); - } - frames_ctx = (AVHWFramesContext*)ist->hw_frames_ctx->data; + /* + av_buffer_unref(&ist->hw_frames_ctx); + ist->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx); + if (!ist->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "Error creating a CUDA frames context\n"); + return AVERROR(ENOMEM); + } - frames_ctx->format = AV_PIX_FMT_CUDA; - frames_ctx->sw_format = avctx->sw_pix_fmt; - frames_ctx->width = avctx->width; - frames_ctx->height = avctx->height; + frames_ctx = (AVHWFramesContext*)ist->hw_frames_ctx->data; - av_log(avctx, AV_LOG_DEBUG, "Initializing CUDA frames context: sw_format = %s, width = %d, height = %d\n", - av_get_pix_fmt_name(frames_ctx->sw_format), frames_ctx->width, frames_ctx->height); + frames_ctx->format = AV_PIX_FMT_CUDA; + frames_ctx->sw_format = avctx->sw_pix_fmt; + frames_ctx->width = avctx->width; + frames_ctx->height = avctx->height; + + av_log(avctx, AV_LOG_DEBUG, "Initializing CUDA frames context: sw_format = %s, width = %d, height = %d\n", + av_get_pix_fmt_name(frames_ctx->sw_format), frames_ctx->width, frames_ctx->height); - ret = av_hwframe_ctx_init(pCodecCtx->hw_device_ctx); - ret = av_hwframe_ctx_init(ist->hw_frames_ctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error initializing a CUDA frame pool\n"); - return ret; - } - */ + ret = av_hwframe_ctx_init(pCodecCtx->hw_device_ctx); + ret = av_hwframe_ctx_init(ist->hw_frames_ctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error initializing a CUDA frame pool\n"); + return ret; + } + */ } else { throw InvalidCodec("Hardware device create failed.", path); } - } - #endif +#endif + // Open video codec if (avcodec_open2(pCodecCtx, pCodec, &opts) < 0) throw InvalidCodec("A video codec was found, but could not be opened.", path); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_de_on && hw_de_supported) { AVHWFramesConstraints *constraints = NULL; void *hwconfig = NULL; hwconfig = av_hwdevice_hwconfig_alloc(hw_device_ctx); - // NOT WORKING needs va_config ! - #if PRAYFORAWONDER + +// TODO: needs va_config! +#if ENABLE_VAAPI ((AVVAAPIHWConfig *)hwconfig)->config_id = ((VAAPIDecodeContext *)(pCodecCtx->priv_data))->va_config; - #endif +#endif constraints = av_hwdevice_get_hwframe_constraints(hw_device_ctx,hwconfig); if (constraints) { if (pCodecCtx->coded_width < constraints->min_width || @@ -555,9 +555,9 @@ void FFmpegReader::Open() else { ZmqLogger::Instance()->AppendDebugMethod("\nDecode in software is used\n", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } - #else +#else retry_decode_open = 0; - #endif +#endif } while (retry_decode_open); // retry_decode_open // Free options av_dict_free(&opts); @@ -567,8 +567,7 @@ void FFmpegReader::Open() } // Is there an audio stream? - if (audioStream != -1) - { + if (audioStream != -1) { // Set the stream index info.audio_stream_index = audioStream; @@ -626,32 +625,28 @@ void FFmpegReader::Open() } } -void FFmpegReader::Close() -{ +void FFmpegReader::Close() { // Close all objects, if reader is 'open' - if (is_open) - { + if (is_open) { // Mark as "closed" is_open = false; ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::Close", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); // Close the codec - if (info.has_video) - { + if (info.has_video) { avcodec_flush_buffers(pCodecCtx); AV_FREE_CONTEXT(pCodecCtx); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_de_on) { if (hw_device_ctx) { av_buffer_unref(&hw_device_ctx); hw_device_ctx = NULL; } } - #endif +#endif } - if (info.has_audio) - { + if (info.has_audio) { avcodec_flush_buffers(aCodecCtx); AV_FREE_CONTEXT(aCodecCtx); } @@ -663,7 +658,7 @@ void FFmpegReader::Close() // Clear processed lists { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processed_video_frames.clear(); processed_audio_frames.clear(); processing_video_frames.clear(); @@ -689,15 +684,14 @@ void FFmpegReader::Close() } } -void FFmpegReader::UpdateAudioInfo() -{ +void FFmpegReader::UpdateAudioInfo() { // Set values of FileInfo struct info.has_audio = true; info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1; info.acodec = aCodecCtx->codec->name; info.channels = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels; if (AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout == 0) - AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout = av_get_default_channel_layout( AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels ); + AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout = av_get_default_channel_layout(AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels); info.channel_layout = (ChannelLayout) AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout; info.sample_rate = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->sample_rate; info.audio_bit_rate = AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->bit_rate; @@ -711,15 +705,13 @@ void FFmpegReader::UpdateAudioInfo() info.duration = aStream->duration * info.audio_timebase.ToDouble(); // Check for an invalid video length - if (info.has_video && info.video_length <= 0) - { + if (info.has_video && info.video_length <= 0) { // Calculate the video length from the audio duration info.video_length = info.duration * info.fps.ToDouble(); } // Set video timebase (if no video stream was found) - if (!info.has_video) - { + if (!info.has_video) { // Set a few important default video settings (so audio can be divided into frames) info.fps.num = 24; info.fps.den = 1; @@ -744,8 +736,7 @@ void FFmpegReader::UpdateAudioInfo() } } -void FFmpegReader::UpdateVideoInfo() -{ +void FFmpegReader::UpdateVideoInfo() { if (check_fps) // Already initialized all the video metadata, no reason to do it again return; @@ -762,18 +753,13 @@ void FFmpegReader::UpdateVideoInfo() info.fps.num = pStream->avg_frame_rate.num; info.fps.den = pStream->avg_frame_rate.den; - if (pStream->sample_aspect_ratio.num != 0) - { + if (pStream->sample_aspect_ratio.num != 0) { info.pixel_ratio.num = pStream->sample_aspect_ratio.num; info.pixel_ratio.den = pStream->sample_aspect_ratio.den; - } - else if (AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.num != 0) - { + } else if (AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.num != 0) { info.pixel_ratio.num = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.num; info.pixel_ratio.den = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->sample_aspect_ratio.den; - } - else - { + } else { info.pixel_ratio.num = 1; info.pixel_ratio.den = 1; } @@ -807,15 +793,12 @@ void FFmpegReader::UpdateVideoInfo() info.duration = (info.file_size / info.video_bit_rate); // No duration found in stream of file - if (info.duration <= 0.0f) - { + if (info.duration <= 0.0f) { // No duration is found in the video stream info.duration = -1; info.video_length = -1; is_duration_known = false; - } - else - { + } else { // Yes, a duration was found is_duration_known = true; @@ -840,8 +823,7 @@ void FFmpegReader::UpdateVideoInfo() } -std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) -{ +std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) { // Check for open reader (or throw exception) if (!is_open) throw ReaderClosed("The FFmpegReader is closed. Call Open() before calling this method.", path); @@ -866,10 +848,8 @@ std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) // Return the cached frame return frame; - } - else - { - #pragma omp critical (ReadStream) + } else { +#pragma omp critical (ReadStream) { // Check the cache a 2nd time (due to a potential previous lock) frame = final_cache.GetFrame(requested_frame); @@ -878,8 +858,7 @@ std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame on 2nd look", requested_frame, "", -1, "", -1, "", -1, "", -1, "", -1); // Return the cached frame - } - else { + } else { // Frame is not in cache // Reset seek count seek_count = 0; @@ -891,20 +870,16 @@ std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) // Are we within X frames of the requested frame? int64_t diff = requested_frame - last_frame; - if (diff >= 1 && diff <= 20) - { + if (diff >= 1 && diff <= 20) { // Continue walking the stream frame = ReadStream(requested_frame); - } - else - { + } else { // Greater than 30 frames away, or backwards, we need to seek to the nearest key frame if (enable_seek) // Only seek if enabled Seek(requested_frame); - else if (!enable_seek && diff < 0) - { + else if (!enable_seek && diff < 0) { // Start over, since we can't seek, and the requested frame is smaller than our position Close(); Open(); @@ -920,8 +895,7 @@ std::shared_ptr FFmpegReader::GetFrame(int64_t requested_frame) } // Read the stream until we find the requested Frame -std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) -{ +std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) { // Allocate video frame bool end_of_stream = false; bool check_seek = false; @@ -931,7 +905,7 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) // Minimum number of packets to process (for performance reasons) int packets_processed = 0; int minimum_packets = OPEN_MP_NUM_PROCESSORS; - int max_packets = 4096; + int max_packets = 4096; // Set the number of threads in OpenMP omp_set_num_threads(OPEN_MP_NUM_PROCESSORS); @@ -941,20 +915,19 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream", "requested_frame", requested_frame, "OPEN_MP_NUM_PROCESSORS", OPEN_MP_NUM_PROCESSORS, "", -1, "", -1, "", -1, "", -1); - #pragma omp parallel +#pragma omp parallel { - #pragma omp single +#pragma omp single { // Loop through the stream until the correct frame is found - while (true) - { + while (true) { // Get the next packet into a local variable called packet packet_error = GetNextPacket(); int processing_video_frames_size = 0; int processing_audio_frames_size = 0; { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_video_frames_size = processing_video_frames.size(); processing_audio_frames_size = processing_audio_frames.size(); } @@ -962,14 +935,13 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) // Wait if too many frames are being processed while (processing_video_frames_size + processing_audio_frames_size >= minimum_packets) { usleep(2500); - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_video_frames_size = processing_video_frames.size(); processing_audio_frames_size = processing_audio_frames.size(); } // Get the next packet (if any) - if (packet_error < 0) - { + if (packet_error < 0) { // Break loop when no more packets found end_of_stream = true; break; @@ -979,29 +951,27 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ReadStream (GetNextPacket)", "requested_frame", requested_frame, "processing_video_frames_size", processing_video_frames_size, "processing_audio_frames_size", processing_audio_frames_size, "minimum_packets", minimum_packets, "packets_processed", packets_processed, "is_seeking", is_seeking); // Video packet - if (info.has_video && packet->stream_index == videoStream) - { + if (info.has_video && packet->stream_index == videoStream) { // Reset this counter, since we have a video packet num_packets_since_video_frame = 0; // Check the status of a seek (if any) - if (is_seeking) - #pragma omp critical (openshot_seek) - check_seek = CheckSeek(true); - else - check_seek = false; + if (is_seeking) +#pragma omp critical (openshot_seek) + check_seek = CheckSeek(true); + else + check_seek = false; - if (check_seek) { - // Jump to the next iteration of this loop - continue; - } + if (check_seek) { + // Jump to the next iteration of this loop + continue; + } // Get the AVFrame from the current packet frame_finished = GetAVFrame(); // Check if the AVFrame is finished and set it - if (frame_finished) - { + if (frame_finished) { // Update PTS / Frame Offset (if any) UpdatePTSOffset(true); @@ -1011,20 +981,19 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) if (openshot::Settings::Instance()->WAIT_FOR_VIDEO_PROCESSING_TASK) { // Wait on each OMP task to complete before moving on to the next one. This slows // down processing considerably, but might be more stable on some systems. - #pragma omp taskwait +#pragma omp taskwait } } } // Audio packet - else if (info.has_audio && packet->stream_index == audioStream) - { + else if (info.has_audio && packet->stream_index == audioStream) { // Increment this (to track # of packets since the last video packet) num_packets_since_video_frame++; // Check the status of a seek (if any) if (is_seeking) - #pragma omp critical (openshot_seek) +#pragma omp critical (openshot_seek) check_seek = CheckSeek(false); else check_seek = false; @@ -1086,8 +1055,7 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) if (frame) { // return the largest processed frame (assuming it was the last in the video file) return frame; - } - else { + } else { // The largest processed frame is no longer in cache, return a blank frame std::shared_ptr f = CreateFrame(largest_frame_processed); f->AddColor(info.width, info.height, "#000"); @@ -1098,43 +1066,40 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) } // Get the next packet (if any) -int FFmpegReader::GetNextPacket() -{ +int FFmpegReader::GetNextPacket() { int found_packet = 0; AVPacket *next_packet; - #pragma omp critical(getnextpacket) +#pragma omp critical(getnextpacket) { - next_packet = new AVPacket(); - found_packet = av_read_frame(pFormatCtx, next_packet); + next_packet = new AVPacket(); + found_packet = av_read_frame(pFormatCtx, next_packet); - if (packet) { - // Remove previous packet before getting next one - RemoveAVPacket(packet); - packet = NULL; + if (packet) { + // Remove previous packet before getting next one + RemoveAVPacket(packet); + packet = NULL; + } + + if (found_packet >= 0) { + // Update current packet pointer + packet = next_packet; + } } - - if (found_packet >= 0) - { - // Update current packet pointer - packet = next_packet; - } -} // Return if packet was found (or error number) return found_packet; } // Get an AVFrame (if any) -bool FFmpegReader::GetAVFrame() -{ +bool FFmpegReader::GetAVFrame() { int frameFinished = -1; int ret = 0; // Decode video frame AVFrame *next_frame = AV_ALLOCATE_FRAME(); - #pragma omp critical (packet_cache) +#pragma omp critical (packet_cache) { - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 frameFinished = 0; ret = avcodec_send_packet(pCodecCtx, packet); @@ -1157,29 +1122,30 @@ bool FFmpegReader::GetAVFrame() } pFrame = new AVFrame(); while (ret >= 0) { - ret = avcodec_receive_frame(pCodecCtx, next_frame2); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { - break; - } - if (ret != 0) { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - } - if (hw_de_on && hw_de_supported) { - int err; - if (next_frame2->format == hw_de_av_pix_fmt) { - next_frame->format = AV_PIX_FMT_YUV420P; - if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - } - if ((err = av_frame_copy_props(next_frame,next_frame2)) < 0) { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to copy props to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - } + ret = avcodec_receive_frame(pCodecCtx, next_frame2); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } + if (ret != 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (invalid return frame received)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + if (hw_de_on && hw_de_supported) { + int err; + if (next_frame2->format == hw_de_av_pix_fmt) { + next_frame->format = AV_PIX_FMT_YUV420P; + if ((err = av_hwframe_transfer_data(next_frame,next_frame2,0)) < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to transfer data to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + } + if ((err = av_frame_copy_props(next_frame,next_frame2)) < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAVFrame (Failed to copy props to output frame)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } } - else - { // No hardware acceleration used -> no copy from GPU memory needed - next_frame = next_frame2; - } + } + else + { // No hardware acceleration used -> no copy from GPU memory needed + next_frame = next_frame2; + } + // TODO also handle possible further frames // Use only the first frame like avcodec_decode_video2 if (frameFinished == 0 ) { @@ -1198,7 +1164,7 @@ bool FFmpegReader::GetAVFrame() AV_FREE_FRAME(&next_frame2); } } - #else +#else avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet); // is frame finished @@ -1217,7 +1183,7 @@ bool FFmpegReader::GetAVFrame() info.top_field_first = next_frame->top_field_first; } } - #endif +#endif } // deallocate the frame @@ -1228,11 +1194,9 @@ bool FFmpegReader::GetAVFrame() } // Check the current seek position and determine if we need to seek again -bool FFmpegReader::CheckSeek(bool is_video) -{ +bool FFmpegReader::CheckSeek(bool is_video) { // Are we seeking for a specific frame? - if (is_seeking) - { + if (is_seeking) { // Determine if both an audio and video packet have been decoded since the seek happened. // If not, allow the ReadStream method to keep looping if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found)) @@ -1248,16 +1212,13 @@ bool FFmpegReader::CheckSeek(bool is_video) max_seeked_frame = seek_video_frame_found; // determine if we are "before" the requested frame - if (max_seeked_frame >= seeking_frame) - { + if (max_seeked_frame >= seeking_frame) { // SEEKED TOO FAR ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckSeek (Too far, seek again)", "is_video_seek", is_video_seek, "max_seeked_frame", max_seeked_frame, "seeking_frame", seeking_frame, "seeking_pts", seeking_pts, "seek_video_frame_found", seek_video_frame_found, "seek_audio_frame_found", seek_audio_frame_found); // Seek again... to the nearest Keyframe Seek(seeking_frame - (10 * seek_count * seek_count)); - } - else - { + } else { // SEEK WORKED ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckSeek (Successful)", "is_video_seek", is_video_seek, "current_pts", packet->pts, "seeking_pts", seeking_pts, "seeking_frame", seeking_frame, "seek_video_frame_found", seek_video_frame_found, "seek_audio_frame_found", seek_audio_frame_found); @@ -1273,8 +1234,7 @@ bool FFmpegReader::CheckSeek(bool is_video) } // Process a video packet -void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) -{ +void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) { // Calculate current frame # int64_t current_frame = ConvertVideoPTStoFrame(GetVideoPTS()); @@ -1283,8 +1243,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) seek_video_frame_found = current_frame; // Are we close enough to decode the frame? and is this frame # valid? - if ((current_frame < (requested_frame - 20)) or (current_frame == -1)) - { + if ((current_frame < (requested_frame - 20)) or (current_frame == -1)) { // Remove frame and packet RemoveAVFrame(pFrame); @@ -1306,10 +1265,10 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) AVFrame *my_frame = pFrame; // Add video frame to list of processing video frames - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_video_frames[current_frame] = current_frame; - #pragma omp task firstprivate(current_frame, my_frame, height, width, video_length, pix_fmt) +#pragma omp task firstprivate(current_frame, my_frame, height, width, video_length, pix_fmt) { // Create variables for a RGB Frame (since most videos are not in RGB, we must convert it) AVFrame *pFrameRGB = NULL; @@ -1333,7 +1292,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) if (max_height <= 0) max_height = info.height; - Clip* parent = (Clip*) GetClip(); + Clip *parent = (Clip *) GetClip(); if (parent) { if (parent->scale == SCALE_FIT || parent->scale == SCALE_STRETCH) { // Best fit or Stretch scaling (based on max timeline size * scaling keyframes) @@ -1354,8 +1313,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) if (width_size.width() >= max_width && width_size.height() >= max_height) { max_width = max(max_width, width_size.width()); max_height = max(max_height, width_size.height()); - } - else { + } else { max_width = max(max_width, height_size.width()); max_height = max(max_height, height_size.height()); } @@ -1389,7 +1347,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) // Determine required buffer size and allocate buffer numBytes = AV_GET_IMAGE_SIZE(PIX_FMT_RGBA, width, height); - #pragma omp critical (video_buffer) +#pragma omp critical (video_buffer) buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); // Copy picture data from one AVFrame (or AVPicture) to another one. @@ -1404,7 +1362,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) // Resize / Convert to RGB sws_scale(img_convert_ctx, my_frame->data, my_frame->linesize, 0, - original_height, pFrameRGB->data, pFrameRGB->linesize); + original_height, pFrameRGB->data, pFrameRGB->linesize); // Create or get the existing frame object std::shared_ptr f = CreateFrame(current_frame); @@ -1416,7 +1374,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) working_cache.Add(f); // Keep track of last last_video_frame - #pragma omp critical (video_buffer) +#pragma omp critical (video_buffer) last_video_frame = f; // Free the RGB image @@ -1429,7 +1387,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) // Remove video frame from list of processing video frames { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_video_frames.erase(current_frame); processed_video_frames[current_frame] = current_frame; } @@ -1442,15 +1400,13 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) } // Process an audio packet -void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_frame, int starting_sample) -{ +void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_frame, int starting_sample) { // Track 1st audio packet after a successful seek if (!seek_audio_frame_found && is_seeking) seek_audio_frame_found = target_frame; // Are we close enough to decode the frame's audio? - if (target_frame < (requested_frame - 20)) - { + if (target_frame < (requested_frame - 20)) { // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ProcessAudioPacket (Skipped)", "requested_frame", requested_frame, "target_frame", target_frame, "starting_sample", starting_sample, "", -1, "", -1, "", -1); @@ -1471,9 +1427,9 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // re-initialize buffer size (it gets changed in the avcodec_decode_audio2 method call) int buf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE; - #pragma omp critical (ProcessAudioPacket) +#pragma omp critical (ProcessAudioPacket) { - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 int ret = 0; frame_finished = 1; while((packet->size > 0 || (!packet->data && frame_finished)) && ret >= 0) { @@ -1500,7 +1456,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr { ret = -1; } - #else +#else int used = avcodec_decode_audio4(aCodecCtx, audio_frame, &frame_finished, packet); #endif } @@ -1508,12 +1464,12 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr if (frame_finished) { // determine how many samples were decoded - int planar = av_sample_fmt_is_planar((AVSampleFormat)AV_GET_CODEC_PIXEL_FORMAT(aStream, aCodecCtx)); + int planar = av_sample_fmt_is_planar((AVSampleFormat) AV_GET_CODEC_PIXEL_FORMAT(aStream, aCodecCtx)); int plane_size = -1; data_size = av_samples_get_buffer_size(&plane_size, - AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels, - audio_frame->nb_samples, - (AVSampleFormat)(AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx)), 1); + AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels, + audio_frame->nb_samples, + (AVSampleFormat) (AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx)), 1); // Calculate total number of samples packet_samples = audio_frame->nb_samples * AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channels; @@ -1539,12 +1495,11 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // Add audio frame to list of processing audio frames { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_audio_frames.insert(pair(previous_packet_location.frame, previous_packet_location.frame)); } - while (pts_remaining_samples) - { + while (pts_remaining_samples) { // Get Samples per frame (for this frame number) int samples_per_frame = Frame::GetSamplesPerFrame(previous_packet_location.frame, info.fps, info.sample_rate, info.channels); @@ -1563,7 +1518,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // Add audio frame to list of processing audio frames { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_audio_frames.insert(pair(previous_packet_location.frame, previous_packet_location.frame)); } @@ -1590,24 +1545,24 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // setup resample context avr = SWR_ALLOC(); - av_opt_set_int(avr, "in_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); + av_opt_set_int(avr, "in_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); av_opt_set_int(avr, "out_channel_layout", AV_GET_CODEC_ATTRIBUTES(aStream, aCodecCtx)->channel_layout, 0); - av_opt_set_int(avr, "in_sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx), 0); - av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); - av_opt_set_int(avr, "in_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr, "in_channels", info.channels, 0); - av_opt_set_int(avr, "out_channels", info.channels, 0); + av_opt_set_int(avr, "in_sample_fmt", AV_GET_SAMPLE_FORMAT(aStream, aCodecCtx), 0); + av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + av_opt_set_int(avr, "in_sample_rate", info.sample_rate, 0); + av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); + av_opt_set_int(avr, "in_channels", info.channels, 0); + av_opt_set_int(avr, "out_channels", info.channels, 0); int r = SWR_INIT(avr); // Convert audio samples - nb_samples = SWR_CONVERT(avr, // audio resample context - audio_converted->data, // output data pointers - audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) - audio_converted->nb_samples, // maximum number of samples that the output buffer can hold - audio_frame->data, // input data pointers - audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) - audio_frame->nb_samples); // number of input samples to convert + nb_samples = SWR_CONVERT(avr, // audio resample context + audio_converted->data, // output data pointers + audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) + audio_converted->nb_samples, // maximum number of samples that the output buffer can hold + audio_frame->data, // input data pointers + audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) + audio_frame->nb_samples); // number of input samples to convert // Copy audio samples over original samples memcpy(audio_buf, audio_converted->data[0], audio_converted->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * info.channels); @@ -1623,8 +1578,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr int64_t starting_frame_number = -1; bool partial_frame = true; - for (int channel_filter = 0; channel_filter < info.channels; channel_filter++) - { + for (int channel_filter = 0; channel_filter < info.channels; channel_filter++) { // Array of floats (to hold samples for each channel) starting_frame_number = target_frame; int channel_buffer_size = packet_samples / info.channels; @@ -1638,11 +1592,9 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // Toggle through each channel number, since channel data is stored like (left right left right) int channel = 0; int position = 0; - for (int sample = 0; sample < packet_samples; sample++) - { + for (int sample = 0; sample < packet_samples; sample++) { // Only add samples for current channel - if (channel_filter == channel) - { + if (channel_filter == channel) { // Add sample (convert from (-32768 to 32768) to (-1.0 to 1.0)) channel_buffer[position] = audio_buf[sample] * (1.0f / (1 << 15)); @@ -1653,7 +1605,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // increment channel (if needed) if ((channel + 1) < info.channels) // move to next channel - channel ++; + channel++; else // reset channel channel = 0; @@ -1662,9 +1614,8 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // Loop through samples, and add them to the correct frames int start = starting_sample; int remaining_samples = channel_buffer_size; - float *iterate_channel_buffer = channel_buffer; // pointer to channel buffer - while (remaining_samples > 0) - { + float *iterate_channel_buffer = channel_buffer; // pointer to channel buffer + while (remaining_samples > 0) { // Get Samples per frame (for this frame number) int samples_per_frame = Frame::GetSamplesPerFrame(starting_frame_number, info.fps, info.sample_rate, info.channels); @@ -1718,7 +1669,7 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr // Remove audio frame from list of processing audio frames { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); // Update all frames as completed for (int64_t f = target_frame; f < starting_frame_number; f++) { // Remove the frame # from the processing list. NOTE: If more than one thread is @@ -1747,10 +1698,8 @@ void FFmpegReader::ProcessAudioPacket(int64_t requested_frame, int64_t target_fr } - // Seek to a specific frame. This is not always frame accurate, it's more of an estimation on many codecs. -void FFmpegReader::Seek(int64_t requested_frame) -{ +void FFmpegReader::Seek(int64_t requested_frame) { // Adjust for a requested frame that is too small or too large if (requested_frame < 1) requested_frame = 1; @@ -1760,7 +1709,7 @@ void FFmpegReader::Seek(int64_t requested_frame) int processing_video_frames_size = 0; int processing_audio_frames_size = 0; { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_video_frames_size = processing_video_frames.size(); processing_audio_frames_size = processing_audio_frames.size(); } @@ -1771,7 +1720,7 @@ void FFmpegReader::Seek(int64_t requested_frame) // Wait for any processing frames to complete while (processing_video_frames_size + processing_audio_frames_size > 0) { usleep(2500); - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_video_frames_size = processing_video_frames.size(); processing_audio_frames_size = processing_audio_frames.size(); } @@ -1782,7 +1731,7 @@ void FFmpegReader::Seek(int64_t requested_frame) // Clear processed lists { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); processing_audio_frames.clear(); processing_video_frames.clear(); processed_video_frames.clear(); @@ -1809,8 +1758,7 @@ void FFmpegReader::Seek(int64_t requested_frame) // If seeking near frame 1, we need to close and re-open the file (this is more reliable than seeking) int buffer_amount = max(OPEN_MP_NUM_PROCESSORS, 8); - if (requested_frame - buffer_amount < 20) - { + if (requested_frame - buffer_amount < 20) { // Close and re-open file (basically seeking to frame 1) Close(); Open(); @@ -1828,21 +1776,18 @@ void FFmpegReader::Seek(int64_t requested_frame) } seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek seek_video_frame_found = 0; // used to detect which frames to throw away after a seek - } - else - { + + } else { // Seek to nearest key-frame (aka, i-frame) bool seek_worked = false; int64_t seek_target = 0; // Seek video stream (if any) - if (!seek_worked && info.has_video) - { + if (!seek_worked && info.has_video) { seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount); if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->AV_FILENAME); - } else - { + } else { // VIDEO SEEK is_video_seek = true; seek_worked = true; @@ -1850,13 +1795,11 @@ void FFmpegReader::Seek(int64_t requested_frame) } // Seek audio stream (if not already seeked... and if an audio stream is found) - if (!seek_worked && info.has_audio) - { + if (!seek_worked && info.has_audio) { seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount); if (av_seek_frame(pFormatCtx, info.audio_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { fprintf(stderr, "%s: error while seeking audio stream\n", pFormatCtx->AV_FILENAME); - } else - { + } else { // AUDIO SEEK is_video_seek = false; seek_worked = true; @@ -1864,8 +1807,7 @@ void FFmpegReader::Seek(int64_t requested_frame) } // Was the seek successful? - if (seek_worked) - { + if (seek_worked) { // Flush audio buffer if (info.has_audio) avcodec_flush_buffers(aCodecCtx); @@ -1888,9 +1830,7 @@ void FFmpegReader::Seek(int64_t requested_frame) seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek seek_video_frame_found = 0; // used to detect which frames to throw away after a seek - } - else - { + } else { // seek failed is_seeking = false; seeking_pts = 0; @@ -1912,10 +1852,9 @@ void FFmpegReader::Seek(int64_t requested_frame) } // Get the PTS for the current video packet -int64_t FFmpegReader::GetVideoPTS() -{ +int64_t FFmpegReader::GetVideoPTS() { int64_t current_pts = 0; - if(packet->dts != AV_NOPTS_VALUE) + if (packet->dts != AV_NOPTS_VALUE) current_pts = packet->dts; // Return adjusted PTS @@ -1923,11 +1862,9 @@ int64_t FFmpegReader::GetVideoPTS() } // Update PTS Offset (if any) -void FFmpegReader::UpdatePTSOffset(bool is_video) -{ +void FFmpegReader::UpdatePTSOffset(bool is_video) { // Determine the offset between the PTS and Frame number (only for 1st frame) - if (is_video) - { + if (is_video) { // VIDEO PACKET if (video_pts_offset == 99999) // Has the offset been set yet? { @@ -1937,9 +1874,7 @@ void FFmpegReader::UpdatePTSOffset(bool is_video) // debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::UpdatePTSOffset (Video)", "video_pts_offset", video_pts_offset, "is_video", is_video, "", -1, "", -1, "", -1, "", -1); } - } - else - { + } else { // AUDIO PACKET if (audio_pts_offset == 99999) // Has the offset been set yet? { @@ -1953,8 +1888,7 @@ void FFmpegReader::UpdatePTSOffset(bool is_video) } // Convert PTS into Frame Number -int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) -{ +int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) { // Apply PTS offset pts = pts + video_pts_offset; int64_t previous_video_frame = current_video_frame; @@ -1974,10 +1908,10 @@ int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) if (frame == previous_video_frame) { // return -1 frame number frame = -1; - } - else + } else { // Increment expected frame current_video_frame++; + } if (current_video_frame < frame) // has missing frames @@ -1985,7 +1919,7 @@ int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) // Sometimes frames are missing due to varying timestamps, or they were dropped. Determine // if we are missing a video frame. - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); while (current_video_frame < frame) { if (!missing_video_frames.count(current_video_frame)) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::ConvertVideoPTStoFrame (tracking missing frame)", "current_video_frame", current_video_frame, "previous_video_frame", previous_video_frame, "", -1, "", -1, "", -1, "", -1); @@ -2006,8 +1940,7 @@ int64_t FFmpegReader::ConvertVideoPTStoFrame(int64_t pts) } // Convert Frame Number into Video PTS -int64_t FFmpegReader::ConvertFrameToVideoPTS(int64_t frame_number) -{ +int64_t FFmpegReader::ConvertFrameToVideoPTS(int64_t frame_number) { // Get timestamp of this frame (in seconds) double seconds = double(frame_number) / info.fps.ToDouble(); @@ -2019,8 +1952,7 @@ int64_t FFmpegReader::ConvertFrameToVideoPTS(int64_t frame_number) } // Convert Frame Number into Video PTS -int64_t FFmpegReader::ConvertFrameToAudioPTS(int64_t frame_number) -{ +int64_t FFmpegReader::ConvertFrameToAudioPTS(int64_t frame_number) { // Get timestamp of this frame (in seconds) double seconds = double(frame_number) / info.fps.ToDouble(); @@ -2032,8 +1964,7 @@ int64_t FFmpegReader::ConvertFrameToAudioPTS(int64_t frame_number) } // Calculate Starting video frame and sample # for an audio PTS -AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) -{ +AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) { // Apply PTS offset pts = pts + audio_pts_offset; @@ -2066,8 +1997,7 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) // Compare to previous audio packet (and fix small gaps due to varying PTS timestamps) if (previous_packet_location.frame != -1) { - if (location.is_near(previous_packet_location, samples_per_frame, samples_per_frame)) - { + if (location.is_near(previous_packet_location, samples_per_frame, samples_per_frame)) { int64_t orig_frame = location.frame; int orig_start = location.sample_start; @@ -2082,7 +2012,7 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAudioPTSLocation (Audio Gap Ignored - too big)", "Previous location frame", previous_packet_location.frame, "Target Frame", location.frame, "Target Audio Sample", location.sample_start, "pts", pts, "", -1, "", -1); - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); for (int64_t audio_frame = previous_packet_location.frame; audio_frame < location.frame; audio_frame++) { if (!missing_audio_frames.count(audio_frame)) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetAudioPTSLocation (tracking missing frame)", "missing_audio_frame", audio_frame, "previous_audio_frame", previous_packet_location.frame, "new location frame", location.frame, "", -1, "", -1, "", -1); @@ -2100,12 +2030,10 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int64_t pts) } // Create a new Frame (or return an existing one) and add it to the working queue. -std::shared_ptr FFmpegReader::CreateFrame(int64_t requested_frame) -{ +std::shared_ptr FFmpegReader::CreateFrame(int64_t requested_frame) { // Check working cache std::shared_ptr output = working_cache.GetFrame(requested_frame); - if (!output) - { + if (!output) { // Create a new frame on the working cache output = std::make_shared(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels); output->SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); // update pixel ratio @@ -2129,20 +2057,21 @@ bool FFmpegReader::IsPartialFrame(int64_t requested_frame) { // Sometimes a seek gets partial frames, and we need to remove them bool seek_trash = false; int64_t max_seeked_frame = seek_audio_frame_found; // determine max seeked frame - if (seek_video_frame_found > max_seeked_frame) + if (seek_video_frame_found > max_seeked_frame) { max_seeked_frame = seek_video_frame_found; + } if ((info.has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) || - (info.has_video && seek_video_frame_found && max_seeked_frame >= requested_frame)) - seek_trash = true; + (info.has_video && seek_video_frame_found && max_seeked_frame >= requested_frame)) { + seek_trash = true; + } return seek_trash; } // Check if a frame is missing and attempt to replace it's frame image (and -bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) -{ +bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) { // Lock - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); // Init # of times this frame has been checked so far int checked_count = 0; @@ -2171,9 +2100,9 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) if (checked_count > 8 && !missing_video_frames.count(requested_frame) && !processing_audio_frames.count(requested_frame) && processed_audio_frames.count(requested_frame) && last_frame && last_video_frame->has_image_data && aCodecId == AV_CODEC_ID_MP3 && (vCodecId == AV_CODEC_ID_MJPEGB || vCodecId == AV_CODEC_ID_MJPEG)) { - missing_video_frames.insert(pair(requested_frame, last_video_frame->number)); - missing_video_frames_source.insert(pair(last_video_frame->number, requested_frame)); - missing_frames.Add(last_video_frame); + missing_video_frames.insert(pair(requested_frame, last_video_frame->number)); + missing_video_frames_source.insert(pair(last_video_frame->number, requested_frame)); + missing_frames.Add(last_video_frame); } } @@ -2238,8 +2167,7 @@ bool FFmpegReader::CheckMissingFrame(int64_t requested_frame) } // Check the working queue, and move finished frames to the finished queue -void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_frame) -{ +void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_frame) { // Loop through all working queue frames bool checked_count_tripped = false; int max_checked_count = 80; @@ -2247,8 +2175,7 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram // Check if requested frame is 'missing' CheckMissingFrame(requested_frame); - while (true) - { + while (true) { // Get the front frame of working cache std::shared_ptr f(working_cache.GetSmallestFrame()); @@ -2272,7 +2199,7 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram bool is_video_ready = false; bool is_audio_ready = false; { // limit scope of next few lines - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); is_video_ready = processed_video_frames.count(f->number); is_audio_ready = processed_audio_frames.count(f->number); @@ -2317,13 +2244,11 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames", "requested_frame", requested_frame, "frame_number", f->number, "is_video_ready", is_video_ready, "is_audio_ready", is_audio_ready, "checked_count", checked_count, "checked_frames_size", checked_frames_size); // Check if working frame is final - if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash) - { + if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash) { // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames (mark frame as final)", "requested_frame", requested_frame, "f->number", f->number, "is_seek_trash", is_seek_trash, "Working Cache Count", working_cache.Count(), "Final Cache Count", final_cache.Count(), "end_of_stream", end_of_stream); - if (!is_seek_trash) - { + if (!is_seek_trash) { // Add missing image (if needed - sometimes end_of_stream causes frames with only audio) if (info.has_video && !is_video_ready && last_video_frame) // Copy image from last frame @@ -2337,7 +2262,7 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram // Add to missing cache (if another frame depends on it) { - const GenericScopedLock lock(processingCriticalSection); + const GenericScopedLock lock(processingCriticalSection); if (missing_video_frames_source.count(f->number)) { // Debug output ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::CheckWorkingFrames (add frame to missing cache)", "f->number", f->number, "is_seek_trash", is_seek_trash, "Missing Cache Count", missing_frames.Count(), "Working Cache Count", working_cache.Count(), "Final Cache Count", final_cache.Count(), "", -1); @@ -2358,16 +2283,16 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram // Seek trash, so delete the frame from the working cache, and never add it to the final cache. working_cache.Remove(f->number); } - } - else + + } else { // Stop looping break; + } } } // Check for the correct frames per second (FPS) value by scanning the 1st few seconds of video packets. -void FFmpegReader::CheckFPS() -{ +void FFmpegReader::CheckFPS() { check_fps = true; @@ -2380,19 +2305,16 @@ void FFmpegReader::CheckFPS() int64_t pts = 0; // Loop through the stream - while (true) - { + while (true) { // Get the next packet (if any) if (GetNextPacket() < 0) // Break loop when no more packets found break; // Video packet - if (packet->stream_index == videoStream) - { + if (packet->stream_index == videoStream) { // Check if the AVFrame is finished and set it - if (GetAVFrame()) - { + if (GetAVFrame()) { // Update PTS / Frame Offset (if any) UpdatePTSOffset(true); @@ -2467,13 +2389,11 @@ void FFmpegReader::CheckFPS() } // Remove AVFrame from cache (and deallocate it's memory) -void FFmpegReader::RemoveAVFrame(AVFrame* remove_frame) -{ +void FFmpegReader::RemoveAVFrame(AVFrame *remove_frame) { // Remove pFrame (if exists) - if (remove_frame) - { + if (remove_frame) { // Free memory - #pragma omp critical (packet_cache) +#pragma omp critical (packet_cache) { av_freep(&remove_frame->data[0]); #ifndef WIN32 @@ -2484,8 +2404,7 @@ void FFmpegReader::RemoveAVFrame(AVFrame* remove_frame) } // Remove AVPacket from cache (and deallocate it's memory) -void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet) -{ +void FFmpegReader::RemoveAVPacket(AVPacket *remove_packet) { // deallocate memory for packet AV_FREE_PACKET(remove_packet); @@ -2494,14 +2413,12 @@ void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet) } /// Get the smallest video frame that is still being processed -int64_t FFmpegReader::GetSmallestVideoFrame() -{ +int64_t FFmpegReader::GetSmallestVideoFrame() { // Loop through frame numbers map::iterator itr; int64_t smallest_frame = -1; - const GenericScopedLock lock(processingCriticalSection); - for(itr = processing_video_frames.begin(); itr != processing_video_frames.end(); ++itr) - { + const GenericScopedLock lock(processingCriticalSection); + for (itr = processing_video_frames.begin(); itr != processing_video_frames.end(); ++itr) { if (itr->first < smallest_frame || smallest_frame == -1) smallest_frame = itr->first; } @@ -2511,14 +2428,12 @@ int64_t FFmpegReader::GetSmallestVideoFrame() } /// Get the smallest audio frame that is still being processed -int64_t FFmpegReader::GetSmallestAudioFrame() -{ +int64_t FFmpegReader::GetSmallestAudioFrame() { // Loop through frame numbers map::iterator itr; int64_t smallest_frame = -1; - const GenericScopedLock lock(processingCriticalSection); - for(itr = processing_audio_frames.begin(); itr != processing_audio_frames.end(); ++itr) - { + const GenericScopedLock lock(processingCriticalSection); + for (itr = processing_audio_frames.begin(); itr != processing_audio_frames.end(); ++itr) { if (itr->first < smallest_frame || smallest_frame == -1) smallest_frame = itr->first; } @@ -2552,18 +2467,16 @@ void FFmpegReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; Json::Reader reader; - bool success = reader.parse( value, root ); + bool success = reader.parse(value, root); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); - try - { + try { // Set all values that match SetJsonValue(root); } - catch (exception e) - { + catch (exception e) { // Error parsing JSON (or missing keys) throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", ""); } @@ -2580,8 +2493,7 @@ void FFmpegReader::SetJsonValue(Json::Value root) { path = root["path"].asString(); // Re-Open path, and re-init everything (if needed) - if (is_open) - { + if (is_open) { Close(); Open(); } From 7930b289dcda88fd078ba01fa1ea9cf14d02ab1a Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 18 Apr 2019 07:51:03 -0400 Subject: [PATCH 106/186] Update Python install path detection This changes the `PYTHON_MODULE_PATH` handling in two ways: * Makes it a cache variable, so detection is only run once and only if it's not already set. This allows it to be overridden on the command line, e.g. `cmake -DPYTHON_MODULE_PATH:PATH=lib/python3.6/dist-packages` * Uses the presence of the `pybuild` executable to sense for a Debian-derived system (only on UNIX AND NOT APPLE), and if found it falls back to the old `getsitepackages()[0]` path extraction method. --- src/bindings/python/CMakeLists.txt | 37 ++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 3418d2de..08182d95 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -66,17 +66,36 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) ${PYTHON_LIBRARIES} openshot) ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + if (UNIX AND NOT APPLE) + ### Special-case for Debian's crazy, by checking to see if pybuild + ### is available. We don't use it, except as a canary in a coal mine + find_program(PYBUILD_EXECUTABLE pybuild + DOC "Path to Debian's pybuild utility") + if (PYBUILD_EXECUTABLE) + # We're on a Debian derivative, fall back to old path detection + set(py_detection "import site; print(site.getsitepackages()[0])") + else() + # Use distutils to detect install path + set (py_detection "\ from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) +print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )") + endif() + endif() - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH}) + if (NOT PYTHON_MODULE_PATH) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "${py_detection}" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH} + CACHE PATH "Install path for Python modules (relative to prefix)") + endif() + + message(STATUS "Will install Python module to: ${PYTHON_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ ### Install Python bindings From dc4d687e712e1ca96035624c4768792cff1ed60f Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Thu, 18 Apr 2019 09:26:20 -0400 Subject: [PATCH 107/186] Travis CI: Also run `make install` Taking my own suggestion, this adds a `make install` step to all three (overkill, maybe?) Travis builds, using `DESTDIR=dist/` to keep the files local to the build dir. Meant to bring the CMake-managed install logic under CI verification. --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4afd8467..2e7db59d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,8 @@ matrix: - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - make os_test - + - make install DESTDIR=dist/ + - language: cpp name: "FFmpeg 3" before_script: @@ -31,7 +32,8 @@ matrix: - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - make os_test - + - make install DESTDIR=dist/ + - language: cpp name: "FFmpeg 4" before_script: @@ -48,3 +50,4 @@ matrix: - cmake -D"CMAKE_BUILD_TYPE:STRING=Debug" ../ - make VERBOSE=1 - make os_test + - make install DESTDIR=dist/ From b3f5406db38c25f3bfff4c9bb408df9880810c6e Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 18 Apr 2019 14:04:37 -0500 Subject: [PATCH 108/186] More code reformatting on FFmpegWriter.h/.cpp --- include/FFmpegWriter.h | 2 +- include/OpenMPUtilities.h | 1 - src/FFmpegWriter.cpp | 753 +++++++++++++++++--------------------- 3 files changed, 344 insertions(+), 412 deletions(-) diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index b93ef7b3..35dd1ed9 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -233,7 +233,7 @@ namespace openshot { void process_video_packet(std::shared_ptr frame); /// write all queued frames' audio to the video file - void write_audio_packets(bool final); + void write_audio_packets(bool is_final); /// write video frame bool write_video_packet(std::shared_ptr frame, AVFrame *frame_final); diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index 0411b6ba..7c198a76 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -42,5 +42,4 @@ using namespace openshot; #define FF_NUM_PROCESSORS (min(omp_get_num_procs(), max(2, openshot::Settings::Instance()->FF_THREADS) )) - #endif diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 1c9094a6..e12ff094 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -83,8 +83,7 @@ FFmpegWriter::FFmpegWriter(string path) : initial_audio_input_frame_size(0), img_convert_ctx(NULL), cache_size(8), num_of_rescalers(32), rescaler_position(0), video_codec(NULL), audio_codec(NULL), is_writing(false), write_video_count(0), write_audio_count(0), original_sample_rate(0), original_channels(0), avr(NULL), avr_planar(NULL), is_open(false), prepare_streams(false), - write_header(false), write_trailer(false), audio_encoder_buffer_size(0), audio_encoder_buffer(NULL) -{ + write_header(false), write_trailer(false), audio_encoder_buffer_size(0), audio_encoder_buffer(NULL) { // Disable audio & video (so they can be independently enabled) info.has_audio = false; @@ -98,9 +97,8 @@ FFmpegWriter::FFmpegWriter(string path) : } // Open the writer -void FFmpegWriter::Open() -{ - if (!is_open) { +void FFmpegWriter::Open() { + if (!is_open) { // Open the writer is_open = true; @@ -121,8 +119,7 @@ void FFmpegWriter::Open() } // auto detect format (from path) -void FFmpegWriter::auto_detect_format() -{ +void FFmpegWriter::auto_detect_format() { // Auto detect the output format from the name. default is mpeg. fmt = av_guess_format(NULL, path.c_str(), NULL); if (!fmt) @@ -147,8 +144,7 @@ void FFmpegWriter::auto_detect_format() } // initialize streams -void FFmpegWriter::initialize_streams() -{ +void FFmpegWriter::initialize_streams() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::initialize_streams", "fmt->video_codec", fmt->video_codec, "fmt->audio_codec", fmt->audio_codec, "AV_CODEC_ID_NONE", AV_CODEC_ID_NONE, "", -1, "", -1, "", -1); // Add the audio and video streams using the default format codecs and initialize the codecs @@ -164,14 +160,12 @@ void FFmpegWriter::initialize_streams() } // Set video export options -void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, int width, int height, Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate) -{ +void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, int width, int height, Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate) { // Set the video options - if (codec.length() > 0) - { + if (codec.length() > 0) { AVCodec *new_codec; // Check if the codec selected is a hardware accelerated codec - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 #if defined(__linux__) if ( (strcmp(codec.c_str(),"h264_vaapi") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); @@ -194,7 +188,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i hw_en_supported = 0; } } - #elif defined(_WIN32) +#elif defined(_WIN32) if ( (strcmp(codec.c_str(),"h264_dxva2") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; @@ -216,7 +210,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i hw_en_supported = 0; } } - #elif defined(__APPLE__) +#elif defined(__APPLE__) if ( (strcmp(codec.c_str(),"h264_qsv") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; @@ -229,12 +223,12 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i hw_en_on = 0; hw_en_supported = 0; } - #else // is FFmpeg 3 but not linux +#else // is FFmpeg 3 but not linux new_codec = avcodec_find_encoder_by_name(codec.c_str()); - #endif //__linux__ - #else // not ffmpeg 3 +#endif //__linux__ +#else // not ffmpeg 3 new_codec = avcodec_find_encoder_by_name(codec.c_str()); - #endif //IS_FFMPEG_3_2 +#endif //IS_FFMPEG_3_2 if (new_codec == NULL) throw InvalidCodec("A valid video codec could not be found for this file.", path); else { @@ -245,8 +239,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i fmt->video_codec = new_codec->id; } } - if (fps.num > 0) - { + if (fps.num > 0) { // Set frames per second (if provided) info.fps.num = fps.num; info.fps.den = fps.den; @@ -259,14 +252,13 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i info.width = width; if (height >= 1) info.height = height; - if (pixel_ratio.num > 0) - { + if (pixel_ratio.num > 0) { info.pixel_ratio.num = pixel_ratio.num; info.pixel_ratio.den = pixel_ratio.den; } - if (bit_rate >= 1000) // bit_rate is the bitrate in b/s + if (bit_rate >= 1000) // bit_rate is the bitrate in b/s info.video_bit_rate = bit_rate; - if ((bit_rate >= 0) && (bit_rate < 64) ) // bit_rate is the bitrate in crf + if ((bit_rate >= 0) && (bit_rate < 64)) // bit_rate is the bitrate in crf info.video_bit_rate = bit_rate; info.interlaced_frame = interlaced; @@ -289,16 +281,13 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i } // Set audio export options -void FFmpegWriter::SetAudioOptions(bool has_audio, string codec, int sample_rate, int channels, ChannelLayout channel_layout, int bit_rate) -{ +void FFmpegWriter::SetAudioOptions(bool has_audio, string codec, int sample_rate, int channels, ChannelLayout channel_layout, int bit_rate) { // Set audio options - if (codec.length() > 0) - { + if (codec.length() > 0) { AVCodec *new_codec = avcodec_find_encoder_by_name(codec.c_str()); if (new_codec == NULL) throw InvalidCodec("A valid audio codec could not be found for this file.", path); - else - { + else { // Set audio codec info.acodec = new_codec->name; @@ -327,8 +316,7 @@ void FFmpegWriter::SetAudioOptions(bool has_audio, string codec, int sample_rate } // Set custom options (some codecs accept additional params) -void FFmpegWriter::SetOption(StreamType stream, string name, string value) -{ +void FFmpegWriter::SetOption(StreamType stream, string name, string value) { // Declare codec context AVCodecContext *c = NULL; AVStream *st = NULL; @@ -338,13 +326,11 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) st = video_st; // Get codec context c = AV_GET_CODEC_PAR_CONTEXT(st, video_codec); - } - else if (info.has_audio && stream == AUDIO_STREAM && audio_st) { + } else if (info.has_audio && stream == AUDIO_STREAM && audio_st) { st = audio_st; // Get codec context c = AV_GET_CODEC_PAR_CONTEXT(st, audio_codec); - } - else + } else throw NoStreamsFound("The stream was not found. Be sure to call PrepareStreams() first.", path); // Init AVOption @@ -357,9 +343,8 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // Was option found? if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" || - name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || - name == "crf")) - { + name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" || + name == "crf")) { // Check for specific named options if (name == "g") // Set gop_size @@ -409,81 +394,79 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // encode quality and special settings like lossless // This might be better in an extra methods as more options // and way to set quality are possible - #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) - #if IS_FFMPEG_3_2 - if (hw_en_on) { - double mbs = 15000000.0; - if (info.video_bit_rate > 0) { - if (info.video_bit_rate > 42) { - mbs = 380000.0; - } - else { - mbs *= pow(0.912,info.video_bit_rate); - } +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) +#if IS_FFMPEG_3_2 + if (hw_en_on) { + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380000.0; } - c->bit_rate = (int)(mbs); - } else - #endif - { - switch (c->codec_id) { - #if (LIBAVCODEC_VERSION_MAJOR >= 58) - case AV_CODEC_ID_AV1 : - c->bit_rate = 0; - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); - break; - #endif - case AV_CODEC_ID_VP8 : - c->bit_rate = 10000000; - av_opt_set_int(c->priv_data, "crf", max(min(stoi(value),63),4), 0); // 4-63 - break; - case AV_CODEC_ID_VP9 : - c->bit_rate = 0; // Must be zero! - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); // 0-63 - if (stoi(value) == 0) { - av_opt_set(c->priv_data, "preset", "veryslow", 0); - av_opt_set_int(c->priv_data, "lossless", 1, 0); - } - break; - case AV_CODEC_ID_H264 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),51), 0); // 0-51 - if (stoi(value) == 0) { - av_opt_set(c->priv_data, "preset", "veryslow", 0); - } - break; - case AV_CODEC_ID_H265 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),51), 0); // 0-51 - if (stoi(value) == 0) { - av_opt_set(c->priv_data, "preset", "veryslow", 0); - av_opt_set_int(c->priv_data, "lossless", 1, 0); - } - break; - default: - // If this codec doesn't support crf calculate a bitrate - // TODO: find better formula - double mbs = 15000000.0; - if (info.video_bit_rate > 0) { - if (info.video_bit_rate > 42) { - mbs = 380000.0; - } - else { - mbs *= pow(0.912,info.video_bit_rate); - } - } - c->bit_rate = (int)(mbs); + else { + mbs *= pow(0.912,info.video_bit_rate); } } - #endif - } - - else + c->bit_rate = (int)(mbs); + } else +#endif + { + switch (c->codec_id) { +#if (LIBAVCODEC_VERSION_MAJOR >= 58) + case AV_CODEC_ID_AV1 : + c->bit_rate = 0; + av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + break; +#endif + case AV_CODEC_ID_VP8 : + c->bit_rate = 10000000; + av_opt_set_int(c->priv_data, "crf", max(min(stoi(value), 63), 4), 0); // 4-63 + break; + case AV_CODEC_ID_VP9 : + c->bit_rate = 0; // Must be zero! + av_opt_set_int(c->priv_data, "crf", min(stoi(value), 63), 0); // 0-63 + if (stoi(value) == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + case AV_CODEC_ID_H264 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value), 51), 0); // 0-51 + if (stoi(value) == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + } + break; + case AV_CODEC_ID_H265 : + av_opt_set_int(c->priv_data, "crf", min(stoi(value), 51), 0); // 0-51 + if (stoi(value) == 0) { + av_opt_set(c->priv_data, "preset", "veryslow", 0); + av_opt_set_int(c->priv_data, "lossless", 1, 0); + } + break; + default: + // If this codec doesn't support crf calculate a bitrate + // TODO: find better formula + double mbs = 15000000.0; + if (info.video_bit_rate > 0) { + if (info.video_bit_rate > 42) { + mbs = 380000.0; + } else { + mbs *= pow(0.912, info.video_bit_rate); + } + } + c->bit_rate = (int) (mbs); + } + } +#endif + } else { // Set AVOption AV_OPTION_SET(st, c->priv_data, name.c_str(), value.c_str(), c); + } ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::SetOption (" + (string)name + ")", "stream == VIDEO_STREAM", stream == VIDEO_STREAM, "", -1, "", -1, "", -1, "", -1, "", -1); - } - else + } else { throw InvalidOptions("The option is not valid for this codec.", path); + } } @@ -500,8 +483,7 @@ bool FFmpegWriter::IsValidCodec(string codec_name) { } // Prepare & initialize streams and open codecs -void FFmpegWriter::PrepareStreams() -{ +void FFmpegWriter::PrepareStreams() { if (!info.has_audio && !info.has_video) throw InvalidOptions("No video or audio options have been set. You must set has_video or has_audio (or both).", path); @@ -515,8 +497,7 @@ void FFmpegWriter::PrepareStreams() } // Write the file header (after the options are set) -void FFmpegWriter::WriteHeader() -{ +void FFmpegWriter::WriteHeader() { if (!info.has_audio && !info.has_video) throw InvalidOptions("No video or audio options have been set. You must set has_video or has_audio (or both).", path); @@ -526,20 +507,19 @@ void FFmpegWriter::WriteHeader() throw InvalidFile("Could not open or write file.", path); } - // Force the output filename (which doesn't always happen for some reason) - snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", path.c_str()); + // Force the output filename (which doesn't always happen for some reason) + snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", path.c_str()); // Write the stream header, if any // TODO: add avoptions / parameters instead of NULL // Add general metadata (if any) - for(std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) - { + for (std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) { av_dict_set(&oc->metadata, iter->first.c_str(), iter->second.c_str(), 0); } if (avformat_write_header(oc, NULL) != 0) { - throw InvalidFile("Could not write header to file.", path); + throw InvalidFile("Could not write header to file.", path); }; // Mark as 'written' @@ -549,8 +529,7 @@ void FFmpegWriter::WriteHeader() } // Add a frame to the queue waiting to be encoded. -void FFmpegWriter::WriteFrame(std::shared_ptr frame) -{ +void FFmpegWriter::WriteFrame(std::shared_ptr frame) { // Check for open reader (or throw exception) if (!is_open) throw WriterClosed("The FFmpegWriter is closed. Call Open() before calling this method.", path); @@ -566,15 +545,13 @@ void FFmpegWriter::WriteFrame(std::shared_ptr frame) ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::WriteFrame", "frame->number", frame->number, "spooled_video_frames.size()", spooled_video_frames.size(), "spooled_audio_frames.size()", spooled_audio_frames.size(), "cache_size", cache_size, "is_writing", is_writing, "", -1); // Write the frames once it reaches the correct cache size - if (spooled_video_frames.size() == cache_size || spooled_audio_frames.size() == cache_size) - { + if (spooled_video_frames.size() == cache_size || spooled_audio_frames.size() == cache_size) { // Is writer currently writing? if (!is_writing) // Write frames to video file write_queued_frames(); - else - { + else { // Write frames to video file write_queued_frames(); } @@ -585,8 +562,7 @@ void FFmpegWriter::WriteFrame(std::shared_ptr frame) } // Write all frames in the queue to the video file. -void FFmpegWriter::write_queued_frames() -{ +void FFmpegWriter::write_queued_frames() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_queued_frames", "spooled_video_frames.size()", spooled_video_frames.size(), "spooled_audio_frames.size()", spooled_audio_frames.size(), "", -1, "", -1, "", -1, "", -1); // Flip writing flag @@ -608,17 +584,16 @@ void FFmpegWriter::write_queued_frames() // Create blank exception bool has_error_encoding_video = false; - #pragma omp parallel +#pragma omp parallel { - #pragma omp single +#pragma omp single { // Process all audio frames (in a separate thread) if (info.has_audio && audio_st && !queued_audio_frames.empty()) write_audio_packets(false); // Loop through each queued image frame - while (!queued_video_frames.empty()) - { + while (!queued_video_frames.empty()) { // Get front frame (from the queue) std::shared_ptr frame = queued_video_frames.front(); @@ -635,22 +610,19 @@ void FFmpegWriter::write_queued_frames() } // end while } // end omp single - #pragma omp single +#pragma omp single { // Loop back through the frames (in order), and write them to the video file - while (!processed_frames.empty()) - { + while (!processed_frames.empty()) { // Get front frame (from the queue) std::shared_ptr frame = processed_frames.front(); - if (info.has_video && video_st) - { + if (info.has_video && video_st) { // Add to deallocate queue (so we can remove the AVFrames when we are done) deallocate_frames.push_back(frame); // Does this frame's AVFrame still exist - if (av_frames.count(frame)) - { + if (av_frames.count(frame)) { // Get AVFrame AVFrame *frame_final = av_frames[frame]; @@ -666,14 +638,12 @@ void FFmpegWriter::write_queued_frames() } // Loop through, and deallocate AVFrames - while (!deallocate_frames.empty()) - { + while (!deallocate_frames.empty()) { // Get front frame (from the queue) std::shared_ptr frame = deallocate_frames.front(); // Does this frame's AVFrame still exist - if (av_frames.count(frame)) - { + if (av_frames.count(frame)) { // Get AVFrame AVFrame *av_frame = av_frames[frame]; @@ -700,13 +670,11 @@ void FFmpegWriter::write_queued_frames() } // Write a block of frames from a reader -void FFmpegWriter::WriteFrame(ReaderBase* reader, int64_t start, int64_t length) -{ +void FFmpegWriter::WriteFrame(ReaderBase *reader, int64_t start, int64_t length) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::WriteFrame (from Reader)", "start", start, "length", length, "", -1, "", -1, "", -1, "", -1); // Loop through each frame (and encoded it) - for (int64_t number = start; number <= length; number++) - { + for (int64_t number = start; number <= length; number++) { // Get the frame std::shared_ptr f = reader->GetFrame(number); @@ -716,8 +684,7 @@ void FFmpegWriter::WriteFrame(ReaderBase* reader, int64_t start, int64_t length) } // Write the file trailer (after all frames are written) -void FFmpegWriter::WriteTrailer() -{ +void FFmpegWriter::WriteTrailer() { // Write any remaining queued frames to video file write_queued_frames(); @@ -741,8 +708,7 @@ void FFmpegWriter::WriteTrailer() } // Flush encoders -void FFmpegWriter::flush_encoders() -{ +void FFmpegWriter::flush_encoders() { if (info.has_audio && audio_codec && AV_GET_CODEC_TYPE(audio_st) == AVMEDIA_TYPE_AUDIO && AV_GET_CODEC_ATTRIBUTES(audio_st, audio_codec)->frame_size <= 1) return; #if (LIBAVFORMAT_VERSION_MAJOR < 58) @@ -750,15 +716,15 @@ void FFmpegWriter::flush_encoders() return; #endif - int error_code = 0; - int stop_encoding = 1; + int error_code = 0; + int stop_encoding = 1; - // FLUSH VIDEO ENCODER - if (info.has_video) + // FLUSH VIDEO ENCODER + if (info.has_video) for (;;) { // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational){info.fps.den, info.fps.num}, video_codec->time_base); + write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base); AVPacket pkt; av_init_packet(&pkt); @@ -772,7 +738,7 @@ void FFmpegWriter::flush_encoders() int got_packet = 0; int error_code = 0; - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 #pragma omp critical (write_video_packet) { // Encode video packet (latest version of FFmpeg) @@ -796,34 +762,35 @@ void FFmpegWriter::flush_encoders() error_code = av_interleaved_write_frame(oc, &pkt); } } - #else +#else // IS_FFMPEG_3_2 - #if LIBAVFORMAT_VERSION_MAJOR >= 54 - // Encode video packet (older than FFmpeg 3.2) - error_code = avcodec_encode_video2(video_codec, &pkt, NULL, &got_packet); +#if LIBAVFORMAT_VERSION_MAJOR >= 54 + // Encode video packet (older than FFmpeg 3.2) + error_code = avcodec_encode_video2(video_codec, &pkt, NULL, &got_packet); - #else - // Encode video packet (even older version of FFmpeg) - int video_outbuf_size = 0; +#else + // Encode video packet (even older version of FFmpeg) + int video_outbuf_size = 0; - /* encode the image */ - int out_size = avcodec_encode_video(video_codec, NULL, video_outbuf_size, NULL); + /* encode the image */ + int out_size = avcodec_encode_video(video_codec, NULL, video_outbuf_size, NULL); - /* if zero size, it means the image was buffered */ - if (out_size > 0) { - if(video_codec->coded_frame->key_frame) - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.data= video_outbuf; - pkt.size= out_size; + /* if zero size, it means the image was buffered */ + if (out_size > 0) { + if(video_codec->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.data= video_outbuf; + pkt.size= out_size; - // got data back (so encode this frame) - got_packet = 1; - } - #endif - #endif + // got data back (so encode this frame) + got_packet = 1; + } +#endif // LIBAVFORMAT_VERSION_MAJOR >= 54 +#endif // IS_FFMPEG_3_2 if (error_code < 0) { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (string)av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (string) av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, + "", -1, "", -1, "", -1); } if (!got_packet) { stop_encoding = 1; @@ -853,8 +820,8 @@ void FFmpegWriter::flush_encoders() av_freep(&video_outbuf); } - // FLUSH AUDIO ENCODER - if (info.has_audio) + // FLUSH AUDIO ENCODER + if (info.has_audio) for (;;) { // Increment PTS (in samples and scaled to the codec's timebase) @@ -873,12 +840,12 @@ void FFmpegWriter::flush_encoders() /* encode the image */ int got_packet = 0; - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 avcodec_send_frame(audio_codec, NULL); got_packet = 0; - #else +#else error_code = avcodec_encode_audio2(audio_codec, &pkt, NULL, &got_packet); - #endif +#endif if (error_code < 0) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (string)av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); } @@ -917,25 +884,23 @@ void FFmpegWriter::flush_encoders() } // Close the video codec -void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) -{ +void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { AV_FREE_CONTEXT(video_codec); video_codec = NULL; - #if IS_FFMPEG_3_2 -// #if defined(__linux__) - if (hw_en_on && hw_en_supported) { - if (hw_device_ctx) { - av_buffer_unref(&hw_device_ctx); - hw_device_ctx = NULL; +#if IS_FFMPEG_3_2 + // #if defined(__linux__) + if (hw_en_on && hw_en_supported) { + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + hw_device_ctx = NULL; + } } - } -// #endif - #endif + // #endif +#endif } // Close the audio codec -void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) -{ +void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) { AV_FREE_CONTEXT(audio_codec); audio_codec = NULL; @@ -962,8 +927,7 @@ void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) } // Close the writer -void FFmpegWriter::Close() -{ +void FFmpegWriter::Close() { // Write trailer (if needed) if (!write_trailer) WriteTrailer(); @@ -1006,24 +970,19 @@ void FFmpegWriter::Close() } // Add an AVFrame to the cache -void FFmpegWriter::add_avframe(std::shared_ptr frame, AVFrame* av_frame) -{ +void FFmpegWriter::add_avframe(std::shared_ptr frame, AVFrame *av_frame) { // Add AVFrame to map (if it does not already exist) - if (!av_frames.count(frame)) - { + if (!av_frames.count(frame)) { // Add av_frame av_frames[frame] = av_frame; - } - else - { + } else { // Do not add, and deallocate this AVFrame AV_FREE_FRAME(&av_frame); } } // Add an audio output stream -AVStream* FFmpegWriter::add_audio_stream() -{ +AVStream *FFmpegWriter::add_audio_stream() { AVCodecContext *c; AVStream *st; @@ -1050,14 +1009,13 @@ AVStream* FFmpegWriter::add_audio_stream() if (codec->supported_samplerates) { int i; for (i = 0; codec->supported_samplerates[i] != 0; i++) - if (info.sample_rate == codec->supported_samplerates[i]) - { + if (info.sample_rate == codec->supported_samplerates[i]) { // Set the valid sample rate c->sample_rate = info.sample_rate; break; } - if (codec->supported_samplerates[i] == 0) - throw InvalidSampleRate("An invalid sample rate was detected for this codec.", path); + if (codec->supported_samplerates[i] == 0) + throw InvalidSampleRate("An invalid sample rate was detected for this codec.", path); } else // Set sample rate c->sample_rate = info.sample_rate; @@ -1068,8 +1026,7 @@ AVStream* FFmpegWriter::add_audio_stream() if (codec->channel_layouts) { int i; for (i = 0; codec->channel_layouts[i] != 0; i++) - if (channel_layout == codec->channel_layouts[i]) - { + if (channel_layout == codec->channel_layouts[i]) { // Set valid channel layout c->channel_layout = channel_layout; break; @@ -1082,8 +1039,7 @@ AVStream* FFmpegWriter::add_audio_stream() // Choose a valid sample_fmt if (codec->sample_fmts) { - for (int i = 0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) - { + for (int i = 0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) { // Set sample format to 1st valid format (and then exit loop) c->sample_fmt = codec->sample_fmts[i]; break; @@ -1109,8 +1065,7 @@ AVStream* FFmpegWriter::add_audio_stream() } // Add a video output stream -AVStream* FFmpegWriter::add_video_stream() -{ +AVStream *FFmpegWriter::add_video_stream() { AVCodecContext *c; AVStream *st; @@ -1138,24 +1093,22 @@ AVStream* FFmpegWriter::add_video_stream() } // Here should be the setting for low fixed bitrate // Defaults are used because mpeg2 otherwise had problems - } - else { + } else { // Check if codec supports crf switch (c->codec_id) { - #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) - #if (LIBAVCODEC_VERSION_MAJOR >= 58) +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) +#if (LIBAVCODEC_VERSION_MAJOR >= 58) case AV_CODEC_ID_AV1 : - #endif +#endif case AV_CODEC_ID_VP9 : case AV_CODEC_ID_H265 : - #endif +#endif case AV_CODEC_ID_VP8 : case AV_CODEC_ID_H264 : if (info.video_bit_rate < 40) { c->qmin = 0; c->qmax = 63; - } - else { + } else { c->qmin = info.video_bit_rate - 5; c->qmax = 63; } @@ -1186,9 +1139,9 @@ AVStream* FFmpegWriter::add_video_stream() identically 1. */ c->time_base.num = info.video_timebase.num; c->time_base.den = info.video_timebase.den; - #if LIBAVFORMAT_VERSION_MAJOR >= 56 +#if LIBAVFORMAT_VERSION_MAJOR >= 56 c->framerate = av_inv_q(c->time_base); - #endif +#endif st->avg_frame_rate = av_inv_q(c->time_base); st->time_base.num = info.video_timebase.num; st->time_base.den = info.video_timebase.den; @@ -1212,7 +1165,7 @@ AVStream* FFmpegWriter::add_video_stream() #endif // Find all supported pixel formats for this codec - const PixelFormat* supported_pixel_formats = codec->pix_fmts; + const PixelFormat *supported_pixel_formats = codec->pix_fmts; while (supported_pixel_formats != NULL && *supported_pixel_formats != PIX_FMT_NONE) { // Assign the 1st valid pixel format (if one is missing) if (c->pix_fmt == PIX_FMT_NONE) @@ -1222,7 +1175,7 @@ AVStream* FFmpegWriter::add_video_stream() // Codec doesn't have any pix formats? if (c->pix_fmt == PIX_FMT_NONE) { - if(fmt->video_codec == AV_CODEC_ID_RAWVIDEO) { + if (fmt->video_codec == AV_CODEC_ID_RAWVIDEO) { // Raw video should use RGB24 c->pix_fmt = PIX_FMT_RGB24; @@ -1249,8 +1202,7 @@ AVStream* FFmpegWriter::add_video_stream() } // open audio codec -void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) -{ +void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) { AVCodec *codec; AV_GET_CODEC_FROM_STREAM(st, audio_codec) @@ -1284,14 +1236,14 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) int s = AV_FIND_DECODER_CODEC_ID(st); switch (s) { - case AV_CODEC_ID_PCM_S16LE: - case AV_CODEC_ID_PCM_S16BE: - case AV_CODEC_ID_PCM_U16LE: - case AV_CODEC_ID_PCM_U16BE: - audio_input_frame_size >>= 1; - break; - default: - break; + case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S16BE: + case AV_CODEC_ID_PCM_U16LE: + case AV_CODEC_ID_PCM_U16BE: + audio_input_frame_size >>= 1; + break; + default: + break; } } else { // Set frame size based on the codec @@ -1313,25 +1265,22 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) audio_encoder_buffer = new uint8_t[audio_encoder_buffer_size]; // Add audio metadata (if any) - for(std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) - { + for (std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) { av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); } ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::open_audio", "audio_codec->thread_count", audio_codec->thread_count, "audio_input_frame_size", audio_input_frame_size, "buffer_size", AVCODEC_MAX_AUDIO_FRAME_SIZE + MY_INPUT_BUFFER_PADDING_SIZE, "", -1, "", -1, "", -1); - } // open video codec -void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) -{ +void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) { AVCodec *codec; AV_GET_CODEC_FROM_STREAM(st, video_codec) // Set number of threads equal to number of processors (not to exceed 16) video_codec->thread_count = min(FF_NUM_PROCESSORS, 16); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { //char *dev_hw = NULL; char adapter[256]; @@ -1341,32 +1290,31 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) adapter_num = openshot::Settings::Instance()->HW_EN_DEVICE_SET; fprintf(stderr, "\n\nEncodiing Device Nr: %d\n", adapter_num); if (adapter_num < 3 && adapter_num >=0) { - #if defined(__linux__) +#if defined(__linux__) snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); // Maybe 127 is better because the first card would be 1?! adapter_ptr = adapter; - #elif defined(_WIN32) +#elif defined(_WIN32) adapter_ptr = NULL; - #elif defined(__APPLE__) +#elif defined(__APPLE__) adapter_ptr = NULL; - #endif +#endif } else { adapter_ptr = NULL; // Just to be sure } // Check if it is there and writable - #if defined(__linux__) +#if defined(__linux__) if( adapter_ptr != NULL && access( adapter_ptr, W_OK ) == 0 ) { - #elif defined(_WIN32) +#elif defined(_WIN32) if( adapter_ptr != NULL ) { - #elif defined(__APPLE__) +#elif defined(__APPLE__) if( adapter_ptr != NULL ) { - #endif +#endif ZmqLogger::Instance()->AppendDebugMethod("Encode Device present using device", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } else { adapter_ptr = NULL; // use default - //cerr << "\n\n\nEncode Device not present using default\n\n\n"; ZmqLogger::Instance()->AppendDebugMethod("Encode Device not present using default", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } if (av_hwdevice_ctx_create(&hw_device_ctx, hw_en_av_device_type, @@ -1375,7 +1323,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) throw InvalidCodec("Could not create hwdevice", path); } } - #endif +#endif + /* find the video encoder */ codec = avcodec_find_encoder_by_name(info.vcodec.c_str()); if (!codec) @@ -1383,15 +1332,15 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) if (!codec) throw InvalidCodec("Could not find codec", path); - /* Force max_b_frames to 0 in some cases (i.e. for mjpeg image sequences */ - if(video_codec->max_b_frames && video_codec->codec_id != AV_CODEC_ID_MPEG4 && video_codec->codec_id != AV_CODEC_ID_MPEG1VIDEO && video_codec->codec_id != AV_CODEC_ID_MPEG2VIDEO) - video_codec->max_b_frames = 0; + /* Force max_b_frames to 0 in some cases (i.e. for mjpeg image sequences */ + if (video_codec->max_b_frames && video_codec->codec_id != AV_CODEC_ID_MPEG4 && video_codec->codec_id != AV_CODEC_ID_MPEG1VIDEO && video_codec->codec_id != AV_CODEC_ID_MPEG2VIDEO) + video_codec->max_b_frames = 0; // Init options AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "experimental", 0); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { video_codec->max_b_frames = 0; // At least this GPU doesn't support b-frames video_codec->pix_fmt = hw_en_av_pix_fmt; @@ -1405,7 +1354,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) fprintf(stderr, "Failed to set hwframe context.\n"); } } - #endif +#endif /* open the codec */ if (avcodec_open2(video_codec, codec, &opts) < 0) @@ -1416,8 +1365,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) av_dict_free(&opts); // Add video metadata (if any) - for(std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) - { + for (std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) { av_dict_set(&st->metadata, iter->first.c_str(), iter->second.c_str(), 0); } @@ -1426,9 +1374,8 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) } // write all queued frames' audio to the video file -void FFmpegWriter::write_audio_packets(bool final) -{ - #pragma omp task firstprivate(final) +void FFmpegWriter::write_audio_packets(bool is_final) { +#pragma omp task firstprivate(is_final) { // Init audio buffers / variables int total_frame_samples = 0; @@ -1439,14 +1386,13 @@ void FFmpegWriter::write_audio_packets(bool final) ChannelLayout channel_layout_in_frame = LAYOUT_MONO; // default channel layout // Create a new array (to hold all S16 audio samples, for the current queued frames - int16_t* all_queued_samples = (int16_t*)av_malloc((sizeof(int16_t)*(queued_audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE))); - int16_t* all_resampled_samples = NULL; - int16_t* final_samples_planar = NULL; - int16_t* final_samples = NULL; + int16_t *all_queued_samples = (int16_t *) av_malloc((sizeof(int16_t) * (queued_audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE))); + int16_t *all_resampled_samples = NULL; + int16_t *final_samples_planar = NULL; + int16_t *final_samples = NULL; // Loop through each queued audio frame - while (!queued_audio_frames.empty()) - { + while (!queued_audio_frames.empty()) { // Get front frame (from the queue) std::shared_ptr frame = queued_audio_frames.front(); @@ -1458,7 +1404,7 @@ void FFmpegWriter::write_audio_packets(bool final) // Get audio sample array - float* frame_samples_float = NULL; + float *frame_samples_float = NULL; // Get samples interleaved together (c1 c2 c1 c2 c1 c2) frame_samples_float = frame->GetInterleavedAudioSamples(sample_rate_in_frame, NULL, &samples_in_frame); @@ -1487,13 +1433,13 @@ void FFmpegWriter::write_audio_packets(bool final) int samples_position = 0; - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets", "final", final, "total_frame_samples", total_frame_samples, "channel_layout_in_frame", channel_layout_in_frame, "channels_in_frame", channels_in_frame, "samples_in_frame", samples_in_frame, "LAYOUT_MONO", LAYOUT_MONO); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets", "is_final", is_final, "total_frame_samples", total_frame_samples, "channel_layout_in_frame", channel_layout_in_frame, "channels_in_frame", channels_in_frame, "samples_in_frame", samples_in_frame, "LAYOUT_MONO", LAYOUT_MONO); // Keep track of the original sample format AVSampleFormat output_sample_fmt = audio_codec->sample_fmt; AVFrame *audio_frame = NULL; - if (!final) { + if (!is_final) { // Create input frame (and allocate arrays) audio_frame = AV_ALLOCATE_FRAME(); AV_RESET_FRAME(audio_frame); @@ -1501,28 +1447,23 @@ void FFmpegWriter::write_audio_packets(bool final) // Fill input frame with sample data avcodec_fill_audio_frame(audio_frame, channels_in_frame, AV_SAMPLE_FMT_S16, (uint8_t *) all_queued_samples, - audio_encoder_buffer_size, 0); + audio_encoder_buffer_size, 0); // Do not convert audio to planar format (yet). We need to keep everything interleaved at this point. - switch (audio_codec->sample_fmt) - { - case AV_SAMPLE_FMT_FLTP: - { + switch (audio_codec->sample_fmt) { + case AV_SAMPLE_FMT_FLTP: { output_sample_fmt = AV_SAMPLE_FMT_FLT; break; } - case AV_SAMPLE_FMT_S32P: - { + case AV_SAMPLE_FMT_S32P: { output_sample_fmt = AV_SAMPLE_FMT_S32; break; } - case AV_SAMPLE_FMT_S16P: - { + case AV_SAMPLE_FMT_S16P: { output_sample_fmt = AV_SAMPLE_FMT_S16; break; } - case AV_SAMPLE_FMT_U8P: - { + case AV_SAMPLE_FMT_U8P: { output_sample_fmt = AV_SAMPLE_FMT_U8; break; } @@ -1546,29 +1487,30 @@ void FFmpegWriter::write_audio_packets(bool final) // setup resample context if (!avr) { avr = SWR_ALLOC(); - av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0); + av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0); av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0); - av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); - av_opt_set_int(avr, "out_sample_fmt", output_sample_fmt, 0); // planar not allowed here - av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0); - av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr, "in_channels", channels_in_frame, 0); - av_opt_set_int(avr, "out_channels", info.channels, 0); + av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); + av_opt_set_int(avr, "out_sample_fmt", output_sample_fmt, 0); // planar not allowed here + av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0); + av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); + av_opt_set_int(avr, "in_channels", channels_in_frame, 0); + av_opt_set_int(avr, "out_channels", info.channels, 0); SWR_INIT(avr); } int nb_samples = 0; // Convert audio samples - nb_samples = SWR_CONVERT(avr, // audio resample context - audio_converted->data, // output data pointers - audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) - audio_converted->nb_samples, // maximum number of samples that the output buffer can hold - audio_frame->data, // input data pointers - audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) - audio_frame->nb_samples); // number of input samples to convert + nb_samples = SWR_CONVERT(avr, // audio resample context + audio_converted->data, // output data pointers + audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) + audio_converted->nb_samples, // maximum number of samples that the output buffer can hold + audio_frame->data, // input data pointers + audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) + audio_frame->nb_samples); // number of input samples to convert // Create a new array (to hold all resampled S16 audio samples) - all_resampled_samples = (int16_t*)av_malloc(sizeof(int16_t) * nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); + all_resampled_samples = (int16_t *) av_malloc( + sizeof(int16_t) * nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); // Copy audio samples over original samples memcpy(all_resampled_samples, audio_converted->data[0], nb_samples * info.channels * av_get_bytes_per_sample(output_sample_fmt)); @@ -1584,7 +1526,7 @@ void FFmpegWriter::write_audio_packets(bool final) } // Loop until no more samples - while (remaining_frame_samples > 0 || final) { + while (remaining_frame_samples > 0 || is_final) { // Get remaining samples needed for this packet int remaining_packet_samples = (audio_input_frame_size * info.channels) - audio_input_position; @@ -1596,9 +1538,10 @@ void FFmpegWriter::write_audio_packets(bool final) diff = remaining_frame_samples; // Copy frame samples into the packet samples array - if (!final) + if (!is_final) //TODO: Make this more sane - memcpy(samples + (audio_input_position * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))), all_resampled_samples + samples_position, diff * av_get_bytes_per_sample(output_sample_fmt)); + memcpy(samples + (audio_input_position * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))), + all_resampled_samples + samples_position, diff * av_get_bytes_per_sample(output_sample_fmt)); // Increment counters audio_input_position += diff; @@ -1607,28 +1550,27 @@ void FFmpegWriter::write_audio_packets(bool final) remaining_packet_samples -= diff; // Do we have enough samples to proceed? - if (audio_input_position < (audio_input_frame_size * info.channels) && !final) + if (audio_input_position < (audio_input_frame_size * info.channels) && !is_final) // Not enough samples to encode... so wait until the next frame break; // Convert to planar (if needed by audio codec) AVFrame *frame_final = AV_ALLOCATE_FRAME(); AV_RESET_FRAME(frame_final); - if (av_sample_fmt_is_planar(audio_codec->sample_fmt)) - { + if (av_sample_fmt_is_planar(audio_codec->sample_fmt)) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets (2nd resampling for Planar formats)", "in_sample_fmt", output_sample_fmt, "out_sample_fmt", audio_codec->sample_fmt, "in_sample_rate", info.sample_rate, "out_sample_rate", info.sample_rate, "in_channels", info.channels, "out_channels", info.channels); // setup resample context if (!avr_planar) { avr_planar = SWR_ALLOC(); - av_opt_set_int(avr_planar, "in_channel_layout", info.channel_layout, 0); + av_opt_set_int(avr_planar, "in_channel_layout", info.channel_layout, 0); av_opt_set_int(avr_planar, "out_channel_layout", info.channel_layout, 0); - av_opt_set_int(avr_planar, "in_sample_fmt", output_sample_fmt, 0); - av_opt_set_int(avr_planar, "out_sample_fmt", audio_codec->sample_fmt, 0); // planar not allowed here - av_opt_set_int(avr_planar, "in_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr_planar, "out_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr_planar, "in_channels", info.channels, 0); - av_opt_set_int(avr_planar, "out_channels", info.channels, 0); + av_opt_set_int(avr_planar, "in_sample_fmt", output_sample_fmt, 0); + av_opt_set_int(avr_planar, "out_sample_fmt", audio_codec->sample_fmt, 0); // planar not allowed here + av_opt_set_int(avr_planar, "in_sample_rate", info.sample_rate, 0); + av_opt_set_int(avr_planar, "out_sample_rate", info.sample_rate, 0); + av_opt_set_int(avr_planar, "in_channels", info.channels, 0); + av_opt_set_int(avr_planar, "out_channels", info.channels, 0); SWR_INIT(avr_planar); } @@ -1638,27 +1580,28 @@ void FFmpegWriter::write_audio_packets(bool final) audio_frame->nb_samples = audio_input_position / info.channels; // Create a new array - final_samples_planar = (int16_t*)av_malloc(sizeof(int16_t) * audio_frame->nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); + final_samples_planar = (int16_t *) av_malloc( + sizeof(int16_t) * audio_frame->nb_samples * info.channels * (av_get_bytes_per_sample(output_sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); // Copy audio into buffer for frame memcpy(final_samples_planar, samples, audio_frame->nb_samples * info.channels * av_get_bytes_per_sample(output_sample_fmt)); // Fill input frame with sample data avcodec_fill_audio_frame(audio_frame, info.channels, output_sample_fmt, (uint8_t *) final_samples_planar, - audio_encoder_buffer_size, 0); + audio_encoder_buffer_size, 0); // Create output frame (and allocate arrays) frame_final->nb_samples = audio_input_frame_size; av_samples_alloc(frame_final->data, frame_final->linesize, info.channels, frame_final->nb_samples, audio_codec->sample_fmt, 0); // Convert audio samples - int nb_samples = SWR_CONVERT(avr_planar, // audio resample context - frame_final->data, // output data pointers - frame_final->linesize[0], // output plane size, in bytes. (0 if unknown) - frame_final->nb_samples, // maximum number of samples that the output buffer can hold - audio_frame->data, // input data pointers - audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) - audio_frame->nb_samples); // number of input samples to convert + int nb_samples = SWR_CONVERT(avr_planar, // audio resample context + frame_final->data, // output data pointers + frame_final->linesize[0], // output plane size, in bytes. (0 if unknown) + frame_final->nb_samples, // maximum number of samples that the output buffer can hold + audio_frame->data, // input data pointers + audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) + audio_frame->nb_samples); // number of input samples to convert // Copy audio samples over original samples if (nb_samples > 0) @@ -1673,7 +1616,8 @@ void FFmpegWriter::write_audio_packets(bool final) } else { // Create a new array - final_samples = (int16_t*)av_malloc(sizeof(int16_t) * audio_input_position * (av_get_bytes_per_sample(audio_codec->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); + final_samples = (int16_t *) av_malloc( + sizeof(int16_t) * audio_input_position * (av_get_bytes_per_sample(audio_codec->sample_fmt) / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16))); // Copy audio into buffer for frame memcpy(final_samples, samples, audio_input_position * av_get_bytes_per_sample(audio_codec->sample_fmt)); @@ -1683,7 +1627,7 @@ void FFmpegWriter::write_audio_packets(bool final) // Fill the final_frame AVFrame with audio (non planar) avcodec_fill_audio_frame(frame_final, audio_codec->channels, audio_codec->sample_fmt, (uint8_t *) final_samples, - audio_encoder_buffer_size, 0); + audio_encoder_buffer_size, 0); } // Increment PTS (in samples) @@ -1702,7 +1646,7 @@ void FFmpegWriter::write_audio_packets(bool final) /* encode the audio samples */ int got_packet_ptr = 0; - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 // Encode audio (latest version of FFmpeg) int error_code; int ret = 0; @@ -1730,10 +1674,10 @@ void FFmpegWriter::write_audio_packets(bool final) ret = -1; } got_packet_ptr = ret; - #else +#else // Encode audio (older versions of FFmpeg) int error_code = avcodec_encode_audio2(audio_codec, &pkt, frame_final, &got_packet_ptr); - #endif +#endif /* if zero size, it means the image was buffered */ if (error_code == 0 && got_packet_ptr) { @@ -1755,15 +1699,13 @@ void FFmpegWriter::write_audio_packets(bool final) /* write the compressed frame in the media file */ int error_code = av_interleaved_write_frame(oc, &pkt); - if (error_code < 0) - { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets ERROR [" + (string)av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); + if (error_code < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets ERROR [" + (string) av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); } } - if (error_code < 0) - { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets ERROR [" + (string)av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); + if (error_code < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_audio_packets ERROR [" + (string) av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); } // deallocate AVFrame @@ -1775,7 +1717,7 @@ void FFmpegWriter::write_audio_packets(bool final) // Reset position audio_input_position = 0; - final = false; + is_final = false; } // Delete arrays (if needed) @@ -1792,8 +1734,7 @@ void FFmpegWriter::write_audio_packets(bool final) } // Allocate an AVFrame object -AVFrame* FFmpegWriter::allocate_avframe(PixelFormat pix_fmt, int width, int height, int *buffer_size, uint8_t *new_buffer) -{ +AVFrame *FFmpegWriter::allocate_avframe(PixelFormat pix_fmt, int width, int height, int *buffer_size, uint8_t *new_buffer) { // Create an RGB AVFrame AVFrame *new_av_frame = NULL; @@ -1806,10 +1747,9 @@ AVFrame* FFmpegWriter::allocate_avframe(PixelFormat pix_fmt, int width, int heig *buffer_size = AV_GET_IMAGE_SIZE(pix_fmt, width, height); // Create buffer (if not provided) - if (!new_buffer) - { + if (!new_buffer) { // New Buffer - new_buffer = (uint8_t*)av_malloc(*buffer_size * sizeof(uint8_t)); + new_buffer = (uint8_t *) av_malloc(*buffer_size * sizeof(uint8_t)); // Attach buffer to AVFrame AV_COPY_PICTURE_DATA(new_av_frame, new_buffer, pix_fmt, width, height); new_av_frame->width = width; @@ -1822,8 +1762,7 @@ AVFrame* FFmpegWriter::allocate_avframe(PixelFormat pix_fmt, int width, int heig } // process video frame -void FFmpegWriter::process_video_packet(std::shared_ptr frame) -{ +void FFmpegWriter::process_video_packet(std::shared_ptr frame) { // Determine the height & width of the source image int source_image_width = frame->GetWidth(); int source_image_height = frame->GetHeight(); @@ -1842,7 +1781,7 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) if (rescaler_position == num_of_rescalers) rescaler_position = 0; - #pragma omp task firstprivate(frame, scaler, source_image_width, source_image_height) +#pragma omp task firstprivate(frame, scaler, source_image_width, source_image_height) { // Allocate an RGB frame & final output frame int bytes_source = 0; @@ -1854,29 +1793,28 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) pixels = frame->GetPixels(); // Init AVFrame for source image & final (converted image) - frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t*) pixels); - #if IS_FFMPEG_3_2 - AVFrame *frame_final; + frame_source = allocate_avframe(PIX_FMT_RGBA, source_image_width, source_image_height, &bytes_source, (uint8_t *) pixels); +#if IS_FFMPEG_3_2 + AVFrame *frame_final; if (hw_en_on && hw_en_supported) { frame_final = allocate_avframe(AV_PIX_FMT_NV12, info.width, info.height, &bytes_final, NULL); - } else - { + } else { frame_final = allocate_avframe((AVPixelFormat)(video_st->codecpar->format), info.width, info.height, &bytes_final, NULL); } - #else +#else AVFrame *frame_final = allocate_avframe(video_codec->pix_fmt, info.width, info.height, &bytes_final, NULL); - #endif +#endif // Fill with data - AV_COPY_PICTURE_DATA(frame_source, (uint8_t*)pixels, PIX_FMT_RGBA, source_image_width, source_image_height); + AV_COPY_PICTURE_DATA(frame_source, (uint8_t *) pixels, PIX_FMT_RGBA, source_image_width, source_image_height); ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::process_video_packet", "frame->number", frame->number, "bytes_source", bytes_source, "bytes_final", bytes_final, "", -1, "", -1, "", -1); // Resize & convert pixel format sws_scale(scaler, frame_source->data, frame_source->linesize, 0, - source_image_height, frame_final->data, frame_final->linesize); + source_image_height, frame_final->data, frame_final->linesize); // Add resized AVFrame to av_frames map - #pragma omp critical (av_frames_section) +#pragma omp critical (av_frames_section) add_avframe(frame, frame_final); // Deallocate memory @@ -1887,8 +1825,7 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) } // write video frame -bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* frame_final) -{ +bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *frame_final) { #if (LIBAVFORMAT_VERSION_MAJOR >= 58) ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags, "", -1, "", -1, "", -1, "", -1); #else @@ -1900,19 +1837,18 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra av_init_packet(&pkt); pkt.flags |= AV_PKT_FLAG_KEY; - pkt.stream_index= video_st->index; - pkt.data= (uint8_t*)frame_final->data; - pkt.size= sizeof(AVPicture); + pkt.stream_index = video_st->index; + pkt.data = (uint8_t *) frame_final->data; + pkt.size = sizeof(AVPicture); // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational){info.fps.den, info.fps.num}, video_codec->time_base); + write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base); pkt.pts = write_video_count; /* write the compressed frame in the media file */ int error_code = av_interleaved_write_frame(oc, &pkt); - if (error_code < 0) - { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (string)av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); + if (error_code < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (string) av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); return false; } @@ -1933,11 +1869,11 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra uint8_t *video_outbuf = NULL; // Increment PTS (in frames and scaled to the codec's timebase) - write_video_count += av_rescale_q(1, (AVRational){info.fps.den, info.fps.num}, video_codec->time_base); + write_video_count += av_rescale_q(1, (AVRational) {info.fps.den, info.fps.num}, video_codec->time_base); // Assign the initial AVFrame PTS from the frame counter frame_final->pts = write_video_count; - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { if (!(hw_frame = av_frame_alloc())) { fprintf(stderr, "Error code: av_hwframe_alloc\n"); @@ -1954,20 +1890,20 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } av_frame_copy_props(hw_frame, frame_final); } - #endif +#endif /* encode the image */ int got_packet_ptr = 0; int error_code = 0; - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 // Write video packet (latest version of FFmpeg) int frameFinished = 0; int ret; - #if IS_FFMPEG_3_2 + if (hw_en_on && hw_en_supported) { ret = avcodec_send_frame(video_codec, hw_frame); //hw_frame!!! - } else - #endif - ret = avcodec_send_frame(video_codec, frame_final); + } else { + ret = avcodec_send_frame(video_codec, frame_final); + } error_code = ret; if (ret < 0 ) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet (Frame not sent)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); @@ -1982,10 +1918,11 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra else { while (ret >= 0) { ret = avcodec_receive_packet(video_codec, &pkt); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { avcodec_flush_buffers(video_codec); got_packet_ptr = 0; - break; + break; } if (ret == 0) { got_packet_ptr = 1; @@ -1993,36 +1930,36 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } } } - #else - #if LIBAVFORMAT_VERSION_MAJOR >= 54 - // Write video packet (older than FFmpeg 3.2) - error_code = avcodec_encode_video2(video_codec, &pkt, frame_final, &got_packet_ptr); - if (error_code != 0 ) { - cerr << "Frame AVERROR_EOF" << "\n"; - } - if (got_packet_ptr == 0 ) { - cerr << "Frame gotpacket error" << "\n"; - } - #else - // Write video packet (even older versions of FFmpeg) - int video_outbuf_size = 200000; - video_outbuf = (uint8_t*) av_malloc(200000); +#else +#if LIBAVFORMAT_VERSION_MAJOR >= 54 + // Write video packet (older than FFmpeg 3.2) + error_code = avcodec_encode_video2(video_codec, &pkt, frame_final, &got_packet_ptr); + if (error_code != 0) { + cerr << "Frame AVERROR_EOF" << "\n"; + } + if (got_packet_ptr == 0) { + cerr << "Frame gotpacket error" << "\n"; + } +#else + // Write video packet (even older versions of FFmpeg) + int video_outbuf_size = 200000; + video_outbuf = (uint8_t*) av_malloc(200000); - /* encode the image */ - int out_size = avcodec_encode_video(video_codec, video_outbuf, video_outbuf_size, frame_final); + /* encode the image */ + int out_size = avcodec_encode_video(video_codec, video_outbuf, video_outbuf_size, frame_final); - /* if zero size, it means the image was buffered */ - if (out_size > 0) { - if(video_codec->coded_frame->key_frame) - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.data= video_outbuf; - pkt.size= out_size; + /* if zero size, it means the image was buffered */ + if (out_size > 0) { + if(video_codec->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.data= video_outbuf; + pkt.size= out_size; - // got data back (so encode this frame) - got_packet_ptr = 1; - } - #endif - #endif + // got data back (so encode this frame) + got_packet_ptr = 1; + } +#endif +#endif /* if zero size, it means the image was buffered */ if (error_code == 0 && got_packet_ptr) { @@ -2042,9 +1979,8 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra /* write the compressed frame in the media file */ int error_code = av_interleaved_write_frame(oc, &pkt); - if (error_code < 0) - { - ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (string)av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); + if (error_code < 0) { + ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet ERROR [" + (string) av_err2str(error_code) + "]", "error_code", error_code, "", -1, "", -1, "", -1, "", -1, "", -1); return false; } } @@ -2055,14 +1991,14 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra // Deallocate packet AV_FREE_PACKET(&pkt); - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { if (hw_frame) { av_frame_free(&hw_frame); hw_frame = NULL; } } - #endif +#endif } // Success @@ -2070,31 +2006,29 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame* fra } // Output the ffmpeg info about this format, streams, and codecs (i.e. dump format) -void FFmpegWriter::OutputStreamInfo() -{ +void FFmpegWriter::OutputStreamInfo() { // output debug info av_dump_format(oc, 0, path.c_str(), 1); } // Init a collection of software rescalers (thread safe) -void FFmpegWriter::InitScalers(int source_width, int source_height) -{ +void FFmpegWriter::InitScalers(int source_width, int source_height) { int scale_mode = SWS_FAST_BILINEAR; if (openshot::Settings::Instance()->HIGH_QUALITY_SCALING) { scale_mode = SWS_LANCZOS; } // Init software rescalers vector (many of them, one for each thread) - for (int x = 0; x < num_of_rescalers; x++) - { + for (int x = 0; x < num_of_rescalers; x++) { // Init the software scaler from FFMpeg - #if IS_FFMPEG_3_2 +#if IS_FFMPEG_3_2 if (hw_en_on && hw_en_supported) { img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_PIX_FMT_NV12, SWS_BILINEAR, NULL, NULL, NULL); } else - #endif +#endif { - img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, NULL, NULL, NULL); + img_convert_ctx = sws_getContext(source_width, source_height, PIX_FMT_RGBA, info.width, info.height, AV_GET_CODEC_PIXEL_FORMAT(video_st, video_st->codec), SWS_BILINEAR, + NULL, NULL, NULL); } // Add rescaler to vector @@ -2109,8 +2043,7 @@ void FFmpegWriter::ResampleAudio(int sample_rate, int channels) { } // Remove & deallocate all software scalers -void FFmpegWriter::RemoveScalers() -{ +void FFmpegWriter::RemoveScalers() { // Close all rescalers for (int x = 0; x < num_of_rescalers; x++) sws_freeContext(image_rescalers[x]); From 19f5fa37f2c915be6ad4bb96323802d3c508f04b Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 18 Apr 2019 16:41:11 -0700 Subject: [PATCH 109/186] Replace qsv with videotoolbox for MacOS codec library. Windows and MacOS is not tested! We need users who test it. --- src/FFmpegReader.cpp | 12 ++++++------ src/FFmpegWriter.cpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 3af851e1..2ea6fcbb 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -248,9 +248,9 @@ static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum A for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { - case AV_PIX_FMT_QSV: - hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; + case AV_PIX_FMT_VIDEOTOOLBOX: + hw_de_av_pix_fmt_global = AV_PIX_FMT_VIDEOTOOLBOX; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; return *p; break; } @@ -413,15 +413,15 @@ void FFmpegReader::Open() { i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; pCodecCtx->get_format = get_hw_dec_format_qs; break; case 5: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; pCodecCtx->get_format = get_hw_dec_format_qs; break; default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; pCodecCtx->get_format = get_hw_dec_format_qs; break; } diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e12ff094..072ac6d7 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -211,12 +211,12 @@ void FFmpegWriter::SetVideoOptions(bool has_video, string codec, Fraction fps, i } } #elif defined(__APPLE__) - if ( (strcmp(codec.c_str(),"h264_qsv") == 0)) { + if ( (strcmp(codec.c_str(),"h264_videotoolbox") == 0)) { new_codec = avcodec_find_encoder_by_name(codec.c_str()); hw_en_on = 1; hw_en_supported = 1; - hw_en_av_pix_fmt = AV_PIX_FMT_QSV; - hw_en_av_device_type = AV_HWDEVICE_TYPE_QSV; + hw_en_av_pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX; + hw_en_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; } else { new_codec = avcodec_find_encoder_by_name(codec.c_str()); From 8d3263f2faacad1235624a9e0acb2327342b034c Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 18 Apr 2019 17:09:20 -0700 Subject: [PATCH 110/186] Some information --- doc/HW-ACCEL.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index edbe85b4..c11d2adc 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -8,8 +8,8 @@ Observations for developers wanting to make hardware acceleration work. * HW accel is supported from ffmpeg version 3.2 (3.3 for nVidia drivers) * HW accel was removed for nVidia drivers in Ubuntu for ffmpeg 4+ -* I could not manage to build a version of ffmpeg 4.1 with the nVidia SDK -that worked with nVidia cards. There might be a problem in ffmpeg 4+ +* I could not manage to build a version of ffmpeg 4.1 with the nVidia SDK +that worked with nVidia cards. There might be a problem in ffmpeg 4+ that prohibits this. **Notice:** The ffmpeg versions of Ubuntu and PPAs for Ubuntu show the @@ -55,7 +55,7 @@ int HW_EN_DEVICE_SET = 0; The correct version of libva is needed (libva in Ubuntu 16.04 or libva2 in Ubuntu 18.04) for the AppImage to work with hardware acceleration. -An AppImage that works on both systems (supporting libva and libva2), +An AppImage that works on both systems (supporting libva and libva2), might be possible when no libva is included in the AppImage. * vaapi is working for intel and AMD @@ -64,14 +64,14 @@ might be possible when no libva is included in the AppImage. ## AMD Graphics Cards (RadeonOpenCompute/ROCm) -Decoding and encoding on the (AMD) GPU can be done on systems where ROCm -is installed and run. Possible future use for GPU acceleration of effects (contributions -welcome). +Decoding and encoding on the (AMD) GPU is possible with the default drivers. +On systems where ROCm is installed and run a future use for GPU acceleration +of effects could be implemented (contributions welcome). ## Multiple Graphics Cards If the computer has multiple graphics cards installed, you can choose which -should be used by libopenshot. Also, you can optionally use one card for +should be used by libopenshot. Also, you can optionally use one card for decoding and the other for encoding (if both cards support acceleration). ## Help Us Improve Hardware Support @@ -82,3 +82,17 @@ this document if you find an error or discover some new information. **Desperately Needed:** a way to compile ffmpeg 4.0 and up with working nVidia hardware acceleration support on Ubuntu Linux! + +**Needed:** a way to get the options and limits of the GPU, like +supported codecs and the supported dimensions (width and height). + +**Would be nice:** a way in python to only have some source for the desired +plattform. Example: VAAPI is not supported in Windows or Mac and should not +be displayed as an option for encoder libraries. + +**Further improvement:** Right now the frame can be decoded on the GPU but the +frame is then copied to CPU memory. Before encoding the frame the frame is then +copied to GPU memory for encoding. That is necessary because the modifications +are done by the CPU. Using the GPU for that too will make it possible to do +away with these two copies. A possible solution would be to use Vulkan compute +which would be available on Linux and Windows natively and on MacOS via MoltenVK. From f6465e3a786f6796210b2d7db66b890d810847a6 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 18 Apr 2019 21:05:31 -0500 Subject: [PATCH 111/186] Experimental Python install path logic --- src/bindings/python/CMakeLists.txt | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index c8686097..2a481aa7 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -30,10 +30,10 @@ FIND_PACKAGE(SWIG 2.0 REQUIRED) INCLUDE(${SWIG_USE_FILE}) ### Enable some legacy SWIG behaviors, in newer CMAKEs -if (CMAKE_VERSION VERSION_GREATER 3.13) +if (POLICY CMP0078) cmake_policy(SET CMP0078 OLD) endif() -if (CMAKE_VERSION VERSION_GREATER 3.14) +if (POLICY CMP0086) cmake_policy(SET CMP0086 OLD) endif() @@ -65,20 +65,29 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} ${PYTHON_LIBRARIES} openshot) - ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ -import site; from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, standard_lib=True, prefix='${CMAKE_INSTALL_PREFIX}' ) \ - + '/' + get_python_lib( plat_specific=False, standard_lib=False, prefix='${CMAKE_INSTALL_PREFIX}' ).split('/')[-1] \ - + '/' )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) + ### Check if the following Debian-friendly python module path exists + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages") + if (NOT EXISTS ${PYTHON_MODULE_PATH}) - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH}) + ### Check if another Debian-friendly python module path exists + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") + if (NOT EXISTS ${PYTHON_MODULE_PATH}) + + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ +from distutils.sysconfig import get_python_lib; \ +print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) + endif() + endif() + message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ ### Install Python bindings From 4c65804d4547cb61343116ea5c349a3653bec4bb Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 19 Apr 2019 15:47:29 -0700 Subject: [PATCH 112/186] User interface is now usable --- doc/HW-ACCEL.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index c11d2adc..3f750e6e 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -86,10 +86,6 @@ hardware acceleration support on Ubuntu Linux! **Needed:** a way to get the options and limits of the GPU, like supported codecs and the supported dimensions (width and height). -**Would be nice:** a way in python to only have some source for the desired -plattform. Example: VAAPI is not supported in Windows or Mac and should not -be displayed as an option for encoder libraries. - **Further improvement:** Right now the frame can be decoded on the GPU but the frame is then copied to CPU memory. Before encoding the frame the frame is then copied to GPU memory for encoding. That is necessary because the modifications From 825e38ac9d8f80eaeb3fd90cd6a2d9cfa1c55400 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 21 Apr 2019 10:04:24 -0700 Subject: [PATCH 113/186] Removing old way to select hardware support Removing the decode setting makes hardware supported decode break. There must be some hidden dependency on that variable somewhere which might also be responsible for the problems with nVidia on Linux. TODO Remove the dependency --- include/Settings.h | 6 +++++- src/Settings.cpp | 6 +++++- tests/Settings_Tests.cpp | 22 +++++++++++++--------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/include/Settings.h b/include/Settings.h index 3e18bc9a..fc98ab4f 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -77,13 +77,17 @@ namespace openshot { public: /// Use video card for faster video decoding (if supported) + // REMOVE_HW_OLD + // Removing this breaks decode completely + // Find bug in libopenshot bool HARDWARE_DECODE = false; /// Use video codec for faster video decoding (if supported) int HARDWARE_DECODER = 0; /// Use video card for faster video encoding (if supported) - bool HARDWARE_ENCODE = false; + // REMOVE_HW_OLD + //bool HARDWARE_ENCODE = false; /// Scale mode used in FFmpeg decoding and encoding (used as an optimization for faster previews) bool HIGH_QUALITY_SCALING = false; diff --git a/src/Settings.cpp b/src/Settings.cpp index 461f9183..e0f8e693 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -40,9 +40,13 @@ Settings *Settings::Instance() if (!m_pInstance) { // Create the actual instance of logger only once m_pInstance = new Settings; + // REMOVE_HW_OLD + // Removing this breaks decode completely + // Find bug in libopenshot m_pInstance->HARDWARE_DECODE = false; m_pInstance->HARDWARE_DECODER = 0; - m_pInstance->HARDWARE_ENCODE = false; + // REMOVE_HW_OLD + //m_pInstance->HARDWARE_ENCODE = false; m_pInstance->HIGH_QUALITY_SCALING = false; m_pInstance->MAX_WIDTH = 0; m_pInstance->MAX_HEIGHT = 0; diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index 86790653..f76d60ba 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -36,8 +36,9 @@ TEST(Settings_Default_Constructor) // Create an empty color Settings *s = Settings::Instance(); - CHECK_EQUAL(false, s->HARDWARE_DECODE); - CHECK_EQUAL(false, s->HARDWARE_ENCODE); + CHECK_EQUAL(1, s->HARDWARE_DECODER); + // REMOVE_HW_OLD + //CHECK_EQUAL(false, s->HARDWARE_ENCODE); CHECK_EQUAL(false, s->HIGH_QUALITY_SCALING); CHECK_EQUAL(false, s->WAIT_FOR_VIDEO_PROCESSING_TASK); } @@ -46,18 +47,21 @@ TEST(Settings_Change_Settings) { // Create an empty color Settings *s = Settings::Instance(); - s->HARDWARE_DECODE = true; - s->HARDWARE_ENCODE = true; + s->HARDWARE_DECODER = 1; + // REMOVE_HW_OLD + //s->HARDWARE_ENCODE = true; s->HIGH_QUALITY_SCALING = true; s->WAIT_FOR_VIDEO_PROCESSING_TASK = true; - CHECK_EQUAL(true, s->HARDWARE_DECODE); - CHECK_EQUAL(true, s->HARDWARE_ENCODE); + CHECK_EQUAL(1, s->HARDWARE_DECODER); + // REMOVE_HW_OLD + //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, s->HIGH_QUALITY_SCALING); CHECK_EQUAL(true, s->WAIT_FOR_VIDEO_PROCESSING_TASK); - CHECK_EQUAL(true, s->HARDWARE_DECODE); - CHECK_EQUAL(true, s->HARDWARE_ENCODE); + CHECK_EQUAL(1, s->HARDWARE_DECODER); + // REMOVE_HW_OLD + //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, Settings::Instance()->HIGH_QUALITY_SCALING); CHECK_EQUAL(true, Settings::Instance()->WAIT_FOR_VIDEO_PROCESSING_TASK); -} \ No newline at end of file +} From bb561ae4e2102505890760f23f80eee19d54590f Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 21 Apr 2019 10:17:31 -0700 Subject: [PATCH 114/186] Temporarily disable test for DECODER --- tests/Settings_Tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index f76d60ba..bc127805 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -36,7 +36,7 @@ TEST(Settings_Default_Constructor) // Create an empty color Settings *s = Settings::Instance(); - CHECK_EQUAL(1, s->HARDWARE_DECODER); + //CHECK_EQUAL(1, s->HARDWARE_DECODER); // REMOVE_HW_OLD //CHECK_EQUAL(false, s->HARDWARE_ENCODE); CHECK_EQUAL(false, s->HIGH_QUALITY_SCALING); @@ -47,19 +47,19 @@ TEST(Settings_Change_Settings) { // Create an empty color Settings *s = Settings::Instance(); - s->HARDWARE_DECODER = 1; + //s->HARDWARE_DECODER = 1; // REMOVE_HW_OLD //s->HARDWARE_ENCODE = true; s->HIGH_QUALITY_SCALING = true; s->WAIT_FOR_VIDEO_PROCESSING_TASK = true; - CHECK_EQUAL(1, s->HARDWARE_DECODER); + //CHECK_EQUAL(1, s->HARDWARE_DECODER); // REMOVE_HW_OLD //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, s->HIGH_QUALITY_SCALING); CHECK_EQUAL(true, s->WAIT_FOR_VIDEO_PROCESSING_TASK); - CHECK_EQUAL(1, s->HARDWARE_DECODER); + //CHECK_EQUAL(1, s->HARDWARE_DECODER); // REMOVE_HW_OLD //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, Settings::Instance()->HIGH_QUALITY_SCALING); From 0e77fbdc3b967b97bed8454cda4fa0e97185e232 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 21 Apr 2019 10:53:53 -0700 Subject: [PATCH 115/186] Re-anable the DECODER test --- tests/Settings_Tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index bc127805..82690bbe 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -36,7 +36,7 @@ TEST(Settings_Default_Constructor) // Create an empty color Settings *s = Settings::Instance(); - //CHECK_EQUAL(1, s->HARDWARE_DECODER); + CHECK_EQUAL(0, s->HARDWARE_DECODER); // REMOVE_HW_OLD //CHECK_EQUAL(false, s->HARDWARE_ENCODE); CHECK_EQUAL(false, s->HIGH_QUALITY_SCALING); @@ -47,19 +47,19 @@ TEST(Settings_Change_Settings) { // Create an empty color Settings *s = Settings::Instance(); - //s->HARDWARE_DECODER = 1; + s->HARDWARE_DECODER = 1; // REMOVE_HW_OLD //s->HARDWARE_ENCODE = true; s->HIGH_QUALITY_SCALING = true; s->WAIT_FOR_VIDEO_PROCESSING_TASK = true; - //CHECK_EQUAL(1, s->HARDWARE_DECODER); + CHECK_EQUAL(1, s->HARDWARE_DECODER); // REMOVE_HW_OLD //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, s->HIGH_QUALITY_SCALING); CHECK_EQUAL(true, s->WAIT_FOR_VIDEO_PROCESSING_TASK); - //CHECK_EQUAL(1, s->HARDWARE_DECODER); + CHECK_EQUAL(1, s->HARDWARE_DECODER); // REMOVE_HW_OLD //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, Settings::Instance()->HIGH_QUALITY_SCALING); From e6efea7a929e21c13e016cef0ba569df4fb653fa Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 21 Apr 2019 11:31:58 -0700 Subject: [PATCH 116/186] Update documentation --- doc/HW-ACCEL.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index 3f750e6e..ed886a5f 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -23,15 +23,12 @@ The following settings are use by libopenshot to enable, disable, and control the various hardware acceleration features. ``` -/// Use video card for faster video decoding (if supported) +/// DEPRECATED Use video card for faster video decoding (if supported) bool HARDWARE_DECODE = false; /// Use video codec for faster video decoding (if supported) int HARDWARE_DECODER = 0; -/// Use video card for faster video encoding (if supported) -bool HARDWARE_ENCODE = false; - /// Number of threads of OpenMP int OMP_THREADS = 12; @@ -83,6 +80,11 @@ this document if you find an error or discover some new information. **Desperately Needed:** a way to compile ffmpeg 4.0 and up with working nVidia hardware acceleration support on Ubuntu Linux! +**BUG:** the use of HARDWARE_DECODE is somehow still needed, otherwise hardware +supported decoding breaks. TODO remove the hidden dependency on this variable. +The variable HARDWARE_DECODER should and does select if and which hardware +decoder is used but somehow HARDWARE_DECODE has to be there too. + **Needed:** a way to get the options and limits of the GPU, like supported codecs and the supported dimensions (width and height). From 65d9134722440d1812e095fb25910046a0dd9677 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 21 Apr 2019 12:18:44 -0700 Subject: [PATCH 117/186] Remove DECODE varaible. Turn out that a buggy graphic driver was the problem. --- doc/HW-ACCEL.md | 12 +++++------- include/Settings.h | 4 +--- src/Settings.cpp | 4 +--- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index ed886a5f..9a8b78b9 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -23,9 +23,6 @@ The following settings are use by libopenshot to enable, disable, and control the various hardware acceleration features. ``` -/// DEPRECATED Use video card for faster video decoding (if supported) -bool HARDWARE_DECODE = false; - /// Use video codec for faster video decoding (if supported) int HARDWARE_DECODER = 0; @@ -80,10 +77,11 @@ this document if you find an error or discover some new information. **Desperately Needed:** a way to compile ffmpeg 4.0 and up with working nVidia hardware acceleration support on Ubuntu Linux! -**BUG:** the use of HARDWARE_DECODE is somehow still needed, otherwise hardware -supported decoding breaks. TODO remove the hidden dependency on this variable. -The variable HARDWARE_DECODER should and does select if and which hardware -decoder is used but somehow HARDWARE_DECODE has to be there too. +**BUG:** hardware supported decoding still has a bug. The speed gains with +decoding are by far not as great as with encoding. In case hardware accelerated +decoding does not work disable it. +Hardware acceleration might also break because of graphics drivers that have +bugs. **Needed:** a way to get the options and limits of the GPU, like supported codecs and the supported dimensions (width and height). diff --git a/include/Settings.h b/include/Settings.h index fc98ab4f..1ea61335 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -78,9 +78,7 @@ namespace openshot { public: /// Use video card for faster video decoding (if supported) // REMOVE_HW_OLD - // Removing this breaks decode completely - // Find bug in libopenshot - bool HARDWARE_DECODE = false; + //bool HARDWARE_DECODE = false; /// Use video codec for faster video decoding (if supported) int HARDWARE_DECODER = 0; diff --git a/src/Settings.cpp b/src/Settings.cpp index e0f8e693..e838cc51 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -41,9 +41,7 @@ Settings *Settings::Instance() // Create the actual instance of logger only once m_pInstance = new Settings; // REMOVE_HW_OLD - // Removing this breaks decode completely - // Find bug in libopenshot - m_pInstance->HARDWARE_DECODE = false; + //m_pInstance->HARDWARE_DECODE = false; m_pInstance->HARDWARE_DECODER = 0; // REMOVE_HW_OLD //m_pInstance->HARDWARE_ENCODE = false; From 79335277cba0d001faf1904b1e9ca907d52c4f4e Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 21 Apr 2019 14:37:06 -0500 Subject: [PATCH 118/186] Removing old commented out code --- doc/HW-ACCEL.md | 13 ++++++------- include/Settings.h | 8 -------- src/Settings.cpp | 4 ---- tests/Settings_Tests.cpp | 8 -------- 4 files changed, 6 insertions(+), 27 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index 9a8b78b9..7ed4c637 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -74,20 +74,19 @@ This information might be wrong, and we would love to continue improving our support for hardware acceleration in OpenShot. Please help us update this document if you find an error or discover some new information. -**Desperately Needed:** a way to compile ffmpeg 4.0 and up with working nVidia +**Desperately Needed:** A way to compile ffmpeg 4.0 and up with working nVidia hardware acceleration support on Ubuntu Linux! -**BUG:** hardware supported decoding still has a bug. The speed gains with +**BUG:** Hardware supported decoding still has a bug. The speed gains with decoding are by far not as great as with encoding. In case hardware accelerated -decoding does not work disable it. -Hardware acceleration might also break because of graphics drivers that have -bugs. +decoding does not work disable it. Hardware acceleration might also break +because of graphics drivers that have bugs. -**Needed:** a way to get the options and limits of the GPU, like +**Needed:** A way to get the options and limits of the GPU, like supported codecs and the supported dimensions (width and height). **Further improvement:** Right now the frame can be decoded on the GPU but the -frame is then copied to CPU memory. Before encoding the frame the frame is then +frame is then copied to CPU memory. Before encoding the frame is then copied to GPU memory for encoding. That is necessary because the modifications are done by the CPU. Using the GPU for that too will make it possible to do away with these two copies. A possible solution would be to use Vulkan compute diff --git a/include/Settings.h b/include/Settings.h index 1ea61335..26edf464 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -76,17 +76,9 @@ namespace openshot { static Settings * m_pInstance; public: - /// Use video card for faster video decoding (if supported) - // REMOVE_HW_OLD - //bool HARDWARE_DECODE = false; - /// Use video codec for faster video decoding (if supported) int HARDWARE_DECODER = 0; - /// Use video card for faster video encoding (if supported) - // REMOVE_HW_OLD - //bool HARDWARE_ENCODE = false; - /// Scale mode used in FFmpeg decoding and encoding (used as an optimization for faster previews) bool HIGH_QUALITY_SCALING = false; diff --git a/src/Settings.cpp b/src/Settings.cpp index e838cc51..99b059e8 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -40,11 +40,7 @@ Settings *Settings::Instance() if (!m_pInstance) { // Create the actual instance of logger only once m_pInstance = new Settings; - // REMOVE_HW_OLD - //m_pInstance->HARDWARE_DECODE = false; m_pInstance->HARDWARE_DECODER = 0; - // REMOVE_HW_OLD - //m_pInstance->HARDWARE_ENCODE = false; m_pInstance->HIGH_QUALITY_SCALING = false; m_pInstance->MAX_WIDTH = 0; m_pInstance->MAX_HEIGHT = 0; diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index 82690bbe..1b8180c9 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -37,8 +37,6 @@ TEST(Settings_Default_Constructor) Settings *s = Settings::Instance(); CHECK_EQUAL(0, s->HARDWARE_DECODER); - // REMOVE_HW_OLD - //CHECK_EQUAL(false, s->HARDWARE_ENCODE); CHECK_EQUAL(false, s->HIGH_QUALITY_SCALING); CHECK_EQUAL(false, s->WAIT_FOR_VIDEO_PROCESSING_TASK); } @@ -48,20 +46,14 @@ TEST(Settings_Change_Settings) // Create an empty color Settings *s = Settings::Instance(); s->HARDWARE_DECODER = 1; - // REMOVE_HW_OLD - //s->HARDWARE_ENCODE = true; s->HIGH_QUALITY_SCALING = true; s->WAIT_FOR_VIDEO_PROCESSING_TASK = true; CHECK_EQUAL(1, s->HARDWARE_DECODER); - // REMOVE_HW_OLD - //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, s->HIGH_QUALITY_SCALING); CHECK_EQUAL(true, s->WAIT_FOR_VIDEO_PROCESSING_TASK); CHECK_EQUAL(1, s->HARDWARE_DECODER); - // REMOVE_HW_OLD - //CHECK_EQUAL(true, s->HARDWARE_ENCODE); CHECK_EQUAL(true, Settings::Instance()->HIGH_QUALITY_SCALING); CHECK_EQUAL(true, Settings::Instance()->WAIT_FOR_VIDEO_PROCESSING_TASK); } From 140fbaddff7e26e472474631765a5956b0b4075c Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 23 Apr 2019 16:45:02 -0500 Subject: [PATCH 119/186] Added new AudioDeviceInfo struct, and populate a vector of them on QtPlayer initialization. This allows a user to overwrite the preferred audio device by using the setting PLAYBACK_AUDIO_DEVICE_NAME. --- include/AudioDeviceInfo.h | 43 ++++++++++++++++++++++++++++++++ include/Qt/AudioPlaybackThread.h | 14 ++++++++--- include/QtPlayer.h | 3 +++ include/Settings.h | 3 +++ src/Qt/AudioPlaybackThread.cpp | 25 +++++++++++++++---- src/QtPlayer.cpp | 11 +++++++- src/Settings.cpp | 2 +- src/bindings/python/openshot.i | 3 +++ src/bindings/ruby/openshot.i | 3 +++ 9 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 include/AudioDeviceInfo.h diff --git a/include/AudioDeviceInfo.h b/include/AudioDeviceInfo.h new file mode 100644 index 00000000..29a89139 --- /dev/null +++ b/include/AudioDeviceInfo.h @@ -0,0 +1,43 @@ +/** + * @file + * @brief Header file for Audio Device Info struct + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2014 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) 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 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . + */ + +#ifndef OPENSHOT_AUDIODEVICEINFO_H +#define OPENSHOT_AUDIODEVICEINFO_H + + +/** + * @brief This struct hold information about Audio Devices + * + * The type and name of the audio device. + */ +struct AudioDeviceInfo +{ + string name; + string type; +}; + +#endif \ No newline at end of file diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index 1d654756..be26c4e8 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -32,6 +32,8 @@ #include "../ReaderBase.h" #include "../RendererBase.h" #include "../AudioReaderSource.h" +#include "../AudioDeviceInfo.h" +#include "../Settings.h" namespace openshot { @@ -66,8 +68,11 @@ namespace openshot /// Error found during JUCE initialise method string initialise_error; - /// Create or get an instance of this singleton (invoke the class with this method) - static AudioDeviceManagerSingleton * Instance(int numChannels); + /// List of valid audio device names + vector audio_device_names; + + /// Override with no channels and no preferred audio device + static AudioDeviceManagerSingleton * Instance(); /// Public device manager property AudioDeviceManager audioDeviceManager; @@ -126,7 +131,10 @@ namespace openshot int getSpeed() const { if (source) return source->getSpeed(); else return 1; } /// Get Audio Error (if any) - string getError() { return AudioDeviceManagerSingleton::Instance(numChannels)->initialise_error; } + string getError() { return AudioDeviceManagerSingleton::Instance()->initialise_error; } + + /// Get Audio Device Names (if any) + vector getAudioDeviceNames() { return AudioDeviceManagerSingleton::Instance()->audio_device_names; }; friend class PlayerPrivate; friend class QtPlayer; diff --git a/include/QtPlayer.h b/include/QtPlayer.h index a1a7ee0c..c9137f5e 100644 --- a/include/QtPlayer.h +++ b/include/QtPlayer.h @@ -62,6 +62,9 @@ namespace openshot /// Get Error (if any) string GetError(); + /// Get Audio Devices from JUCE + vector GetAudioDeviceNames(); + /// Play the video void Play(); diff --git a/include/Settings.h b/include/Settings.h index 26edf464..859b2fab 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -109,6 +109,9 @@ namespace openshot { /// Which GPU to use to encode (0 is the first) int HW_EN_DEVICE_SET = 0; + /// The audio device name to use during playback + string PLAYBACK_AUDIO_DEVICE_NAME = ""; + /// Create or get an instance of this logger singleton (invoke the class with this method) static Settings * Instance(); }; diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index c64bd688..28db8df6 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -35,7 +35,7 @@ namespace openshot AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::m_pInstance = NULL; // Create or Get an instance of the device manager singleton - AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::Instance(int numChannels) + AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::Instance() { if (!m_pInstance) { // Create the actual instance of device manager only once @@ -44,9 +44,10 @@ namespace openshot // Initialize audio device only 1 time String error = m_pInstance->audioDeviceManager.initialise ( 0, /* number of input channels */ - numChannels, /* number of output channels */ + 2, /* number of output channels */ 0, /* no XML settings.. */ - true /* select default device on failure */); + true, /* select default device on failure */ + Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME /* preferredDefaultDeviceName */); // Persist any errors detected if (error.isNotEmpty()) { @@ -54,6 +55,20 @@ namespace openshot } else { m_pInstance->initialise_error = ""; } + + // Get all audio device names + for (int i = 0; i < m_pInstance->audioDeviceManager.getAvailableDeviceTypes().size(); ++i) + { + const AudioIODeviceType* t = m_pInstance->audioDeviceManager.getAvailableDeviceTypes()[i]; + const StringArray deviceNames = t->getDeviceNames (); + + for (int j = 0; j < deviceNames.size (); ++j ) + { + const String deviceName = deviceNames[j]; + AudioDeviceInfo deviceInfo = {deviceName.toStdString(), t->getTypeName().toStdString()}; + m_pInstance->audio_device_names.push_back(deviceInfo); + } + } } return m_pInstance; @@ -149,7 +164,7 @@ namespace openshot // Start new audio device (or get existing one) // Add callback - AudioDeviceManagerSingleton::Instance(numChannels)->audioDeviceManager.addAudioCallback(&player); + AudioDeviceManagerSingleton::Instance()->audioDeviceManager.addAudioCallback(&player); // Create TimeSliceThread for audio buffering time_thread.startThread(); @@ -182,7 +197,7 @@ namespace openshot transport.setSource(NULL); player.setSource(NULL); - AudioDeviceManagerSingleton::Instance(0)->audioDeviceManager.removeAudioCallback(&player); + AudioDeviceManagerSingleton::Instance()->audioDeviceManager.removeAudioCallback(&player); // Remove source delete source; diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp index 4f53c7ca..3287c19d 100644 --- a/src/QtPlayer.cpp +++ b/src/QtPlayer.cpp @@ -56,7 +56,7 @@ QtPlayer::~QtPlayer() void QtPlayer::CloseAudioDevice() { // Close audio device (only do this once, when all audio playback is finished) - AudioDeviceManagerSingleton::Instance(0)->CloseAudioDevice(); + AudioDeviceManagerSingleton::Instance()->CloseAudioDevice(); } // Return any error string during initialization @@ -69,6 +69,15 @@ string QtPlayer::GetError() { } } +/// Get Audio Devices from JUCE +vector QtPlayer::GetAudioDeviceNames() { + if (reader && threads_started) { + return p->audioPlayback->getAudioDeviceNames(); + } else { + return vector(); + } +} + void QtPlayer::SetSource(const std::string &source) { FFmpegReader *ffreader = new FFmpegReader(source); diff --git a/src/Settings.cpp b/src/Settings.cpp index 99b059e8..8193ec6b 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -51,7 +51,7 @@ Settings *Settings::Instance() m_pInstance->DE_LIMIT_WIDTH_MAX = 1950; m_pInstance->HW_DE_DEVICE_SET = 0; m_pInstance->HW_EN_DEVICE_SET = 0; - + m_pInstance->PLAYBACK_AUDIO_DEVICE_NAME = ""; } return m_pInstance; diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index de1f020c..ed34b658 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -87,6 +87,7 @@ #include "../../../include/Settings.h" #include "../../../include/Timeline.h" #include "../../../include/ZmqLogger.h" +#include "../../../include/AudioDeviceInfo.h" %} @@ -154,6 +155,7 @@ %include "../../../include/Settings.h" %include "../../../include/Timeline.h" %include "../../../include/ZmqLogger.h" +%include "../../../include/AudioDeviceInfo.h" #ifdef USE_IMAGEMAGICK %include "../../../include/ImageReader.h" @@ -187,4 +189,5 @@ namespace std { %template(FieldVector) vector; %template(MappedFrameVector) vector; %template(MappedMetadata) map; + %template(AudioDeviceInfoVector) vector; } diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index b9a35d41..1cd9bb75 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -91,6 +91,7 @@ namespace std { #include "../../../include/Settings.h" #include "../../../include/Timeline.h" #include "../../../include/ZmqLogger.h" +#include "../../../include/AudioDeviceInfo.h" %} @@ -147,6 +148,7 @@ namespace std { %include "../../../include/Settings.h" %include "../../../include/Timeline.h" %include "../../../include/ZmqLogger.h" +%include "../../../include/AudioDeviceInfo.h" #ifdef USE_IMAGEMAGICK %include "../../../include/ImageReader.h" @@ -181,4 +183,5 @@ namespace std { %template(FieldVector) vector; %template(MappedFrameVector) vector; %template(MappedMetadata) map; + %template(AudioDeviceInfoVector) vector; } From a69c34ffbb49c5f2a79a5f124e8bf9b2b41df8ff Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Wed, 24 Apr 2019 09:41:52 -0500 Subject: [PATCH 120/186] Small refactor to audio device manager initialise (to prevent compile breakage on Mac) --- src/Qt/AudioPlaybackThread.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index 28db8df6..d31f719e 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -41,13 +41,16 @@ namespace openshot // Create the actual instance of device manager only once m_pInstance = new AudioDeviceManagerSingleton; + // Get preferred audio device name (if any) + string preferred_audio_device = Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME; + // Initialize audio device only 1 time String error = m_pInstance->audioDeviceManager.initialise ( 0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ true, /* select default device on failure */ - Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME /* preferredDefaultDeviceName */); + preferred_audio_device /* preferredDefaultDeviceName */); // Persist any errors detected if (error.isNotEmpty()) { From ef2ed569065beaf28049b2b9767fcbc6dfa84aa6 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Wed, 24 Apr 2019 10:08:22 -0500 Subject: [PATCH 121/186] More refactoring for Mac compile breakage --- src/Qt/AudioPlaybackThread.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index d31f719e..678a9c09 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -42,10 +42,10 @@ namespace openshot m_pInstance = new AudioDeviceManagerSingleton; // Get preferred audio device name (if any) - string preferred_audio_device = Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME; + juce::String preferred_audio_device = juce::String(Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME.c_str()); // Initialize audio device only 1 time - String error = m_pInstance->audioDeviceManager.initialise ( + juce::String error = m_pInstance->audioDeviceManager.initialise ( 0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ @@ -67,7 +67,7 @@ namespace openshot for (int j = 0; j < deviceNames.size (); ++j ) { - const String deviceName = deviceNames[j]; + juce::String deviceName = deviceNames[j]; AudioDeviceInfo deviceInfo = {deviceName.toStdString(), t->getTypeName().toStdString()}; m_pInstance->audio_device_names.push_back(deviceInfo); } From 49831a24b00ea46b749fbd6fe9101fb74fbc6972 Mon Sep 17 00:00:00 2001 From: Sergey Parfenyuk Date: Sat, 27 Apr 2019 12:37:24 +0200 Subject: [PATCH 122/186] Add virtual destructor for abstract classes --- include/CacheBase.h | 1 + include/ClipBase.h | 1 + include/EffectBase.h | 1 + include/PlayerBase.h | 1 + include/ReaderBase.h | 2 ++ include/WriterBase.h | 2 ++ 6 files changed, 8 insertions(+) diff --git a/include/CacheBase.h b/include/CacheBase.h index aaef5320..a7f8c88f 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -109,6 +109,7 @@ namespace openshot { virtual void SetJson(string value) = 0; ///< Load JSON string into this object virtual Json::Value JsonValue() = 0; ///< Generate Json::JsonValue for this object virtual void SetJsonValue(Json::Value root) = 0; ///< Load Json::JsonValue into this object + virtual ~CacheBase() = default; }; diff --git a/include/ClipBase.h b/include/ClipBase.h index 3dae8a53..4678f25a 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -101,6 +101,7 @@ namespace openshot { /// of all properties at any time) virtual string PropertiesJSON(int64_t requested_frame) = 0; + virtual ~ClipBase() = default; }; diff --git a/include/EffectBase.h b/include/EffectBase.h index d38e3f45..26add05d 100644 --- a/include/EffectBase.h +++ b/include/EffectBase.h @@ -105,6 +105,7 @@ namespace openshot /// Set the order that this effect should be executed. void Order(int new_order) { order = new_order; } + virtual ~EffectBase() = default; }; } diff --git a/include/PlayerBase.h b/include/PlayerBase.h index ecc222a8..f1ce2d80 100644 --- a/include/PlayerBase.h +++ b/include/PlayerBase.h @@ -104,6 +104,7 @@ namespace openshot /// Set the Volume (1.0 = normal volume, <1.0 = quieter, >1.0 louder) virtual void Volume(float new_volume) = 0; + virtual ~PlayerBase() = default; }; } diff --git a/include/ReaderBase.h b/include/ReaderBase.h index b0a1b3db..ce665f1d 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -147,6 +147,8 @@ namespace openshot /// Open the reader (and start consuming resources, such as images or video files) virtual void Open() = 0; + + virtual ~ReaderBase() = default; }; } diff --git a/include/WriterBase.h b/include/WriterBase.h index 8f424054..3fd80c7f 100644 --- a/include/WriterBase.h +++ b/include/WriterBase.h @@ -116,6 +116,8 @@ namespace openshot /// Open the writer (and start initializing streams) virtual void Open() = 0; + + virtual ~WriterBase() = default; }; } From 665a03f9e23973a626abcc9520071fe1f6644142 Mon Sep 17 00:00:00 2001 From: Sergey Parfenyuk Date: Sat, 27 Apr 2019 12:50:31 +0200 Subject: [PATCH 123/186] Fix logical statements --- src/AudioResampler.cpp | 4 ++-- src/KeyFrame.cpp | 2 +- src/QtImageReader.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AudioResampler.cpp b/src/AudioResampler.cpp index 442a91d9..d7829ec5 100644 --- a/src/AudioResampler.cpp +++ b/src/AudioResampler.cpp @@ -74,9 +74,9 @@ AudioResampler::~AudioResampler() void AudioResampler::SetBuffer(AudioSampleBuffer *new_buffer, double sample_rate, double new_sample_rate) { if (sample_rate <= 0) - sample_rate == 44100; + sample_rate = 44100; if (new_sample_rate <= 0) - new_sample_rate == 44100; + new_sample_rate = 44100; // Set the sample ratio (the ratio of sample rate change) source_ratio = sample_rate / new_sample_rate; diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 025484a3..a2c2362d 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -784,7 +784,7 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { // Add new value to the vector Coordinate new_coord(current_frame, current_value); - if (Segment == 0 || Segment > 0 && current_frame > p1.co.X) + if (Segment == 0 || (Segment > 0 && current_frame > p1.co.X)) // Add to "values" vector Values.push_back(new_coord); diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index c500d221..8cc2debc 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -209,7 +209,7 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) } // Scale image smaller (or use a previous scaled image) - if (!cached_image || (cached_image && cached_image->width() != max_width || cached_image->height() != max_height)) { + if (!cached_image || (cached_image->width() != max_width || cached_image->height() != max_height)) { #if USE_RESVG == 1 // If defined and found in CMake, utilize the libresvg for parsing From eea67ad97296e6c5ca475086cebd99ccc61c0496 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sat, 27 Apr 2019 13:36:21 -0700 Subject: [PATCH 124/186] Link to instruction to produce ffmpeg 4 plus the libraries on Ubuntu that support nVidia GPU acceleration. Tested on Mint 19.1. --- doc/HW-ACCEL.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index 7ed4c637..34e05e4f 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -74,8 +74,13 @@ This information might be wrong, and we would love to continue improving our support for hardware acceleration in OpenShot. Please help us update this document if you find an error or discover some new information. -**Desperately Needed:** A way to compile ffmpeg 4.0 and up with working nVidia -hardware acceleration support on Ubuntu Linux! +**Desperately Needed:** The manual at: +https://www.tal.org/tutorials/ffmpeg_nvidia_encode +works pretty well. I could compile and install a version of ffmpeg 4.1.3 +on Mint 19.1 that supports the GPU on nVidia cards. A version of openshot +with hardware support using these libraries could use the nVidia GPU. +(A way to compile ffmpeg 4.0 and up with working nVidia +hardware acceleration support on Ubuntu Linux!) **BUG:** Hardware supported decoding still has a bug. The speed gains with decoding are by far not as great as with encoding. In case hardware accelerated From 3bd2ae5f2394dd725363d66bf85979fa7c02c341 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 28 Apr 2019 14:03:45 -0500 Subject: [PATCH 125/186] Integrating VDPAU decoding into libopenshot --- doc/HW-ACCEL.md | 6 ++++++ src/FFmpegReader.cpp | 21 +++++++++++++++++++++ src/examples/Example.cpp | 4 ++++ 3 files changed, 31 insertions(+) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index 34e05e4f..b785a9ce 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -96,3 +96,9 @@ copied to GPU memory for encoding. That is necessary because the modifications are done by the CPU. Using the GPU for that too will make it possible to do away with these two copies. A possible solution would be to use Vulkan compute which would be available on Linux and Windows natively and on MacOS via MoltenVK. + +## Credit + +A big thanks to Peter M (https://github.com/eisneinechse) for all his work +on integrating hardware accelleration into libopenshot! The community thanks +you for this major contribution! diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2ea6fcbb..929ddf72 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -186,6 +186,23 @@ static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum A ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_cu (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } + +static enum AVPixelFormat get_hw_dec_format_vd(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { + case AV_PIX_FMT_VDPAU: + hw_de_av_pix_fmt_global = AV_PIX_FMT_VDPAU; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VDPAU; + return *p; + break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_vd (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} #endif #if defined(_WIN32) @@ -377,6 +394,10 @@ void FFmpegReader::Open() { hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; pCodecCtx->get_format = get_hw_dec_format_cu; break; + case 6: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU; + pCodecCtx->get_format = get_hw_dec_format_vd; + break; default: hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 411abdda..80339684 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -36,6 +36,10 @@ using namespace openshot; int main(int argc, char* argv[]) { + Settings *s = Settings::Instance(); + s->HARDWARE_DECODER = 2; // 1 VA-API, 2 NVDEC + s->HW_DE_DEVICE_SET = 1; + FFmpegReader r9("/home/jonathan/Videos/sintel_trailer-720p.mp4"); r9.Open(); r9.DisplayInfo(); From 2bafe60448eb72a82665b96a164558d61f4033fa Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 28 Apr 2019 17:18:43 -0500 Subject: [PATCH 126/186] Removing 0 cases, and adding new QSV decoder support (experimental) --- src/FFmpegReader.cpp | 47 ++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 929ddf72..480e835b 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -259,7 +259,7 @@ static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum A #endif #if defined(__APPLE__) -static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +static enum AVPixelFormat get_hw_dec_format_vt(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; @@ -272,11 +272,28 @@ static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_qs (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_vt (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } #endif +static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + switch (*p) { + case AV_PIX_FMT_QSV: + hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; + return *p; + break; + } + } + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_qs (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + return AV_PIX_FMT_NONE; +} + int FFmpegReader::IsHardwareDecodeSupported(int codecid) { int ret; @@ -382,10 +399,6 @@ void FFmpegReader::Open() { adapter_ptr = adapter; i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { - case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; - break; case 1: hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; @@ -398,6 +411,10 @@ void FFmpegReader::Open() { hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU; pCodecCtx->get_format = get_hw_dec_format_vd; break; + case 7: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; default: hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; pCodecCtx->get_format = get_hw_dec_format_va; @@ -408,10 +425,6 @@ void FFmpegReader::Open() { adapter_ptr = NULL; i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { - case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; case 2: hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; pCodecCtx->get_format = get_hw_dec_format_cu; @@ -424,6 +437,10 @@ void FFmpegReader::Open() { hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; pCodecCtx->get_format = get_hw_dec_format_d3; break; + case 7: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + pCodecCtx->get_format = get_hw_dec_format_qs; + break; default: hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; pCodecCtx->get_format = get_hw_dec_format_dx; @@ -433,17 +450,17 @@ void FFmpegReader::Open() { adapter_ptr = NULL; i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; switch (i_decoder_hw) { - case 0: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; case 5: hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; + pCodecCtx->get_format = get_hw_dec_format_vt; + break; + case 7: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; pCodecCtx->get_format = get_hw_dec_format_qs; break; default: hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; - pCodecCtx->get_format = get_hw_dec_format_qs; + pCodecCtx->get_format = get_hw_dec_format_vt; break; } #endif From cdb4ae5483d43748d5af8ecbc6a7e5b112b5c850 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 29 Apr 2019 17:05:13 -0500 Subject: [PATCH 127/186] Fixing crash on Mac due to juce::String again --- src/FFmpegReader.cpp | 2 +- src/Qt/AudioPlaybackThread.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 480e835b..690af140 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -76,7 +76,7 @@ using namespace openshot; int hw_de_on = 0; #if IS_FFMPEG_3_2 -AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE; + AVPixelFormat hw_de_av_pix_fmt_global = AV_PIX_FMT_NONE; AVHWDeviceType hw_de_av_device_type_global = AV_HWDEVICE_TYPE_NONE; #endif diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index 678a9c09..7bad4649 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -45,7 +45,7 @@ namespace openshot juce::String preferred_audio_device = juce::String(Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME.c_str()); // Initialize audio device only 1 time - juce::String error = m_pInstance->audioDeviceManager.initialise ( + juce::String audio_error = m_pInstance->audioDeviceManager.initialise ( 0, /* number of input channels */ 2, /* number of output channels */ 0, /* no XML settings.. */ @@ -53,8 +53,8 @@ namespace openshot preferred_audio_device /* preferredDefaultDeviceName */); // Persist any errors detected - if (error.isNotEmpty()) { - m_pInstance->initialise_error = error.toStdString(); + if (audio_error.isNotEmpty()) { + m_pInstance->initialise_error = audio_error.toRawUTF8(); } else { m_pInstance->initialise_error = ""; } @@ -68,7 +68,8 @@ namespace openshot for (int j = 0; j < deviceNames.size (); ++j ) { juce::String deviceName = deviceNames[j]; - AudioDeviceInfo deviceInfo = {deviceName.toStdString(), t->getTypeName().toStdString()}; + juce::String typeName = t->getTypeName(); + AudioDeviceInfo deviceInfo = {deviceName.toRawUTF8(), typeName.toRawUTF8()}; m_pInstance->audio_device_names.push_back(deviceInfo); } } From 70f07ca4f81196d6e919858a4395fc72184f2a70 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 30 Apr 2019 13:17:43 -0500 Subject: [PATCH 128/186] Improving HW-ACCEL documentation --- doc/HW-ACCEL.md | 88 ++++++++++++++++++++++++++++++---------------- include/Settings.h | 13 ++++++- 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index b785a9ce..af5bb091 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -1,20 +1,33 @@ ## Hardware Acceleration -Observations for developers wanting to make hardware acceleration work. +OpenShot now has experimental support for hardware acceleration, which uses 1 (or more) +graphics cards to offload some of the work for both decoding and encoding. This is +very new and experimental (as of May 2019), but we look forward to "accelerating" +our support for this in the future! -*All observations are for Linux (but contributions welcome).* +The following table summarizes our current level of support: + +| | Linux Decode | Linux Encode | Mac Decode | Mac Encode | Windows Decode | Windows Encode | Notes | +|--------------------|--------------|--------------|------------|------------|----------------------|----------------|----------------| +| VA-API | Verified | Verified | - | - | - | - | Linux Only | +| VDPAU | Verified | Verified | - | - | - | - | Linux Only | +| CUDA (NVDEC/NVENC) | Verified | Verified | - | - | - | Verified | Cross Platform | +| VideoToolBox | - | - | Verified | Crashes | - | - | Mac Only | +| DXVA2 | - | - | - | - | Fails (green frames) | Verified | Windows Only | +| D3D11VA | - | - | - | - | Fails (green frames) | - | Windows Only | +| QSV | Fails | Fails | Fails | Fails | Fails | Fails | Cross Platform | ## Supported FFmpeg Versions -* HW accel is supported from ffmpeg version 3.2 (3.3 for nVidia drivers) -* HW accel was removed for nVidia drivers in Ubuntu for ffmpeg 4+ -* I could not manage to build a version of ffmpeg 4.1 with the nVidia SDK -that worked with nVidia cards. There might be a problem in ffmpeg 4+ +* HW accel is supported from FFmpeg version 3.2 (3.3 for nVidia drivers) +* HW accel was removed for nVidia drivers in Ubuntu for FFmpeg 4+ +* We could not manage to build a version of FFmpeg 4.1 with the nVidia SDK +that worked with nVidia cards. There might be a problem in FFmpeg 4+ that prohibits this. -**Notice:** The ffmpeg versions of Ubuntu and PPAs for Ubuntu show the -same behaviour. ffmpeg 3 has working nVidia hardware acceleration while -ffmpeg 4+ has no support for nVidia hardware acceleration +**Notice:** The FFmpeg versions of Ubuntu and PPAs for Ubuntu show the +same behaviour. FFmpeg 3 has working nVidia hardware acceleration while +FFmpeg 4+ has no support for nVidia hardware acceleration included. ## OpenShot Settings @@ -26,10 +39,19 @@ the various hardware acceleration features. /// Use video codec for faster video decoding (if supported) int HARDWARE_DECODER = 0; +/* 0 - No acceleration + 1 - Linux VA-API + 2 - nVidia NVDEC + 3 - Windows D3D9 + 4 - Windows D3D11 + 5 - MacOS / VideoToolBox + 6 - Linux VDPAU + 7 - Intel QSV */ + /// Number of threads of OpenMP int OMP_THREADS = 12; -/// Number of threads that ffmpeg uses +/// Number of threads that FFmpeg uses int FF_THREADS = 8; /// Maximum rows that hardware decode can handle @@ -38,10 +60,10 @@ int DE_LIMIT_HEIGHT_MAX = 1100; /// Maximum columns that hardware decode can handle int DE_LIMIT_WIDTH_MAX = 1950; -/// Which GPU to use to decode (0 is the first) +/// Which GPU to use to decode (0 is the first, LINUX ONLY) int HW_DE_DEVICE_SET = 0; -/// Which GPU to use to encode (0 is the first) +/// Which GPU to use to encode (0 is the first, LINUX ONLY) int HW_EN_DEVICE_SET = 0; ``` @@ -67,38 +89,44 @@ of effects could be implemented (contributions welcome). If the computer has multiple graphics cards installed, you can choose which should be used by libopenshot. Also, you can optionally use one card for decoding and the other for encoding (if both cards support acceleration). +This is currently only supported on Linux, due to the device name FFmpeg +expects (i.e. **/dev/dri/render128**). Contributions welcome if anyone can +determine what string format to pass for Windows and Mac. ## Help Us Improve Hardware Support This information might be wrong, and we would love to continue improving our support for hardware acceleration in OpenShot. Please help us update -this document if you find an error or discover some new information. +this document if you find an error or discover new and/or useful information. -**Desperately Needed:** The manual at: +**FFmpeg 4 + nVidia** The manual at: https://www.tal.org/tutorials/ffmpeg_nvidia_encode -works pretty well. I could compile and install a version of ffmpeg 4.1.3 +works pretty well. We could compile and install a version of FFmpeg 4.1.3 on Mint 19.1 that supports the GPU on nVidia cards. A version of openshot with hardware support using these libraries could use the nVidia GPU. -(A way to compile ffmpeg 4.0 and up with working nVidia -hardware acceleration support on Ubuntu Linux!) -**BUG:** Hardware supported decoding still has a bug. The speed gains with -decoding are by far not as great as with encoding. In case hardware accelerated -decoding does not work disable it. Hardware acceleration might also break -because of graphics drivers that have bugs. +**BUG:** Hardware supported decoding still has some bugs (as you can see from +the chart above). Also, the speed gains with decoding are not as great +as with encoding. Currently, if hardware decoding fails, there is no +fallback (you either get green frames or an "invalid file" error in OpenShot). +This needs to be improved to successfully fall-back to software decoding. -**Needed:** A way to get the options and limits of the GPU, like -supported codecs and the supported dimensions (width and height). +**Needed:** + * A way to get options and limits of the GPU, such as + supported dimensions (width and height). + * A way to list the actual Graphic Cards available to FFmpeg (for the + user to choose which card for decoding and encoding, as opposed + to "Graphics Card X") -**Further improvement:** Right now the frame can be decoded on the GPU but the -frame is then copied to CPU memory. Before encoding the frame is then -copied to GPU memory for encoding. That is necessary because the modifications -are done by the CPU. Using the GPU for that too will make it possible to do -away with these two copies. A possible solution would be to use Vulkan compute -which would be available on Linux and Windows natively and on MacOS via MoltenVK. +**Further improvement:** Right now the frame can be decoded on the GPU, but the +frame is then copied to CPU memory for modifications. It is then copied back to +GPU memory for encoding. Using the GPU for both decoding and modifications +will make it possible to do away with these two copies. A possible solution would +be to use Vulkan compute which would be available on Linux and Windows natively +and on MacOS via MoltenVK. ## Credit A big thanks to Peter M (https://github.com/eisneinechse) for all his work -on integrating hardware accelleration into libopenshot! The community thanks +on integrating hardware acceleration into libopenshot! The community thanks you for this major contribution! diff --git a/include/Settings.h b/include/Settings.h index 859b2fab..89561034 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -76,7 +76,18 @@ namespace openshot { static Settings * m_pInstance; public: - /// Use video codec for faster video decoding (if supported) + /** + * @brief Use video codec for faster video decoding (if supported) + * + * 0 - No acceleration, + * 1 - Linux VA-API, + * 2 - nVidia NVDEC, + * 3 - Windows D3D9, + * 4 - Windows D3D11, + * 5 - MacOS / VideoToolBox, + * 6 - Linux VDPAU, + * 7 - Intel QSV + */ int HARDWARE_DECODER = 0; /// Scale mode used in FFmpeg decoding and encoding (used as an optimization for faster previews) From 27450a8a869ccd400db115b16b8c6c3122810b23 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Tue, 30 Apr 2019 14:05:52 -0700 Subject: [PATCH 129/186] Clarify table --- doc/HW-ACCEL.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index af5bb091..1dd8c92c 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -1,8 +1,8 @@ ## Hardware Acceleration -OpenShot now has experimental support for hardware acceleration, which uses 1 (or more) +OpenShot now has experimental support for hardware acceleration, which uses 1 (or more) graphics cards to offload some of the work for both decoding and encoding. This is -very new and experimental (as of May 2019), but we look forward to "accelerating" +very new and experimental (as of May 2019), but we look forward to "accelerating" our support for this in the future! The following table summarizes our current level of support: @@ -10,8 +10,8 @@ The following table summarizes our current level of support: | | Linux Decode | Linux Encode | Mac Decode | Mac Encode | Windows Decode | Windows Encode | Notes | |--------------------|--------------|--------------|------------|------------|----------------------|----------------|----------------| | VA-API | Verified | Verified | - | - | - | - | Linux Only | -| VDPAU | Verified | Verified | - | - | - | - | Linux Only | -| CUDA (NVDEC/NVENC) | Verified | Verified | - | - | - | Verified | Cross Platform | +| VDPAU | Verified(+) | N/A(++) | - | - | - | - | Linux Only | +| CUDA (NVDEC/NVENC) | Fails(+++) | Verified | - | - | - | Verified | Cross Platform | | VideoToolBox | - | - | Verified | Crashes | - | - | Mac Only | | DXVA2 | - | - | - | - | Fails (green frames) | Verified | Windows Only | | D3D11VA | - | - | - | - | Fails (green frames) | - | Windows Only | @@ -21,9 +21,9 @@ The following table summarizes our current level of support: * HW accel is supported from FFmpeg version 3.2 (3.3 for nVidia drivers) * HW accel was removed for nVidia drivers in Ubuntu for FFmpeg 4+ -* We could not manage to build a version of FFmpeg 4.1 with the nVidia SDK -that worked with nVidia cards. There might be a problem in FFmpeg 4+ -that prohibits this. +* (+) VDPAU for some reason needs a card number one higher than it really is +* (++) VDPAU is a decoder only. +* (+++) Green frames **Notice:** The FFmpeg versions of Ubuntu and PPAs for Ubuntu show the same behaviour. FFmpeg 3 has working nVidia hardware acceleration while @@ -106,23 +106,23 @@ on Mint 19.1 that supports the GPU on nVidia cards. A version of openshot with hardware support using these libraries could use the nVidia GPU. **BUG:** Hardware supported decoding still has some bugs (as you can see from -the chart above). Also, the speed gains with decoding are not as great +the chart above). Also, the speed gains with decoding are not as great as with encoding. Currently, if hardware decoding fails, there is no fallback (you either get green frames or an "invalid file" error in OpenShot). This needs to be improved to successfully fall-back to software decoding. -**Needed:** - * A way to get options and limits of the GPU, such as +**Needed:** + * A way to get options and limits of the GPU, such as supported dimensions (width and height). - * A way to list the actual Graphic Cards available to FFmpeg (for the - user to choose which card for decoding and encoding, as opposed + * A way to list the actual Graphic Cards available to FFmpeg (for the + user to choose which card for decoding and encoding, as opposed to "Graphics Card X") **Further improvement:** Right now the frame can be decoded on the GPU, but the -frame is then copied to CPU memory for modifications. It is then copied back to +frame is then copied to CPU memory for modifications. It is then copied back to GPU memory for encoding. Using the GPU for both decoding and modifications -will make it possible to do away with these two copies. A possible solution would -be to use Vulkan compute which would be available on Linux and Windows natively +will make it possible to do away with these two copies. A possible solution would +be to use Vulkan compute which would be available on Linux and Windows natively and on MacOS via MoltenVK. ## Credit From 9324b691e9a2152ad1dfb6fdfed1ccd44b4c750e Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 30 Apr 2019 17:11:04 -0500 Subject: [PATCH 130/186] Improving HW-ACCEL documentation --- doc/HW-ACCEL.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index 1dd8c92c..c04c3b88 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -7,23 +7,24 @@ our support for this in the future! The following table summarizes our current level of support: -| | Linux Decode | Linux Encode | Mac Decode | Mac Encode | Windows Decode | Windows Encode | Notes | -|--------------------|--------------|--------------|------------|------------|----------------------|----------------|----------------| -| VA-API | Verified | Verified | - | - | - | - | Linux Only | -| VDPAU | Verified(+) | N/A(++) | - | - | - | - | Linux Only | -| CUDA (NVDEC/NVENC) | Fails(+++) | Verified | - | - | - | Verified | Cross Platform | -| VideoToolBox | - | - | Verified | Crashes | - | - | Mac Only | -| DXVA2 | - | - | - | - | Fails (green frames) | Verified | Windows Only | -| D3D11VA | - | - | - | - | Fails (green frames) | - | Windows Only | -| QSV | Fails | Fails | Fails | Fails | Fails | Fails | Cross Platform | +| | Linux Decode | Linux Encode | Mac Decode | Mac Encode | Windows Decode | Windows Encode | Notes | +|--------------------|--------------|--------------|------------|------------|----------------|----------------|----------------| +| VA-API | Verified | Verified | - | - | - | - | Linux Only | +| VDPAU | Verified(+) | N/A(++) | - | - | - | - | Linux Only | +| CUDA (NVDEC/NVENC) | Fails(+++) | Verified | - | - | - | Verified | Cross Platform | +| VideoToolBox | - | - | Verified | Crashes | - | - | Mac Only | +| DXVA2 | - | - | - | - | Fails(+++) | - | Windows Only | +| D3D11VA | - | - | - | - | Fails(+++) | - | Windows Only | +| QSV | Fails | Fails | Fails | Fails | Fails | Fails | Cross Platform | + +* *(+) VDPAU for some reason needs a card number one higher than it really is* +* *(++) VDPAU is a decoder only.* +* *(+++) Green frames (pixel data not correctly tranferred back to system memory)* ## Supported FFmpeg Versions * HW accel is supported from FFmpeg version 3.2 (3.3 for nVidia drivers) * HW accel was removed for nVidia drivers in Ubuntu for FFmpeg 4+ -* (+) VDPAU for some reason needs a card number one higher than it really is -* (++) VDPAU is a decoder only. -* (+++) Green frames **Notice:** The FFmpeg versions of Ubuntu and PPAs for Ubuntu show the same behaviour. FFmpeg 3 has working nVidia hardware acceleration while From fad8f40cf577e314b9890e8db7a76480c6b98959 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 30 Apr 2019 17:43:15 -0500 Subject: [PATCH 131/186] Simplifying hardware decoder logic (when looking for pixmap) --- src/FFmpegReader.cpp | 285 +++++++++++++++---------------------------- 1 file changed, 95 insertions(+), 190 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 690af140..acd3b55f 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -152,137 +152,53 @@ bool AudioLocation::is_near(AudioLocation location, int samples_per_frame, int64 #if IS_FFMPEG_3_2 -#if defined(__linux__) -static enum AVPixelFormat get_hw_dec_format_va(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_VAAPI: - hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_va (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} - -static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_CUDA: - hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_cu (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} - -static enum AVPixelFormat get_hw_dec_format_vd(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_VDPAU: - hw_de_av_pix_fmt_global = AV_PIX_FMT_VDPAU; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VDPAU; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_vd (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} -#endif - -#if defined(_WIN32) -static enum AVPixelFormat get_hw_dec_format_dx(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_DXVA2_VLD: - hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_dx (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} - -static enum AVPixelFormat get_hw_dec_format_d3(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_D3D11: - hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_d3 (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} - -static enum AVPixelFormat get_hw_dec_format_cu(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_CUDA: - hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_cu (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} -#endif - -#if defined(__APPLE__) -static enum AVPixelFormat get_hw_dec_format_vt(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) -{ - const enum AVPixelFormat *p; - - for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { - switch (*p) { - case AV_PIX_FMT_VIDEOTOOLBOX: - hw_de_av_pix_fmt_global = AV_PIX_FMT_VIDEOTOOLBOX; - hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; - return *p; - break; - } - } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_vt (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); - return AV_PIX_FMT_NONE; -} -#endif - -static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) +// Get hardware pix format +static enum AVPixelFormat get_hw_dec_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) { const enum AVPixelFormat *p; for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { switch (*p) { +#if defined(__linux__) + // Linux pix formats + case AV_PIX_FMT_VAAPI: + hw_de_av_pix_fmt_global = AV_PIX_FMT_VAAPI; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VAAPI; + return *p; + break; + case AV_PIX_FMT_VDPAU: + hw_de_av_pix_fmt_global = AV_PIX_FMT_VDPAU; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VDPAU; + return *p; + break; +#endif +#if defined(_WIN32) + // Windows pix formats + case AV_PIX_FMT_DXVA2_VLD: + hw_de_av_pix_fmt_global = AV_PIX_FMT_DXVA2_VLD; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_DXVA2; + return *p; + break; + case AV_PIX_FMT_D3D11: + hw_de_av_pix_fmt_global = AV_PIX_FMT_D3D11; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_D3D11VA; + return *p; + break; +#endif +#if defined(__APPLE__) + // Apple pix formats + case AV_PIX_FMT_VIDEOTOOLBOX: + hw_de_av_pix_fmt_global = AV_PIX_FMT_VIDEOTOOLBOX; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; + return *p; + break; +#endif + // Cross-platform pix formats + case AV_PIX_FMT_CUDA: + hw_de_av_pix_fmt_global = AV_PIX_FMT_CUDA; + hw_de_av_device_type_global = AV_HWDEVICE_TYPE_CUDA; + return *p; + break; case AV_PIX_FMT_QSV: hw_de_av_pix_fmt_global = AV_PIX_FMT_QSV; hw_de_av_device_type_global = AV_HWDEVICE_TYPE_QSV; @@ -290,7 +206,7 @@ static enum AVPixelFormat get_hw_dec_format_qs(AVCodecContext *ctx, const enum A break; } } - ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format_qs (Unable to decode this file using hardware decode.)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::get_hw_dec_format (Unable to decode this file using hardware decode)", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); return AV_PIX_FMT_NONE; } @@ -304,15 +220,14 @@ int FFmpegReader::IsHardwareDecodeSupported(int codecid) case AV_CODEC_ID_WMV1: case AV_CODEC_ID_WMV2: case AV_CODEC_ID_WMV3: - ret = 1; - break; - default : - ret = 0; - break; + ret = 1; + break; + default : + ret = 0; + break; } return ret; } - #endif void FFmpegReader::Open() { @@ -393,76 +308,66 @@ void FFmpegReader::Open() { adapter_num = openshot::Settings::Instance()->HW_DE_DEVICE_SET; fprintf(stderr, "\n\nDecodiing Device Nr: %d\n", adapter_num); + // Set hardware pix format (callback) + pCodecCtx->get_format = get_hw_dec_format; + if (adapter_num < 3 && adapter_num >=0) { #if defined(__linux__) - snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); - adapter_ptr = adapter; - i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; - switch (i_decoder_hw) { - case 1: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; - break; - case 2: - hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - pCodecCtx->get_format = get_hw_dec_format_cu; - break; - case 6: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU; - pCodecCtx->get_format = get_hw_dec_format_vd; - break; - case 7: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; - pCodecCtx->get_format = get_hw_dec_format_va; - break; - } - -#elif defined(_WIN32) - adapter_ptr = NULL; - i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; - switch (i_decoder_hw) { + snprintf(adapter,sizeof(adapter),"/dev/dri/renderD%d", adapter_num+128); + adapter_ptr = adapter; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 1: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; + break; case 2: hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; - pCodecCtx->get_format = get_hw_dec_format_cu; break; - case 3: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; - break; - case 4: - hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; - pCodecCtx->get_format = get_hw_dec_format_d3; + case 6: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VDPAU; break; case 7: hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; break; default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; - pCodecCtx->get_format = get_hw_dec_format_dx; + hw_de_av_device_type = AV_HWDEVICE_TYPE_VAAPI; break; } + +#elif defined(_WIN32) + adapter_ptr = NULL; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 2: + hw_de_av_device_type = AV_HWDEVICE_TYPE_CUDA; + break; + case 3: + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + break; + case 4: + hw_de_av_device_type = AV_HWDEVICE_TYPE_D3D11VA; + break; + case 7: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_DXVA2; + break; + } #elif defined(__APPLE__) - adapter_ptr = NULL; - i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; - switch (i_decoder_hw) { - case 5: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; - pCodecCtx->get_format = get_hw_dec_format_vt; - break; - case 7: - hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; - pCodecCtx->get_format = get_hw_dec_format_qs; - break; - default: - hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; - pCodecCtx->get_format = get_hw_dec_format_vt; - break; - } + adapter_ptr = NULL; + i_decoder_hw = openshot::Settings::Instance()->HARDWARE_DECODER; + switch (i_decoder_hw) { + case 5: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; + break; + case 7: + hw_de_av_device_type = AV_HWDEVICE_TYPE_QSV; + break; + default: + hw_de_av_device_type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX; + break; + } #endif } else { From 2b42574ffdbbb1207601f306e03b842da37eb854 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Wed, 1 May 2019 18:02:25 -0500 Subject: [PATCH 132/186] Adding SetJson support for display_ratio and pixel_ratio updates, and improving SetMaxSize to maintain aspect ratio correctly, regardless of what is passed in. This helps support things like square aspect ratios. --- src/Timeline.cpp | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 5cb9ff5e..b3a24461 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -1371,6 +1371,33 @@ void Timeline::apply_json_to_timeline(Json::Value change) { else if (root_key == "fps" && sub_key == "den") // Set fps.den info.fps.den = change["value"].asInt(); + else if (root_key == "display_ratio" && sub_key == "" && change["value"].isObject()) { + // Set display_ratio fraction + if (!change["value"]["num"].isNull()) + info.display_ratio.num = change["value"]["num"].asInt(); + if (!change["value"]["den"].isNull()) + info.display_ratio.den = change["value"]["den"].asInt(); + } + else if (root_key == "display_ratio" && sub_key == "num") + // Set display_ratio.num + info.display_ratio.num = change["value"].asInt(); + else if (root_key == "display_ratio" && sub_key == "den") + // Set display_ratio.den + info.display_ratio.den = change["value"].asInt(); + else if (root_key == "pixel_ratio" && sub_key == "" && change["value"].isObject()) { + // Set pixel_ratio fraction + if (!change["value"]["num"].isNull()) + info.pixel_ratio.num = change["value"]["num"].asInt(); + if (!change["value"]["den"].isNull()) + info.pixel_ratio.den = change["value"]["den"].asInt(); + } + else if (root_key == "pixel_ratio" && sub_key == "num") + // Set pixel_ratio.num + info.pixel_ratio.num = change["value"].asInt(); + else if (root_key == "pixel_ratio" && sub_key == "den") + // Set pixel_ratio.den + info.pixel_ratio.den = change["value"].asInt(); + else if (root_key == "sample_rate") // Set sample rate info.sample_rate = change["value"].asInt(); @@ -1380,9 +1407,7 @@ void Timeline::apply_json_to_timeline(Json::Value change) { else if (root_key == "channel_layout") // Set channel layout info.channel_layout = (ChannelLayout) change["value"].asInt(); - else - // Error parsing JSON (or missing keys) throw InvalidJSONKey("JSON change key is invalid", change.toStyledString()); @@ -1443,7 +1468,14 @@ void Timeline::ClearAllCache() { // Set Max Image Size (used for performance optimization). Convenience function for setting // Settings::Instance()->MAX_WIDTH and Settings::Instance()->MAX_HEIGHT. void Timeline::SetMaxSize(int width, int height) { - // Init max image size (choose the smallest one) - Settings::Instance()->MAX_WIDTH = min(width, info.width); - Settings::Instance()->MAX_HEIGHT = min(height, info.height); + // Maintain aspect ratio regardless of what size is passed in + QSize display_ratio_size = QSize(info.display_ratio.num * info.pixel_ratio.ToFloat(), info.display_ratio.den * info.pixel_ratio.ToFloat()); + QSize proposed_size = QSize(min(width, info.width), min(height, info.height)); + + // Scale QSize up to proposed size + display_ratio_size.scale(proposed_size, Qt::KeepAspectRatio); + + // Set max size + Settings::Instance()->MAX_WIDTH = display_ratio_size.width(); + Settings::Instance()->MAX_HEIGHT = display_ratio_size.height(); } \ No newline at end of file From 6f00062b7b2526b23e51adb3b5f55f8be1a00d63 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 2 May 2019 11:43:34 -0500 Subject: [PATCH 133/186] Fixing small regression with SetMaxSize and missing display_ratio and pixel_ratio --- src/Timeline.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index b3a24461..b229a3de 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -58,6 +58,9 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha info.has_audio = true; info.has_video = true; info.video_length = info.fps.ToFloat() * info.duration; + info.display_ratio = openshot::Fraction(width, height); + info.display_ratio.Reduce(); + info.pixel_ratio = openshot::Fraction(1, 1); // Init max image size SetMaxSize(info.width, info.height); From da07ab250be91ce07267568f51330e3a36dc1ba4 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 2 May 2019 12:02:56 -0500 Subject: [PATCH 134/186] Updating hwaccel table to use emojis (instead of words) --- doc/HW-ACCEL.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index c04c3b88..8d29a11f 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -7,19 +7,20 @@ our support for this in the future! The following table summarizes our current level of support: -| | Linux Decode | Linux Encode | Mac Decode | Mac Encode | Windows Decode | Windows Encode | Notes | -|--------------------|--------------|--------------|------------|------------|----------------|----------------|----------------| -| VA-API | Verified | Verified | - | - | - | - | Linux Only | -| VDPAU | Verified(+) | N/A(++) | - | - | - | - | Linux Only | -| CUDA (NVDEC/NVENC) | Fails(+++) | Verified | - | - | - | Verified | Cross Platform | -| VideoToolBox | - | - | Verified | Crashes | - | - | Mac Only | -| DXVA2 | - | - | - | - | Fails(+++) | - | Windows Only | -| D3D11VA | - | - | - | - | Fails(+++) | - | Windows Only | -| QSV | Fails | Fails | Fails | Fails | Fails | Fails | Cross Platform | +| | Linux Decode | Linux Encode | Mac Decode | Mac Encode |Windows Decode| Windows Encode | Notes | +|--------------------|------------------------|----------------------|------------------|---------------|--------------|------------------|------------------| +| VA-API | :heavy_check_mark: | :heavy_check_mark: | - | - | - | - | *Linux Only* | +| VDPAU | :heavy_check_mark:(+) |:white_check_mark:(++)| - | - | - | - | *Linux Only* | +| CUDA (NVDEC/NVENC) | :x:(+++) | :heavy_check_mark: | - | - | - |:heavy_check_mark:| *Cross Platform* | +| VideoToolBox | - | - |:heavy_check_mark:| :x:(++++) | - | - | *Mac Only* | +| DXVA2 | - | - | - | - | :x:(+++) | - | *Windows Only* | +| D3D11VA | - | - | - | - | :x:(+++) | - | *Windows Only* | +| QSV | :x:(+++) | :x: | :x: | :x: | :x: | :x: | *Cross Platform* | * *(+) VDPAU for some reason needs a card number one higher than it really is* * *(++) VDPAU is a decoder only.* * *(+++) Green frames (pixel data not correctly tranferred back to system memory)* +* *(++++) Crashes and burns ## Supported FFmpeg Versions From 10ef8838b18326be51c68e2e90640e6882d1ef16 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 2 May 2019 12:03:58 -0500 Subject: [PATCH 135/186] Updating hwaccel table to use emojis (instead of words) --- doc/HW-ACCEL.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index 8d29a11f..f78fcd3a 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -7,15 +7,15 @@ our support for this in the future! The following table summarizes our current level of support: -| | Linux Decode | Linux Encode | Mac Decode | Mac Encode |Windows Decode| Windows Encode | Notes | -|--------------------|------------------------|----------------------|------------------|---------------|--------------|------------------|------------------| -| VA-API | :heavy_check_mark: | :heavy_check_mark: | - | - | - | - | *Linux Only* | -| VDPAU | :heavy_check_mark:(+) |:white_check_mark:(++)| - | - | - | - | *Linux Only* | -| CUDA (NVDEC/NVENC) | :x:(+++) | :heavy_check_mark: | - | - | - |:heavy_check_mark:| *Cross Platform* | -| VideoToolBox | - | - |:heavy_check_mark:| :x:(++++) | - | - | *Mac Only* | -| DXVA2 | - | - | - | - | :x:(+++) | - | *Windows Only* | -| D3D11VA | - | - | - | - | :x:(+++) | - | *Windows Only* | -| QSV | :x:(+++) | :x: | :x: | :x: | :x: | :x: | *Cross Platform* | +| | Linux Decode | Linux Encode | Mac Decode | Mac Encode |Windows Decode| Windows Encode | Notes | +|--------------------|------------------------|----------------------|------------------|----------------|--------------|------------------|------------------| +| VA-API | :heavy_check_mark: | :heavy_check_mark: | - | - | - | - | *Linux Only* | +| VDPAU | :heavy_check_mark:(+) |:white_check_mark:(++)| - | - | - | - | *Linux Only* | +| CUDA (NVDEC/NVENC) | :x:(+++) | :heavy_check_mark: | - | - | - |:heavy_check_mark:| *Cross Platform* | +| VideoToolBox | - | - |:heavy_check_mark:| :x:(++++) | - | - | *Mac Only* | +| DXVA2 | - | - | - | - | :x:(+++) | - | *Windows Only* | +| D3D11VA | - | - | - | - | :x:(+++) | - | *Windows Only* | +| QSV | :x:(+++) | :x: | :x: | :x: | :x: | :x: | *Cross Platform* | * *(+) VDPAU for some reason needs a card number one higher than it really is* * *(++) VDPAU is a decoder only.* From 4a0f0fa1c6297e4fba2c76968f1586c521a820a8 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 2 May 2019 12:04:51 -0500 Subject: [PATCH 136/186] Updating hwaccel table to use emojis (instead of words) take 3 --- doc/HW-ACCEL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/HW-ACCEL.md b/doc/HW-ACCEL.md index f78fcd3a..b8ee7b4e 100644 --- a/doc/HW-ACCEL.md +++ b/doc/HW-ACCEL.md @@ -20,7 +20,7 @@ The following table summarizes our current level of support: * *(+) VDPAU for some reason needs a card number one higher than it really is* * *(++) VDPAU is a decoder only.* * *(+++) Green frames (pixel data not correctly tranferred back to system memory)* -* *(++++) Crashes and burns +* *(++++) Crashes and burns* ## Supported FFmpeg Versions From eab0bbbe18eb77f84c7cea17eb4fce79f14eaa03 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Thu, 2 May 2019 14:19:14 -0500 Subject: [PATCH 137/186] Revert "Update Python install path detection" --- src/bindings/python/CMakeLists.txt | 48 +++++++++++++----------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 08182d95..2a481aa7 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -65,37 +65,29 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} ${PYTHON_LIBRARIES} openshot) - ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - if (UNIX AND NOT APPLE) - ### Special-case for Debian's crazy, by checking to see if pybuild - ### is available. We don't use it, except as a canary in a coal mine - find_program(PYBUILD_EXECUTABLE pybuild - DOC "Path to Debian's pybuild utility") - if (PYBUILD_EXECUTABLE) - # We're on a Debian derivative, fall back to old path detection - set(py_detection "import site; print(site.getsitepackages()[0])") - else() - # Use distutils to detect install path - set (py_detection "\ + ### Check if the following Debian-friendly python module path exists + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages") + if (NOT EXISTS ${PYTHON_MODULE_PATH}) + + ### Check if another Debian-friendly python module path exists + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") + if (NOT EXISTS ${PYTHON_MODULE_PATH}) + + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )") +print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) endif() endif() - - if (NOT PYTHON_MODULE_PATH) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "${py_detection}" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH} - CACHE PATH "Install path for Python modules (relative to prefix)") - endif() - - message(STATUS "Will install Python module to: ${PYTHON_MODULE_PATH}") + message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ ### Install Python bindings From 626a2f73f5b4f200cef8965963efc21e80c0030b Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 2 May 2019 20:14:45 -0400 Subject: [PATCH 138/186] Python: Assume /usr/local prefix on Debian If we're using the fallback path detection method on Debian, we shouldn't compute the install path relative to `${CMAKE_INSTALL_PREFIX}` since it _isn't_. So, we assume it's relative to `/usr/local` instead. --- src/bindings/python/CMakeLists.txt | 50 ++++++++++++++++++------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 2a481aa7..3f8ff2c1 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -65,29 +65,39 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} ${PYTHON_LIBRARIES} openshot) - ### Check if the following Debian-friendly python module path exists - SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages") - if (NOT EXISTS ${PYTHON_MODULE_PATH}) - - ### Check if another Debian-friendly python module path exists - SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") - if (NOT EXISTS ${PYTHON_MODULE_PATH}) - - ### Calculate the python module path (using distutils) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ + ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) + if (UNIX AND NOT APPLE) + ### Special-case for Debian's crazy, by checking to see if pybuild + ### is available. We don't use it, except as a canary in a coal mine + find_program(PYBUILD_EXECUTABLE pybuild + DOC "Path to Debian's pybuild utility") + if (PYBUILD_EXECUTABLE) + # We're on a Debian derivative, fall back to old path detection + set(py_detection "import site; print(site.getsitepackages()[0])") + set(PY_INSTALL_PREFIX "/usr/local") # An assumption (bad one?) + else() + # Use distutils to detect install path + set (py_detection "\ from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) +print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )") + set(PY_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) endif() endif() - message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") + + if (NOT PYTHON_MODULE_PATH) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "${py_detection}" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${PY_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH} + CACHE PATH "Install path for Python modules (relative to prefix)") + endif() + + message(STATUS "Will install Python module to: ${PYTHON_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ ### Install Python bindings From bfa8a838643989316ede715b731e2998d893fbff Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Fri, 3 May 2019 13:13:45 -0700 Subject: [PATCH 139/186] The default return value is present Remove else so that the default return value is used if no other return was used."else if" in line 334 had no else and therefore in some cases no return value was present. --- src/KeyFrame.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 025484a3..d83adc7f 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -336,9 +336,8 @@ bool Keyframe::IsIncreasing(int index) return false; } } - else - // return default true (since most curves increase) - return true; + // return default true (since most curves increase) + return true; } // Generate JSON string of this object From c55d8551c15b2f2c913627765476015d6343def1 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Sun, 5 May 2019 18:18:14 -0700 Subject: [PATCH 140/186] Simplification Further simplify the else branches. Thanks to SuslikV for pointing this out. --- src/KeyFrame.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index d83adc7f..2b0389de 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -327,11 +327,7 @@ bool Keyframe::IsIncreasing(int index) } } - if (current_value < next_value) { - // Increasing - return true; - } - else if (current_value >= next_value) { + if (current_value >= next_value) { // Decreasing return false; } From d23197c9b64b183826ee0aa1d7b304ff78f8bc95 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Wed, 8 May 2019 14:00:55 -0500 Subject: [PATCH 141/186] Updating hwaccel table to use emojis (instead of words) take 3 --- include/QtImageReader.h | 7 ++++--- src/QtImageReader.cpp | 11 +++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/QtImageReader.h b/include/QtImageReader.h index 6b260f15..e4d14f9b 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -65,9 +65,10 @@ namespace openshot { private: string path; - std::shared_ptr image; ///> Original image (full quality) - std::shared_ptr cached_image; ///> Scaled for performance - bool is_open; + std::shared_ptr image; ///> Original image (full quality) + std::shared_ptr cached_image; ///> Scaled for performance + bool is_open; ///> Is Reader opened + QSize max_size; ///> Current max_size as calculated with Clip properties public: diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index c500d221..a9682bd9 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -130,6 +130,10 @@ void QtImageReader::Open() info.display_ratio.num = size.num; info.display_ratio.den = size.den; + // Set current max size + max_size.setWidth(info.width); + max_size.setHeight(info.height); + // Mark as "open" is_open = true; } @@ -209,8 +213,7 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) } // Scale image smaller (or use a previous scaled image) - if (!cached_image || (cached_image && cached_image->width() != max_width || cached_image->height() != max_height)) { - + if (!cached_image || (cached_image && max_size.width() != max_width || max_size.height() != max_height)) { #if USE_RESVG == 1 // If defined and found in CMake, utilize the libresvg for parsing // SVG files and rasterizing them to QImages. @@ -239,6 +242,10 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) cached_image = std::shared_ptr(new QImage(image->scaled(max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation))); cached_image = std::shared_ptr(new QImage(cached_image->convertToFormat(QImage::Format_RGBA8888))); #endif + + // Set max size (to later determine if max_size is changed) + max_size.setWidth(max_width); + max_size.setHeight(max_height); } // Create or get frame object From 833fcb8e8e69dc0cffa15b19424942165d190c19 Mon Sep 17 00:00:00 2001 From: Chris Kirmse Date: Wed, 8 May 2019 14:53:23 -0700 Subject: [PATCH 142/186] fix a number of memory leaks - some were with libav functions - same were due to non-virtual destructors --- include/CacheBase.h | 2 ++ include/CacheMemory.h | 2 +- include/Clip.h | 2 +- include/ClipBase.h | 1 + include/FFmpegReader.h | 2 +- include/FFmpegUtilities.h | 6 +++--- include/Frame.h | 2 +- include/FrameMapper.h | 2 +- include/QtImageReader.h | 2 ++ include/ReaderBase.h | 2 ++ include/Timeline.h | 2 ++ src/CacheBase.cpp | 5 ++++- src/ClipBase.cpp | 5 ++++- src/FFmpegReader.cpp | 15 +++++++++++++-- src/FFmpegWriter.cpp | 22 +++++++--------------- src/Frame.cpp | 2 +- src/FrameMapper.cpp | 3 +++ src/QtImageReader.cpp | 6 +++++- src/ReaderBase.cpp | 3 +++ src/Timeline.cpp | 7 ++++++- 20 files changed, 63 insertions(+), 30 deletions(-) diff --git a/include/CacheBase.h b/include/CacheBase.h index aaef5320..c764b2d9 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -60,6 +60,8 @@ namespace openshot { /// @param max_bytes The maximum bytes to allow in the cache. Once exceeded, the cache will purge the oldest frames. CacheBase(int64_t max_bytes); + virtual ~CacheBase(); + /// @brief Add a Frame to the cache /// @param frame The openshot::Frame object needing to be cached. virtual void Add(std::shared_ptr frame) = 0; diff --git a/include/CacheMemory.h b/include/CacheMemory.h index 2f3f018b..29187799 100644 --- a/include/CacheMemory.h +++ b/include/CacheMemory.h @@ -71,7 +71,7 @@ namespace openshot { CacheMemory(int64_t max_bytes); // Default destructor - ~CacheMemory(); + virtual ~CacheMemory(); /// @brief Add a Frame to the cache /// @param frame The openshot::Frame object needing to be cached. diff --git a/include/Clip.h b/include/Clip.h index 346629e4..b1869a90 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -160,7 +160,7 @@ namespace openshot { Clip(ReaderBase* new_reader); /// Destructor - ~Clip(); + virtual ~Clip(); /// @brief Add an effect to the clip /// @param effect Add an effect to the clip. An effect can modify the audio or video of an openshot::Frame. diff --git a/include/ClipBase.h b/include/ClipBase.h index 3dae8a53..1c5534fc 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -69,6 +69,7 @@ namespace openshot { /// Constructor for the base clip ClipBase() { }; + virtual ~ClipBase(); // Compare a clip using the Position() property bool operator< ( ClipBase& a) { return (Position() < a.Position()); } diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index abf1af57..7ef44c50 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -243,7 +243,7 @@ namespace openshot { FFmpegReader(string path, bool inspect_reader); /// Destructor - ~FFmpegReader(); + virtual ~FFmpegReader(); /// Close File void Close(); diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 0d12ba72..7e3e0070 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -209,9 +209,9 @@ #define AV_FORMAT_NEW_STREAM(oc, st_codec, av_codec, av_st) av_st = avformat_new_stream(oc, NULL);\ if (!av_st) \ throw OutOfMemory("Could not allocate memory for the video stream.", path); \ - c = avcodec_alloc_context3(av_codec); \ - st_codec = c; \ - av_st->codecpar->codec_id = av_codec->id; + avcodec_get_context_defaults3(av_st->codec, av_codec); \ + c = av_st->codec; \ + st_codec = c; #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) avcodec_parameters_from_context(av_stream->codecpar, av_codec); #elif LIBAVFORMAT_VERSION_MAJOR >= 55 #define AV_REGISTER_ALL av_register_all(); diff --git a/include/Frame.h b/include/Frame.h index 66d8ccfa..56a2a3ec 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -159,7 +159,7 @@ namespace openshot Frame& operator= (const Frame& other); /// Destructor - ~Frame(); + virtual ~Frame(); /// Add (or replace) pixel data to the frame (based on a solid color) void AddColor(int new_width, int new_height, string new_color); diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 216fe73f..1901cb91 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -170,7 +170,7 @@ namespace openshot FrameMapper(ReaderBase *reader, Fraction target_fps, PulldownType target_pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout); /// Destructor - ~FrameMapper(); + virtual ~FrameMapper(); /// Change frame rate or audio mapping details void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout); diff --git a/include/QtImageReader.h b/include/QtImageReader.h index e4d14f9b..d26c9b79 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -81,6 +81,8 @@ namespace openshot /// when you are inflating the object using JSON after instantiating it. QtImageReader(string path, bool inspect_reader); + virtual ~QtImageReader(); + /// Close File void Close(); diff --git a/include/ReaderBase.h b/include/ReaderBase.h index b0a1b3db..efbd5bc7 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -107,6 +107,8 @@ namespace openshot /// Constructor for the base reader, where many things are initialized. ReaderBase(); + virtual ~ReaderBase(); + /// Information about the current media file ReaderInfo info; diff --git a/include/Timeline.h b/include/Timeline.h index 312add2e..97923153 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -205,6 +205,8 @@ namespace openshot { /// @param channel_layout The channel layout (i.e. mono, stereo, 3 point surround, etc...) Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout); + virtual ~Timeline(); + /// @brief Add an openshot::Clip to the timeline /// @param clip Add an openshot::Clip to the timeline. A clip can contain any type of Reader. void AddClip(Clip* clip); diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp index cffd995d..874674c0 100644 --- a/src/CacheBase.cpp +++ b/src/CacheBase.cpp @@ -42,6 +42,9 @@ CacheBase::CacheBase(int64_t max_bytes) : max_bytes(max_bytes) { cacheCriticalSection = new CriticalSection(); }; +CacheBase::~CacheBase() { +}; + // Set maximum bytes to a different amount based on a ReaderInfo struct void CacheBase::SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels) { @@ -69,4 +72,4 @@ void CacheBase::SetJsonValue(Json::Value root) { // Set data from Json (if key is found) if (!root["max_bytes"].isNull()) max_bytes = atoll(root["max_bytes"].asString().c_str()); -} \ No newline at end of file +} diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp index 80cad87d..b2926244 100644 --- a/src/ClipBase.cpp +++ b/src/ClipBase.cpp @@ -29,6 +29,9 @@ using namespace openshot; +ClipBase::~ClipBase() { +} + // Generate Json::JsonValue for this object Json::Value ClipBase::JsonValue() { @@ -108,4 +111,4 @@ Json::Value ClipBase::add_property_choice_json(string name, int value, int selec // return JsonValue return new_choice; -} \ No newline at end of file +} diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index acd3b55f..0b67da4e 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -576,6 +576,12 @@ void FFmpegReader::Close() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::Close", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + if (packet) { + // Remove previous packet before getting next one + RemoveAVPacket(packet); + packet = NULL; + } + // Close the codec if (info.has_video) { avcodec_flush_buffers(pCodecCtx); @@ -624,6 +630,8 @@ void FFmpegReader::Close() { seek_video_frame_found = 0; current_video_frame = 0; has_missing_frames = false; + + last_video_frame.reset(); } } @@ -926,7 +934,9 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) { // down processing considerably, but might be more stable on some systems. #pragma omp taskwait } - } + } else { + RemoveAVFrame(pFrame); + } } // Audio packet @@ -1063,7 +1073,7 @@ bool FFmpegReader::GetAVFrame() { { next_frame2 = next_frame; } - pFrame = new AVFrame(); + pFrame = AV_ALLOCATE_FRAME(); while (ret >= 0) { ret = avcodec_receive_frame(pCodecCtx, next_frame2); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { @@ -1206,6 +1216,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) { int width = info.width; int64_t video_length = info.video_length; AVFrame *my_frame = pFrame; + pFrame = NULL; // Add video frame to list of processing video frames const GenericScopedLock lock(processingCriticalSection); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 072ac6d7..ddcd4e16 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -884,9 +884,8 @@ void FFmpegWriter::flush_encoders() { } // Close the video codec -void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { - AV_FREE_CONTEXT(video_codec); - video_codec = NULL; +void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) +{ #if IS_FFMPEG_3_2 // #if defined(__linux__) if (hw_en_on && hw_en_supported) { @@ -900,10 +899,8 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { } // Close the audio codec -void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) { - AV_FREE_CONTEXT(audio_codec); - audio_codec = NULL; - +void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) +{ // Clear buffers delete[] samples; delete[] audio_outbuf; @@ -942,12 +939,6 @@ void FFmpegWriter::Close() { if (image_rescalers.size() > 0) RemoveScalers(); - // Free the streams - for (int i = 0; i < oc->nb_streams; i++) { - av_freep(AV_GET_CODEC_ATTRIBUTES(&oc->streams[i], &oc->streams[i])); - av_freep(&oc->streams[i]); - } - if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ avio_close(oc->pb); @@ -957,8 +948,9 @@ void FFmpegWriter::Close() { write_video_count = 0; write_audio_count = 0; - // Free the context - av_freep(&oc); + // Free the context which frees the streams too + avformat_free_context(oc); + oc = NULL; // Close writer is_open = false; diff --git a/src/Frame.cpp b/src/Frame.cpp index 24b653a9..6ef44d67 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -120,7 +120,7 @@ void Frame::DeepCopy(const Frame& other) wave_image = std::shared_ptr(new QImage(*(other.wave_image))); } -// Descructor +// Destructor Frame::~Frame() { // Clear all pointers image.reset(); diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 73b7bb22..cf6955f2 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -61,6 +61,9 @@ FrameMapper::~FrameMapper() { if (is_open) // Auto Close if not already Close(); + + delete reader; + reader = NULL; } /// Get the current reader diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index a9682bd9..502ddb9a 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -57,6 +57,10 @@ QtImageReader::QtImageReader(string path, bool inspect_reader) : path(path), is_ } } +QtImageReader::~QtImageReader() +{ +} + // Open image file void QtImageReader::Open() { @@ -147,7 +151,7 @@ void QtImageReader::Close() { // Mark as "closed" is_open = false; - + // Delete the image image.reset(); diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index f2607cfd..3b1bb76f 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -63,6 +63,9 @@ ReaderBase::ReaderBase() parent = NULL; } +ReaderBase::~ReaderBase() { +} + // Display file information void ReaderBase::DisplayInfo() { cout << fixed << setprecision(2) << boolalpha; diff --git a/src/Timeline.cpp b/src/Timeline.cpp index b229a3de..e40de562 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -70,6 +70,11 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); } +Timeline::~Timeline() { + delete final_cache; + final_cache = NULL; +} + // Add an openshot::Clip to the timeline void Timeline::AddClip(Clip* clip) { @@ -1481,4 +1486,4 @@ void Timeline::SetMaxSize(int width, int height) { // Set max size Settings::Instance()->MAX_WIDTH = display_ratio_size.width(); Settings::Instance()->MAX_HEIGHT = display_ratio_size.height(); -} \ No newline at end of file +} From d5a29500a52ccef98bf9cc00e0c20f1d4750fb53 Mon Sep 17 00:00:00 2001 From: Chris Kirmse Date: Thu, 9 May 2019 10:51:40 -0700 Subject: [PATCH 143/186] change freeing of frame_mappers allocated in Timeline - each class is now responsible to free whatever it allocates - all tests passed on my machine with ffmpeg 3.2 - Clip is now more careful about freeing a reader if it allocated it as well --- include/Clip.h | 5 ++++- include/DummyReader.h | 2 ++ include/Timeline.h | 2 ++ src/Clip.cpp | 19 ++++++++----------- src/DummyReader.cpp | 3 +++ src/FrameMapper.cpp | 1 - src/Timeline.cpp | 22 +++++++++++++++++++--- 7 files changed, 38 insertions(+), 16 deletions(-) diff --git a/include/Clip.h b/include/Clip.h index b1869a90..58eacab7 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -112,7 +112,10 @@ namespace openshot { // File Reader object ReaderBase* reader; - bool manage_reader; + + /// If we allocated a reader, we store it here to free it later + /// (reader member variable itself may have been replaced) + ReaderBase* allocated_reader; /// Adjust frame number minimum value int64_t adjust_frame_number_minimum(int64_t frame_number); diff --git a/include/DummyReader.h b/include/DummyReader.h index 559215de..e9bce1b5 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -64,6 +64,8 @@ namespace openshot /// Constructor for DummyReader. DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration); + virtual ~DummyReader(); + /// Close File void Close(); diff --git a/include/Timeline.h b/include/Timeline.h index 97923153..eecafec1 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include "CacheBase.h" @@ -152,6 +153,7 @@ namespace openshot { map open_clips; /// effects; /// allocated_frame_mappers; /// all the frame mappers we allocated and must free /// Process a new layer of video or audio void add_layer(std::shared_ptr new_frame, Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume); diff --git a/src/Clip.cpp b/src/Clip.cpp index 207494e3..2099705d 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -101,9 +101,6 @@ void Clip::init_settings() // Init audio and video overrides has_audio = Keyframe(-1.0); has_video = Keyframe(-1.0); - - // Default pointers - manage_reader = false; } // Init reader's rotation (if any) @@ -131,14 +128,14 @@ void Clip::init_reader_rotation() { } // Default Constructor for a clip -Clip::Clip() : reader(NULL), resampler(NULL), audio_cache(NULL) +Clip::Clip() : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); } // Constructor with reader -Clip::Clip(ReaderBase* new_reader) : reader(new_reader), resampler(NULL), audio_cache(NULL) +Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader(new_reader), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -152,7 +149,7 @@ Clip::Clip(ReaderBase* new_reader) : reader(new_reader), resampler(NULL), audio_ } // Constructor with filepath -Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL) +Clip::Clip(string path) : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -194,7 +191,7 @@ Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL) // Update duration if (reader) { End(reader->info.duration); - manage_reader = true; + allocated_reader = reader; init_reader_rotation(); } } @@ -203,9 +200,9 @@ Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL) Clip::~Clip() { // Delete the reader if clip created it - if (manage_reader && reader) { - delete reader; - reader = NULL; + if (allocated_reader) { + delete allocated_reader; + allocated_reader = NULL; } // Close the resampler @@ -968,7 +965,7 @@ void Clip::SetJsonValue(Json::Value root) { // mark as managed reader and set parent if (reader) { reader->SetClip(this); - manage_reader = true; + allocated_reader = reader; } // Re-Open reader (if needed) diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 8fe039ab..dc77db5b 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -71,6 +71,9 @@ DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, i Close(); } +DummyReader::~DummyReader() { +} + // Open image file void DummyReader::Open() { diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index cf6955f2..ca2038a9 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -62,7 +62,6 @@ FrameMapper::~FrameMapper() { // Auto Close if not already Close(); - delete reader; reader = NULL; } diff --git a/src/Timeline.cpp b/src/Timeline.cpp index e40de562..8692d17f 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -71,8 +71,12 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha } Timeline::~Timeline() { - delete final_cache; - final_cache = NULL; + if (is_open) + // Auto Close if not already + Close(); + + delete final_cache; + final_cache = NULL; } // Add an openshot::Clip to the timeline @@ -128,7 +132,9 @@ void Timeline::apply_mapper_to_clip(Clip* clip) } else { // Create a new FrameMapper to wrap the current reader - clip_reader = (ReaderBase*) new FrameMapper(clip->Reader(), info.fps, PULLDOWN_NONE, info.sample_rate, info.channels, info.channel_layout); + FrameMapper* mapper = new FrameMapper(clip->Reader(), info.fps, PULLDOWN_NONE, info.sample_rate, info.channels, info.channel_layout); + allocated_frame_mappers.insert(mapper); + clip_reader = (ReaderBase*) mapper; } // Update the mapping @@ -642,6 +648,16 @@ void Timeline::Close() update_open_clips(clip, false); } + // Free all allocated frame mappers + set::iterator frame_mapper_itr; + for (frame_mapper_itr=allocated_frame_mappers.begin(); frame_mapper_itr != allocated_frame_mappers.end(); ++frame_mapper_itr) + { + // Get frame mapper object from the iterator + FrameMapper *frame_mapper = (*frame_mapper_itr); + delete frame_mapper; + } + allocated_frame_mappers.clear(); + // Mark timeline as closed is_open = false; From 8ea0af59c60e77ce0ff260a134876ce511fa4c0c Mon Sep 17 00:00:00 2001 From: Chris Kirmse Date: Fri, 10 May 2019 11:39:26 -0700 Subject: [PATCH 144/186] fix allocations to be done the same for ffmpeg < 3.2 - fixes freeing an invalid pointer on old ffmpeg - now all tests pass --- src/FFmpegReader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 0b67da4e..38d59f83 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -1120,11 +1120,13 @@ bool FFmpegReader::GetAVFrame() { #else avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet); + // always allocate pFrame (because we do that in the ffmpeg >= 3.2 as well); it will always be freed later + pFrame = AV_ALLOCATE_FRAME(); + // is frame finished if (frameFinished) { // AVFrames are clobbered on the each call to avcodec_decode_video, so we // must make a copy of the image data before this method is called again. - pFrame = AV_ALLOCATE_FRAME(); avpicture_alloc((AVPicture *) pFrame, pCodecCtx->pix_fmt, info.width, info.height); av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width, info.height); From bd21d1a751b3d1375cae37747e6d193e2e38d17c Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 13 May 2019 16:18:15 -0500 Subject: [PATCH 145/186] Fixing crash on Timeline::Close due to deleted FrameMappers --- src/Timeline.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 8692d17f..fd79364a 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -75,8 +75,20 @@ Timeline::~Timeline() { // Auto Close if not already Close(); - delete final_cache; - final_cache = NULL; + // Free all allocated frame mappers + set::iterator frame_mapper_itr; + for (frame_mapper_itr = allocated_frame_mappers.begin(); frame_mapper_itr != allocated_frame_mappers.end(); ++frame_mapper_itr) { + // Get frame mapper object from the iterator + FrameMapper *frame_mapper = (*frame_mapper_itr); + delete frame_mapper; + } + allocated_frame_mappers.clear(); + + // Remove cache + if (final_cache) { + delete final_cache; + final_cache = NULL; + } } // Add an openshot::Clip to the timeline @@ -648,16 +660,6 @@ void Timeline::Close() update_open_clips(clip, false); } - // Free all allocated frame mappers - set::iterator frame_mapper_itr; - for (frame_mapper_itr=allocated_frame_mappers.begin(); frame_mapper_itr != allocated_frame_mappers.end(); ++frame_mapper_itr) - { - // Get frame mapper object from the iterator - FrameMapper *frame_mapper = (*frame_mapper_itr); - delete frame_mapper; - } - allocated_frame_mappers.clear(); - // Mark timeline as closed is_open = false; From 968e472c73bccac9179a139fa7584a05acf8a95b Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 13 May 2019 17:11:40 -0500 Subject: [PATCH 146/186] Tweak how Timeline manages the cache object (sometimes itself, and sometimes by the user if they call SetCache) --- include/Timeline.h | 6 ++++-- src/Timeline.cpp | 13 ++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/Timeline.h b/include/Timeline.h index eecafec1..11911d40 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -153,7 +153,8 @@ namespace openshot { map open_clips; /// effects; /// allocated_frame_mappers; /// all the frame mappers we allocated and must free + set allocated_frame_mappers; ///< all the frame mappers we allocated and must free + bool managed_cache; ///< Does this timeline instance manage the cache object /// Process a new layer of video or audio void add_layer(std::shared_ptr new_frame, Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume); @@ -241,7 +242,8 @@ namespace openshot { /// Get the cache object used by this reader CacheBase* GetCache() { return final_cache; }; - /// Get the cache object used by this reader + /// Set the cache object used by this reader. You must now manage the lifecycle + /// of this cache object though (Timeline will not delete it for you). void SetCache(CacheBase* new_cache); /// Get an openshot::Frame object for a specific frame number of this timeline. diff --git a/src/Timeline.cpp b/src/Timeline.cpp index fd79364a..91194399 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -31,7 +31,7 @@ using namespace openshot; // Default Constructor for the timeline (which sets the canvas width and height) Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout) : - is_open(false), auto_map_clips(true) + is_open(false), auto_map_clips(true), managed_cache(true) { // Create CrashHandler and Attach (incase of errors) CrashHandler::Instance(); @@ -84,8 +84,8 @@ Timeline::~Timeline() { } allocated_frame_mappers.clear(); - // Remove cache - if (final_cache) { + // Destroy previous cache (if managed by timeline) + if (managed_cache && final_cache) { delete final_cache; final_cache = NULL; } @@ -923,6 +923,13 @@ vector Timeline::find_intersecting_clips(int64_t requested_frame, int num // Get the cache object used by this reader void Timeline::SetCache(CacheBase* new_cache) { + // Destroy previous cache (if managed by timeline) + if (managed_cache && final_cache) { + delete final_cache; + final_cache = NULL; + managed_cache = false; + } + // Set new cache final_cache = new_cache; } From 6335d6f06cfbfa796454eeabd19ac00547432579 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 13 May 2019 22:48:21 -0500 Subject: [PATCH 147/186] Adding debugging messaging to unit test which is failing on Travis CI --- tests/Timeline_Tests.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index 8c81579c..a59907b3 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -185,7 +185,9 @@ TEST(Timeline_Check_Two_Track_Video) TEST(Timeline_Clip_Order) { // Create a timeline + cout << "A" << endl; Timeline t(640, 480, Fraction(30, 1), 44100, 2, LAYOUT_STEREO); + cout << "B" << endl; // Add some clips out of order stringstream path_top; @@ -193,40 +195,51 @@ TEST(Timeline_Clip_Order) Clip clip_top(path_top.str()); clip_top.Layer(2); t.AddClip(&clip_top); + cout << "C" << endl; stringstream path_middle; path_middle << TEST_MEDIA_PATH << "front.png"; Clip clip_middle(path_middle.str()); clip_middle.Layer(0); t.AddClip(&clip_middle); + cout << "D" << endl; stringstream path_bottom; path_bottom << TEST_MEDIA_PATH << "back.png"; Clip clip_bottom(path_bottom.str()); clip_bottom.Layer(1); t.AddClip(&clip_bottom); + cout << "E" << endl; // Open Timeline t.Open(); + cout << "F" << endl; // Loop through Clips and check order (they should have been sorted into the correct order) // Bottom layer to top layer, then by position. list::iterator clip_itr; list clips = t.Clips(); + cout << "G" << endl; int counter = 0; for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr) { + cout << "H" << endl; // Get clip object from the iterator Clip *clip = (*clip_itr); + cout << "I" << endl; + switch (counter) { case 0: + cout << "J" << endl; CHECK_EQUAL(0, clip->Layer()); break; case 1: + cout << "K" << endl; CHECK_EQUAL(1, clip->Layer()); break; case 2: + cout << "L" << endl; CHECK_EQUAL(2, clip->Layer()); break; } @@ -235,6 +248,8 @@ TEST(Timeline_Clip_Order) counter++; } + cout << "M" << endl; + // Add another clip stringstream path_middle1; path_middle1 << TEST_MEDIA_PATH << "interlaced.png"; @@ -243,28 +258,35 @@ TEST(Timeline_Clip_Order) clip_middle1.Position(0.5); t.AddClip(&clip_middle1); + cout << "N" << endl; // Loop through clips again, and re-check order counter = 0; clips = t.Clips(); + cout << "O" << endl; for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr) { // Get clip object from the iterator Clip *clip = (*clip_itr); + cout << "P" << endl; switch (counter) { case 0: + cout << "Q" << endl; CHECK_EQUAL(0, clip->Layer()); break; case 1: + cout << "R" << endl; CHECK_EQUAL(1, clip->Layer()); CHECK_CLOSE(0.0, clip->Position(), 0.0001); break; case 2: + cout << "S" << endl; CHECK_EQUAL(1, clip->Layer()); CHECK_CLOSE(0.5, clip->Position(), 0.0001); break; case 3: + cout << "T" << endl; CHECK_EQUAL(2, clip->Layer()); break; } @@ -273,8 +295,12 @@ TEST(Timeline_Clip_Order) counter++; } + cout << "U" << endl; + // Close reader t.Close(); + + cout << "V" << endl; } From 9ffd6a6f754ac03200aec40b3a20820116f7f72d Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 13 May 2019 23:55:03 -0500 Subject: [PATCH 148/186] Fixing crash when destructing Timeline/Clips/FrameMapper --- include/FrameMapper.h | 3 +++ src/Timeline.cpp | 2 ++ tests/Timeline_Tests.cpp | 27 --------------------------- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 1901cb91..d046af25 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -213,6 +213,9 @@ namespace openshot /// Get the current reader ReaderBase* Reader(); + /// Set the current reader + void Reader(ReaderBase *new_reader) { reader = new_reader; } + /// Resample audio and map channels (if needed) void ResampleMappedAudio(std::shared_ptr frame, int64_t original_frame_number); diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 91194399..2ca24e84 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -80,6 +80,8 @@ Timeline::~Timeline() { for (frame_mapper_itr = allocated_frame_mappers.begin(); frame_mapper_itr != allocated_frame_mappers.end(); ++frame_mapper_itr) { // Get frame mapper object from the iterator FrameMapper *frame_mapper = (*frame_mapper_itr); + frame_mapper->Reader(NULL); + frame_mapper->Close(); delete frame_mapper; } allocated_frame_mappers.clear(); diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index a59907b3..22f33894 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -185,9 +185,7 @@ TEST(Timeline_Check_Two_Track_Video) TEST(Timeline_Clip_Order) { // Create a timeline - cout << "A" << endl; Timeline t(640, 480, Fraction(30, 1), 44100, 2, LAYOUT_STEREO); - cout << "B" << endl; // Add some clips out of order stringstream path_top; @@ -195,51 +193,40 @@ TEST(Timeline_Clip_Order) Clip clip_top(path_top.str()); clip_top.Layer(2); t.AddClip(&clip_top); - cout << "C" << endl; stringstream path_middle; path_middle << TEST_MEDIA_PATH << "front.png"; Clip clip_middle(path_middle.str()); clip_middle.Layer(0); t.AddClip(&clip_middle); - cout << "D" << endl; stringstream path_bottom; path_bottom << TEST_MEDIA_PATH << "back.png"; Clip clip_bottom(path_bottom.str()); clip_bottom.Layer(1); t.AddClip(&clip_bottom); - cout << "E" << endl; // Open Timeline t.Open(); - cout << "F" << endl; // Loop through Clips and check order (they should have been sorted into the correct order) // Bottom layer to top layer, then by position. list::iterator clip_itr; list clips = t.Clips(); - cout << "G" << endl; int counter = 0; for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr) { - cout << "H" << endl; // Get clip object from the iterator Clip *clip = (*clip_itr); - cout << "I" << endl; - switch (counter) { case 0: - cout << "J" << endl; CHECK_EQUAL(0, clip->Layer()); break; case 1: - cout << "K" << endl; CHECK_EQUAL(1, clip->Layer()); break; case 2: - cout << "L" << endl; CHECK_EQUAL(2, clip->Layer()); break; } @@ -248,8 +235,6 @@ TEST(Timeline_Clip_Order) counter++; } - cout << "M" << endl; - // Add another clip stringstream path_middle1; path_middle1 << TEST_MEDIA_PATH << "interlaced.png"; @@ -258,35 +243,27 @@ TEST(Timeline_Clip_Order) clip_middle1.Position(0.5); t.AddClip(&clip_middle1); - cout << "N" << endl; - // Loop through clips again, and re-check order counter = 0; clips = t.Clips(); - cout << "O" << endl; for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr) { // Get clip object from the iterator Clip *clip = (*clip_itr); - cout << "P" << endl; switch (counter) { case 0: - cout << "Q" << endl; CHECK_EQUAL(0, clip->Layer()); break; case 1: - cout << "R" << endl; CHECK_EQUAL(1, clip->Layer()); CHECK_CLOSE(0.0, clip->Position(), 0.0001); break; case 2: - cout << "S" << endl; CHECK_EQUAL(1, clip->Layer()); CHECK_CLOSE(0.5, clip->Position(), 0.0001); break; case 3: - cout << "T" << endl; CHECK_EQUAL(2, clip->Layer()); break; } @@ -295,12 +272,8 @@ TEST(Timeline_Clip_Order) counter++; } - cout << "U" << endl; - // Close reader t.Close(); - - cout << "V" << endl; } From 4a3985e209902f51798758766d1860956343b028 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 14 May 2019 00:20:32 -0500 Subject: [PATCH 149/186] Updating comment --- src/Timeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 2ca24e84..37d3f71c 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -923,7 +923,7 @@ vector Timeline::find_intersecting_clips(int64_t requested_frame, int num return matching_clips; } -// Get the cache object used by this reader +// Set the cache object used by this reader void Timeline::SetCache(CacheBase* new_cache) { // Destroy previous cache (if managed by timeline) if (managed_cache && final_cache) { From fab70dde1ed88c5643672146e45808b43d9fef2a Mon Sep 17 00:00:00 2001 From: Chad Walker Date: Wed, 15 May 2019 10:27:48 -0500 Subject: [PATCH 150/186] plug another small leak --- src/FFmpegReader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 38d59f83..e8f135ce 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -1038,6 +1038,8 @@ int FFmpegReader::GetNextPacket() { // Update current packet pointer packet = next_packet; } + else + delete next_packet; } // Return if packet was found (or error number) return found_packet; From 25e51d815efa3f30b337fd79bdd831ade6a88033 Mon Sep 17 00:00:00 2001 From: Chris Kirmse Date: Thu, 30 May 2019 09:40:18 -0700 Subject: [PATCH 151/186] free cache in FrameMapper::Close() - this hugely reduces the memory used by rendering a timeline with a lot of clips - could be related to issue #239 --- src/FrameMapper.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index ca2038a9..113171a2 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -651,6 +651,16 @@ void FrameMapper::Close() // Close internal reader reader->Close(); + // Clear the fields & frames lists + fields.clear(); + frames.clear(); + + // Mark as dirty + is_dirty = true; + + // Clear cache + final_cache.Clear(); + // Deallocate resample buffer if (avr) { SWR_CLOSE(avr); From 13e74b147abe530e0373c836bcadaa4cf58fad84 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 31 May 2019 19:02:28 -0500 Subject: [PATCH 152/186] Adding new CheckPixel method to validate a specific pixel color --- include/Frame.h | 3 +++ src/Frame.cpp | 22 ++++++++++++++++++++++ tests/FFmpegReader_Tests.cpp | 8 ++++++++ 3 files changed, 33 insertions(+) diff --git a/include/Frame.h b/include/Frame.h index 56a2a3ec..72822188 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -249,6 +249,9 @@ namespace openshot /// Get pixel data (for only a single scan-line) const unsigned char* GetPixels(int row); + /// Check a specific pixel color value (returns True/False) + bool CheckPixel(int row, int col, int red, int green, int blue, int alpha); + /// Get height of image int GetHeight(); diff --git a/src/Frame.cpp b/src/Frame.cpp index 6ef44d67..27bf5f71 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -480,6 +480,28 @@ const unsigned char* Frame::GetPixels(int row) return image->scanLine(row); } +// Check a specific pixel color value (returns True/False) +bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha) { + int col_pos = col * 4; // Find column array position + if (!image || row < 0 || row >= (height - 1) || + col_pos < 0 || col_pos >= (width - 1) ) { + // invalid row / col + return false; + } + // Check pixel color + const unsigned char* pixels = GetPixels(row); + if (pixels[col_pos + 0] == red && + pixels[col_pos + 1] == green && + pixels[col_pos + 2] == blue && + pixels[col_pos + 3] == alpha) { + // Pixel color matches successfully + return true; + } else { + // Pixel color does not match + return false; + } +} + // Set Pixel Aspect Ratio void Frame::SetPixelRatio(int num, int den) { diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 53563cac..454420a4 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -100,6 +100,10 @@ TEST(FFmpegReader_Check_Video_File) CHECK_EQUAL(0, (int)pixels[pixel_index + 2]); CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + // Check pixel function + CHECK_EQUAL(true, f->CheckPixel(10, 112, 21, 191, 0, 255)); + CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0)); + // Get frame 1 f = r.GetFrame(2); @@ -113,6 +117,10 @@ TEST(FFmpegReader_Check_Video_File) CHECK_EQUAL(188, (int)pixels[pixel_index + 2]); CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + // Check pixel function + CHECK_EQUAL(true, f->CheckPixel(10, 112, 0, 96, 188, 255)); + CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0)); + // Close reader r.Close(); } From 855fd85de2b3d24f04fcb62ebdc4cf3f2e1794bc Mon Sep 17 00:00:00 2001 From: Jeff Shillitto Date: Fri, 10 May 2019 13:23:25 +1000 Subject: [PATCH 153/186] Fix path to Settings.h --- include/OpenMPUtilities.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index 7c198a76..4dd02b59 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -32,7 +32,7 @@ #include #include -#include "../include/Settings.h" +#include "Settings.h" using namespace std; using namespace openshot; From e1b474e812c0be721f3f6784205a722225538620 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Mon, 3 Jun 2019 11:44:59 -0700 Subject: [PATCH 154/186] Silence deprecated warnings in ffmpeg 3.x --- src/FFmpegWriter.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 072ac6d7..64618ce5 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -992,7 +992,14 @@ AVStream *FFmpegWriter::add_audio_stream() { throw InvalidCodec("A valid audio codec could not be found for this file.", path); // Create a new audio stream +#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) +_Pragma ("GCC diagnostic push") +_Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#endif AV_FORMAT_NEW_STREAM(oc, audio_codec, codec, st) +#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) +_Pragma ("GCC diagnostic pop") +#endif c->codec_id = codec->id; #if LIBAVFORMAT_VERSION_MAJOR >= 53 @@ -1075,7 +1082,14 @@ AVStream *FFmpegWriter::add_video_stream() { throw InvalidCodec("A valid video codec could not be found for this file.", path); // Create a new video stream +#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) +_Pragma ("GCC diagnostic push") +_Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#endif AV_FORMAT_NEW_STREAM(oc, video_codec, codec, st) +#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) +_Pragma ("GCC diagnostic pop") +#endif c->codec_id = codec->id; #if LIBAVFORMAT_VERSION_MAJOR >= 53 From 2be5e5e16845cdcf2f80383b1329808558e98c87 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 4 Jun 2019 13:42:46 -0500 Subject: [PATCH 155/186] Fixing crash on certain hardware accelerator modes (specifically decoder 2, device 0) --- src/FFmpegReader.cpp | 4 +--- src/examples/Example.cpp | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index e8f135ce..6aa0938e 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -934,9 +934,7 @@ std::shared_ptr FFmpegReader::ReadStream(int64_t requested_frame) { // down processing considerably, but might be more stable on some systems. #pragma omp taskwait } - } else { - RemoveAVFrame(pFrame); - } + } } // Audio packet diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 80339684..1e19f4d9 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -38,7 +38,7 @@ int main(int argc, char* argv[]) { Settings *s = Settings::Instance(); s->HARDWARE_DECODER = 2; // 1 VA-API, 2 NVDEC - s->HW_DE_DEVICE_SET = 1; + s->HW_DE_DEVICE_SET = 0; FFmpegReader r9("/home/jonathan/Videos/sintel_trailer-720p.mp4"); r9.Open(); From 438b2c333e1366e206957b18baef6e17d73f4a38 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 8 Jun 2019 12:21:56 -0500 Subject: [PATCH 156/186] Update Frame.cpp --- src/Frame.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Frame.cpp b/src/Frame.cpp index 27bf5f71..cacd91d9 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -481,7 +481,7 @@ const unsigned char* Frame::GetPixels(int row) } // Check a specific pixel color value (returns True/False) -bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha) { +bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha, int threshold) { int col_pos = col * 4; // Find column array position if (!image || row < 0 || row >= (height - 1) || col_pos < 0 || col_pos >= (width - 1) ) { @@ -490,10 +490,10 @@ bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha } // Check pixel color const unsigned char* pixels = GetPixels(row); - if (pixels[col_pos + 0] == red && - pixels[col_pos + 1] == green && - pixels[col_pos + 2] == blue && - pixels[col_pos + 3] == alpha) { + if (pixels[col_pos + 0] >= (red - threshold) && pixels[col_pos + 0] <= (red + threshold) && + pixels[col_pos + 0] >= (green - threshold) && pixels[col_pos + 0] <= (green + threshold) && + pixels[col_pos + 0] >= (blue - threshold) && pixels[col_pos + 0] <= (blue + threshold) && + pixels[col_pos + 0] >= (alpha - threshold) && pixels[col_pos + 0] <= (alpha + threshold)) { // Pixel color matches successfully return true; } else { From 2b308c6d5974a6cd643f2414b1f5b41285d831d2 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 8 Jun 2019 12:23:26 -0500 Subject: [PATCH 157/186] Update Frame.h --- include/Frame.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Frame.h b/include/Frame.h index 72822188..6b682edb 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -250,7 +250,7 @@ namespace openshot const unsigned char* GetPixels(int row); /// Check a specific pixel color value (returns True/False) - bool CheckPixel(int row, int col, int red, int green, int blue, int alpha); + bool CheckPixel(int row, int col, int red, int green, int blue, int alpha, int threshold); /// Get height of image int GetHeight(); From 238e2d16d8a5a45716297415892dac50f2824761 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 8 Jun 2019 12:24:49 -0500 Subject: [PATCH 158/186] Update FFmpegReader_Tests.cpp --- tests/FFmpegReader_Tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 454420a4..72f5462d 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -101,8 +101,8 @@ TEST(FFmpegReader_Check_Video_File) CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); // Check pixel function - CHECK_EQUAL(true, f->CheckPixel(10, 112, 21, 191, 0, 255)); - CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0)); + CHECK_EQUAL(true, f->CheckPixel(10, 112, 21, 191, 0, 255, 5)); + CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0, 5)); // Get frame 1 f = r.GetFrame(2); From 3f926f45df8f7c2c30c0872346749beb47bf37f9 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 8 Jun 2019 12:45:13 -0500 Subject: [PATCH 159/186] Update FFmpegReader_Tests.cpp --- tests/FFmpegReader_Tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 72f5462d..462a77c3 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -118,8 +118,8 @@ TEST(FFmpegReader_Check_Video_File) CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); // Check pixel function - CHECK_EQUAL(true, f->CheckPixel(10, 112, 0, 96, 188, 255)); - CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0)); + CHECK_EQUAL(true, f->CheckPixel(10, 112, 0, 96, 188, 255, 5)); + CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0, 5)); // Close reader r.Close(); From 722d672f5838fc6799aa5faec0cc9da821750691 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 8 Jun 2019 12:52:35 -0500 Subject: [PATCH 160/186] Update Frame.cpp --- src/Frame.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Frame.cpp b/src/Frame.cpp index cacd91d9..aa7c0d87 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -491,9 +491,9 @@ bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha // Check pixel color const unsigned char* pixels = GetPixels(row); if (pixels[col_pos + 0] >= (red - threshold) && pixels[col_pos + 0] <= (red + threshold) && - pixels[col_pos + 0] >= (green - threshold) && pixels[col_pos + 0] <= (green + threshold) && - pixels[col_pos + 0] >= (blue - threshold) && pixels[col_pos + 0] <= (blue + threshold) && - pixels[col_pos + 0] >= (alpha - threshold) && pixels[col_pos + 0] <= (alpha + threshold)) { + pixels[col_pos + 1] >= (green - threshold) && pixels[col_pos + 1] <= (green + threshold) && + pixels[col_pos + 2] >= (blue - threshold) && pixels[col_pos + 2] <= (blue + threshold) && + pixels[col_pos + 3] >= (alpha - threshold) && pixels[col_pos + 3] <= (alpha + threshold)) { // Pixel color matches successfully return true; } else { From 0327c2ab5c126d07b07f7a321689d7be1d9aeb7c Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 9 Jun 2019 08:31:04 -0400 Subject: [PATCH 161/186] Remove license block from documentation comment --- include/AudioBufferSource.h | 5 ++++- include/AudioDeviceInfo.h | 5 ++++- include/AudioReaderSource.h | 5 ++++- include/AudioResampler.h | 5 ++++- include/CacheBase.h | 5 ++++- include/CacheDisk.h | 5 ++++- include/CacheMemory.h | 5 ++++- include/ChannelLayouts.h | 5 ++++- include/ChunkReader.h | 5 ++++- include/ChunkWriter.h | 5 ++++- include/Clip.h | 5 ++++- include/ClipBase.h | 5 ++++- include/Color.h | 5 ++++- include/Coordinate.h | 5 ++++- include/CrashHandler.h | 5 ++++- include/DecklinkInput.h | 5 ++++- include/DecklinkOutput.h | 5 ++++- include/DecklinkReader.h | 5 ++++- include/DecklinkWriter.h | 5 ++++- include/DummyReader.h | 5 ++++- include/EffectBase.h | 5 ++++- include/EffectInfo.h | 5 ++++- include/Effects.h | 5 ++++- include/Enums.h | 5 ++++- include/Exceptions.h | 5 ++++- include/FFmpegReader.h | 5 ++++- include/FFmpegUtilities.h | 5 ++++- include/FFmpegWriter.h | 5 ++++- include/Fraction.h | 5 ++++- include/Frame.h | 5 ++++- include/FrameMapper.h | 5 ++++- include/ImageReader.h | 5 ++++- include/ImageWriter.h | 5 ++++- include/Json.h | 5 ++++- include/KeyFrame.h | 5 ++++- include/OpenMPUtilities.h | 5 ++++- include/OpenShot.h | 1 + include/PlayerBase.h | 5 ++++- include/Point.h | 5 ++++- include/Profiles.h | 5 ++++- include/Qt/AudioPlaybackThread.h | 5 ++++- include/Qt/PlayerDemo.h | 5 ++++- include/Qt/PlayerPrivate.h | 5 ++++- include/Qt/VideoCacheThread.h | 5 ++++- include/Qt/VideoPlaybackThread.h | 5 ++++- include/Qt/VideoRenderWidget.h | 5 ++++- include/Qt/VideoRenderer.h | 5 ++++- include/QtImageReader.h | 5 ++++- include/QtPlayer.h | 5 ++++- include/ReaderBase.h | 5 ++++- include/RendererBase.h | 5 ++++- include/Settings.h | 5 ++++- include/Tests.h | 5 ++++- include/TextReader.h | 5 ++++- include/Timeline.h | 5 ++++- include/Version.h | 5 ++++- include/WriterBase.h | 5 ++++- include/ZmqLogger.h | 5 ++++- include/effects/Bars.h | 5 ++++- include/effects/Blur.h | 5 ++++- include/effects/Brightness.h | 5 ++++- include/effects/ChromaKey.h | 5 ++++- include/effects/ColorShift.h | 5 ++++- include/effects/Crop.h | 5 ++++- include/effects/Deinterlace.h | 5 ++++- include/effects/Hue.h | 5 ++++- include/effects/Mask.h | 5 ++++- include/effects/Negate.h | 5 ++++- include/effects/Pixelate.h | 5 ++++- include/effects/Saturation.h | 5 ++++- include/effects/Shift.h | 5 ++++- include/effects/Wave.h | 5 ++++- src/AudioBufferSource.cpp | 5 ++++- src/AudioReaderSource.cpp | 5 ++++- src/AudioResampler.cpp | 5 ++++- src/CacheBase.cpp | 5 ++++- src/CacheDisk.cpp | 5 ++++- src/CacheMemory.cpp | 5 ++++- src/ChunkReader.cpp | 5 ++++- src/ChunkWriter.cpp | 5 ++++- src/Clip.cpp | 5 ++++- src/ClipBase.cpp | 5 ++++- src/Color.cpp | 5 ++++- src/Coordinate.cpp | 5 ++++- src/CrashHandler.cpp | 5 ++++- src/DecklinkInput.cpp | 5 ++++- src/DecklinkOutput.cpp | 5 ++++- src/DecklinkReader.cpp | 5 ++++- src/DecklinkWriter.cpp | 5 ++++- src/DummyReader.cpp | 5 ++++- src/EffectBase.cpp | 5 ++++- src/EffectInfo.cpp | 5 ++++- src/FFmpegReader.cpp | 5 ++++- src/FFmpegWriter.cpp | 5 ++++- src/Fraction.cpp | 5 ++++- src/Frame.cpp | 5 ++++- src/FrameMapper.cpp | 5 ++++- src/ImageReader.cpp | 5 ++++- src/ImageWriter.cpp | 5 ++++- src/KeyFrame.cpp | 5 ++++- src/PlayerBase.cpp | 5 ++++- src/Point.cpp | 5 ++++- src/Profiles.cpp | 5 ++++- src/Qt/AudioPlaybackThread.cpp | 5 ++++- src/Qt/PlayerDemo.cpp | 5 ++++- src/Qt/PlayerPrivate.cpp | 5 ++++- src/Qt/VideoCacheThread.cpp | 5 ++++- src/Qt/VideoPlaybackThread.cpp | 5 ++++- src/Qt/VideoRenderWidget.cpp | 5 ++++- src/Qt/VideoRenderer.cpp | 5 ++++- src/Qt/demo/main.cpp | 5 ++++- src/QtImageReader.cpp | 5 ++++- src/QtPlayer.cpp | 5 ++++- src/ReaderBase.cpp | 5 ++++- src/RendererBase.cpp | 5 ++++- src/Settings.cpp | 5 ++++- src/TextReader.cpp | 5 ++++- src/Timeline.cpp | 5 ++++- src/WriterBase.cpp | 5 ++++- src/ZmqLogger.cpp | 5 ++++- src/effects/Bars.cpp | 5 ++++- src/effects/Blur.cpp | 5 ++++- src/effects/Brightness.cpp | 5 ++++- src/effects/ChromaKey.cpp | 5 ++++- src/effects/ColorShift.cpp | 5 ++++- src/effects/Crop.cpp | 5 ++++- src/effects/Deinterlace.cpp | 5 ++++- src/effects/Hue.cpp | 5 ++++- src/effects/Mask.cpp | 5 ++++- src/effects/Negate.cpp | 5 ++++- src/effects/Pixelate.cpp | 5 ++++- src/effects/Saturation.cpp | 5 ++++- src/effects/Shift.cpp | 5 ++++- src/effects/Wave.cpp | 5 ++++- src/examples/Example.cpp | 5 ++++- src/examples/ExampleBlackmagic.cpp | 5 ++++- tests/Cache_Tests.cpp | 5 ++++- tests/Clip_Tests.cpp | 5 ++++- tests/Color_Tests.cpp | 5 ++++- tests/Coordinate_Tests.cpp | 5 ++++- tests/FFmpegReader_Tests.cpp | 5 ++++- tests/FFmpegWriter_Tests.cpp | 5 ++++- tests/Fraction_Tests.cpp | 5 ++++- tests/FrameMapper_Tests.cpp | 5 ++++- tests/ImageWriter_Tests.cpp | 5 ++++- tests/KeyFrame_Tests.cpp | 5 ++++- tests/Point_Tests.cpp | 5 ++++- tests/ReaderBase_Tests.cpp | 5 ++++- tests/Settings_Tests.cpp | 5 ++++- tests/Timeline_Tests.cpp | 5 ++++- tests/tests.cpp | 5 ++++- 151 files changed, 601 insertions(+), 150 deletions(-) diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h index b1571c8d..0b72aa5d 100644 --- a/include/AudioBufferSource.h +++ b/include/AudioBufferSource.h @@ -3,7 +3,10 @@ * @brief Header file for AudioBufferSource class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/AudioDeviceInfo.h b/include/AudioDeviceInfo.h index 29a89139..f58c1562 100644 --- a/include/AudioDeviceInfo.h +++ b/include/AudioDeviceInfo.h @@ -3,7 +3,10 @@ * @brief Header file for Audio Device Info struct * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index 76c3dc7d..a60f940e 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -3,7 +3,10 @@ * @brief Header file for AudioReaderSource class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/AudioResampler.h b/include/AudioResampler.h index b81bfc3e..16d35906 100644 --- a/include/AudioResampler.h +++ b/include/AudioResampler.h @@ -3,7 +3,10 @@ * @brief Header file for AudioResampler class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/CacheBase.h b/include/CacheBase.h index c764b2d9..d8bcf805 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -3,7 +3,10 @@ * @brief Header file for CacheBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/CacheDisk.h b/include/CacheDisk.h index adecda9a..03935dcb 100644 --- a/include/CacheDisk.h +++ b/include/CacheDisk.h @@ -3,7 +3,10 @@ * @brief Header file for CacheDisk class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/CacheMemory.h b/include/CacheMemory.h index 29187799..03db05d1 100644 --- a/include/CacheMemory.h +++ b/include/CacheMemory.h @@ -3,7 +3,10 @@ * @brief Header file for CacheMemory class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ChannelLayouts.h b/include/ChannelLayouts.h index 657d2757..4c12822f 100644 --- a/include/ChannelLayouts.h +++ b/include/ChannelLayouts.h @@ -3,7 +3,10 @@ * @brief Header file for ChannelLayout class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ChunkReader.h b/include/ChunkReader.h index b780602b..022dfb77 100644 --- a/include/ChunkReader.h +++ b/include/ChunkReader.h @@ -3,7 +3,10 @@ * @brief Header file for ChunkReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ChunkWriter.h b/include/ChunkWriter.h index 2cdef4fe..2ecdf06e 100644 --- a/include/ChunkWriter.h +++ b/include/ChunkWriter.h @@ -3,7 +3,10 @@ * @brief Header file for ChunkWriter class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Clip.h b/include/Clip.h index 58eacab7..9f10148f 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -3,7 +3,10 @@ * @brief Header file for Clip class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ClipBase.h b/include/ClipBase.h index 1c5534fc..97d60ef6 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -3,7 +3,10 @@ * @brief Header file for ClipBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Color.h b/include/Color.h index a0edd602..8e9d152f 100644 --- a/include/Color.h +++ b/include/Color.h @@ -3,7 +3,10 @@ * @brief Header file for Color class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Coordinate.h b/include/Coordinate.h index bf561084..40e4bb63 100644 --- a/include/Coordinate.h +++ b/include/Coordinate.h @@ -3,7 +3,10 @@ * @brief Header file for Coordinate class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/CrashHandler.h b/include/CrashHandler.h index 12c79a86..1c6ed187 100644 --- a/include/CrashHandler.h +++ b/include/CrashHandler.h @@ -3,7 +3,10 @@ * @brief Header file for CrashHandler class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/DecklinkInput.h b/include/DecklinkInput.h index cfd5b6b1..ebac2baf 100644 --- a/include/DecklinkInput.h +++ b/include/DecklinkInput.h @@ -3,7 +3,10 @@ * @brief Header file for DecklinkInput class * @author Jonathan Thomas , Blackmagic Design * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2009 Blackmagic Design * diff --git a/include/DecklinkOutput.h b/include/DecklinkOutput.h index ddb6e9bc..f653b8dd 100644 --- a/include/DecklinkOutput.h +++ b/include/DecklinkOutput.h @@ -3,7 +3,10 @@ * @brief Header file for DecklinkOutput class * @author Jonathan Thomas , Blackmagic Design * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2009 Blackmagic Design * diff --git a/include/DecklinkReader.h b/include/DecklinkReader.h index 3ce9273f..29a8fdcb 100644 --- a/include/DecklinkReader.h +++ b/include/DecklinkReader.h @@ -3,7 +3,10 @@ * @brief Header file for DecklinkReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/DecklinkWriter.h b/include/DecklinkWriter.h index 00ac8b3e..3a65f0c1 100644 --- a/include/DecklinkWriter.h +++ b/include/DecklinkWriter.h @@ -3,7 +3,10 @@ * @brief Header file for DecklinkWriter class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/DummyReader.h b/include/DummyReader.h index e9bce1b5..692c7589 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -3,7 +3,10 @@ * @brief Header file for DummyReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/EffectBase.h b/include/EffectBase.h index d38e3f45..20cd8edc 100644 --- a/include/EffectBase.h +++ b/include/EffectBase.h @@ -3,7 +3,10 @@ * @brief Header file for EffectBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/EffectInfo.h b/include/EffectInfo.h index 999c9b6a..59b7d234 100644 --- a/include/EffectInfo.h +++ b/include/EffectInfo.h @@ -3,7 +3,10 @@ * @brief Header file for the EffectInfo class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Effects.h b/include/Effects.h index 224c48be..7297ba07 100644 --- a/include/Effects.h +++ b/include/Effects.h @@ -6,7 +6,10 @@ * @brief This header includes all commonly used effects for libopenshot, for ease-of-use. * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Enums.h b/include/Enums.h index fb91f1fa..505c28f6 100644 --- a/include/Enums.h +++ b/include/Enums.h @@ -3,7 +3,10 @@ * @brief Header file for TextReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Exceptions.h b/include/Exceptions.h index fe76d6dc..ae9755ae 100644 --- a/include/Exceptions.h +++ b/include/Exceptions.h @@ -3,7 +3,10 @@ * @brief Header file for all Exception classes * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index 7ef44c50..331ca32a 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -3,7 +3,10 @@ * @brief Header file for FFmpegReader class * @author Jonathan Thomas , Fabrice Bellard * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 7e3e0070..1069bb2c 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -3,7 +3,10 @@ * @brief Header file for FFmpegUtilities * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 35dd1ed9..e4ebe176 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -3,7 +3,10 @@ * @brief Header file for FFmpegWriter class * @author Jonathan Thomas , Fabrice Bellard * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of diff --git a/include/Fraction.h b/include/Fraction.h index 7f5e5881..178cca41 100644 --- a/include/Fraction.h +++ b/include/Fraction.h @@ -3,7 +3,10 @@ * @brief Header file for Fraction class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Frame.h b/include/Frame.h index 6b682edb..d34800ff 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -3,7 +3,10 @@ * @brief Header file for Frame class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/FrameMapper.h b/include/FrameMapper.h index d046af25..66020951 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -3,7 +3,10 @@ * @brief Header file for the FrameMapper class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ImageReader.h b/include/ImageReader.h index e698e0c1..2ba2be8d 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -3,7 +3,10 @@ * @brief Header file for ImageReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 25177134..41c460e1 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -3,7 +3,10 @@ * @brief Header file for ImageWriter class * @author Jonathan Thomas , Fabrice Bellard * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of diff --git a/include/Json.h b/include/Json.h index 970034a5..bacd59a1 100644 --- a/include/Json.h +++ b/include/Json.h @@ -3,7 +3,10 @@ * @brief Header file for JSON class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/KeyFrame.h b/include/KeyFrame.h index bab87f7c..1aca9cc0 100644 --- a/include/KeyFrame.h +++ b/include/KeyFrame.h @@ -3,7 +3,10 @@ * @brief Header file for the Keyframe class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index 7c198a76..dcde3c32 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -3,7 +3,10 @@ * @brief Header file for OpenMPUtilities (set some common macros) * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/OpenShot.h b/include/OpenShot.h index 207f4b42..d7c62af6 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -71,6 +71,7 @@ * ### Want to Learn More? ### * To continue learning about libopenshot, take a look at the full list of classes available. * + * \anchor License * ### License & Copyright ### * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/PlayerBase.h b/include/PlayerBase.h index ecc222a8..d6ff64f5 100644 --- a/include/PlayerBase.h +++ b/include/PlayerBase.h @@ -3,7 +3,10 @@ * @brief Header file for PlayerBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Point.h b/include/Point.h index 139aa64d..8eabf7c8 100644 --- a/include/Point.h +++ b/include/Point.h @@ -3,7 +3,10 @@ * @brief Header file for Point class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Profiles.h b/include/Profiles.h index fa279d57..f7621551 100644 --- a/include/Profiles.h +++ b/include/Profiles.h @@ -3,7 +3,10 @@ * @brief Header file for Profile class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index be26c4e8..eaf3b73c 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/PlayerDemo.h b/include/Qt/PlayerDemo.h index c02f863c..3749ce4c 100644 --- a/include/Qt/PlayerDemo.h +++ b/include/Qt/PlayerDemo.h @@ -3,7 +3,10 @@ * @brief Header file for demo application for QtPlayer class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/PlayerPrivate.h b/include/Qt/PlayerPrivate.h index f626fb99..4745018e 100644 --- a/include/Qt/PlayerPrivate.h +++ b/include/Qt/PlayerPrivate.h @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/VideoCacheThread.h b/include/Qt/VideoCacheThread.h index 4afb7ee5..db932263 100644 --- a/include/Qt/VideoCacheThread.h +++ b/include/Qt/VideoCacheThread.h @@ -3,7 +3,10 @@ * @brief Source file for VideoCacheThread class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/VideoPlaybackThread.h b/include/Qt/VideoPlaybackThread.h index 90dc3681..363c5d1d 100644 --- a/include/Qt/VideoPlaybackThread.h +++ b/include/Qt/VideoPlaybackThread.h @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/VideoRenderWidget.h b/include/Qt/VideoRenderWidget.h index 19675cc8..82bb8320 100644 --- a/include/Qt/VideoRenderWidget.h +++ b/include/Qt/VideoRenderWidget.h @@ -3,7 +3,10 @@ * @brief Header file for Video RendererWidget class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Qt/VideoRenderer.h b/include/Qt/VideoRenderer.h index aaf973ca..4b1fcc89 100644 --- a/include/Qt/VideoRenderer.h +++ b/include/Qt/VideoRenderer.h @@ -3,7 +3,10 @@ * @brief Header file for Video Renderer class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/QtImageReader.h b/include/QtImageReader.h index d26c9b79..c7196e6b 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -3,7 +3,10 @@ * @brief Header file for QtImageReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/QtPlayer.h b/include/QtPlayer.h index c9137f5e..aaa12fa0 100644 --- a/include/QtPlayer.h +++ b/include/QtPlayer.h @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ReaderBase.h b/include/ReaderBase.h index efbd5bc7..4f9f724d 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -3,7 +3,10 @@ * @brief Header file for ReaderBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/RendererBase.h b/include/RendererBase.h index c71d664a..787a254f 100644 --- a/include/RendererBase.h +++ b/include/RendererBase.h @@ -3,7 +3,10 @@ * @brief Header file for RendererBase class * @author Duzy Chan * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Settings.h b/include/Settings.h index 89561034..984e3685 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -3,7 +3,10 @@ * @brief Header file for global Settings class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Tests.h b/include/Tests.h index b7d9dbf5..208cfaf1 100644 --- a/include/Tests.h +++ b/include/Tests.h @@ -3,7 +3,10 @@ * @brief Header file for UnitTests * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/TextReader.h b/include/TextReader.h index d7d653d2..447ae08c 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -3,7 +3,10 @@ * @brief Header file for TextReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Timeline.h b/include/Timeline.h index 11911d40..dea81bf2 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -3,7 +3,10 @@ * @brief Header file for Timeline class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/Version.h b/include/Version.h index 6077cde5..be17ca9a 100644 --- a/include/Version.h +++ b/include/Version.h @@ -3,7 +3,10 @@ * @brief Header file that includes the version number of libopenshot * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/WriterBase.h b/include/WriterBase.h index 8f424054..e8caf72f 100644 --- a/include/WriterBase.h +++ b/include/WriterBase.h @@ -3,7 +3,10 @@ * @brief Header file for WriterBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index 8ababac0..ba736382 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -3,7 +3,10 @@ * @brief Header file for ZeroMQ-based Logger class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Bars.h b/include/effects/Bars.h index 27d21725..c9d90325 100644 --- a/include/effects/Bars.h +++ b/include/effects/Bars.h @@ -3,7 +3,10 @@ * @brief Header file for Bars effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Blur.h b/include/effects/Blur.h index 314dabbe..c4a92772 100644 --- a/include/effects/Blur.h +++ b/include/effects/Blur.h @@ -3,7 +3,10 @@ * @brief Header file for Blur effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h index 67ab4c9c..572f2b11 100644 --- a/include/effects/Brightness.h +++ b/include/effects/Brightness.h @@ -3,7 +3,10 @@ * @brief Header file for Brightness class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h index 000dbba4..c08a09f5 100644 --- a/include/effects/ChromaKey.h +++ b/include/effects/ChromaKey.h @@ -3,7 +3,10 @@ * @brief Header file for ChromaKey class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/ColorShift.h b/include/effects/ColorShift.h index 4b3de2bb..b2f2f115 100644 --- a/include/effects/ColorShift.h +++ b/include/effects/ColorShift.h @@ -3,7 +3,10 @@ * @brief Header file for Color Shift effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Crop.h b/include/effects/Crop.h index 7921a78d..da78dbe3 100644 --- a/include/effects/Crop.h +++ b/include/effects/Crop.h @@ -3,7 +3,10 @@ * @brief Header file for Crop effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h index c1fb7227..7614fb37 100644 --- a/include/effects/Deinterlace.h +++ b/include/effects/Deinterlace.h @@ -3,7 +3,10 @@ * @brief Header file for De-interlace class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Hue.h b/include/effects/Hue.h index 4f680047..c023fdef 100644 --- a/include/effects/Hue.h +++ b/include/effects/Hue.h @@ -3,7 +3,10 @@ * @brief Header file for Hue effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Mask.h b/include/effects/Mask.h index ef707f5f..badbaf40 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -3,7 +3,10 @@ * @brief Header file for Mask class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Negate.h b/include/effects/Negate.h index 84621132..1618a427 100644 --- a/include/effects/Negate.h +++ b/include/effects/Negate.h @@ -3,7 +3,10 @@ * @brief Header file for Negate class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Pixelate.h b/include/effects/Pixelate.h index b8ca2998..50f555d6 100644 --- a/include/effects/Pixelate.h +++ b/include/effects/Pixelate.h @@ -3,7 +3,10 @@ * @brief Header file for Pixelate effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h index d49069a6..a7b3806f 100644 --- a/include/effects/Saturation.h +++ b/include/effects/Saturation.h @@ -3,7 +3,10 @@ * @brief Header file for Saturation class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Shift.h b/include/effects/Shift.h index 86ccf7a4..d6f2066b 100644 --- a/include/effects/Shift.h +++ b/include/effects/Shift.h @@ -3,7 +3,10 @@ * @brief Header file for Shift effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/include/effects/Wave.h b/include/effects/Wave.h index 04c1620f..ed28b8a0 100644 --- a/include/effects/Wave.h +++ b/include/effects/Wave.h @@ -3,7 +3,10 @@ * @brief Header file for Wave effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp index 3b00f742..c7eed591 100644 --- a/src/AudioBufferSource.cpp +++ b/src/AudioBufferSource.cpp @@ -3,7 +3,10 @@ * @brief Source file for AudioBufferSource class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index b1bb2cd3..84d0bd0b 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -3,7 +3,10 @@ * @brief Source file for AudioReaderSource class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/AudioResampler.cpp b/src/AudioResampler.cpp index 442a91d9..0b5d2d3c 100644 --- a/src/AudioResampler.cpp +++ b/src/AudioResampler.cpp @@ -3,7 +3,10 @@ * @brief Source file for AudioResampler class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp index 874674c0..44abbdcf 100644 --- a/src/CacheBase.cpp +++ b/src/CacheBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for CacheBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp index 23854f3a..ce14d109 100644 --- a/src/CacheDisk.cpp +++ b/src/CacheDisk.cpp @@ -3,7 +3,10 @@ * @brief Source file for CacheDisk class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/CacheMemory.cpp b/src/CacheMemory.cpp index f830d74e..9536878a 100644 --- a/src/CacheMemory.cpp +++ b/src/CacheMemory.cpp @@ -3,7 +3,10 @@ * @brief Source file for Cache class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp index fe552243..bfd25575 100644 --- a/src/ChunkReader.cpp +++ b/src/ChunkReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for ChunkReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ChunkWriter.cpp b/src/ChunkWriter.cpp index 958fecb7..2734bb1b 100644 --- a/src/ChunkWriter.cpp +++ b/src/ChunkWriter.cpp @@ -3,7 +3,10 @@ * @brief Source file for ChunkWriter class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Clip.cpp b/src/Clip.cpp index 2099705d..2e99106c 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -3,7 +3,10 @@ * @brief Source file for Clip class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp index b2926244..26e7710b 100644 --- a/src/ClipBase.cpp +++ b/src/ClipBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for EffectBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Color.cpp b/src/Color.cpp index df2cf097..dec1571a 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -3,7 +3,10 @@ * @brief Source file for EffectBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp index 60ea90b2..3fd293d6 100644 --- a/src/Coordinate.cpp +++ b/src/Coordinate.cpp @@ -3,7 +3,10 @@ * @brief Source file for Coordinate class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/CrashHandler.cpp b/src/CrashHandler.cpp index e7827d09..24d8975b 100644 --- a/src/CrashHandler.cpp +++ b/src/CrashHandler.cpp @@ -3,7 +3,10 @@ * @brief Source file for CrashHandler class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/DecklinkInput.cpp b/src/DecklinkInput.cpp index 99d13341..5a83931c 100644 --- a/src/DecklinkInput.cpp +++ b/src/DecklinkInput.cpp @@ -3,7 +3,10 @@ * @brief Source file for DecklinkInput class * @author Jonathan Thomas , Blackmagic Design * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2009 Blackmagic Design * diff --git a/src/DecklinkOutput.cpp b/src/DecklinkOutput.cpp index 8606420a..d86fe777 100644 --- a/src/DecklinkOutput.cpp +++ b/src/DecklinkOutput.cpp @@ -3,7 +3,10 @@ * @brief Source file for DecklinkOutput class * @author Jonathan Thomas , Blackmagic Design * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2009 Blackmagic Design * diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp index 1d9b70b9..512389f6 100644 --- a/src/DecklinkReader.cpp +++ b/src/DecklinkReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for DecklinkReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/DecklinkWriter.cpp b/src/DecklinkWriter.cpp index dd0de9c5..25e2db27 100644 --- a/src/DecklinkWriter.cpp +++ b/src/DecklinkWriter.cpp @@ -3,7 +3,10 @@ * @brief Source file for DecklinkWriter class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index dc77db5b..8e7c82c5 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for DummyReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp index c0afded8..6c095402 100644 --- a/src/EffectBase.cpp +++ b/src/EffectBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for EffectBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index f9e4c409..9d094564 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -3,7 +3,10 @@ * @brief Source file for EffectInfo class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 6aa0938e..b6c9dd1e 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for FFmpegReader class * @author Jonathan Thomas , Fabrice Bellard * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index ddcd4e16..e052bc63 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -3,7 +3,10 @@ * @brief Source file for FFmpegWriter class * @author Jonathan Thomas , Fabrice Bellard * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of diff --git a/src/Fraction.cpp b/src/Fraction.cpp index 2d9c449c..ee5a961b 100644 --- a/src/Fraction.cpp +++ b/src/Fraction.cpp @@ -3,7 +3,10 @@ * @brief Source file for Fraction class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Frame.cpp b/src/Frame.cpp index aa7c0d87..d7edc889 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -3,7 +3,10 @@ * @brief Source file for Frame class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 113171a2..2b725615 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -3,7 +3,10 @@ * @brief Source file for the FrameMapper class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index f535666a..0f09631e 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for ImageReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 41626b09..1205a8ee 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -3,7 +3,10 @@ * @brief Source file for ImageWriter class * @author Jonathan Thomas , Fabrice Bellard * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 2b0389de..b82fa2ea 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -3,7 +3,10 @@ * @brief Source file for the Keyframe class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/PlayerBase.cpp b/src/PlayerBase.cpp index 2cfec475..f4686d9f 100644 --- a/src/PlayerBase.cpp +++ b/src/PlayerBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for PlayerBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Point.cpp b/src/Point.cpp index e55e6453..4b73bf6f 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -3,7 +3,10 @@ * @brief Source file for Point class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Profiles.cpp b/src/Profiles.cpp index 390e5765..a39100bc 100644 --- a/src/Profiles.cpp +++ b/src/Profiles.cpp @@ -3,7 +3,10 @@ * @brief Source file for Profile class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index 7bad4649..3a286729 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/PlayerDemo.cpp b/src/Qt/PlayerDemo.cpp index 8c5d267e..55862a96 100644 --- a/src/Qt/PlayerDemo.cpp +++ b/src/Qt/PlayerDemo.cpp @@ -3,7 +3,10 @@ * @brief Source file for Demo QtPlayer application * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/PlayerPrivate.cpp b/src/Qt/PlayerPrivate.cpp index 1839f1eb..2040375e 100644 --- a/src/Qt/PlayerPrivate.cpp +++ b/src/Qt/PlayerPrivate.cpp @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp index 208fcaab..1a90f1c6 100644 --- a/src/Qt/VideoCacheThread.cpp +++ b/src/Qt/VideoCacheThread.cpp @@ -3,7 +3,10 @@ * @brief Source file for VideoCacheThread class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/VideoPlaybackThread.cpp b/src/Qt/VideoPlaybackThread.cpp index cd116162..505a11d8 100644 --- a/src/Qt/VideoPlaybackThread.cpp +++ b/src/Qt/VideoPlaybackThread.cpp @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/VideoRenderWidget.cpp b/src/Qt/VideoRenderWidget.cpp index 8dd6a73c..64b539ff 100644 --- a/src/Qt/VideoRenderWidget.cpp +++ b/src/Qt/VideoRenderWidget.cpp @@ -3,7 +3,10 @@ * @brief Source file for Video RendererWidget class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/VideoRenderer.cpp b/src/Qt/VideoRenderer.cpp index 21e2e07b..70986b03 100644 --- a/src/Qt/VideoRenderer.cpp +++ b/src/Qt/VideoRenderer.cpp @@ -3,7 +3,10 @@ * @brief Source file for VideoRenderer class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Qt/demo/main.cpp b/src/Qt/demo/main.cpp index 795b3c25..9c7e18eb 100644 --- a/src/Qt/demo/main.cpp +++ b/src/Qt/demo/main.cpp @@ -3,7 +3,10 @@ * @brief Demo Qt application to test the QtPlayer class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 502ddb9a..c9fe6b4e 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for QtImageReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp index 3287c19d..08d7df5e 100644 --- a/src/QtPlayer.cpp +++ b/src/QtPlayer.cpp @@ -4,7 +4,10 @@ * @author Duzy Chan * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index 3b1bb76f..1aa39e5a 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for ReaderBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/RendererBase.cpp b/src/RendererBase.cpp index e21d984b..edd1f795 100644 --- a/src/RendererBase.cpp +++ b/src/RendererBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for RendererBase class * @author Duzy Chan * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Settings.cpp b/src/Settings.cpp index 8193ec6b..7c284624 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -3,7 +3,10 @@ * @brief Source file for global Settings class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/TextReader.cpp b/src/TextReader.cpp index 8234aa5d..fd9dcfef 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -3,7 +3,10 @@ * @brief Source file for TextReader class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 37d3f71c..d28b4ff8 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -3,7 +3,10 @@ * @brief Source file for Timeline class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/WriterBase.cpp b/src/WriterBase.cpp index 3697c52a..3a8b5f72 100644 --- a/src/WriterBase.cpp +++ b/src/WriterBase.cpp @@ -3,7 +3,10 @@ * @brief Source file for WriterBase class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/ZmqLogger.cpp b/src/ZmqLogger.cpp index 27da2977..cc38f9a4 100644 --- a/src/ZmqLogger.cpp +++ b/src/ZmqLogger.cpp @@ -3,7 +3,10 @@ * @brief Source file for ZeroMQ-based Logger class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Bars.cpp b/src/effects/Bars.cpp index a4a72c19..cc541cc2 100644 --- a/src/effects/Bars.cpp +++ b/src/effects/Bars.cpp @@ -3,7 +3,10 @@ * @brief Source file for Bars effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Blur.cpp b/src/effects/Blur.cpp index 6eafc2a1..39c70921 100644 --- a/src/effects/Blur.cpp +++ b/src/effects/Blur.cpp @@ -3,7 +3,10 @@ * @brief Source file for Blur effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp index 591bce6a..cac05b14 100644 --- a/src/effects/Brightness.cpp +++ b/src/effects/Brightness.cpp @@ -3,7 +3,10 @@ * @brief Source file for Brightness class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp index 2c3008f2..3329b4df 100644 --- a/src/effects/ChromaKey.cpp +++ b/src/effects/ChromaKey.cpp @@ -3,7 +3,10 @@ * @brief Source file for ChromaKey class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/ColorShift.cpp b/src/effects/ColorShift.cpp index 00300561..2adb88ff 100644 --- a/src/effects/ColorShift.cpp +++ b/src/effects/ColorShift.cpp @@ -3,7 +3,10 @@ * @brief Source file for Color Shift effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Crop.cpp b/src/effects/Crop.cpp index 53953ec2..390d537e 100644 --- a/src/effects/Crop.cpp +++ b/src/effects/Crop.cpp @@ -3,7 +3,10 @@ * @brief Source file for Crop effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp index bf34d13f..fce8e1b1 100644 --- a/src/effects/Deinterlace.cpp +++ b/src/effects/Deinterlace.cpp @@ -3,7 +3,10 @@ * @brief Source file for De-interlace class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Hue.cpp b/src/effects/Hue.cpp index ae401a8b..e6c7e761 100644 --- a/src/effects/Hue.cpp +++ b/src/effects/Hue.cpp @@ -3,7 +3,10 @@ * @brief Source file for Hue effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index f8f34ac6..d0adf8e7 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -3,7 +3,10 @@ * @brief Source file for Mask class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp index 8ff6e0d6..383ded34 100644 --- a/src/effects/Negate.cpp +++ b/src/effects/Negate.cpp @@ -3,7 +3,10 @@ * @brief Source file for Negate class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Pixelate.cpp b/src/effects/Pixelate.cpp index 78030283..3f27f7f8 100644 --- a/src/effects/Pixelate.cpp +++ b/src/effects/Pixelate.cpp @@ -3,7 +3,10 @@ * @brief Source file for Pixelate effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp index ecb3165f..4500ff9b 100644 --- a/src/effects/Saturation.cpp +++ b/src/effects/Saturation.cpp @@ -3,7 +3,10 @@ * @brief Source file for Saturation class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Shift.cpp b/src/effects/Shift.cpp index 80a7b2d7..30aaa5ae 100644 --- a/src/effects/Shift.cpp +++ b/src/effects/Shift.cpp @@ -3,7 +3,10 @@ * @brief Source file for Shift effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/effects/Wave.cpp b/src/effects/Wave.cpp index 0a1c5273..71b75dbd 100644 --- a/src/effects/Wave.cpp +++ b/src/effects/Wave.cpp @@ -3,7 +3,10 @@ * @brief Source file for Wave effect class * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 1e19f4d9..314a5ea2 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -3,7 +3,10 @@ * @brief Source file for Example Executable (example app for libopenshot) * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/src/examples/ExampleBlackmagic.cpp b/src/examples/ExampleBlackmagic.cpp index 0af6c9b4..84bbe809 100644 --- a/src/examples/ExampleBlackmagic.cpp +++ b/src/examples/ExampleBlackmagic.cpp @@ -3,7 +3,10 @@ * @brief Source file for Main_Blackmagic class (live greenscreen example app) * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Cache_Tests.cpp b/tests/Cache_Tests.cpp index 8cf64c40..4f97061f 100644 --- a/tests/Cache_Tests.cpp +++ b/tests/Cache_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Cache * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp index 1134e8ab..c8b23862 100644 --- a/tests/Clip_Tests.cpp +++ b/tests/Clip_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Clip * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Color_Tests.cpp b/tests/Color_Tests.cpp index b1976ea8..e01fe853 100644 --- a/tests/Color_Tests.cpp +++ b/tests/Color_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Color * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Coordinate_Tests.cpp b/tests/Coordinate_Tests.cpp index 0d513027..a871a911 100644 --- a/tests/Coordinate_Tests.cpp +++ b/tests/Coordinate_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Coordinate * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 462a77c3..aff6cc64 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::FFmpegReader * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/FFmpegWriter_Tests.cpp b/tests/FFmpegWriter_Tests.cpp index 73357f21..67882b05 100644 --- a/tests/FFmpegWriter_Tests.cpp +++ b/tests/FFmpegWriter_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::FFmpegWriter * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Fraction_Tests.cpp b/tests/Fraction_Tests.cpp index 89becdef..4fabcf6d 100644 --- a/tests/Fraction_Tests.cpp +++ b/tests/Fraction_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Fraction * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/FrameMapper_Tests.cpp b/tests/FrameMapper_Tests.cpp index 053df31f..6b0042dd 100644 --- a/tests/FrameMapper_Tests.cpp +++ b/tests/FrameMapper_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::FrameMapper * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/ImageWriter_Tests.cpp b/tests/ImageWriter_Tests.cpp index 107ee399..6400f84e 100644 --- a/tests/ImageWriter_Tests.cpp +++ b/tests/ImageWriter_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::ImageWriter * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp index cbd1a0e0..1a16de0d 100644 --- a/tests/KeyFrame_Tests.cpp +++ b/tests/KeyFrame_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Keyframe * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Point_Tests.cpp b/tests/Point_Tests.cpp index 376a69d1..107f661c 100644 --- a/tests/Point_Tests.cpp +++ b/tests/Point_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Point * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp index 70ca90d5..e4a3935b 100644 --- a/tests/ReaderBase_Tests.cpp +++ b/tests/ReaderBase_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::ReaderBase * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index 1b8180c9..5bb020f1 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Color * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index 22f33894..9ad42f2c 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -3,7 +3,10 @@ * @brief Unit tests for openshot::Timeline * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of diff --git a/tests/tests.cpp b/tests/tests.cpp index 2321513d..ca01331c 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -3,7 +3,10 @@ * @brief Source code for Unit test executable (runs all tests and reports successes and failures) * @author Jonathan Thomas * - * @section LICENSE + * @ref License + */ + +/* LICENSE * * Copyright (c) 2008-2014 OpenShot Studios, LLC * . This file is part of From ae96690e074fa8ff7c52fe1eeda727d9d0617b03 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Sun, 9 Jun 2019 08:31:40 -0400 Subject: [PATCH 162/186] Doxyfile.in: Exclude python source --- Doxyfile.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doxyfile.in b/Doxyfile.in index 7cf50631..ba047c6b 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -798,7 +798,9 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = "*/.*" \ "*/.*/*" \ "*/src/Main.cpp*" \ - "*/src/Main_Blackmagic.cpp*" + "*/src/Main_Blackmagic.cpp*" \ + "*/src/bindings/*" \ + "*.py" # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the From be7db1148074aa3a3f7524300310192ab150fe5d Mon Sep 17 00:00:00 2001 From: SuslikV Date: Tue, 11 Jun 2019 10:49:45 +0300 Subject: [PATCH 163/186] Add streamable file format options for mp4, mov Add 2 new multiplexing presets for mp4, mov files: mp4_faststart mp4_fragmented The Preset usage from openshot-qt export.py as follows (example): w.SetOption(openshot.VIDEO_STREAM, "muxing_preset", "mp4_faststart") YouTube suggest to use streamable file formats to process the uploading videos faster (by starting its processing when upload not yet complete) MP4, MOV files export requires additional dictionary keys to be set in this case. --- src/FFmpegWriter.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index ddcd4e16..45ff31b8 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -38,6 +38,9 @@ using namespace openshot; #pragma message "You are compiling only with software encode" #endif +// Multiplexer parameters temporary storage +AVDictionary *mux_dict = NULL; + #if IS_FFMPEG_3_2 int hw_en_on = 1; // Is set in UI int hw_en_supported = 0; // Is set by FFmpegWriter @@ -464,6 +467,17 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) { ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::SetOption (" + (string)name + ")", "stream == VIDEO_STREAM", stream == VIDEO_STREAM, "", -1, "", -1, "", -1, "", -1, "", -1); + // Muxing dictionary is not part of the codec context. + // Just reusing SetOption function to set popular multiplexing presets. + } else if (name == "muxing_preset") { + if (value == "mp4_faststart") { + // 'moov' box to the beginning; only for MOV, MP4 + av_dict_set(&mux_dict, "movflags", "faststart", 0); + } else if (value == "mp4_fragmented") { + // write selfcontained fragmented file, minimum length of the fragment 8 sec; only for MOV, MP4 + av_dict_set(&mux_dict, "movflags", "frag_keyframe", 0); + av_dict_set(&mux_dict, "min_frag_duration", "8000000", 0); + } } else { throw InvalidOptions("The option is not valid for this codec.", path); } @@ -511,17 +525,29 @@ void FFmpegWriter::WriteHeader() { snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", path.c_str()); // Write the stream header, if any - // TODO: add avoptions / parameters instead of NULL // Add general metadata (if any) for (std::map::iterator iter = info.metadata.begin(); iter != info.metadata.end(); ++iter) { av_dict_set(&oc->metadata, iter->first.c_str(), iter->second.c_str(), 0); } - if (avformat_write_header(oc, NULL) != 0) { + // Set multiplexing parameters + AVDictionary *dict = NULL; + + bool is_mp4 = strcmp(oc->oformat->name, "mp4"); + bool is_mov = strcmp(oc->oformat->name, "mov"); + // Set dictionary preset only for MP4 and MOV files + if (is_mp4 || is_mov) + av_dict_copy(&dict, mux_dict, 0); + + if (avformat_write_header(oc, &dict) != 0) { throw InvalidFile("Could not write header to file.", path); }; + // Free multiplexing dictionaries sets + if (dict) av_dict_free(&dict); + if (mux_dict) av_dict_free(&mux_dict); + // Mark as 'written' write_header = true; From f170fdd009465ffea765e58e8d5cebd1d541fdfe Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 11 Jun 2019 06:48:32 -0400 Subject: [PATCH 164/186] Update copyright range to current year --- include/AudioBufferSource.h | 2 +- include/AudioDeviceInfo.h | 2 +- include/AudioReaderSource.h | 2 +- include/AudioResampler.h | 2 +- include/CacheBase.h | 2 +- include/CacheDisk.h | 2 +- include/CacheMemory.h | 2 +- include/ChannelLayouts.h | 2 +- include/ChunkReader.h | 2 +- include/ChunkWriter.h | 2 +- include/Clip.h | 2 +- include/ClipBase.h | 2 +- include/Color.h | 2 +- include/Coordinate.h | 2 +- include/CrashHandler.h | 2 +- include/DecklinkInput.h | 2 +- include/DecklinkOutput.h | 2 +- include/DecklinkReader.h | 2 +- include/DecklinkWriter.h | 2 +- include/DummyReader.h | 2 +- include/EffectBase.h | 2 +- include/EffectInfo.h | 2 +- include/Effects.h | 2 +- include/Enums.h | 2 +- include/Exceptions.h | 2 +- include/FFmpegUtilities.h | 2 +- include/Fraction.h | 2 +- include/Frame.h | 2 +- include/FrameMapper.h | 2 +- include/ImageReader.h | 2 +- include/Json.h | 2 +- include/KeyFrame.h | 2 +- include/OpenMPUtilities.h | 2 +- include/OpenShot.h | 2 +- include/PlayerBase.h | 2 +- include/Point.h | 2 +- include/Profiles.h | 2 +- include/Qt/AudioPlaybackThread.h | 2 +- include/Qt/PlayerDemo.h | 2 +- include/Qt/PlayerPrivate.h | 2 +- include/Qt/VideoCacheThread.h | 2 +- include/Qt/VideoPlaybackThread.h | 2 +- include/Qt/VideoRenderWidget.h | 2 +- include/Qt/VideoRenderer.h | 2 +- include/QtImageReader.h | 2 +- include/QtPlayer.h | 2 +- include/ReaderBase.h | 2 +- include/RendererBase.h | 2 +- include/Settings.h | 2 +- include/Tests.h | 2 +- include/TextReader.h | 2 +- include/Timeline.h | 2 +- include/Version.h | 2 +- include/WriterBase.h | 2 +- include/ZmqLogger.h | 2 +- include/effects/Bars.h | 2 +- include/effects/Blur.h | 2 +- include/effects/Brightness.h | 2 +- include/effects/ChromaKey.h | 2 +- include/effects/ColorShift.h | 2 +- include/effects/Crop.h | 2 +- include/effects/Deinterlace.h | 2 +- include/effects/Hue.h | 2 +- include/effects/Mask.h | 2 +- include/effects/Negate.h | 2 +- include/effects/Pixelate.h | 2 +- include/effects/Saturation.h | 2 +- include/effects/Shift.h | 2 +- include/effects/Wave.h | 2 +- src/AudioBufferSource.cpp | 2 +- src/AudioReaderSource.cpp | 2 +- src/AudioResampler.cpp | 2 +- src/CMakeLists.txt | 2 +- src/CacheBase.cpp | 2 +- src/CacheDisk.cpp | 2 +- src/CacheMemory.cpp | 2 +- src/ChunkReader.cpp | 2 +- src/ChunkWriter.cpp | 2 +- src/Clip.cpp | 2 +- src/ClipBase.cpp | 2 +- src/Color.cpp | 2 +- src/Coordinate.cpp | 2 +- src/CrashHandler.cpp | 2 +- src/DecklinkInput.cpp | 2 +- src/DecklinkOutput.cpp | 2 +- src/DecklinkReader.cpp | 2 +- src/DecklinkWriter.cpp | 2 +- src/DummyReader.cpp | 2 +- src/EffectBase.cpp | 2 +- src/EffectInfo.cpp | 2 +- src/Fraction.cpp | 2 +- src/Frame.cpp | 2 +- src/FrameMapper.cpp | 2 +- src/ImageReader.cpp | 2 +- src/KeyFrame.cpp | 2 +- src/PlayerBase.cpp | 2 +- src/Point.cpp | 2 +- src/Profiles.cpp | 2 +- src/Qt/AudioPlaybackThread.cpp | 2 +- src/Qt/PlayerDemo.cpp | 2 +- src/Qt/PlayerPrivate.cpp | 2 +- src/Qt/VideoCacheThread.cpp | 2 +- src/Qt/VideoPlaybackThread.cpp | 2 +- src/Qt/VideoRenderWidget.cpp | 2 +- src/Qt/VideoRenderer.cpp | 2 +- src/Qt/demo/main.cpp | 2 +- src/QtImageReader.cpp | 2 +- src/QtPlayer.cpp | 2 +- src/ReaderBase.cpp | 2 +- src/RendererBase.cpp | 2 +- src/Settings.cpp | 2 +- src/TextReader.cpp | 2 +- src/Timeline.cpp | 2 +- src/WriterBase.cpp | 2 +- src/ZmqLogger.cpp | 2 +- src/bindings/CMakeLists.txt | 2 +- src/bindings/python/CMakeLists.txt | 2 +- src/bindings/python/openshot.i | 2 +- src/bindings/ruby/CMakeLists.txt | 2 +- src/bindings/ruby/openshot.i | 2 +- src/effects/Bars.cpp | 2 +- src/effects/Blur.cpp | 2 +- src/effects/Brightness.cpp | 2 +- src/effects/ChromaKey.cpp | 2 +- src/effects/ColorShift.cpp | 2 +- src/effects/Crop.cpp | 2 +- src/effects/Deinterlace.cpp | 2 +- src/effects/Hue.cpp | 2 +- src/effects/Mask.cpp | 2 +- src/effects/Negate.cpp | 2 +- src/effects/Pixelate.cpp | 2 +- src/effects/Saturation.cpp | 2 +- src/effects/Shift.cpp | 2 +- src/effects/Wave.cpp | 2 +- src/examples/Example.cpp | 2 +- src/examples/ExampleBlackmagic.cpp | 2 +- tests/CMakeLists.txt | 2 +- tests/Cache_Tests.cpp | 2 +- tests/Clip_Tests.cpp | 2 +- tests/Color_Tests.cpp | 2 +- tests/Coordinate_Tests.cpp | 2 +- tests/FFmpegReader_Tests.cpp | 2 +- tests/FFmpegWriter_Tests.cpp | 2 +- tests/Fraction_Tests.cpp | 2 +- tests/FrameMapper_Tests.cpp | 2 +- tests/ImageWriter_Tests.cpp | 2 +- tests/KeyFrame_Tests.cpp | 2 +- tests/Point_Tests.cpp | 2 +- tests/ReaderBase_Tests.cpp | 2 +- tests/Settings_Tests.cpp | 2 +- tests/Timeline_Tests.cpp | 2 +- tests/tests.cpp | 2 +- 152 files changed, 152 insertions(+), 152 deletions(-) diff --git a/include/AudioBufferSource.h b/include/AudioBufferSource.h index 0b72aa5d..4addb37d 100644 --- a/include/AudioBufferSource.h +++ b/include/AudioBufferSource.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/AudioDeviceInfo.h b/include/AudioDeviceInfo.h index f58c1562..4099430e 100644 --- a/include/AudioDeviceInfo.h +++ b/include/AudioDeviceInfo.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/AudioReaderSource.h b/include/AudioReaderSource.h index a60f940e..679aed61 100644 --- a/include/AudioReaderSource.h +++ b/include/AudioReaderSource.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/AudioResampler.h b/include/AudioResampler.h index 16d35906..85a44b1f 100644 --- a/include/AudioResampler.h +++ b/include/AudioResampler.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/CacheBase.h b/include/CacheBase.h index d8bcf805..af24b153 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/CacheDisk.h b/include/CacheDisk.h index 03935dcb..11a8808c 100644 --- a/include/CacheDisk.h +++ b/include/CacheDisk.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/CacheMemory.h b/include/CacheMemory.h index 03db05d1..eb11f273 100644 --- a/include/CacheMemory.h +++ b/include/CacheMemory.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ChannelLayouts.h b/include/ChannelLayouts.h index 4c12822f..673eeccd 100644 --- a/include/ChannelLayouts.h +++ b/include/ChannelLayouts.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ChunkReader.h b/include/ChunkReader.h index 022dfb77..5b330b70 100644 --- a/include/ChunkReader.h +++ b/include/ChunkReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ChunkWriter.h b/include/ChunkWriter.h index 2ecdf06e..5ac9be4a 100644 --- a/include/ChunkWriter.h +++ b/include/ChunkWriter.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Clip.h b/include/Clip.h index 9f10148f..52be853e 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ClipBase.h b/include/ClipBase.h index 97d60ef6..adbf11ef 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Color.h b/include/Color.h index 8e9d152f..d06bee91 100644 --- a/include/Color.h +++ b/include/Color.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Coordinate.h b/include/Coordinate.h index 40e4bb63..6ab296dc 100644 --- a/include/Coordinate.h +++ b/include/Coordinate.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/CrashHandler.h b/include/CrashHandler.h index 1c6ed187..76d788f2 100644 --- a/include/CrashHandler.h +++ b/include/CrashHandler.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/DecklinkInput.h b/include/DecklinkInput.h index ebac2baf..87207505 100644 --- a/include/DecklinkInput.h +++ b/include/DecklinkInput.h @@ -33,7 +33,7 @@ * DEALINGS IN THE SOFTWARE. * * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/DecklinkOutput.h b/include/DecklinkOutput.h index f653b8dd..ebaa9ab4 100644 --- a/include/DecklinkOutput.h +++ b/include/DecklinkOutput.h @@ -33,7 +33,7 @@ * DEALINGS IN THE SOFTWARE. * * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/DecklinkReader.h b/include/DecklinkReader.h index 29a8fdcb..3dc7e23d 100644 --- a/include/DecklinkReader.h +++ b/include/DecklinkReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/DecklinkWriter.h b/include/DecklinkWriter.h index 3a65f0c1..809890f3 100644 --- a/include/DecklinkWriter.h +++ b/include/DecklinkWriter.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/DummyReader.h b/include/DummyReader.h index 692c7589..adae512f 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/EffectBase.h b/include/EffectBase.h index 20cd8edc..cd39c272 100644 --- a/include/EffectBase.h +++ b/include/EffectBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/EffectInfo.h b/include/EffectInfo.h index 59b7d234..7806f096 100644 --- a/include/EffectInfo.h +++ b/include/EffectInfo.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Effects.h b/include/Effects.h index 7297ba07..746da4c0 100644 --- a/include/Effects.h +++ b/include/Effects.h @@ -11,7 +11,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Enums.h b/include/Enums.h index 505c28f6..387191ea 100644 --- a/include/Enums.h +++ b/include/Enums.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Exceptions.h b/include/Exceptions.h index ae9755ae..0fb2bb1e 100644 --- a/include/Exceptions.h +++ b/include/Exceptions.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 1069bb2c..a6b83015 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Fraction.h b/include/Fraction.h index 178cca41..9ffcda1f 100644 --- a/include/Fraction.h +++ b/include/Fraction.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Frame.h b/include/Frame.h index d34800ff..911e2713 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 66020951..78e8944e 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ImageReader.h b/include/ImageReader.h index 2ba2be8d..25bdc68c 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Json.h b/include/Json.h index bacd59a1..3a10ab74 100644 --- a/include/Json.h +++ b/include/Json.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/KeyFrame.h b/include/KeyFrame.h index 1aca9cc0..14f519a1 100644 --- a/include/KeyFrame.h +++ b/include/KeyFrame.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h index dcde3c32..b78c3742 100644 --- a/include/OpenMPUtilities.h +++ b/include/OpenMPUtilities.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/OpenShot.h b/include/OpenShot.h index d7c62af6..8987f5e5 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -73,7 +73,7 @@ * * \anchor License * ### License & Copyright ### - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/PlayerBase.h b/include/PlayerBase.h index d6ff64f5..ecc8f5f2 100644 --- a/include/PlayerBase.h +++ b/include/PlayerBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Point.h b/include/Point.h index 8eabf7c8..d9a5e33d 100644 --- a/include/Point.h +++ b/include/Point.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Profiles.h b/include/Profiles.h index f7621551..a6e3d22d 100644 --- a/include/Profiles.h +++ b/include/Profiles.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index eaf3b73c..94abf806 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/PlayerDemo.h b/include/Qt/PlayerDemo.h index 3749ce4c..e5d304a4 100644 --- a/include/Qt/PlayerDemo.h +++ b/include/Qt/PlayerDemo.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/PlayerPrivate.h b/include/Qt/PlayerPrivate.h index 4745018e..f846fb2a 100644 --- a/include/Qt/PlayerPrivate.h +++ b/include/Qt/PlayerPrivate.h @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/VideoCacheThread.h b/include/Qt/VideoCacheThread.h index db932263..6fbf6d58 100644 --- a/include/Qt/VideoCacheThread.h +++ b/include/Qt/VideoCacheThread.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/VideoPlaybackThread.h b/include/Qt/VideoPlaybackThread.h index 363c5d1d..753c7778 100644 --- a/include/Qt/VideoPlaybackThread.h +++ b/include/Qt/VideoPlaybackThread.h @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/VideoRenderWidget.h b/include/Qt/VideoRenderWidget.h index 82bb8320..429940e7 100644 --- a/include/Qt/VideoRenderWidget.h +++ b/include/Qt/VideoRenderWidget.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Qt/VideoRenderer.h b/include/Qt/VideoRenderer.h index 4b1fcc89..1bdbfac3 100644 --- a/include/Qt/VideoRenderer.h +++ b/include/Qt/VideoRenderer.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/QtImageReader.h b/include/QtImageReader.h index c7196e6b..a6f70165 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/QtPlayer.h b/include/QtPlayer.h index aaa12fa0..5d0beba6 100644 --- a/include/QtPlayer.h +++ b/include/QtPlayer.h @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ReaderBase.h b/include/ReaderBase.h index 4f9f724d..4579ebb6 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/RendererBase.h b/include/RendererBase.h index 787a254f..2638d336 100644 --- a/include/RendererBase.h +++ b/include/RendererBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Settings.h b/include/Settings.h index 984e3685..11d7f76c 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Tests.h b/include/Tests.h index 208cfaf1..b647cb0e 100644 --- a/include/Tests.h +++ b/include/Tests.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/TextReader.h b/include/TextReader.h index 447ae08c..0444c2d5 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Timeline.h b/include/Timeline.h index dea81bf2..a9ada689 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/Version.h b/include/Version.h index be17ca9a..ec9e94a6 100644 --- a/include/Version.h +++ b/include/Version.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/WriterBase.h b/include/WriterBase.h index e8caf72f..e03263ed 100644 --- a/include/WriterBase.h +++ b/include/WriterBase.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/ZmqLogger.h b/include/ZmqLogger.h index ba736382..96e16213 100644 --- a/include/ZmqLogger.h +++ b/include/ZmqLogger.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Bars.h b/include/effects/Bars.h index c9d90325..eb49a07f 100644 --- a/include/effects/Bars.h +++ b/include/effects/Bars.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Blur.h b/include/effects/Blur.h index c4a92772..cdb1402a 100644 --- a/include/effects/Blur.h +++ b/include/effects/Blur.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h index 572f2b11..cb828442 100644 --- a/include/effects/Brightness.h +++ b/include/effects/Brightness.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h index c08a09f5..eca5cf74 100644 --- a/include/effects/ChromaKey.h +++ b/include/effects/ChromaKey.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/ColorShift.h b/include/effects/ColorShift.h index b2f2f115..ba2326f7 100644 --- a/include/effects/ColorShift.h +++ b/include/effects/ColorShift.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Crop.h b/include/effects/Crop.h index da78dbe3..c79ec83d 100644 --- a/include/effects/Crop.h +++ b/include/effects/Crop.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h index 7614fb37..14b13e21 100644 --- a/include/effects/Deinterlace.h +++ b/include/effects/Deinterlace.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Hue.h b/include/effects/Hue.h index c023fdef..02d8cf9b 100644 --- a/include/effects/Hue.h +++ b/include/effects/Hue.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Mask.h b/include/effects/Mask.h index badbaf40..253dbfe3 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Negate.h b/include/effects/Negate.h index 1618a427..89969a9e 100644 --- a/include/effects/Negate.h +++ b/include/effects/Negate.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Pixelate.h b/include/effects/Pixelate.h index 50f555d6..5cb0cffb 100644 --- a/include/effects/Pixelate.h +++ b/include/effects/Pixelate.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h index a7b3806f..cd714d6e 100644 --- a/include/effects/Saturation.h +++ b/include/effects/Saturation.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Shift.h b/include/effects/Shift.h index d6f2066b..c208ded6 100644 --- a/include/effects/Shift.h +++ b/include/effects/Shift.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/include/effects/Wave.h b/include/effects/Wave.h index ed28b8a0..ce2e8618 100644 --- a/include/effects/Wave.h +++ b/include/effects/Wave.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/AudioBufferSource.cpp b/src/AudioBufferSource.cpp index c7eed591..912d2552 100644 --- a/src/AudioBufferSource.cpp +++ b/src/AudioBufferSource.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index 84d0bd0b..4c42d2ed 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/AudioResampler.cpp b/src/AudioResampler.cpp index 0b5d2d3c..3aafb75d 100644 --- a/src/AudioResampler.cpp +++ b/src/AudioResampler.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d793ffa2..538f2284 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp index 44abbdcf..8270b393 100644 --- a/src/CacheBase.cpp +++ b/src/CacheBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp index ce14d109..2027cee6 100644 --- a/src/CacheDisk.cpp +++ b/src/CacheDisk.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/CacheMemory.cpp b/src/CacheMemory.cpp index 9536878a..5b4c9a6b 100644 --- a/src/CacheMemory.cpp +++ b/src/CacheMemory.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp index bfd25575..1c78b5dd 100644 --- a/src/ChunkReader.cpp +++ b/src/ChunkReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/ChunkWriter.cpp b/src/ChunkWriter.cpp index 2734bb1b..5dad4df3 100644 --- a/src/ChunkWriter.cpp +++ b/src/ChunkWriter.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Clip.cpp b/src/Clip.cpp index 2e99106c..50a46f6e 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp index 26e7710b..1517a7e3 100644 --- a/src/ClipBase.cpp +++ b/src/ClipBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Color.cpp b/src/Color.cpp index dec1571a..fafe8a8f 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp index 3fd293d6..2a5bdfbe 100644 --- a/src/Coordinate.cpp +++ b/src/Coordinate.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/CrashHandler.cpp b/src/CrashHandler.cpp index 24d8975b..1782f5ba 100644 --- a/src/CrashHandler.cpp +++ b/src/CrashHandler.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/DecklinkInput.cpp b/src/DecklinkInput.cpp index 5a83931c..da5a8d00 100644 --- a/src/DecklinkInput.cpp +++ b/src/DecklinkInput.cpp @@ -33,7 +33,7 @@ * DEALINGS IN THE SOFTWARE. * * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/DecklinkOutput.cpp b/src/DecklinkOutput.cpp index d86fe777..2dee7e9e 100644 --- a/src/DecklinkOutput.cpp +++ b/src/DecklinkOutput.cpp @@ -33,7 +33,7 @@ * DEALINGS IN THE SOFTWARE. * * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp index 512389f6..3f45830a 100644 --- a/src/DecklinkReader.cpp +++ b/src/DecklinkReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/DecklinkWriter.cpp b/src/DecklinkWriter.cpp index 25e2db27..7dcede04 100644 --- a/src/DecklinkWriter.cpp +++ b/src/DecklinkWriter.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 8e7c82c5..6b643d88 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp index 6c095402..33d0cc72 100644 --- a/src/EffectBase.cpp +++ b/src/EffectBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/EffectInfo.cpp b/src/EffectInfo.cpp index 9d094564..0b9c360d 100644 --- a/src/EffectInfo.cpp +++ b/src/EffectInfo.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Fraction.cpp b/src/Fraction.cpp index ee5a961b..c9cdad55 100644 --- a/src/Fraction.cpp +++ b/src/Fraction.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Frame.cpp b/src/Frame.cpp index d7edc889..2fff3435 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 2b725615..d68270e0 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index 0f09631e..1de252bd 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index b82fa2ea..776bd03a 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/PlayerBase.cpp b/src/PlayerBase.cpp index f4686d9f..3c904afd 100644 --- a/src/PlayerBase.cpp +++ b/src/PlayerBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Point.cpp b/src/Point.cpp index 4b73bf6f..0606dca6 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Profiles.cpp b/src/Profiles.cpp index a39100bc..0da0efe9 100644 --- a/src/Profiles.cpp +++ b/src/Profiles.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/AudioPlaybackThread.cpp b/src/Qt/AudioPlaybackThread.cpp index 3a286729..7a6e4569 100644 --- a/src/Qt/AudioPlaybackThread.cpp +++ b/src/Qt/AudioPlaybackThread.cpp @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/PlayerDemo.cpp b/src/Qt/PlayerDemo.cpp index 55862a96..110b69dc 100644 --- a/src/Qt/PlayerDemo.cpp +++ b/src/Qt/PlayerDemo.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/PlayerPrivate.cpp b/src/Qt/PlayerPrivate.cpp index 2040375e..d0f17842 100644 --- a/src/Qt/PlayerPrivate.cpp +++ b/src/Qt/PlayerPrivate.cpp @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp index 1a90f1c6..fbe784f7 100644 --- a/src/Qt/VideoCacheThread.cpp +++ b/src/Qt/VideoCacheThread.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/VideoPlaybackThread.cpp b/src/Qt/VideoPlaybackThread.cpp index 505a11d8..730a1d37 100644 --- a/src/Qt/VideoPlaybackThread.cpp +++ b/src/Qt/VideoPlaybackThread.cpp @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/VideoRenderWidget.cpp b/src/Qt/VideoRenderWidget.cpp index 64b539ff..2bfe8fa2 100644 --- a/src/Qt/VideoRenderWidget.cpp +++ b/src/Qt/VideoRenderWidget.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/VideoRenderer.cpp b/src/Qt/VideoRenderer.cpp index 70986b03..8d0e3a1d 100644 --- a/src/Qt/VideoRenderer.cpp +++ b/src/Qt/VideoRenderer.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Qt/demo/main.cpp b/src/Qt/demo/main.cpp index 9c7e18eb..3e5f00ba 100644 --- a/src/Qt/demo/main.cpp +++ b/src/Qt/demo/main.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index c9fe6b4e..111d83d7 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp index 08d7df5e..c53de79d 100644 --- a/src/QtPlayer.cpp +++ b/src/QtPlayer.cpp @@ -9,7 +9,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index 1aa39e5a..ece0684f 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/RendererBase.cpp b/src/RendererBase.cpp index edd1f795..b2bea40e 100644 --- a/src/RendererBase.cpp +++ b/src/RendererBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Settings.cpp b/src/Settings.cpp index 7c284624..e48fd981 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/TextReader.cpp b/src/TextReader.cpp index fd9dcfef..d435b77e 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/Timeline.cpp b/src/Timeline.cpp index d28b4ff8..da960230 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/WriterBase.cpp b/src/WriterBase.cpp index 3a8b5f72..29fefe48 100644 --- a/src/WriterBase.cpp +++ b/src/WriterBase.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/ZmqLogger.cpp b/src/ZmqLogger.cpp index cc38f9a4..f9ecc875 100644 --- a/src/ZmqLogger.cpp +++ b/src/ZmqLogger.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index 0858eb4e..831b7bde 100644 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 2a481aa7..eb7c989a 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/src/bindings/python/openshot.i b/src/bindings/python/openshot.i index ed34b658..74d2705b 100644 --- a/src/bindings/python/openshot.i +++ b/src/bindings/python/openshot.i @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt index 7e3bce99..e0987ca4 100644 --- a/src/bindings/ruby/CMakeLists.txt +++ b/src/bindings/ruby/CMakeLists.txt @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/src/bindings/ruby/openshot.i b/src/bindings/ruby/openshot.i index 2868708e..775421b6 100644 --- a/src/bindings/ruby/openshot.i +++ b/src/bindings/ruby/openshot.i @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/src/effects/Bars.cpp b/src/effects/Bars.cpp index cc541cc2..2868165f 100644 --- a/src/effects/Bars.cpp +++ b/src/effects/Bars.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Blur.cpp b/src/effects/Blur.cpp index 39c70921..69c1bbb2 100644 --- a/src/effects/Blur.cpp +++ b/src/effects/Blur.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp index cac05b14..ea438fc6 100644 --- a/src/effects/Brightness.cpp +++ b/src/effects/Brightness.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp index 3329b4df..c0889e5e 100644 --- a/src/effects/ChromaKey.cpp +++ b/src/effects/ChromaKey.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/ColorShift.cpp b/src/effects/ColorShift.cpp index 2adb88ff..e80a1d0f 100644 --- a/src/effects/ColorShift.cpp +++ b/src/effects/ColorShift.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Crop.cpp b/src/effects/Crop.cpp index 390d537e..fa6d20ea 100644 --- a/src/effects/Crop.cpp +++ b/src/effects/Crop.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp index fce8e1b1..6da40d08 100644 --- a/src/effects/Deinterlace.cpp +++ b/src/effects/Deinterlace.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Hue.cpp b/src/effects/Hue.cpp index e6c7e761..a24595fc 100644 --- a/src/effects/Hue.cpp +++ b/src/effects/Hue.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index d0adf8e7..4da1bb0a 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp index 383ded34..650b1258 100644 --- a/src/effects/Negate.cpp +++ b/src/effects/Negate.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Pixelate.cpp b/src/effects/Pixelate.cpp index 3f27f7f8..92d13ea8 100644 --- a/src/effects/Pixelate.cpp +++ b/src/effects/Pixelate.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp index 4500ff9b..8f2874da 100644 --- a/src/effects/Saturation.cpp +++ b/src/effects/Saturation.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Shift.cpp b/src/effects/Shift.cpp index 30aaa5ae..474f4466 100644 --- a/src/effects/Shift.cpp +++ b/src/effects/Shift.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/effects/Wave.cpp b/src/effects/Wave.cpp index 71b75dbd..32075780 100644 --- a/src/effects/Wave.cpp +++ b/src/effects/Wave.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 314a5ea2..eec8d00e 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/src/examples/ExampleBlackmagic.cpp b/src/examples/ExampleBlackmagic.cpp index 84bbe809..91a6655d 100644 --- a/src/examples/ExampleBlackmagic.cpp +++ b/src/examples/ExampleBlackmagic.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e358fb44..6388f4e8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,7 +4,7 @@ # # @section LICENSE # -# Copyright (c) 2008-2014 OpenShot Studios, LLC +# Copyright (c) 2008-2019 OpenShot Studios, LLC # . This file is part of # OpenShot Library (libopenshot), an open-source project dedicated to # delivering high quality video editing and animation solutions to the diff --git a/tests/Cache_Tests.cpp b/tests/Cache_Tests.cpp index 4f97061f..7e42c741 100644 --- a/tests/Cache_Tests.cpp +++ b/tests/Cache_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp index c8b23862..b66724b8 100644 --- a/tests/Clip_Tests.cpp +++ b/tests/Clip_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Color_Tests.cpp b/tests/Color_Tests.cpp index e01fe853..86b3a458 100644 --- a/tests/Color_Tests.cpp +++ b/tests/Color_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Coordinate_Tests.cpp b/tests/Coordinate_Tests.cpp index a871a911..ec8c29a1 100644 --- a/tests/Coordinate_Tests.cpp +++ b/tests/Coordinate_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index aff6cc64..4ef570ae 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/FFmpegWriter_Tests.cpp b/tests/FFmpegWriter_Tests.cpp index 67882b05..53a9cbf2 100644 --- a/tests/FFmpegWriter_Tests.cpp +++ b/tests/FFmpegWriter_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Fraction_Tests.cpp b/tests/Fraction_Tests.cpp index 4fabcf6d..72bd6407 100644 --- a/tests/Fraction_Tests.cpp +++ b/tests/Fraction_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/FrameMapper_Tests.cpp b/tests/FrameMapper_Tests.cpp index 6b0042dd..ce43fc20 100644 --- a/tests/FrameMapper_Tests.cpp +++ b/tests/FrameMapper_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/ImageWriter_Tests.cpp b/tests/ImageWriter_Tests.cpp index 6400f84e..d44bbd84 100644 --- a/tests/ImageWriter_Tests.cpp +++ b/tests/ImageWriter_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp index 1a16de0d..3d790739 100644 --- a/tests/KeyFrame_Tests.cpp +++ b/tests/KeyFrame_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Point_Tests.cpp b/tests/Point_Tests.cpp index 107f661c..ed560a9d 100644 --- a/tests/Point_Tests.cpp +++ b/tests/Point_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp index e4a3935b..b3be12fa 100644 --- a/tests/ReaderBase_Tests.cpp +++ b/tests/ReaderBase_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Settings_Tests.cpp b/tests/Settings_Tests.cpp index 5bb020f1..cf7b8a00 100644 --- a/tests/Settings_Tests.cpp +++ b/tests/Settings_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index 9ad42f2c..1290bee7 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the diff --git a/tests/tests.cpp b/tests/tests.cpp index ca01331c..20d5fd33 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2014 OpenShot Studios, LLC + * Copyright (c) 2008-2019 OpenShot Studios, LLC * . This file is part of * OpenShot Library (libopenshot), an open-source project dedicated to * delivering high quality video editing and animation solutions to the From 9261f46772a9943a22dc2183738ff0c2dda3544c Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Tue, 11 Jun 2019 06:51:37 -0400 Subject: [PATCH 165/186] More copyright, missed a few older ones --- include/FFmpegReader.h | 2 +- include/FFmpegWriter.h | 2 +- include/ImageWriter.h | 2 +- src/FFmpegReader.cpp | 2 +- src/FFmpegWriter.cpp | 2 +- src/ImageWriter.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index 331ca32a..923c8c18 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard + * Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of * OpenShot Library (http://www.openshot.org), an open-source project * dedicated to delivering high quality video editing and animation solutions diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index e4ebe176..d27d8238 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard + * Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of * OpenShot Library (http://www.openshot.org), an open-source project * dedicated to delivering high quality video editing and animation solutions diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 41c460e1..03aeadb6 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard + * Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of * OpenShot Library (http://www.openshot.org), an open-source project * dedicated to delivering high quality video editing and animation solutions diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index b6c9dd1e..ef1702bf 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard + * Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of * OpenShot Library (http://www.openshot.org), an open-source project * dedicated to delivering high quality video editing and animation solutions diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index e052bc63..b20f6b23 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard + * Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of * OpenShot Library (http://www.openshot.org), an open-source project * dedicated to delivering high quality video editing and animation solutions diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 1205a8ee..2cbd26d3 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -8,7 +8,7 @@ /* LICENSE * - * Copyright (c) 2008-2013 OpenShot Studios, LLC, Fabrice Bellard + * Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard * (http://www.openshotstudios.com). This file is part of * OpenShot Library (http://www.openshot.org), an open-source project * dedicated to delivering high quality video editing and animation solutions From 7d8c1da2c283cd6c9a2fae840864ba1ff4830f3b Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Wed, 12 Jun 2019 21:16:56 -0400 Subject: [PATCH 166/186] Doxyfile.in: Exclude all examples The source has been reorganized since the doxygen configs were last updated; there are more examples that should be excluded, and they're all now under `src/examples/`, so exclude the entire dir. --- Doxyfile.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index ba047c6b..a4be716d 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -797,8 +797,7 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = "*/.*" \ "*/.*/*" \ - "*/src/Main.cpp*" \ - "*/src/Main_Blackmagic.cpp*" \ + "*/src/examples/*" \ "*/src/bindings/*" \ "*.py" From df4fc4b05473599d44247346a0e4d071fb145a01 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 12 Jun 2019 21:20:37 -0400 Subject: [PATCH 167/186] Doxyfile.in: Remove doc/InstallationGuide.pdf No longer exists. --- Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doxyfile.in b/Doxyfile.in index a4be716d..48c74100 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1083,7 +1083,7 @@ HTML_EXTRA_STYLESHEET = # 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 = "doc/InstallationGuide.pdf" +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 From 3ba6ba2a2908e47024330b9a7e0ce7891d411fe6 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 12 Jun 2019 21:21:58 -0400 Subject: [PATCH 168/186] Upgrade Doyfile.in Some arguments are obsolete with recent doxygen (and we never used them anyway), upgraded file with `doxygen -u` to remove. --- Doxyfile.in | 555 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 367 insertions(+), 188 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 48c74100..05af5ea1 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.6 +# Doxyfile 1.8.15 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # 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. +# This tag specifies the encoding used for all characters in the configuration +# 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 +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -46,10 +46,10 @@ PROJECT_NUMBER = "@PROJECT_VERSION@" PROJECT_BRIEF = -# 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. +# With the PROJECT_LOGO tag one can specify a logo or an 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 = @@ -60,7 +60,7 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = "@DOXYFILE_OUTPUT_DIR@" -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# 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 @@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = "@DOXYFILE_OUTPUT_DIR@" CREATE_SUBDIRS = NO +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = 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. @@ -85,14 +93,22 @@ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# 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 +# 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 @@ -127,7 +143,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# 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. @@ -197,9 +213,9 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES -# 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. +# 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 @@ -218,7 +234,12 @@ TAB_SIZE = 8 # 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. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) ALIASES = @@ -256,16 +277,28 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = 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. +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. 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: 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. @@ -274,7 +307,7 @@ 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. +# documentation. See https://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. @@ -282,10 +315,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + # 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. +# be prevented in individual cases 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 @@ -307,7 +349,7 @@ BUILTIN_STL_SUPPORT = 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 +# https://www.riverbankcomputing.com/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. @@ -325,13 +367,20 @@ SIP_SUPPORT = NO 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 +# 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 +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = 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 @@ -390,7 +439,7 @@ LOOKUP_CACHE_SIZE = 0 # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# 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. @@ -400,35 +449,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# 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 = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# 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 +# 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 = NO -# 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 +# 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, +# This flag is only useful for Objective-C code. If 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 in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -453,21 +502,21 @@ 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. +# 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 +# (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 +# 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. @@ -481,7 +530,7 @@ HIDE_IN_BODY_DOCS = 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 +# 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. @@ -490,12 +539,19 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES # 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 +# 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 HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= 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. @@ -523,14 +579,14 @@ INLINE_INFO = YES # 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. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # 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 that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. @@ -575,27 +631,25 @@ SORT_BY_SCOPE_NAME = 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 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 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 +# 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 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. @@ -620,8 +674,8 @@ ENABLED_SECTIONS = 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 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 @@ -666,11 +720,10 @@ 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. +# to be installed. See also https://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. +# search path. See also \cite for info how to create references. CITE_BIB_FILES = @@ -686,7 +739,7 @@ CITE_BIB_FILES = QUIET = YES # 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 +# 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. @@ -694,7 +747,7 @@ QUIET = YES WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# 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. @@ -711,12 +764,19 @@ 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. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = 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 @@ -740,7 +800,7 @@ WARN_LOGFILE = # 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. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/include" \ @@ -749,7 +809,7 @@ INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/include" \ # 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 +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. @@ -757,12 +817,17 @@ 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. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# 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, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -852,6 +917,10 @@ IMAGE_PATH = "@CMAKE_CURRENT_SOURCE_DIR@" # 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. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = @@ -861,11 +930,15 @@ INPUT_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. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. 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 +# 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. @@ -913,7 +986,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -925,7 +998,7 @@ REFERENCED_BY_RELATION = 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 +# 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. @@ -945,12 +1018,12 @@ 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 +# (see https://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 +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1002,7 +1075,7 @@ IGNORE_PREFIX = # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1064,13 +1137,15 @@ HTML_FOOTER = 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 +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are 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. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1083,12 +1158,12 @@ HTML_EXTRA_STYLESHEET = # 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 = +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 +# will adjust the colors in the style sheet 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 +# https://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. @@ -1117,12 +1192,24 @@ 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. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = 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. @@ -1146,13 +1233,13 @@ 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 +# environment (see: https://developer.apple.com/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. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1191,7 +1278,7 @@ 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 +# (see: https://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 @@ -1214,28 +1301,29 @@ GENERATE_HTMLHELP = NO 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 +# 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 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) +# 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 BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1266,7 +1354,7 @@ 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). +# (see: http://doc.qt.io/archives/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. @@ -1274,7 +1362,7 @@ QHP_NAMESPACE = # 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 (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1283,7 +1371,7 @@ 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 (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1291,7 +1379,7 @@ 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 (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1299,7 +1387,7 @@ 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). +# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1348,7 +1436,7 @@ DISABLE_INDEX = NO # 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 +# HTML help feature. Via custom style sheets (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 @@ -1376,7 +1464,7 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If 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. @@ -1392,7 +1480,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT 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. # @@ -1404,8 +1492,8 @@ FORMULA_FONTSIZE = 10 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 +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered 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. @@ -1431,8 +1519,8 @@ MATHJAX_FORMAT = HTML-CSS # 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. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1475,11 +1563,11 @@ SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1491,9 +1579,9 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1504,9 +1592,9 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1542,7 +1630,7 @@ EXTRA_SEARCH_MAPPINGS = # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = @DOXYFILE_GENERATE_LATEX@ @@ -1558,22 +1646,35 @@ LATEX_OUTPUT = "@DOXYFILE_LATEX_DIR@" # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = "@LATEX_COMPILER@" # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = "@MAKEINDEX_COMPILER@" -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: \makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = \makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1591,9 +1692,12 @@ COMPACT_LATEX = NO PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1607,23 +1711,36 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output # directory. Note that the files will be copied as-is; there are no commands or @@ -1641,8 +1758,8 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1677,17 +1794,33 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# 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: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1702,7 +1835,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1722,9 +1855,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1733,17 +1866,27 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1767,6 +1910,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1780,7 +1930,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1794,19 +1944,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1815,11 +1953,18 @@ XML_DTD = XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1833,14 +1978,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1849,7 +2003,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1857,7 +2011,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1865,9 +2019,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1887,14 +2041,14 @@ PERLMOD_MAKEVAR_PREFIX = # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1910,7 +2064,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1952,9 +2106,9 @@ PREDEFINED = EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1974,7 +2128,7 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. @@ -1986,20 +2140,21 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2016,7 +2171,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2041,7 +2196,7 @@ MSCGEN_PATH = DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2066,7 +2221,7 @@ HAVE_DOT = @DOXYFILE_DOT@ DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2074,7 +2229,7 @@ DOT_NUM_THREADS = 0 # The default value is: Helvetica. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = +DOT_FONTNAME = # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # dot graphs. @@ -2114,7 +2269,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2166,7 +2321,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2177,7 +2333,8 @@ CALL_GRAPH = NO # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2200,11 +2357,15 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2247,6 +2408,24 @@ MSCFILE_DIRS = DIAFILE_DIRS = +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized @@ -2283,7 +2462,7 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = YES -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2300,7 +2479,7 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. From 5292661dec36df8f0f2d69ba6915059f6dc72b7f Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 12 Jun 2019 21:26:18 -0400 Subject: [PATCH 169/186] Also remove install guide ref from OpenShot.h --- include/OpenShot.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/OpenShot.h b/include/OpenShot.h index 8987f5e5..c3fde052 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -64,10 +64,6 @@ * canvas (i.e. pan & scan). * \image html /doc/images/Timeline_Layers.png * - * ### Build Instructions (Linux, Mac, and Windows) ### - * For a step-by-step guide to building / compiling libopenshot, check out the - * Official Installation Guide. - * * ### Want to Learn More? ### * To continue learning about libopenshot, take a look at the full list of classes available. * From 4455f77bd93d4cd5dd62f05cb380ae575cc3ffcd Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 12 Jun 2019 21:27:53 -0400 Subject: [PATCH 170/186] Crop.h: Remove nonexistent color argument Doxygen caught this one: the default constructor for Crop() doesn't take an argument 'color', though it was documented to. --- include/effects/Crop.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/effects/Crop.h b/include/effects/Crop.h index 7921a78d..39779f07 100644 --- a/include/effects/Crop.h +++ b/include/effects/Crop.h @@ -69,7 +69,6 @@ namespace openshot /// Default constructor, which takes 4 curves. These curves animate the crop over time. /// - /// @param color The curve to adjust the color of bars /// @param left The curve to adjust the left bar size (between 0 and 1) /// @param top The curve to adjust the top bar size (between 0 and 1) /// @param right The curve to adjust the right bar size (between 0 and 1) From 7319201e37b1b82da2832d8280328532dfc7724e Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 12 Jun 2019 22:44:05 -0400 Subject: [PATCH 171/186] Doygen: Include doc/*.md in docs Also include the documentation MarkDown pages in the Doxygen docs. These will show up as Related Pages in the interface. * The formatting of `INSTALL-*.md` had to be changed some: - Doxygen doesn't support headings in bulleted lists (lines starting with `* ###`) -- I'm not even sure that's legal markdown. They were changed to just level 3 headings (lines starting with `###`). - ALL Windows paths in `INSTALL-WINDOWS.md` were wrapped in backticks, to prevent Doxygen parsing them as markup commands. - Level 1 headings were added to the top of the three install docs, giving them the title "Building libopenshot for ___(OS)___". Otherwise all three pages were titled "Getting Started". * Separately, the table at the top of `HW-ACCEL.md` does not translate well to Doxygen. It will need further polishing. But the docs are all quite readable now. --- Doxyfile.in | 4 ++- doc/INSTALL-LINUX.md | 38 ++++++++++++++------------ doc/INSTALL-MAC.md | 38 ++++++++++++++------------ doc/INSTALL-WINDOWS.md | 62 ++++++++++++++++++++++-------------------- 4 files changed, 75 insertions(+), 67 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 05af5ea1..4d4649c6 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -804,7 +804,9 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/include" \ - "@CMAKE_CURRENT_SOURCE_DIR@/src" + "@CMAKE_CURRENT_SOURCE_DIR@/src" \ + "@CMAKE_CURRENT_SOURCE_DIR@/doc" + # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/doc/INSTALL-LINUX.md b/doc/INSTALL-LINUX.md index 6ed4f3f6..2a0bbe1b 100644 --- a/doc/INSTALL-LINUX.md +++ b/doc/INSTALL-LINUX.md @@ -1,3 +1,5 @@ +# Building libopenshot for Linux + ## Getting Started The best way to get started with libopenshot, is to learn about our build system, obtain all the source code, @@ -22,47 +24,47 @@ The following libraries are required to build libopenshot. Instructions on how dependencies vary for each operating system. Libraries and Executables have been labeled in the list below to help distinguish between them. -* ### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) +### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) * http://www.ffmpeg.org/ `(Library)` * This library is used to decode and encode video, audio, and image files. It is also used to obtain information about media files, such as frame rate, sample rate, aspect ratio, and other common attributes. -* ### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) +### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) * http://www.imagemagick.org/script/magick++.php `(Library)` * This library is **optional**, and used to decode and encode images. -* ### OpenShot Audio Library (libopenshot-audio) +### OpenShot Audio Library (libopenshot-audio) * https://github.com/OpenShot/libopenshot-audio/ `(Library)` * This library is used to mix, resample, host plug-ins, and play audio. It is based on the JUCE project, which is an outstanding audio library used by many different applications -* ### Qt 5 (libqt5) +### Qt 5 (libqt5) * http://www.qt.io/qt5/ `(Library)` * Qt5 is used to display video, store image data, composite images, apply image effects, and many other utility functions, such as file system manipulation, high resolution timers, etc... -* ### CMake (cmake) +### CMake (cmake) * http://www.cmake.org/ `(Executable)` * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process. -* ### SWIG (swig) +### SWIG (swig) * http://www.swig.org/ `(Executable)` * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages. -* ### Python 3 (libpython) +### Python 3 (libpython) * http://www.python.org/ `(Executable and Library)` * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot). -* ### Doxygen (doxygen) +### Doxygen (doxygen) * http://www.stack.nl/~dimitri/doxygen/ `(Executable)` * This executable is used to auto-generate the documentation used by libopenshot. -* ### UnitTest++ (libunittest++) +### UnitTest++ (libunittest++) * https://github.com/unittest-cpp/ `(Library)` * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. -* ### ZeroMQ (libzmq) +### ZeroMQ (libzmq) * http://zeromq.org/ `(Library)` * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot. -* ### OpenMP (-fopenmp) +### OpenMP (-fopenmp) * http://openmp.org/wp/ `(Compiler Flag)` * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors. @@ -99,25 +101,25 @@ git clone https://github.com/OpenShot/libopenshot-audio.git The source code is divided up into the following folders. -* ### build/ +### build/ * This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). -* ### cmake/ +### cmake/ * This folder contains custom modules not included by default in cmake, used to find dependency libraries and headers and determine if these libraries are installed. -* ### doc/ +### doc/ * This folder contains documentation and related files, such as logos and images required by the doxygen auto-generated documentation. -* ### include/ +### include/ * This folder contains all headers (*.h) used by libopenshot. -* ### src/ +### src/ * This folder contains all source code (*.cpp) used by libopenshot. -* ### tests/ +### tests/ * This folder contains all unit test code. Each class has it’s own test file (*.cpp), and uses UnitTest++ macros to keep the test code simple and manageable. -* ### thirdparty/ +### thirdparty/ * This folder contains code not written by the OpenShot team. For example, jsoncpp, an open-source JSON parser. ## Install Dependencies diff --git a/doc/INSTALL-MAC.md b/doc/INSTALL-MAC.md index ab7f79c3..ac0c7f7c 100644 --- a/doc/INSTALL-MAC.md +++ b/doc/INSTALL-MAC.md @@ -1,3 +1,5 @@ +# Building libopenshot for MacOS + ## Getting Started The best way to get started with libopenshot, is to learn about our build system, obtain all the source code, @@ -22,47 +24,47 @@ The following libraries are required to build libopenshot. Instructions on how dependencies vary for each operating system. Libraries and Executables have been labeled in the list below to help distinguish between them. -* ### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) +### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) * http://www.ffmpeg.org/ `(Library)` * This library is used to decode and encode video, audio, and image files. It is also used to obtain information about media files, such as frame rate, sample rate, aspect ratio, and other common attributes. -* ### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) +### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) * http://www.imagemagick.org/script/magick++.php `(Library)` * This library is **optional**, and used to decode and encode images. -* ### OpenShot Audio Library (libopenshot-audio) +### OpenShot Audio Library (libopenshot-audio) * https://github.com/OpenShot/libopenshot-audio/ `(Library)` * This library is used to mix, resample, host plug-ins, and play audio. It is based on the JUCE project, which is an outstanding audio library used by many different applications -* ### Qt 5 (libqt5) +### Qt 5 (libqt5) * http://www.qt.io/qt5/ `(Library)` * Qt5 is used to display video, store image data, composite images, apply image effects, and many other utility functions, such as file system manipulation, high resolution timers, etc... -* ### CMake (cmake) +### CMake (cmake) * http://www.cmake.org/ `(Executable)` * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process. -* ### SWIG (swig) +### SWIG (swig) * http://www.swig.org/ `(Executable)` * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages. -* ### Python 3 (libpython) +### Python 3 (libpython) * http://www.python.org/ `(Executable and Library)` * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot). -* ### Doxygen (doxygen) +### Doxygen (doxygen) * http://www.stack.nl/~dimitri/doxygen/ `(Executable)` * This executable is used to auto-generate the documentation used by libopenshot. -* ### UnitTest++ (libunittest++) +### UnitTest++ (libunittest++) * https://github.com/unittest-cpp/ `(Library)` * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. -* ### ZeroMQ (libzmq) +### ZeroMQ (libzmq) * http://zeromq.org/ `(Library)` * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot. -* ### OpenMP (-fopenmp) +### OpenMP (-fopenmp) * http://openmp.org/wp/ `(Compiler Flag)` * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors. @@ -98,25 +100,25 @@ git clone https://github.com/OpenShot/libopenshot-audio.git The source code is divided up into the following folders. -* ### build/ +### build/ * This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). -* ### cmake/ +### cmake/ * This folder contains custom modules not included by default in cmake, used to find dependency libraries and headers and determine if these libraries are installed. -* ### doc/ +### doc/ * This folder contains documentation and related files, such as logos and images required by the doxygen auto-generated documentation. -* ### include/ +### include/ * This folder contains all headers (*.h) used by libopenshot. -* ### src/ +### src/ * This folder contains all source code (*.cpp) used by libopenshot. -* ### tests/ +### tests/ * This folder contains all unit test code. Each class has it’s own test file (*.cpp), and uses UnitTest++ macros to keep the test code simple and manageable. -* ### thirdparty/ +### thirdparty/ * This folder contains code not written by the OpenShot team. For example, jsoncpp, an open-source JSON parser. ## Install Dependencies diff --git a/doc/INSTALL-WINDOWS.md b/doc/INSTALL-WINDOWS.md index 7f5b8f78..2b17569b 100644 --- a/doc/INSTALL-WINDOWS.md +++ b/doc/INSTALL-WINDOWS.md @@ -1,3 +1,5 @@ +# Building libopenshot for Windows + ## Getting Started The best way to get started with libopenshot, is to learn about our build system, obtain all the @@ -24,47 +26,47 @@ The following libraries are required to build libopenshot. Instructions on how install these dependencies vary for each operating system. Libraries and Executables have been labeled in the list below to help distinguish between them. -* ### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) +### FFmpeg (libavformat, libavcodec, libavutil, libavdevice, libavresample, libswscale) * http://www.ffmpeg.org/ `(Library)` * This library is used to decode and encode video, audio, and image files. It is also used to obtain information about media files, such as frame rate, sample rate, aspect ratio, and other common attributes. -* ### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) +### ImageMagick++ (libMagick++, libMagickWand, libMagickCore) * http://www.imagemagick.org/script/magick++.php `(Library)` * This library is **optional**, and used to decode and encode images. -* ### OpenShot Audio Library (libopenshot-audio) +### OpenShot Audio Library (libopenshot-audio) * https://github.com/OpenShot/libopenshot-audio/ `(Library)` * This library is used to mix, resample, host plug-ins, and play audio. It is based on the JUCE project, which is an outstanding audio library used by many different applications -* ### Qt 5 (libqt5) +### Qt 5 (libqt5) * http://www.qt.io/qt5/ `(Library)` * Qt5 is used to display video, store image data, composite images, apply image effects, and many other utility functions, such as file system manipulation, high resolution timers, etc... -* ### CMake (cmake) +### CMake (cmake) * http://www.cmake.org/ `(Executable)` * This executable is used to automate the generation of Makefiles, check for dependencies, and is the backbone of libopenshot’s cross-platform build process. -* ### SWIG (swig) +### SWIG (swig) * http://www.swig.org/ `(Executable)` * This executable is used to generate the Python and Ruby bindings for libopenshot. It is a simple and powerful wrapper for C++ libraries, and supports many languages. -* ### Python 3 (libpython) +### Python 3 (libpython) * http://www.python.org/ `(Executable and Library)` * This library is used by swig to create the Python (version 3+) bindings for libopenshot. This is also the official language used by OpenShot Video Editor (a graphical interface to libopenshot). -* ### Doxygen (doxygen) +### Doxygen (doxygen) * http://www.stack.nl/~dimitri/doxygen/ `(Executable)` * This executable is used to auto-generate the documentation used by libopenshot. -* ### UnitTest++ (libunittest++) +### UnitTest++ (libunittest++) * https://github.com/unittest-cpp/ `(Library)` * This library is used to execute unit tests for libopenshot. It contains many macros used to keep our unit testing code very clean and simple. -* ### ZeroMQ (libzmq) +### ZeroMQ (libzmq) * http://zeromq.org/ `(Library)` * This library is used to communicate between libopenshot and other applications (publisher / subscriber). Primarily used to send debug data from libopenshot. -* ### OpenMP (-fopenmp) +### OpenMP (-fopenmp) * http://openmp.org/wp/ `(Compiler Flag)` * If your compiler supports this flag (GCC, Clang, and most other compilers), it provides libopenshot with easy methods of using parallel programming techniques to improve performance and take advantage of multi-core processors. @@ -109,7 +111,7 @@ check each folder path for accuracy, as your paths will likely be different than * UNITTEST_DIR (`C:\UnitTest++`) * ZMQDIR (`C:\msys2\usr\local\`) * PATH (`The following paths are an example`) - * C:\Qt5\bin; C:\Qt5\MinGW\bin\; C:\msys\1.0\local\lib; C:\Program Files\CMake 2.8\bin; C:\UnitTest++\build; C:\libopenshot\build\src; C:\Program Files\doxygen\bin; C:\ffmpeg-git-95f163b-win32-dev\lib; C:\swigwin-2.0.4; C:\Python33; C:\Program Files\Project\lib; C:\msys2\usr\local\ + * `C:\Qt5\bin; C:\Qt5\MinGW\bin\; C:\msys\1.0\local\lib; C:\Program Files\CMake 2.8\bin; C:\UnitTest++\build; C:\libopenshot\build\src; C:\Program Files\doxygen\bin; C:\ffmpeg-git-95f163b-win32-dev\lib; C:\swigwin-2.0.4; C:\Python33; C:\Program Files\Project\lib; C:\msys2\usr\local\` @@ -130,29 +132,29 @@ git clone https://github.com/OpenShot/libopenshot-audio.git The source code is divided up into the following folders. -* ### build/ +### build/ * This folder needs to be manually created, and is used by cmake to store the temporary build files, such as makefiles, as well as the final binaries (library and test executables). -* ### cmake/ +### cmake/ * This folder contains custom modules not included by default in cmake, used to find dependency libraries and headers and determine if these libraries are installed. -* ### doc/ +### doc/ * This folder contains documentation and related files, such as logos and images required by the doxygen auto-generated documentation. -* ### include/ +### include/ * This folder contains all headers (*.h) used by libopenshot. -* ### src/ +### src/ * This folder contains all source code (*.cpp) used by libopenshot. -* ### tests/ +### tests/ * This folder contains all unit test code. Each class has it’s own test file (*.cpp), and uses UnitTest++ macros to keep the test code simple and manageable. -* ### thirdparty/ +### thirdparty/ * This folder contains code not written by the OpenShot team. For example, jsoncpp, an open-source JSON parser. @@ -240,28 +242,28 @@ mingw32-make install ## Manual Dependencies -* ### DLfcn +### DLfcn * https://github.com/dlfcn-win32/dlfcn-win32 - * Download and Extract the Win32 Static (.tar.bz2) archive to a local folder: C:\libdl\ - * Create an environment variable called DL_DIR and set the value to C:\libdl\. This environment variable will be used by CMake to find the binary and header file. + * Download and Extract the Win32 Static (.tar.bz2) archive to a local folder: `C:\libdl\` + * Create an environment variable called DL_DIR and set the value to `C:\libdl\`. This environment variable will be used by CMake to find the binary and header file. -* ### DirectX SDK / Windows SDK +### DirectX SDK / Windows SDK * Windows 7: (DirectX SDK) http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=6812 * Windows 8: (Windows SDK) * https://msdn.microsoft.com/en-us/windows/desktop/aa904949 * Download and Install the SDK Setup program. This is needed for the JUCE library to play audio on Windows. -Create an environment variable called DXSDK_DIR and set the value to C:\Program Files\Microsoft DirectX SDK (June 2010)\ (your path might be different). This environment variable will be used by CMake to find the binaries and header files. +Create an environment variable called DXSDK_DIR and set the value to `C:\Program Files\Microsoft DirectX SDK (June 2010)\` (your path might be different). This environment variable will be used by CMake to find the binaries and header files. -* ### libSndFile +### libSndFile * http://www.mega-nerd.com/libsndfile/#Download * Download and Install the Win32 Setup program. - * Create an environment variable called SNDFILE_DIR and set the value to C:\Program Files\libsndfile. This environment variable will be used by CMake to find the binary and header files. + * Create an environment variable called SNDFILE_DIR and set the value to `C:\Program Files\libsndfile`. This environment variable will be used by CMake to find the binary and header files. -* ### libzmq +### libzmq * http://zeromq.org/intro:get-the-software * Download source code (zip) * Follow their instructions, and build with mingw - * Create an environment variable called ZMQDIR and set the value to C:\libzmq\build\ (the location of the compiled version). This environment variable will be used by CMake to find the binary and header files. + * Create an environment variable called ZMQDIR and set the value to `C:\libzmq\build\` (the location of the compiled version). This environment variable will be used by CMake to find the binary and header files. ## Windows Build Instructions (libopenshot-audio) In order to compile libopenshot-audio, launch a command prompt and enter the following commands. This does not require the MSYS2 prompt, but it should work in both the Windows command prompt and the MSYS2 prompt. @@ -314,8 +316,8 @@ built, we need to install it (i.e. copy it to the correct folder, so other libra mingw32-make install ``` -This should copy the binary files to C:\Program Files\openshot\lib\, and the header -files to C:\Program Files\openshot\include\... This is where other projects will +This should copy the binary files to `C:\Program Files\openshot\lib\`, and the header +files to `C:\Program Files\openshot\include\...` This is where other projects will look for the libopenshot files when building.. Python 3 bindings are also installed at this point. let's verify the python bindings work: From 0dcbc20921bbb180679f7fc94cce3413826b1071 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 12 Jun 2019 22:55:54 -0400 Subject: [PATCH 172/186] Doxygen docs: Link to install docs This adds references to all three `INSTALL-*.md` documents to the main page text in `include/OpenShot.h`, replacing the previous link to the PDF. --- include/OpenShot.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/OpenShot.h b/include/OpenShot.h index c3fde052..fb53164c 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -64,6 +64,12 @@ * canvas (i.e. pan & scan). * \image html /doc/images/Timeline_Layers.png * + * ### Build Instructions ### + * Build instructions are available for all three major Operating Systems: + * * [Building libopenshot for Windows](doc/INSTALL-WINDOWS.md) + * * [Building libopenshot for MacOS](doc/INSTALL-MAC.md) + * * [Building libopenshot for Linux](doc/INSTALL-LINUX.md) + * * ### Want to Learn More? ### * To continue learning about libopenshot, take a look at the full list of classes available. * From 55f26a226dbfcd1e0a82270fe4b4f8402d542286 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 13 Jun 2019 00:06:01 -0400 Subject: [PATCH 173/186] Doxyfile.in: Switch on referenced-by linking --- Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doxyfile.in b/Doxyfile.in index 4d4649c6..3499d643 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -991,7 +991,7 @@ STRIP_CODE_COMMENTS = NO # entity all documented functions referencing it will be listed. # The default value is: NO. -REFERENCED_BY_RELATION = NO +REFERENCED_BY_RELATION = YES # 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. From 95aca48831cdc1672054530c7de194c4fda4a48d Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 13 Jun 2019 06:54:16 -0400 Subject: [PATCH 174/186] Fix some bugs in UseDoxygen.cmake There was a bug in the definition of `DOXYFILE_LATEX`, and _another_ in the processing of it (which were the only reason it wasn't defaulting on, the way it appeared to be configured), fixed the bug and changed it to default OFF. But now it _can_ be enabled. Also moved the handling of `DOXYFILE_DOT` out of the latex-only section, so that it can be turned on with the new config variable `DOXYFILE_USE_DOT` (default on). If `DOXYFILE_USE_DOT` is enabled and the `dot` executable is found, `DOXYFILE_DOT` will be set "YES" and `dot` will be used for the HTML as well, giving better graphs. --- cmake/Modules/UseDoxygen.cmake | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/UseDoxygen.cmake b/cmake/Modules/UseDoxygen.cmake index b261d431..807dbac6 100644 --- a/cmake/Modules/UseDoxygen.cmake +++ b/cmake/Modules/UseDoxygen.cmake @@ -105,12 +105,18 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND) STRING "Additional source files/directories separated by space") set(DOXYFILE_SOURE_DIRS "\"${DOXYFILE_SOURCE_DIR}\" ${DOXYFILE_EXTRA_SOURCES}") - usedoxygen_set_default(DOXYFILE_LATEX YES BOOL "Generate LaTeX API documentation" OFF) + usedoxygen_set_default(DOXYFILE_LATEX OFF BOOL "Generate LaTeX API documentation") usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex" STRING "LaTex output directory") mark_as_advanced(DOXYFILE_OUTPUT_DIR DOXYFILE_HTML_DIR DOXYFILE_LATEX_DIR DOXYFILE_SOURCE_DIR DOXYFILE_EXTRA_SOURCE_DIRS DOXYFILE_IN) + ## Dot + usedoxygen_set_default(DOXYFILE_USE_DOT ON BOOL "Use dot (part of graphviz) to generate graphs") + set(DOXYFILE_DOT "NO") + if(DOXYFILE_USE_DOT AND DOXYGEN_DOT_EXECUTABLE) + set(DOXYFILE_DOT "YES") + endif() set_property(DIRECTORY APPEND PROPERTY @@ -125,13 +131,12 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND) ## LaTeX set(DOXYFILE_PDFLATEX "NO") - set(DOXYFILE_DOT "NO") set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") - if(DOXYFILE_LATEX STREQUAL "ON") + if(DOXYFILE_LATEX) set(DOXYFILE_GENERATE_LATEX "YES") find_package(LATEX) find_program(DOXYFILE_MAKE make) @@ -140,9 +145,6 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND) if(PDFLATEX_COMPILER) set(DOXYFILE_PDFLATEX "YES") endif() - if(DOXYGEN_DOT_EXECUTABLE) - set(DOXYFILE_DOT "YES") - endif() add_custom_command(TARGET doxygen POST_BUILD From 26090c2f0c9c98753ef4ac6811fc2096742256f4 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Thu, 13 Jun 2019 06:57:54 -0400 Subject: [PATCH 175/186] Set the dot graphs to generate as interactive SVG --- Doxyfile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile.in b/Doxyfile.in index 3499d643..7b54a9c0 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -2371,7 +2371,7 @@ DIRECTORY_GRAPH = YES # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = svg # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. @@ -2383,7 +2383,7 @@ DOT_IMAGE_FORMAT = png # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -INTERACTIVE_SVG = NO +INTERACTIVE_SVG = YES # The DOT_PATH tag can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. From eab81b0b7d0873869dd0bdd40ea4113172007620 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Jun 2019 20:58:43 -0400 Subject: [PATCH 176/186] Upgrade jsoncpp to 1.8.4 This current version supports the new `Json::CharReader`, which replaces the now-deprecated `Json::Reader`. It's necessary to eliminate `Json::Reader` from libopenshot because using it causes a flood of deprecation warnings when building with system jsoncpp. Also, the `thirdparty/jsoncpp` directory was generated using the jsoncpp project's `amalgamate.py` tool, which condenses the library down to a single C++ source file and two headers, making it easier to incorporate into libopenshot. --- src/CMakeLists.txt | 6 +- thirdparty/jsoncpp/LICENSE | 56 +- thirdparty/jsoncpp/include/json/autolink.h | 19 - thirdparty/jsoncpp/include/json/config.h | 43 - thirdparty/jsoncpp/include/json/features.h | 42 - thirdparty/jsoncpp/include/json/forwards.h | 39 - thirdparty/jsoncpp/include/json/json.h | 10 - thirdparty/jsoncpp/include/json/reader.h | 196 - thirdparty/jsoncpp/include/json/value.h | 1069 ---- thirdparty/jsoncpp/include/json/writer.h | 174 - thirdparty/jsoncpp/json/json-forwards.h | 320 + thirdparty/jsoncpp/json/json.h | 2346 +++++++ thirdparty/jsoncpp/jsoncpp.cpp | 5406 +++++++++++++++++ .../src/lib_json/json_batchallocator.h | 125 - .../src/lib_json/json_internalarray.inl | 448 -- .../jsoncpp/src/lib_json/json_internalmap.inl | 607 -- .../jsoncpp/src/lib_json/json_reader.cpp | 883 --- .../jsoncpp/src/lib_json/json_value.cpp | 1717 ------ .../src/lib_json/json_valueiterator.inl | 292 - .../jsoncpp/src/lib_json/json_writer.cpp | 828 --- thirdparty/jsoncpp/src/lib_json/sconscript | 8 - 21 files changed, 8129 insertions(+), 6505 deletions(-) delete mode 100644 thirdparty/jsoncpp/include/json/autolink.h delete mode 100644 thirdparty/jsoncpp/include/json/config.h delete mode 100644 thirdparty/jsoncpp/include/json/features.h delete mode 100644 thirdparty/jsoncpp/include/json/forwards.h delete mode 100644 thirdparty/jsoncpp/include/json/json.h delete mode 100644 thirdparty/jsoncpp/include/json/reader.h delete mode 100644 thirdparty/jsoncpp/include/json/value.h delete mode 100644 thirdparty/jsoncpp/include/json/writer.h create mode 100644 thirdparty/jsoncpp/json/json-forwards.h create mode 100644 thirdparty/jsoncpp/json/json.h create mode 100644 thirdparty/jsoncpp/jsoncpp.cpp delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_batchallocator.h delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_internalarray.inl delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_internalmap.inl delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_reader.cpp delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_value.cpp delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_valueiterator.inl delete mode 100644 thirdparty/jsoncpp/src/lib_json/json_writer.cpp delete mode 100644 thirdparty/jsoncpp/src/lib_json/sconscript diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d793ffa2..7aa16720 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -205,7 +205,7 @@ if (USE_SYSTEM_JSONCPP) message(STATUS "Discovering system JsonCPP - done") else() message(STATUS "Using embedded JsonCpp (USE_SYSTEM_JSONCPP not enabled)") - include_directories("../thirdparty/jsoncpp/include") + include_directories("../thirdparty/jsoncpp") endif(USE_SYSTEM_JSONCPP) ############### PROFILING ################# @@ -262,9 +262,7 @@ SET ( OPENSHOT_SOURCE_FILES IF (NOT USE_SYSTEM_JSONCPP) # Third Party JSON Parser SET ( OPENSHOT_SOURCE_FILES ${OPENSHOT_SOURCE_FILES} - ../thirdparty/jsoncpp/src/lib_json/json_reader.cpp - ../thirdparty/jsoncpp/src/lib_json/json_value.cpp - ../thirdparty/jsoncpp/src/lib_json/json_writer.cpp) + ../thirdparty/jsoncpp/jsoncpp.cpp ) ENDIF (NOT USE_SYSTEM_JSONCPP) # ImageMagic related files diff --git a/thirdparty/jsoncpp/LICENSE b/thirdparty/jsoncpp/LICENSE index d20fb29a..89280a6c 100644 --- a/thirdparty/jsoncpp/LICENSE +++ b/thirdparty/jsoncpp/LICENSE @@ -1 +1,55 @@ -The json-cpp library and this documentation are in Public Domain. +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. diff --git a/thirdparty/jsoncpp/include/json/autolink.h b/thirdparty/jsoncpp/include/json/autolink.h deleted file mode 100644 index 37c9258e..00000000 --- a/thirdparty/jsoncpp/include/json/autolink.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef JSON_AUTOLINK_H_INCLUDED -# define JSON_AUTOLINK_H_INCLUDED - -# include "config.h" - -# ifdef JSON_IN_CPPTL -# include -# endif - -# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) -# define CPPTL_AUTOLINK_NAME "json" -# undef CPPTL_AUTOLINK_DLL -# ifdef JSON_DLL -# define CPPTL_AUTOLINK_DLL -# endif -# include "autolink.h" -# endif - -#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/config.h b/thirdparty/jsoncpp/include/json/config.h deleted file mode 100644 index 5d334cbc..00000000 --- a/thirdparty/jsoncpp/include/json/config.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef JSON_CONFIG_H_INCLUDED -# define JSON_CONFIG_H_INCLUDED - -/// If defined, indicates that json library is embedded in CppTL library. -//# define JSON_IN_CPPTL 1 - -/// If defined, indicates that json may leverage CppTL library -//# define JSON_USE_CPPTL 1 -/// If defined, indicates that cpptl vector based map should be used instead of std::map -/// as Value container. -//# define JSON_USE_CPPTL_SMALLMAP 1 -/// If defined, indicates that Json specific container should be used -/// (hash table & simple deque container with customizable allocator). -/// THIS FEATURE IS STILL EXPERIMENTAL! -//# define JSON_VALUE_USE_INTERNAL_MAP 1 -/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. -/// The memory pools allocator used optimization (initializing Value and ValueInternalLink -/// as if it was a POD) that may cause some validation tool to report errors. -/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. -//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 - -/// If defined, indicates that Json use exception to report invalid type manipulation -/// instead of C assert macro. -# define JSON_USE_EXCEPTION 1 - -# ifdef JSON_IN_CPPTL -# include -# ifndef JSON_USE_CPPTL -# define JSON_USE_CPPTL 1 -# endif -# endif - -# ifdef JSON_IN_CPPTL -# define JSON_API CPPTL_API -# elif defined(JSON_DLL_BUILD) -# define JSON_API __declspec(dllexport) -# elif defined(JSON_DLL) -# define JSON_API __declspec(dllimport) -# else -# define JSON_API -# endif - -#endif // JSON_CONFIG_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/features.h b/thirdparty/jsoncpp/include/json/features.h deleted file mode 100644 index ac25b887..00000000 --- a/thirdparty/jsoncpp/include/json/features.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef CPPTL_JSON_FEATURES_H_INCLUDED -# define CPPTL_JSON_FEATURES_H_INCLUDED - -# include "forwards.h" - -namespace Json { - - /** @brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ - class JSON_API Features - { - public: - /** @brief A configuration that allows all features and assumes all strings are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** @brief A configuration that is strictly compatible with the JSON specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** @brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_; - - /// \c true if root must be either an array or an object value. Default: \c false. - bool strictRoot_; - }; - -} // namespace Json - -#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/forwards.h b/thirdparty/jsoncpp/include/json/forwards.h deleted file mode 100644 index d0ce8300..00000000 --- a/thirdparty/jsoncpp/include/json/forwards.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef JSON_FORWARDS_H_INCLUDED -# define JSON_FORWARDS_H_INCLUDED - -# include "config.h" - -namespace Json { - - // writer.h - class FastWriter; - class StyledWriter; - - // reader.h - class Reader; - - // features.h - class Features; - - // value.h - typedef int Int; - typedef unsigned int UInt; - class StaticString; - class Path; - class PathArgument; - class Value; - class ValueIteratorBase; - class ValueIterator; - class ValueConstIterator; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - class ValueAllocator; - class ValueMapAllocator; - class ValueInternalLink; - class ValueInternalArray; - class ValueInternalMap; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - -} // namespace Json - - -#endif // JSON_FORWARDS_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/json.h b/thirdparty/jsoncpp/include/json/json.h deleted file mode 100644 index c71ed65a..00000000 --- a/thirdparty/jsoncpp/include/json/json.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef JSON_JSON_H_INCLUDED -# define JSON_JSON_H_INCLUDED - -# include "autolink.h" -# include "value.h" -# include "reader.h" -# include "writer.h" -# include "features.h" - -#endif // JSON_JSON_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/reader.h b/thirdparty/jsoncpp/include/json/reader.h deleted file mode 100644 index 95da3767..00000000 --- a/thirdparty/jsoncpp/include/json/reader.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef CPPTL_JSON_READER_H_INCLUDED -# define CPPTL_JSON_READER_H_INCLUDED - -# include "features.h" -# include "value.h" -# include -# include -# include -# include - -namespace Json { - - /** @brief Unserialize a JSON document into a Value. - * - */ - class JSON_API Reader - { - public: - typedef char Char; - typedef const Char *Location; - - /** @brief Constructs a Reader allowing all features - * for parsing. - */ - Reader(); - - /** @brief Constructs a Reader allowing the specified feature set - * for parsing. - */ - Reader( const Features &features ); - - /** @brief Read a Value from a JSON document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const std::string &document, - Value &root, - bool collectComments = true ); - - /** @brief Read a Value from a JSON document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments = true ); - - /// @brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse( std::istream &is, - Value &root, - bool collectComments = true ); - - /** @brief Returns a user friendly string that list errors in the parsed document. - * \return Formatted error message with the list of errors with their location in - * the parsed document. An empty string is returned if no error occurred - * during parsing. - */ - std::string getFormatedErrorMessages() const; - - private: - enum TokenType - { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token - { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo - { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque Errors; - - bool expectToken( TokenType type, Token &token, const char *message ); - bool readToken( Token &token ); - void skipSpaces(); - bool match( Location pattern, - int patternLength ); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject( Token &token ); - bool readArray( Token &token ); - bool decodeNumber( Token &token ); - bool decodeString( Token &token ); - bool decodeString( Token &token, std::string &decoded ); - bool decodeDouble( Token &token ); - bool decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool addError( const std::string &message, - Token &token, - Location extra = 0 ); - bool recoverFromError( TokenType skipUntilToken ); - bool addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ); - void skipUntilSpace(); - Value ¤tValue(); - Char getNextChar(); - void getLocationLineAndColumn( Location location, - int &line, - int &column ) const; - std::string getLocationLineAndColumn( Location location ) const; - void addComment( Location begin, - Location end, - CommentPlacement placement ); - void skipCommentTokens( Token &token ); - - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value *lastValue_; - std::string commentsBefore_; - Features features_; - bool collectComments_; - }; - - /** @brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - Json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim - { - "dir": { - "file": { - // The input stream JSON would be nested here. - } - } - } - \endverbatim - \throw std::exception on parse error. - \see Json::operator<<() - */ - std::istream& operator>>( std::istream&, Value& ); - -} // namespace Json - -#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/value.h b/thirdparty/jsoncpp/include/json/value.h deleted file mode 100644 index 7e56ded6..00000000 --- a/thirdparty/jsoncpp/include/json/value.h +++ /dev/null @@ -1,1069 +0,0 @@ -#ifndef CPPTL_JSON_H_INCLUDED -# define CPPTL_JSON_H_INCLUDED - -# include "forwards.h" -# include -# include - -# ifndef JSON_USE_CPPTL_SMALLMAP -# include -# else -# include -# endif -# ifdef JSON_USE_CPPTL -# include -# endif - -/** @brief JSON (JavaScript Object Notation). - */ -namespace Json { - - /** @brief Type of the value held by a Value object. - */ - enum ValueType - { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). - }; - - enum CommentPlacement - { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for root value) - numberOfCommentPlacement - }; - -//# ifdef JSON_USE_CPPTL -// typedef CppTL::AnyEnumerator EnumMemberNames; -// typedef CppTL::AnyEnumerator EnumValues; -//# endif - - /** @brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignement takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - class JSON_API StaticString - { - public: - explicit StaticString( const char *czstring ) - : str_( czstring ) - { - } - - operator const char *() const - { - return str_; - } - - const char *c_str() const - { - return str_; - } - - private: - const char *str_; - }; - - /** @brief Represents a JSON value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. - * Non const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resize and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtanis default value in the case the required element - * does not exist. - * - * It is possible to iterate over the list of a #objectValue values using - * the getMemberNames() method. - */ - class JSON_API Value - { - friend class ValueIteratorBase; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - friend class ValueInternalLink; - friend class ValueInternalMap; -# endif - public: - typedef std::vector Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; - typedef UInt ArrayIndex; - - static const Value null; - static const Int minInt; - static const Int maxInt; - static const UInt maxUInt; - - private: -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION -# ifndef JSON_VALUE_USE_INTERNAL_MAP - class CZString - { - public: - enum DuplicationPolicy - { - noDuplication = 0, - duplicate, - duplicateOnCopy - }; - CZString( int index ); - CZString( const char *cstr, DuplicationPolicy allocate ); - CZString( const CZString &other ); - ~CZString(); - CZString &operator =( const CZString &other ); - bool operator<( const CZString &other ) const; - bool operator==( const CZString &other ) const; - int index() const; - const char *c_str() const; - bool isStaticString() const; - private: - void swap( CZString &other ); - const char *cstr_; - int index_; - }; - - public: -# ifndef JSON_USE_CPPTL_SMALLMAP - typedef std::map ObjectValues; -# else - typedef CppTL::SmallMap ObjectValues; -# endif // ifndef JSON_USE_CPPTL_SMALLMAP -# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - public: - /** @brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass arrayValue. - To create an empty object, pass objectValue. - Another Value can then be set to this one by assignment. - This is useful since clear() and resize() will not alter types. - - Examples: - \code - Json::Value null_value; // null - Json::Value arr_value(Json::arrayValue); // [] - Json::Value obj_value(Json::objectValue); // {} - \endcode - */ - Value( ValueType type = nullValue ); - Value( Int value ); - Value( UInt value ); - Value( double value ); - Value( const char *value ); - Value( const char *beginValue, const char *endValue ); - /** @brief Constructs a value from a static string. - - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to this - * constructor. - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * \endcode - */ - Value( const StaticString &value ); - Value( const std::string &value ); -# ifdef JSON_USE_CPPTL - Value( const CppTL::ConstString &value ); -# endif - Value( bool value ); - Value( const Value &other ); - ~Value(); - - Value &operator=( const Value &other ); - /// Swap values. - /// \note Currently, comments are intentionally not swapped, for - /// both logic and efficiency. - void swap( Value &other ); - - ValueType type() const; - - bool operator <( const Value &other ) const; - bool operator <=( const Value &other ) const; - bool operator >=( const Value &other ) const; - bool operator >( const Value &other ) const; - - bool operator ==( const Value &other ) const; - bool operator !=( const Value &other ) const; - - int compare( const Value &other ); - - const char *asCString() const; - std::string asString() const; -# ifdef JSON_USE_CPPTL - CppTL::ConstString asConstString() const; -# endif - Int asInt() const; - UInt asUInt() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isUInt() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - bool isConvertibleTo( ValueType other ) const; - - /// Number of values in array or object - UInt size() const; - - /// @brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return isNull() - bool operator!() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to size elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize( UInt size ); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value &operator[]( UInt index ); - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value &operator[]( UInt index ) const; - /// If the array contains at least index+1 elements, returns the element value, - /// otherwise returns defaultValue. - Value get( UInt index, - const Value &defaultValue ) const; - /// Return true if index < size(). - bool isValidIndex( UInt index ) const; - /// @brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value &append( const Value &value ); - - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const char *key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const char *key ) const; - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const std::string &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const std::string &key ) const; - /** @brief Access an object value by name, create a null member if it does not exist. - - * If the object as no entry for that name, then the member name used to store - * the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value &operator[]( const StaticString &key ); -# ifdef JSON_USE_CPPTL - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const CppTL::ConstString &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const CppTL::ConstString &key ) const; -# endif - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const char *key, - const Value &defaultValue ) const; - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const std::string &key, - const Value &defaultValue ) const; -# ifdef JSON_USE_CPPTL - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const CppTL::ConstString &key, - const Value &defaultValue ) const; -# endif - /// @brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - Value removeMember( const char* key ); - /// Same as removeMember(const char*) - Value removeMember( const std::string &key ); - - /// Return true if the object has a member named key. - bool isMember( const char *key ) const; - /// Return true if the object has a member named key. - bool isMember( const std::string &key ) const; -# ifdef JSON_USE_CPPTL - /// Return true if the object has a member named key. - bool isMember( const CppTL::ConstString &key ) const; -# endif - - /// @brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - -//# ifdef JSON_USE_CPPTL -// EnumMemberNames enumMemberNames() const; -// EnumValues enumValues() const; -//# endif - - /// Comments must be //... or /* ... */ - void setComment( const char *comment, - CommentPlacement placement ); - /// Comments must be //... or /* ... */ - void setComment( const std::string &comment, - CommentPlacement placement ); - bool hasComment( CommentPlacement placement ) const; - /// Include delimiters and embedded newlines. - std::string getComment( CommentPlacement placement ) const; - - std::string toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - private: - Value &resolveReference( const char *key, - bool isStatic ); - -# ifdef JSON_VALUE_USE_INTERNAL_MAP - inline bool isItemAvailable() const - { - return itemIsUsed_ == 0; - } - - inline void setItemUsed( bool isUsed = true ) - { - itemIsUsed_ = isUsed ? 1 : 0; - } - - inline bool isMemberNameStatic() const - { - return memberNameIsStatic_ == 0; - } - - inline void setMemberNameIsStatic( bool isStatic ) - { - memberNameIsStatic_ = isStatic ? 1 : 0; - } -# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP - - private: - struct CommentInfo - { - CommentInfo(); - ~CommentInfo(); - - void setComment( const char *text ); - - char *comment_; - }; - - //struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder - { - Int int_; - UInt uint_; - double real_; - bool bool_; - char *string_; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - ValueInternalArray *array_; - ValueInternalMap *map_; -#else - ObjectValues *map_; -# endif - } value_; - ValueType type_ : 8; - int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. -# ifdef JSON_VALUE_USE_INTERNAL_MAP - unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. - int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. -# endif - CommentInfo *comments_; - }; - - - /** @brief Experimental and untested: represents an element of the "path" to access a node. - */ - class PathArgument - { - public: - friend class Path; - - PathArgument(); - PathArgument( UInt index ); - PathArgument( const char *key ); - PathArgument( const std::string &key ); - - private: - enum Kind - { - kindNone = 0, - kindIndex, - kindKey - }; - std::string key_; - UInt index_; - Kind kind_; - }; - - /** @brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provied as parameter - */ - class Path - { - public: - Path( const std::string &path, - const PathArgument &a1 = PathArgument(), - const PathArgument &a2 = PathArgument(), - const PathArgument &a3 = PathArgument(), - const PathArgument &a4 = PathArgument(), - const PathArgument &a5 = PathArgument() ); - - const Value &resolve( const Value &root ) const; - Value resolve( const Value &root, - const Value &defaultValue ) const; - /// Creates the "path" to access the specified node and returns a reference on the node. - Value &make( Value &root ) const; - - private: - typedef std::vector InArgs; - typedef std::vector Args; - - void makePath( const std::string &path, - const InArgs &in ); - void addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ); - void invalidPath( const std::string &path, - int location ); - - Args args_; - }; - - /** @brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. - * - * - makeMemberName() and releaseMemberName() are called to respectively duplicate and - * free an Json::objectValue member name. - * - duplicateStringValue() and releaseStringValue() are called similarly to - * duplicate and free a Json::stringValue value. - */ - class ValueAllocator - { - public: - enum { unknown = (unsigned)-1 }; - - virtual ~ValueAllocator(); - - virtual char *makeMemberName( const char *memberName ) = 0; - virtual void releaseMemberName( char *memberName ) = 0; - virtual char *duplicateStringValue( const char *value, - unsigned int length = unknown ) = 0; - virtual void releaseStringValue( char *value ) = 0; - }; - -#ifdef JSON_VALUE_USE_INTERNAL_MAP - /** @brief Allocator to customize Value internal map. - * Below is an example of a simple implementation (default implementation actually - * use memory pool for speed). - * \code - class DefaultValueMapAllocator : public ValueMapAllocator - { - public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - return new ValueInternalMap(); - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - return new ValueInternalMap( other ); - } - - virtual void destructMap( ValueInternalMap *map ) - { - delete map; - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - return new ValueInternalLink(); - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - delete link; - } - }; - * \endcode - */ - class JSON_API ValueMapAllocator - { - public: - virtual ~ValueMapAllocator(); - virtual ValueInternalMap *newMap() = 0; - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; - virtual void destructMap( ValueInternalMap *map ) = 0; - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; - virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; - virtual ValueInternalLink *allocateMapLink() = 0; - virtual void releaseMapLink( ValueInternalLink *link ) = 0; - }; - - /** @brief ValueInternalMap hash-map bucket chain link (for internal use only). - * \internal previous_ & next_ allows for bidirectional traversal. - */ - class JSON_API ValueInternalLink - { - public: - enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. - enum InternalFlags { - flagAvailable = 0, - flagUsed = 1 - }; - - ValueInternalLink(); - - ~ValueInternalLink(); - - Value items_[itemPerLink]; - char *keys_[itemPerLink]; - ValueInternalLink *previous_; - ValueInternalLink *next_; - }; - - - /** @brief A linked page based hash-table implementation used internally by Value. - * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked - * list in each bucket to handle collision. There is an addional twist in that - * each node of the collision linked list is a page containing a fixed amount of - * value. This provides a better compromise between memory usage and speed. - * - * Each bucket is made up of a chained list of ValueInternalLink. The last - * link of a given bucket can be found in the 'previous_' field of the following bucket. - * The last link of the last bucket is stored in tailLink_ as it has no following bucket. - * Only the last link of a bucket may contains 'available' item. The last link always - * contains at least one element unless is it the bucket one very first link. - */ - class JSON_API ValueInternalMap - { - friend class ValueIteratorBase; - friend class Value; - public: - typedef unsigned int HashKey; - typedef unsigned int BucketIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState - { - IteratorState() - : map_(0) - , link_(0) - , itemIndex_(0) - , bucketIndex_(0) - { - } - ValueInternalMap *map_; - ValueInternalLink *link_; - BucketIndex itemIndex_; - BucketIndex bucketIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalMap(); - ValueInternalMap( const ValueInternalMap &other ); - ValueInternalMap &operator =( const ValueInternalMap &other ); - ~ValueInternalMap(); - - void swap( ValueInternalMap &other ); - - BucketIndex size() const; - - void clear(); - - bool reserveDelta( BucketIndex growth ); - - bool reserve( BucketIndex newItemCount ); - - const Value *find( const char *key ) const; - - Value *find( const char *key ); - - Value &resolveReference( const char *key, - bool isStatic ); - - void remove( const char *key ); - - void doActualRemove( ValueInternalLink *link, - BucketIndex index, - BucketIndex bucketIndex ); - - ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); - - Value &setNewItem( const char *key, - bool isStatic, - ValueInternalLink *link, - BucketIndex index ); - - Value &unsafeAdd( const char *key, - bool isStatic, - HashKey hashedKey ); - - HashKey hash( const char *key ) const; - - int compare( const ValueInternalMap &other ) const; - - private: - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void incrementBucket( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static const char *key( const IteratorState &iterator ); - static const char *key( const IteratorState &iterator, bool &isStatic ); - static Value &value( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - - private: - ValueInternalLink *buckets_; - ValueInternalLink *tailLink_; - BucketIndex bucketsSize_; - BucketIndex itemCount_; - }; - - /** @brief A simplified deque implementation used internally by Value. - * \internal - * It is based on a list of fixed "page", each page contains a fixed number of items. - * Instead of using a linked-list, a array of pointer is used for fast item look-up. - * Look-up for an element is as follow: - * - compute page index: pageIndex = itemIndex / itemsPerPage - * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] - * - * Insertion is amortized constant time (only the array containing the index of pointers - * need to be reallocated when items are appended). - */ - class JSON_API ValueInternalArray - { - friend class Value; - friend class ValueIteratorBase; - public: - enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. - typedef Value::ArrayIndex ArrayIndex; - typedef unsigned int PageIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState // Must be a POD - { - IteratorState() - : array_(0) - , currentPageIndex_(0) - , currentItemIndex_(0) - { - } - ValueInternalArray *array_; - Value **currentPageIndex_; - unsigned int currentItemIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalArray(); - ValueInternalArray( const ValueInternalArray &other ); - ValueInternalArray &operator =( const ValueInternalArray &other ); - ~ValueInternalArray(); - void swap( ValueInternalArray &other ); - - void clear(); - void resize( ArrayIndex newSize ); - - Value &resolveReference( ArrayIndex index ); - - Value *find( ArrayIndex index ) const; - - ArrayIndex size() const; - - int compare( const ValueInternalArray &other ) const; - - private: - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static Value &dereference( const IteratorState &iterator ); - static Value &unsafeDereference( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - static ArrayIndex indexOf( const IteratorState &iterator ); - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - void makeIterator( IteratorState &it, ArrayIndex index ) const; - - void makeIndexValid( ArrayIndex index ); - - Value **pages_; - ArrayIndex size_; - PageIndex pageCount_; - }; - - /** @brief Experimental: do not use. Allocator to customize Value internal array. - * Below is an example of a simple implementation (actual implementation use - * memory pool). - \code -class DefaultValueArrayAllocator : public ValueArrayAllocator -{ -public: // overridden from ValueArrayAllocator - virtual ~DefaultValueArrayAllocator() - { - } - - virtual ValueInternalArray *newArray() - { - return new ValueInternalArray(); - } - - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) - { - return new ValueInternalArray( other ); - } - - virtual void destruct( ValueInternalArray *array ) - { - delete array; - } - - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) - { - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast( newIndexes ); - } - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) - { - if ( indexes ) - free( indexes ); - } - - virtual Value *allocateArrayPage() - { - return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); - } - - virtual void releaseArrayPage( Value *value ) - { - if ( value ) - free( value ); - } -}; - \endcode - */ - class JSON_API ValueArrayAllocator - { - public: - virtual ~ValueArrayAllocator(); - virtual ValueInternalArray *newArray() = 0; - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; - virtual void destructArray( ValueInternalArray *array ) = 0; - /** @brief Reallocate array page index. - * Reallocates an array of pointer on each page. - * \param indexes [input] pointer on the current index. May be \c NULL. - * [output] pointer on the new index of at least - * \a minNewIndexCount pages. - * \param indexCount [input] current number of pages in the index. - * [output] number of page the reallocated index can handle. - * \b MUST be >= \a minNewIndexCount. - * \param minNewIndexCount Minimum number of page the new index must be able to - * handle. - */ - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) = 0; - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) = 0; - virtual Value *allocateArrayPage() = 0; - virtual void releaseArrayPage( Value *value ) = 0; - }; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - - - /** @brief base class for Value iterators. - * - */ - class ValueIteratorBase - { - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; - - ValueIteratorBase(); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); -#else - ValueIteratorBase( const ValueInternalArray::IteratorState &state ); - ValueIteratorBase( const ValueInternalMap::IteratorState &state ); -#endif - - bool operator ==( const SelfType &other ) const - { - return isEqual( other ); - } - - bool operator !=( const SelfType &other ) const - { - return !isEqual( other ); - } - - difference_type operator -( const SelfType &other ) const - { - return computeDistance( other ); - } - - /// Return either the index or the member name of the referenced value as a Value. - Value key() const; - - /// Return the index of the referenced Value. -1 if it is not an arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value. "" if it is not an objectValue. - const char *memberName() const; - - protected: - Value &deref() const; - - void increment(); - - void decrement(); - - difference_type computeDistance( const SelfType &other ) const; - - bool isEqual( const SelfType &other ) const; - - void copy( const SelfType &other ); - - private: -#ifndef JSON_VALUE_USE_INTERNAL_MAP - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_; -#else - union - { - ValueInternalArray::IteratorState array_; - ValueInternalMap::IteratorState map_; - } iterator_; - bool isArray_; -#endif - }; - - /** @brief const iterator for object and array value. - * - */ - class ValueConstIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef const Value &reference; - typedef const Value *pointer; - typedef ValueConstIterator SelfType; - - ValueConstIterator(); - private: - /*! \internal Use by Value to create an iterator. - */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); -#else - ValueConstIterator( const ValueInternalArray::IteratorState &state ); - ValueConstIterator( const ValueInternalMap::IteratorState &state ); -#endif - public: - SelfType &operator =( const ValueIteratorBase &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; - - - /** @brief Iterator for object and array value. - */ - class ValueIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef Value &reference; - typedef Value *pointer; - typedef ValueIterator SelfType; - - ValueIterator(); - ValueIterator( const ValueConstIterator &other ); - ValueIterator( const ValueIterator &other ); - private: - /*! \internal Use by Value to create an iterator. - */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); -#else - ValueIterator( const ValueInternalArray::IteratorState &state ); - ValueIterator( const ValueInternalMap::IteratorState &state ); -#endif - public: - - SelfType &operator =( const SelfType &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; - - -} // namespace Json - - -#endif // CPPTL_JSON_H_INCLUDED diff --git a/thirdparty/jsoncpp/include/json/writer.h b/thirdparty/jsoncpp/include/json/writer.h deleted file mode 100644 index 706c8e6a..00000000 --- a/thirdparty/jsoncpp/include/json/writer.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef JSON_WRITER_H_INCLUDED -# define JSON_WRITER_H_INCLUDED - -# include "value.h" -# include -# include -# include - -namespace Json { - - class Value; - - /** @brief Abstract class for writers. - */ - class JSON_API Writer - { - public: - virtual ~Writer(); - - virtual std::string write( const Value &root ) = 0; - }; - - /** @brief Outputs a Value in JSON format without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' consumption, - * but may be usefull to support feature such as RPC where bandwith is limited. - * \sa Reader, Value - */ - class JSON_API FastWriter : public Writer - { - public: - FastWriter(); - virtual ~FastWriter(){} - - void enableYAMLCompatibility(); - - public: // overridden from Writer - virtual std::string write( const Value &root ); - - private: - void writeValue( const Value &value ); - - std::string document_; - bool yamlCompatiblityEnabled_; - }; - - /** @brief Writes a Value in JSON format in a human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledWriter: public Writer - { - public: - StyledWriter(); - virtual ~StyledWriter(){} - - public: // overridden from Writer - /** @brief Serialize a Value in JSON format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - virtual std::string write( const Value &root ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; - bool addChildValues_; - }; - - /** @brief Writes a Value in JSON format in a human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledStreamWriter - { - public: - StyledStreamWriter( std::string indentation="\t" ); - ~StyledStreamWriter(){} - - public: - /** @brief Serialize a Value in JSON format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not return a value. - */ - void write( std::ostream &out, const Value &root ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - bool addChildValues_; - }; - - std::string JSON_API valueToString( Int value ); - std::string JSON_API valueToString( UInt value ); - std::string JSON_API valueToString( double value ); - std::string JSON_API valueToString( bool value ); - std::string JSON_API valueToQuotedString( const char *value ); - - /// @brief Output using the StyledStreamWriter. - /// \see Json::operator>>() - std::ostream& operator<<( std::ostream&, const Value &root ); - -} // namespace Json - - - -#endif // JSON_WRITER_H_INCLUDED diff --git a/thirdparty/jsoncpp/json/json-forwards.h b/thirdparty/jsoncpp/json/json-forwards.h new file mode 100644 index 00000000..dd9a9bf3 --- /dev/null +++ b/thirdparty/jsoncpp/json/json-forwards.h @@ -0,0 +1,320 @@ +/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED +# define JSON_FORWARD_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include +#include +#include +#include +#include +#include +#include + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#elif defined(__GNUC__) || defined(__clang__) +#define JSON_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error \ + "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// As recommended at +// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +extern JSON_API int +msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...); +#define jsoncpp_snprintf msvc_pre1900_c99_snprintf +#else +#define jsoncpp_snprintf std::snprintf +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. +#define JSONCPP_OVERRIDE override + +#if __cplusplus >= 201103L +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER < 1900 +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT +#endif + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates MSVC) +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif // __clang__ || __GNUC__ || _MSC_VER + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "allocator.h" +#include "version.h" + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) + +template +using Allocator = typename std::conditional, + std::allocator>::type; +using String = std::basic_string, Allocator>; +using IStringStream = std::basic_istringstream; +using OStringStream = std::basic_ostringstream; +using IStream = std::istream; +using OStream = std::ostream; +} // namespace Json + +// Legacy names (formerly macros). +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED diff --git a/thirdparty/jsoncpp/json/json.h b/thirdparty/jsoncpp/json/json.h new file mode 100644 index 00000000..c5963843 --- /dev/null +++ b/thirdparty/jsoncpp/json/json.h @@ -0,0 +1,2346 @@ +/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGAMATED_H_INCLUDED +# define JSON_AMALGAMATED_H_INCLUDED +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +#define JSON_VERSION_H_INCLUDED + +#define JSONCPP_VERSION_STRING "1.8.4" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 8 +#define JSONCPP_VERSION_PATCH 4 +#define JSONCPP_VERSION_QUALIFIER +#define JSONCPP_VERSION_HEXA \ + ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ + (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/allocator.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED +#define CPPTL_JSON_ALLOCATOR_H_INCLUDED + +#include +#include + +#pragma pack(push, 8) + +namespace Json { +template class SecureAllocator { +public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) { + // allocate using "global operator new" + return static_cast(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + * The pointer argument is tagged as "volatile" to prevent the + * compiler optimizing out this critical step. + */ + void deallocate(volatile pointer p, size_type n) { + std::memset(p, 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template void construct(pointer p, Args&&... args) { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast(p)) T(std::forward(args)...); + } + + size_type max_size() const { return size_t(-1) / sizeof(T); } + + pointer address(reference x) const { return std::addressof(x); } + + const_pointer address(const_reference x) const { return std::addressof(x); } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template SecureAllocator(const SecureAllocator&) {} + template struct rebind { using other = SecureAllocator; }; +}; + +template +bool operator==(const SecureAllocator&, const SecureAllocator&) { + return true; +} + +template +bool operator!=(const SecureAllocator&, const SecureAllocator&) { + return false; +} + +} // namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/allocator.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include +#include +#include +#include +#include +#include +#include + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgamated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgamated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#elif defined(__GNUC__) || defined(__clang__) +#define JSON_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1800 +#error \ + "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities" +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +// As recommended at +// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +extern JSON_API int +msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...); +#define jsoncpp_snprintf msvc_pre1900_c99_snprintf +#else +#define jsoncpp_snprintf std::snprintf +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. +#define JSONCPP_OVERRIDE override + +#if __cplusplus >= 201103L +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER < 1900 +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT explicit +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define JSONCPP_NOEXCEPT noexcept +#define JSONCPP_OP_EXPLICIT explicit +#else +#define JSONCPP_NOEXCEPT throw() +#define JSONCPP_OP_EXPLICIT +#endif + +#ifdef __clang__ +#if __has_extension(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif // GNUC version +#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates MSVC) +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif // __clang__ || __GNUC__ || _MSC_VER + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +#include "allocator.h" +#include "version.h" + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) + +template +using Allocator = typename std::conditional, + std::allocator>::type; +using String = std::basic_string, Allocator>; +using IStringStream = std::basic_istringstream; +using OStringStream = std::basic_ostringstream; +using IStream = std::istream; +using OStream = std::ostream; +} // namespace Json + +// Legacy names (formerly macros). +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_{true}; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_{false}; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_{false}; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_{false}; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +// Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +#if defined(_MSC_VER) +#define JSONCPP_NORETURN __declspec(noreturn) +#elif defined(__GNUC__) +#define JSONCPP_NORETURN __attribute__((__noreturn__)) +#else +#define JSONCPP_NORETURN +#endif +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(String msg); + ~Exception() JSONCPP_NOEXCEPT override; + char const* what() const JSONCPP_NOEXCEPT override; + +protected: + String msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(String const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(String const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(String const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(String const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +/** \brief Type of precision for formatting of real values. + */ +enum PrecisionType { + significantDigits = 0, ///< we set max number of significant digits in string + decimalPlaces ///< we set max number of digits after "." in string +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignment takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of member keys of an object using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; + +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + // Required for boost integration, e. g. BOOST_TEST + typedef std::string value_type; + + static const Value& null; ///< We regret this reference to a global instance; + ///< prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same + ///< as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + + /// Default precision for real value for string representation. + static const UInt defaultRealPrecision; + +// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler +// when using gcc and clang backend compilers. CZString +// cannot be defined as private. See issue #486 +#ifdef __NVCC__ +public: +#else +private: +#endif +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); + CZString(CZString&& other); + ~CZString(); + CZString& operator=(const CZString& other); + CZString& operator=(CZString&& other); + + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + // const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_ : 2; + unsigned length_ : 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const String& value); ///< Copy data() til size(). Embedded + ///< zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + Value(const Value& other); + Value(Value&& other); + ~Value(); + + /// \note Overwrite existing comments. To preserve comments, use + /// #swapPayload(). + Value& operator=(const Value& other); + Value& operator=(Value&& other); + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; // Allows you to understand the length of + // the CString +#endif + String asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString(char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return !isNull() + JSONCPP_OP_EXPLICIT operator bool() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to newSize elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex newSize); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + Value& append(Value&& value); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const String& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const String& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to + store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value + get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const String& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + void removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + void removeMember(const String& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(String const& key, Value* removed); + /// Same as removeMember(String const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true if removed (no exceptions) + */ + bool removeIndex(ArrayIndex index, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const String& key) const; + /// Same as isMember(String const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(String const&) instead.") + void setComment(const char* comment, CommentPlacement placement) { + setComment(String(comment, strlen(comment)), placement); + } + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement) { + setComment(String(comment, len), placement); + } + /// Comments must be //... or /* ... */ + void setComment(String comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + String getComment(CommentPlacement placement) const; + + String toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void setType(ValueType v) { bits_.value_type_ = static_cast (v); } + bool isAllocated() const { return bits_.allocated_; } + void setIsAllocated(bool v) { bits_.allocated_ = v; } + + void initBasic(ValueType type, bool allocated = false); + void dupPayload(const Value& other); + void releasePayload(); + void dupMeta(const Value& other); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // if allocated_, ptr to { unsigned, char[] }. + ObjectValues* map_; + } value_; + + struct { + // Really a ValueType, but types should agree for bitfield packing. + unsigned int value_type_ : 8; + // Unless allocated_, string_ must be null-terminated. + unsigned int allocated_ : 1; + } bits_; + + class Comments { + public: + Comments() = default; + Comments(const Comments& that); + Comments(Comments&& that); + Comments& operator=(const Comments& that); + Comments& operator=(Comments&& that); + bool has(CommentPlacement slot) const; + String get(CommentPlacement slot) const; + void set(CommentPlacement slot, String s); + + private: + using Array = std::array; + std::unique_ptr ptr_; + }; + Comments comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const String& key); + +private: + enum Kind { kindNone = 0, kindIndex, kindKey }; + String key_; + ArrayIndex index_{}; + Kind kind_{kindNone}; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const String& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const String& path, const InArgs& in); + void addPathInArg(const String& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + static void invalidPath(const String& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an + /// arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + String name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be + /// embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_{true}; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + // typedef unsigned int size_t; + // typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: + /*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); + +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +inline void swap(Value& a, Value& b) { a.swap(b); } + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(IStream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + String getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + String getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const String& message, const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + String message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, String& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const String& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + String getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static String normalizeEOL(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + String document_; + Location begin_{}; + Location end_{}; + Location current_{}; + Location lastValueEnd_{}; + Value* lastValue_{}; + String commentsBefore_; + Features features_; + bool collectComments_{}; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() = default; + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to + read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + String* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() = default; + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + String errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See + StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an + object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() override; + + CharReader* newCharReader() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream(CharReader::Factory const&, + IStream&, + Value* root, + std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API IStream& operator>>(IStream&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#pragma pack(push, 8) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + OStream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the + stream instead.) \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, OStream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +String JSON_API writeString(StreamWriter::Factory const& factory, + Value const& root); + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "". + - Setting this to an empty string also omits newline characters. + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's JavaScript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative + infinity as "-Infinity". + - "precision": int + - Number of precision digits for formatting of real values. + - "precisionType": "significant"(default) or "decimal" + - Type of precision for formatting of real values. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() override; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const override; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](const String& key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +public: + virtual ~Writer(); + + virtual String write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be useful to support feature such as RPC where bandwidth is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter + : public Writer { +public: + FastWriter(); + ~FastWriter() override = default; + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's JavaScript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + + String document_; + bool yamlCompatibilityEnabled_{false}; + bool dropNullPlaceholders_{false}; + bool omitEndingLineFeed_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() override = default; + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + String write(const Value& root) override; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + String document_; + String indentString_; + unsigned int rightMargin_{74}; + unsigned int indentSize_{3}; + bool addChildValues_{false}; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4996) // Deriving from deprecated class +#endif +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API + StyledStreamWriter { +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(String indentation = "\t"); + ~StyledStreamWriter() = default; + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(OStream& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultilineArray(const Value& value); + void pushValue(const String& value); + void writeIndent(); + void writeWithIndent(const String& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + static bool hasCommentForValue(const Value& value); + static String normalizeEOL(const String& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + OStream* document_; + String indentString_; + unsigned int rightMargin_{74}; + String indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(JSON_HAS_INT64) +String JSON_API valueToString(Int value); +String JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +String JSON_API valueToString(LargestInt value); +String JSON_API valueToString(LargestUInt value); +String JSON_API +valueToString(double value, + unsigned int precision = Value::defaultRealPrecision, + PrecisionType precisionType = PrecisionType::significantDigits); +String JSON_API valueToString(bool value); +String JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API OStream& operator<<(OStream&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +#define JSON_ASSERT(condition) \ + { \ + if (!(condition)) { \ + Json::throwLogicError("assert json failed"); \ + } \ + } + +#define JSON_FAIL_MESSAGE(message) \ + { \ + OStringStream oss; \ + oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +#define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +#define JSON_FAIL_MESSAGE(message) \ + { \ + OStringStream oss; \ + oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGAMATED_H_INCLUDED diff --git a/thirdparty/jsoncpp/jsoncpp.cpp b/thirdparty/jsoncpp/jsoncpp.cpp new file mode 100644 index 00000000..86ca3435 --- /dev/null +++ b/thirdparty/jsoncpp/jsoncpp.cpp @@ -0,0 +1,5406 @@ +/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and +The JsonCpp Authors, and is released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" + +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include +#endif + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include +#endif + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { +static inline char getDecimalPoint() { +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline String codePointToUTF8(unsigned int cp) { + String result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned integer to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +template Iter fixNumericLocale(Iter begin, Iter end) { + for (; begin != end; ++begin) { + if (*begin == ',') { + *begin = '.'; + } + } + return begin; +} + +template void fixNumericLocaleInput(Iter begin, Iter end) { + char decimalPoint = getDecimalPoint(); + if (decimalPoint == '\0' || decimalPoint == '.') { + return; + } + for (; begin != end; ++begin) { + if (*begin == '.') { + *begin = decimalPoint; + } + } +} + +/** + * Return iterator that would be the new end of the range [begin,end), if we + * were to delete zeros in the end of string, but not the last zero before '.'. + */ +template Iter fixZerosInTheEnd(Iter begin, Iter end) { + for (; begin != end; --end) { + if (*(end - 1) != '0') { + return end; + } + // Don't delete the last zero before the decimal point. + if (begin != (end - 1) && *(end - 2) == '.') { + return end; + } + } + return end; +} + +} // namespace Json + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if __cplusplus >= 201103L + +#if !defined(sscanf) +#define sscanf std::sscanf +#endif + +#endif //__cplusplus + +#if defined(_MSC_VER) +#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES +#endif //_MSC_VER + +#if defined(_MSC_VER) +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile +// time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = + JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() = default; + +Features Features::all() { return {}; } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), commentsBefore_(), features_(Features::all()) {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool Reader::parse(const std::string& document, + Value& root, + bool collectComments) { + document_.assign(document.begin(), document.end()); + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& is, Value& root, bool collectComments) { + // std::istream_iterator begin(is); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since String is reference-counted, this at least does not + // create an extra copy. + String doc; + std::getline(is, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just + // after calling readValue(). parse() executes one nodes_.push(), so > instead + // of >=. + if (nodes_.size() > stackLimit_g) + throwRuntimeError("Exceeded stackLimit in readValue()."); + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { + String normalized; + normalized.reserve(static_cast(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void Reader::addComment(Location begin, + Location end, + CommentPlacement placement) { + assert(collectComments_); + const String& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != nullptr); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char* p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } +} + +bool Reader::readString() { + Char c = '\0'; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& token) { + Token tokenName; + String name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = String(numberName.asCString()); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool Reader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + auto digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + String buffer(token.start_, token.end_); + IStringStream is(buffer); + if (!(is >> value)) + return addError( + "'" + String(token.start_, token.end_) + "' is not a number.", token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + String decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, String& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool Reader::addError(const String& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + size_t const errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const String& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +String Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +String Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +String Reader::getFormattedErrorMessages() const { + String formattedMessage; + for (const auto& error : errors_) { + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector Reader::getStructuredErrors() const { + std::vector allErrors; + for (const auto& error : errors_) { + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const String& message) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = nullptr; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, + const String& message, + const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { return errors_.empty(); } + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + size_t stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return {}; } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + String message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + String getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const String& message); + bool pushError(const Value& value, const String& message, const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + String message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, String& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const String& message, Token& token, Location extra = nullptr); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const String& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + String getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static String normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + String document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + String commentsBefore_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +bool OurReader::containsNewLine(OurReader::Location begin, + OurReader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; + commentsBefore_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if ((features_.strictRoot_ || token.type_ != tokenError) && + token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + // To preserve the old behaviour we cast size_t to int. + if (nodes_.size() > features_.stackLimit_) + throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenFalse: { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNull: { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNaN: { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenPosInf: { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenNegInf: { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else fall through + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +String OurReader::normalizeEOL(OurReader::Location begin, + OurReader::Location end) { + String normalized; + normalized.reserve(static_cast(end - begin)); + OurReader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void OurReader::addComment(Location begin, + Location end, + CommentPlacement placement) { + assert(collectComments_); + const String& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != nullptr); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while ((current_ + 1) < end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char* p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : '\0'; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : '\0'; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : '\0'; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& token) { + Token tokenName; + String name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name.clear(); + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover("Missing ':' after object member name", colon, + tokenObjectEnd); + } + if (name.length() >= (1U << 30)) + throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + String msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover(msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover("Missing ',' or '}' in object declaration", + comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover("Missing '}' or object member name", tokenName, + tokenObjectEnd); +} + +bool OurReader::readArray(Token& token) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(token.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token currentToken; + // Accept Comment after last item in the array. + ok = readToken(currentToken); + while (currentToken.type_ == tokenComment && ok) { + ok = readToken(currentToken); + } + bool badTokenType = (currentToken.type_ != tokenArraySeparator && + currentToken.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover("Missing ',' or ']' in array declaration", + currentToken, tokenArrayEnd); + } + if (currentToken.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of + // them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + auto digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + auto const ulength = static_cast(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } else { + String buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError( + "'" + String(token.start_, token.end_) + "' is not a number.", token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + String decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, String& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, current); + if (*(current++) == '\\' && *(current++) == 'u') { + unsigned int surrogatePair; + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool OurReader::addError(const String& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const String& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +String OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +String OurReader::getFormattedErrorMessages() const { + String formattedMessage; + for (const auto& error : errors_) { + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector OurReader::getStructuredErrors() const { + std::vector allErrors; + for (const auto& error : errors_) { + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const String& message) { + ptrdiff_t length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = nullptr; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, + const String& message, + const Value& extra) { + ptrdiff_t length = end_ - begin_; + if (value.getOffsetStart() > length || value.getOffsetLimit() > length || + extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { return errors_.empty(); } + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; + +public: + OurCharReader(bool collectComments, OurFeatures const& features) + : collectComments_(collectComments), reader_(features) {} + bool parse(char const* beginDoc, + char const* endDoc, + Value* root, + String* errs) override { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } +CharReaderBuilder::~CharReaderBuilder() = default; +CharReader* CharReaderBuilder::newCharReader() const { + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = + settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); +#if defined(JSON_HAS_INT64) + features.stackLimit_ = settings_["stackLimit"].asUInt64(); +#else + features.stackLimit_ = settings_["stackLimit"].asUInt(); +#endif + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) { + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const { + Json::Value my_invalid; + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + String const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return inv.empty(); +} +Value& CharReaderBuilder::operator[](const String& key) { + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) { + //! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; + //! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) { + //! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; + //! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream(CharReader::Factory const& fact, + IStream& sin, + Value* root, + String* errs) { + OStringStream ssin; + ssin << sin.rdbuf(); + String doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +IStream& operator>>(IStream& sin, Value& root) { + CharReaderBuilder b; + String errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() : current_() {} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { return current_->second; } + +void ValueIteratorBase::increment() { ++current_; } + +void ValueIteratorBase::decrement() { --current_; } + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +String ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) + return String(); + return String(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = nullptr; + return nullptr; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() = default; + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() = default; + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) = default; + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // min() +#include // size_t + +// Provide implementation equivalent of std::snprintf for older _MSC compilers +#if defined(_MSC_VER) && _MSC_VER < 1900 +#include +static int msvc_pre1900_c99_vsnprintf(char* outBuf, + size_t size, + const char* format, + va_list ap) { + int count = -1; + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + return count; +} + +int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, + size_t size, + const char* format, + ...) { + va_list ap; + va_start(ap, format); + const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + return count; +} +#endif + +// Disable warning C4702 : unreachable code +#if defined(_MSC_VER) +#pragma warning(disable : 4702) +#endif + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +template +static std::unique_ptr cloneUnique(const std::unique_ptr& p) { + std::unique_ptr r; + if (p) { + r = std::unique_ptr(new T(*p)); + } + return r; +} + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +// static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +// const unsigned char& kNullRef = kNull[0]; +// const Value& Value::null = reinterpret_cast(kNullRef); +// const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() { + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but +// DO NOT use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +const UInt Value::defaultRealPrecision = 17; + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + // return d >= static_cast(min) && d <= static_cast(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + + static_cast(Int64(value & 1)); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == nullptr) { + throwRuntimeError("in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue(const char* value, + unsigned int length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - + sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == nullptr) { + throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = + 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString(bool isPrefixed, + char const* prefixed, + unsigned* length, + char const** value) { + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by + * duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length == 0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { free(value); } +static inline void releaseStringValue(char* value, unsigned) { free(value); } +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(String msg) : msg_(std::move(msg)) {} +Exception::~Exception() JSONCPP_NOEXCEPT {} +char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } +RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} +LogicError::LogicError(String const& msg) : Exception(msg) {} +JSONCPP_NORETURN void throwRuntimeError(String const& msg) { + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(String const& msg) { + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} + +Value::CZString::CZString(char const* str, + unsigned length, + DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = length & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = + static_cast( + other.cstr_ + ? (static_cast(other.storage_.policy_) == + noDuplication + ? noDuplication + : duplicate) + : static_cast(other.storage_.policy_)) & + 3U; + storage_.length_ = other.storage_.length_; +} + +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), + storage_.length_ + 1u); // +1 for null terminating + // character for sake of + // completeness but not actually + // necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(const CZString& other) { + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +Value::CZString& Value::CZString::operator=(CZString&& other) { + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = nullptr; + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) + return index_ < other.index_; + // return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) + return index_ == other.index_; + // return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) + return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +// const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { + return storage_.policy_ == noDuplication; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType type) { + static char const emptyString[] = ""; + initBasic(type); + switch (type) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast(static_cast(emptyString)); + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + JSON_ASSERT_MESSAGE(value != nullptr, + "Null Value Passed to Value Constructor"); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(strlen(value))); +} + +Value::Value(const char* begin, const char* end) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(begin, static_cast(end - begin)); +} + +Value::Value(const String& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(const Value& other) { + dupPayload(other); + dupMeta(other); +} + +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} + +Value::~Value() { + releasePayload(); + value_.uint_ = 0; +} + +Value& Value::operator=(const Value& other) { + Value(other).swap(*this); + return *this; +} + +Value& Value::operator=(Value&& other) { + other.swap(*this); + return *this; +} + +void Value::swapPayload(Value& other) { + std::swap(bits_, other.bits_); + std::swap(value_, other.value_); +} + +void Value::copyPayload(const Value& other) { + releasePayload(); + dupPayload(other); +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +void Value::copy(const Value& other) { + copyPayload(other); + dupMeta(other); +} + +ValueType Value::type() const { + return static_cast(bits_.value_type_); +} + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type() - other.type(); + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type()) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { + if (other.value_.string_) + return true; + else + return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, + &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) + return true; + if (comp > 0) + return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + if (type() != other.type()) + return false; + switch (type()) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, + &other_str); + if (this_len != other_len) + return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type() == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == nullptr) + return nullptr; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type() == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) + return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** begin, char const** end) const { + if (type() != stringValue) + return false; + if (value_.string_ == nullptr) + return false; + unsigned length; + decodePrefixedString(this->isAllocated(), this->value_.string_, &length, + begin); + *end = *begin + length; + return true; +} + +String Value::asString() const { + switch (type()) { + case nullValue: + return ""; + case stringValue: { + if (value_.string_ == nullptr) + return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, + &this_str); + return String(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(isAllocated(), value_.string_, &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type()) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type()) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type()) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type()) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type()) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type()) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type()) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type() == booleanValue && value_.bool_ == false) || + (type() == stringValue && asString().empty()) || + (type() == arrayValue && value_.map_->empty()) || + (type() == objectValue && value_.map_->empty()) || + type() == nullValue; + case intValue: + return isInt() || + (type() == realValue && InRange(value_.real_, minInt, maxInt)) || + type() == booleanValue || type() == nullValue; + case uintValue: + return isUInt() || + (type() == realValue && InRange(value_.real_, 0, maxUInt)) || + type() == booleanValue || type() == nullValue; + case realValue: + return isNumeric() || type() == booleanValue || type() == nullValue; + case booleanValue: + return isNumeric() || type() == booleanValue || type() == nullValue; + case stringValue: + return isNumeric() || type() == booleanValue || type() == stringValue || + type() == nullValue; + case arrayValue: + return type() == arrayValue || type() == nullValue; + case objectValue: + return type() == objectValue || type() == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type()) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +Value::operator bool() const { return !isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue || + type() == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type()) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type() == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + this->operator[](newSize - 1); + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type() == nullValue) + *this = Value(arrayValue); + CZString key(index); + auto it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type() == nullValue) + return nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType type, bool allocated) { + setType(type); + setIsAllocated(allocated); + comments_ = Comments{}; + start_ = 0; + limit_ = 0; +} + +void Value::dupPayload(const Value& other) { + setType(other.type()); + setIsAllocated(false); + switch (type()) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.isAllocated()) { + unsigned len; + char const* str; + decodePrefixedString(other.isAllocated(), other.value_.string_, &len, + &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + setIsAllocated(true); + } else { + value_.string_ = other.value_.string_; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::releasePayload() { + switch (type()) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (isAllocated()) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +void Value::dupMeta(const Value& other) { + comments_ = other.comments_; + start_ = other.start_; + limit_ = other.limit_; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type() == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast(strlen(key)), + CZString::noDuplication); // NOTE! + auto it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* end) { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type() == nullValue) + *this = Value(objectValue); + CZString actualKey(key, static_cast(end - key), + CZString::duplicateOnCopy); + auto it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullSingleton()); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullSingleton() ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* begin, char const* end) const { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::find(begin, end): requires " + "objectValue or nullValue"); + if (type() == nullValue) + return nullptr; + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return nullptr; + return &(*it).second; +} +Value* Value::demand(char const* begin, char const* end) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::demand(begin, end): requires " + "objectValue or nullValue"); + return &resolveReference(begin, end); +} +const Value& Value::operator[](const char* key) const { + Value const* found = find(key, key + strlen(key)); + if (!found) + return nullSingleton(); + return *found; +} +Value const& Value::operator[](const String& key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const String& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const { + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) + return nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value& Value::append(Value&& value) { + return (*this)[size()] = std::move(value); +} + +Value Value::get(char const* begin, + char const* end, + Value const& defaultValue) const { + Value const* found = find(begin, end); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const { + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(String const& key, Value const& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); +} + +bool Value::removeMember(const char* begin, const char* end, Value* removed) { + if (type() != objectValue) { + return false; + } + CZString actualKey(begin, static_cast(end - begin), + CZString::noDuplication); + auto it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + if (removed) + *removed = std::move(it->second); + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) { + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(String const& key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); +} +void Value::removeMember(const char* key) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type() == nullValue) + return; + + CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); + value_.map_->erase(actualKey); +} +void Value::removeMember(const String& key) { removeMember(key.c_str()); } + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type() != arrayValue) { + return false; + } + CZString key(index); + auto it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + if (removed) + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i) { + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + auto itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* begin, char const* end) const { + Value const* value = find(begin, end); + return nullptr != value; +} +bool Value::isMember(char const* key) const { + return isMember(key, key + strlen(key)); +} +bool Value::isMember(String const& key) const { + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type() == nullValue || type() == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type() == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(String((*it).first.data(), (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type() == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type() == objectValue || type() == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type() == nullValue; } + +bool Value::isBool() const { return type() == booleanValue; } + +bool Value::isInt() const { + switch (type()) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type()) { + case intValue: +#if defined(JSON_HAS_INT64) + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif + case uintValue: +#if defined(JSON_HAS_INT64) + return value_.uint_ <= maxUInt; +#else + return true; +#endif + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type()) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type()) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { + switch (type()) { + case intValue: + case uintValue: + return true; + case realValue: +#if defined(JSON_HAS_INT64) + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); +#else + return value_.real_ >= minInt && value_.real_ <= maxUInt && + IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; +} + +bool Value::isDouble() const { + return type() == intValue || type() == uintValue || type() == realValue; +} + +bool Value::isNumeric() const { return isDouble(); } + +bool Value::isString() const { return type() == stringValue; } + +bool Value::isArray() const { return type() == arrayValue; } + +bool Value::isObject() const { return type() == objectValue; } + +Value::Comments::Comments(const Comments& that) + : ptr_{cloneUnique(that.ptr_)} {} + +Value::Comments::Comments(Comments&& that) + : ptr_{std::move(that.ptr_)} {} + +Value::Comments& Value::Comments::operator=(const Comments& that) { + ptr_ = cloneUnique(that.ptr_); + return *this; +} + +Value::Comments& Value::Comments::operator=(Comments&& that) { + ptr_ = std::move(that.ptr_); + return *this; +} + +bool Value::Comments::has(CommentPlacement slot) const { + return ptr_ && !(*ptr_)[slot].empty(); +} + +String Value::Comments::get(CommentPlacement slot) const { + if (!ptr_) + return {}; + return (*ptr_)[slot]; +} + +void Value::Comments::set(CommentPlacement slot, String comment) { + if (!ptr_) { + ptr_ = std::unique_ptr(new Array()); + } + (*ptr_)[slot] = std::move(comment); +} + +void Value::setComment(String comment, CommentPlacement placement) { + if (!comment.empty() && (comment.back() == '\n')) { + // Always discard trailing newline, to aid indentation. + comment.pop_back(); + } + JSON_ASSERT(!comment.empty()); + JSON_ASSERT_MESSAGE( + comment[0] == '\0' || comment[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + comments_.set(placement, std::move(comment)); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_.has(placement); +} + +String Value::getComment(CommentPlacement placement) const { + return comments_.get(placement); +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +String Value::toStyledString() const { + StreamWriterBuilder builder; + + String out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += '\n'; + + return out; +} + +Value::const_iterator Value::begin() const { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return {}; +} + +Value::const_iterator Value::end() const { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return {}; +} + +Value::iterator Value::begin() { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type()) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_() {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const String& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const String& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.reserve(5); + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const String& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + auto itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *++current != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.' || *current == ']') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(String(beginName, current)); + } + } +} + +void Path::addPathInArg(const String& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg++); + } +} + +void Path::invalidPath(const String& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (const auto& arg : args_) { + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + return Value::null; + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (const auto& arg : args_) { + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (const auto& arg : args_) { + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include "json_tool.h" +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include + +#if __cplusplus >= 201103L +#include +#include + +#if !defined(isnan) +#define isnan std::isnan +#endif + +#if !defined(isfinite) +#define isfinite std::isfinite +#endif + +#else +#include +#include + +#if defined(_MSC_VER) +#if !defined(isnan) +#include +#define isnan _isnan +#endif + +#if !defined(isfinite) +#include +#define isfinite _finite +#endif + +#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES + +#endif //_MSC_VER + +#if defined(__sun) && defined(__SVR4) // Solaris +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#endif + +#if defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) \ + ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) +#endif +#endif +#endif + +#if !defined(isnan) +// IEEE standard states that NaN values will not compare to themselves +#define isnan(x) (x != x) +#endif + +#if !defined(__APPLE__) +#if !defined(isfinite) +#define isfinite finite +#endif +#endif +#endif + +#if defined(_MSC_VER) +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +String valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +String valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +String valueToString(Int value) { return valueToString(LargestInt(value)); } + +String valueToString(UInt value) { return valueToString(LargestUInt(value)); } + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +String valueToString(double value, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) { + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distinguish the + // concepts of reals and integers. + if (!isfinite(value)) { + static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, + {"null", "-1e+9999", "1e+9999"}}; + return reps[useSpecialFloats ? 0 : 1] + [isnan(value) ? 0 : (value < 0) ? 1 : 2]; + } + + String buffer(size_t(36), '\0'); + while (true) { + int len = jsoncpp_snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); + assert(len >= 0); + auto wouldPrint = static_cast(len); + if (wouldPrint >= buffer.size()) { + buffer.resize(wouldPrint + 1); + continue; + } + buffer.resize(wouldPrint); + break; + } + + buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); + } + + // try to ensure we preserve the fact that this was given to us as a double on + // input + if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { + buffer += ".0"; + } + return buffer; +} +} // namespace + +String valueToString(double value, + unsigned int precision, + PrecisionType precisionType) { + return valueToString(value, false, precision, precisionType); +} + +String valueToString(bool value) { return value ? "true" : "false"; } + +static bool isAnyCharRequiredQuoting(char const* s, size_t n) { + assert(s || !n); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + if (*cur == '\\' || *cur == '\"' || *cur < ' ' || + static_cast(*cur) < 0x80) + return true; + } + return false; +} + +static unsigned int utf8ToCodepoint(const char*& s, const char* e) { + const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; + + unsigned int firstByte = static_cast(*s); + + if (firstByte < 0x80) + return firstByte; + + if (firstByte < 0xE0) { + if (e - s < 2) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = + ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); + s += 1; + // oversized encoded characters are invalid + return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF0) { + if (e - s < 3) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x0F) << 12) | + ((static_cast(s[1]) & 0x3F) << 6) | + (static_cast(s[2]) & 0x3F); + s += 2; + // surrogates aren't valid codepoints itself + // shouldn't be UTF-8 encoded + if (calculated >= 0xD800 && calculated <= 0xDFFF) + return REPLACEMENT_CHARACTER; + // oversized encoded characters are invalid + return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; + } + + if (firstByte < 0xF8) { + if (e - s < 4) + return REPLACEMENT_CHARACTER; + + unsigned int calculated = ((firstByte & 0x07) << 18) | + ((static_cast(s[1]) & 0x3F) << 12) | + ((static_cast(s[2]) & 0x3F) << 6) | + (static_cast(s[3]) & 0x3F); + s += 3; + // oversized encoded characters are invalid + return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; + } + + return REPLACEMENT_CHARACTER; +} + +static const char hex2[] = "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; + +static String toHex16Bit(unsigned int x) { + const unsigned int hi = (x >> 8) & 0xff; + const unsigned int lo = x & 0xff; + String result(4, ' '); + result[0] = hex2[2 * hi]; + result[1] = hex2[2 * hi + 1]; + result[2] = hex2[2 * lo]; + result[3] = hex2[2 * lo + 1]; + return result; +} + +static String valueToQuotedStringN(const char* value, unsigned length) { + if (value == nullptr) + return ""; + + if (!isAnyCharRequiredQuoting(value, length)) + return String("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to String is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL + String result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid = 0x20) + result += static_cast(cp); + else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane + result += "\\u"; + result += toHex16Bit(cp); + } else { // codepoint is not in Basic Multilingual Plane + // convert to surrogate pair first + cp -= 0x10000; + result += "\\u"; + result += toHex16Bit((cp >> 10) + 0xD800); + result += "\\u"; + result += toHex16Bit((cp & 0x3FF) + 0xDC00); + } + } break; + } + } + result += "\""; + return result; +} + +String valueToQuotedString(const char* value) { + return valueToQuotedStringN(value, static_cast(strlen(value))); +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() = default; + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + + = default; + +void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +String FastWriter::write(const Value& root) { + document_.clear(); + writeValue(root); + if (!omitEndingLineFeed_) + document_ += '\n'; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + document_ += valueToQuotedStringN(str, static_cast(end - str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (auto it = members.begin(); it != members.end(); ++it) { + const String& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), + static_cast(name.length())); + document_ += yamlCompatibilityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() = default; + +String StyledWriter::write(const Value& root) { + document_.clear(); + addChildValues_ = false; + indentString_.clear(); + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += '\n'; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + auto it = members.begin(); + for (;;) { + const String& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + !childValue.empty()); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const String& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const String& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += '\n'; + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += '\n'; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += '\n'; + document_ += root.getComment(commentAfter); + document_ += '\n'; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(String indentation) + : document_(nullptr), indentation_(std::move(indentation)), + addChildValues_(), indented_(false) {} + +void StyledStreamWriter::write(OStream& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_.clear(); + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = nullptr; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + auto it = members.begin(); + for (;;) { + const String& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultilineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultilineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + !childValue.empty()); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const String& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const String& value) { + if (!indented_) + writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter { + BuiltStyledStreamWriter(String indentation, + CommentStyle::Enum cs, + String colonSymbol, + String nullSymbol, + String endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType); + int write(Value const& root, OStream* sout) override; + +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultilineArray(Value const& value); + void pushValue(String const& value); + void writeIndent(); + void writeWithIndent(String const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + String indentString_; + unsigned int rightMargin_; + String indentation_; + CommentStyle::Enum cs_; + String colonSymbol_; + String nullSymbol_; + String endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; + PrecisionType precisionType_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter(String indentation, + CommentStyle::Enum cs, + String colonSymbol, + String nullSymbol, + String endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision, + PrecisionType precisionType) + : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), + colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), + endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), + addChildValues_(false), indented_(false), + useSpecialFloats_(useSpecialFloats), precision_(precision), + precisionType_(precisionType) {} +int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_.clear(); + writeCommentBeforeValue(root); + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = nullptr; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, + precisionType_)); + break; + case stringValue: { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) + pushValue(valueToQuotedStringN(str, static_cast(end - str))); + else + pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + auto it = members.begin(); + for (;;) { + String const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN( + name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) + writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) + *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) + *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + !childValue.empty()); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(String const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(String const& value) { + if (!indented_) + writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) + writeIndent(); + const String& comment = root.getComment(commentBefore); + String::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( + Value const& root) { + if (cs_ == CommentStyle::None) + return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() : sout_(nullptr) {} +StreamWriter::~StreamWriter() = default; +StreamWriter::Factory::~Factory() = default; +StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } +StreamWriterBuilder::~StreamWriterBuilder() = default; +StreamWriter* StreamWriterBuilder::newStreamWriter() const { + String indentation = settings_["indentation"].asString(); + String cs_str = settings_["commentStyle"].asString(); + String pt_str = settings_["precisionType"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + PrecisionType precisionType(significantDigits); + if (pt_str == "significant") { + precisionType = PrecisionType::significantDigits; + } else if (pt_str == "decimal") { + precisionType = PrecisionType::decimalPlaces; + } else { + throwRuntimeError("precisionType must be 'significant' or 'decimal'"); + } + String colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + String nullSymbol = "null"; + if (dnp) { + nullSymbol.clear(); + } + if (pre > 17) + pre = 17; + String endingLineFeedSymbol; + return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, + endingLineFeedSymbol, usf, pre, + precisionType); +} +static void getValidWriterKeys(std::set* valid_keys) { + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); + valid_keys->insert("precisionType"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const { + Json::Value my_invalid; + if (!invalid) + invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + String const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return inv.empty(); +} +Value& StreamWriterBuilder::operator[](const String& key) { + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) { + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + (*settings)["precisionType"] = "significant"; + //! [StreamWriterBuilderDefaults] +} + +String writeString(StreamWriter::Factory const& factory, Value const& root) { + OStringStream sout; + StreamWriterPtr const writer(factory.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +OStream& operator<<(OStream& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/thirdparty/jsoncpp/src/lib_json/json_batchallocator.h b/thirdparty/jsoncpp/src/lib_json/json_batchallocator.h deleted file mode 100644 index 87ea5ed8..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_batchallocator.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED -# define JSONCPP_BATCHALLOCATOR_H_INCLUDED - -# include -# include - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -namespace Json { - -/* Fast memory allocator. - * - * This memory allocator allocates memory for a batch of object (specified by - * the page size, the number of object in each page). - * - * It does not allow the destruction of a single object. All the allocated objects - * can be destroyed at once. The memory can be either released or reused for future - * allocation. - * - * The in-place new operator must be used to construct the object using the pointer - * returned by allocate. - */ -template -class BatchAllocator -{ -public: - typedef AllocatedType Type; - - BatchAllocator( unsigned int objectsPerPage = 255 ) - : freeHead_( 0 ) - , objectsPerPage_( objectsPerPage ) - { -// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); - assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. - assert( objectsPerPage >= 16 ); - batches_ = allocateBatch( 0 ); // allocated a dummy page - currentBatch_ = batches_; - } - - ~BatchAllocator() - { - for ( BatchInfo *batch = batches_; batch; ) - { - BatchInfo *nextBatch = batch->next_; - free( batch ); - batch = nextBatch; - } - } - - /// allocate space for an array of objectPerAllocation object. - /// @warning it is the responsability of the caller to call objects constructors. - AllocatedType *allocate() - { - if ( freeHead_ ) // returns node from free list. - { - AllocatedType *object = freeHead_; - freeHead_ = *(AllocatedType **)object; - return object; - } - if ( currentBatch_->used_ == currentBatch_->end_ ) - { - currentBatch_ = currentBatch_->next_; - while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) - currentBatch_ = currentBatch_->next_; - - if ( !currentBatch_ ) // no free batch found, allocate a new one - { - currentBatch_ = allocateBatch( objectsPerPage_ ); - currentBatch_->next_ = batches_; // insert at the head of the list - batches_ = currentBatch_; - } - } - AllocatedType *allocated = currentBatch_->used_; - currentBatch_->used_ += objectPerAllocation; - return allocated; - } - - /// Release the object. - /// @warning it is the responsability of the caller to actually destruct the object. - void release( AllocatedType *object ) - { - assert( object != 0 ); - *(AllocatedType **)object = freeHead_; - freeHead_ = object; - } - -private: - struct BatchInfo - { - BatchInfo *next_; - AllocatedType *used_; - AllocatedType *end_; - AllocatedType buffer_[objectPerAllocation]; - }; - - // disabled copy constructor and assignement operator. - BatchAllocator( const BatchAllocator & ); - void operator =( const BatchAllocator &); - - static BatchInfo *allocateBatch( unsigned int objectsPerPage ) - { - const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation - + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; - BatchInfo *batch = static_cast( malloc( mallocSize ) ); - batch->next_ = 0; - batch->used_ = batch->buffer_; - batch->end_ = batch->buffer_ + objectsPerPage; - return batch; - } - - BatchInfo *batches_; - BatchInfo *currentBatch_; - /// Head of a single linked list within the allocated space of freeed object - AllocatedType *freeHead_; - unsigned int objectsPerPage_; -}; - - -} // namespace Json - -# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION - -#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED - diff --git a/thirdparty/jsoncpp/src/lib_json/json_internalarray.inl b/thirdparty/jsoncpp/src/lib_json/json_internalarray.inl deleted file mode 100644 index 9b985d25..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_internalarray.inl +++ /dev/null @@ -1,448 +0,0 @@ -// included by json_value.cpp -// everything is within Json namespace - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueInternalArray -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueArrayAllocator::~ValueArrayAllocator() -{ -} - -// ////////////////////////////////////////////////////////////////// -// class DefaultValueArrayAllocator -// ////////////////////////////////////////////////////////////////// -#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -class DefaultValueArrayAllocator : public ValueArrayAllocator -{ -public: // overridden from ValueArrayAllocator - virtual ~DefaultValueArrayAllocator() - { - } - - virtual ValueInternalArray *newArray() - { - return new ValueInternalArray(); - } - - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) - { - return new ValueInternalArray( other ); - } - - virtual void destructArray( ValueInternalArray *array ) - { - delete array; - } - - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) - { - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast( newIndexes ); - } - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) - { - if ( indexes ) - free( indexes ); - } - - virtual Value *allocateArrayPage() - { - return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); - } - - virtual void releaseArrayPage( Value *value ) - { - if ( value ) - free( value ); - } -}; - -#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -/// @todo make this thread-safe (lock when accessign batch allocator) -class DefaultValueArrayAllocator : public ValueArrayAllocator -{ -public: // overridden from ValueArrayAllocator - virtual ~DefaultValueArrayAllocator() - { - } - - virtual ValueInternalArray *newArray() - { - ValueInternalArray *array = arraysAllocator_.allocate(); - new (array) ValueInternalArray(); // placement new - return array; - } - - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) - { - ValueInternalArray *array = arraysAllocator_.allocate(); - new (array) ValueInternalArray( other ); // placement new - return array; - } - - virtual void destructArray( ValueInternalArray *array ) - { - if ( array ) - { - array->~ValueInternalArray(); - arraysAllocator_.release( array ); - } - } - - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) - { - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast( newIndexes ); - } - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) - { - if ( indexes ) - free( indexes ); - } - - virtual Value *allocateArrayPage() - { - return static_cast( pagesAllocator_.allocate() ); - } - - virtual void releaseArrayPage( Value *value ) - { - if ( value ) - pagesAllocator_.release( value ); - } -private: - BatchAllocator arraysAllocator_; - BatchAllocator pagesAllocator_; -}; -#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR - -static ValueArrayAllocator *&arrayAllocator() -{ - static DefaultValueArrayAllocator defaultAllocator; - static ValueArrayAllocator *arrayAllocator = &defaultAllocator; - return arrayAllocator; -} - -static struct DummyArrayAllocatorInitializer { - DummyArrayAllocatorInitializer() - { - arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). - } -} dummyArrayAllocatorInitializer; - -// ////////////////////////////////////////////////////////////////// -// class ValueInternalArray -// ////////////////////////////////////////////////////////////////// -bool -ValueInternalArray::equals( const IteratorState &x, - const IteratorState &other ) -{ - return x.array_ == other.array_ - && x.currentItemIndex_ == other.currentItemIndex_ - && x.currentPageIndex_ == other.currentPageIndex_; -} - - -void -ValueInternalArray::increment( IteratorState &it ) -{ - JSON_ASSERT_MESSAGE( it.array_ && - (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ - != it.array_->size_, - "ValueInternalArray::increment(): moving iterator beyond end" ); - ++(it.currentItemIndex_); - if ( it.currentItemIndex_ == itemsPerPage ) - { - it.currentItemIndex_ = 0; - ++(it.currentPageIndex_); - } -} - - -void -ValueInternalArray::decrement( IteratorState &it ) -{ - JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ - && it.currentItemIndex_ == 0, - "ValueInternalArray::decrement(): moving iterator beyond end" ); - if ( it.currentItemIndex_ == 0 ) - { - it.currentItemIndex_ = itemsPerPage-1; - --(it.currentPageIndex_); - } - else - { - --(it.currentItemIndex_); - } -} - - -Value & -ValueInternalArray::unsafeDereference( const IteratorState &it ) -{ - return (*(it.currentPageIndex_))[it.currentItemIndex_]; -} - - -Value & -ValueInternalArray::dereference( const IteratorState &it ) -{ - JSON_ASSERT_MESSAGE( it.array_ && - (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ - < it.array_->size_, - "ValueInternalArray::dereference(): dereferencing invalid iterator" ); - return unsafeDereference( it ); -} - -void -ValueInternalArray::makeBeginIterator( IteratorState &it ) const -{ - it.array_ = const_cast( this ); - it.currentItemIndex_ = 0; - it.currentPageIndex_ = pages_; -} - - -void -ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const -{ - it.array_ = const_cast( this ); - it.currentItemIndex_ = index % itemsPerPage; - it.currentPageIndex_ = pages_ + index / itemsPerPage; -} - - -void -ValueInternalArray::makeEndIterator( IteratorState &it ) const -{ - makeIterator( it, size_ ); -} - - -ValueInternalArray::ValueInternalArray() - : pages_( 0 ) - , size_( 0 ) - , pageCount_( 0 ) -{ -} - - -ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) - : pages_( 0 ) - , pageCount_( 0 ) - , size_( other.size_ ) -{ - PageIndex minNewPages = other.size_ / itemsPerPage; - arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); - JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, - "ValueInternalArray::reserve(): bad reallocation" ); - IteratorState itOther; - other.makeBeginIterator( itOther ); - Value *value; - for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) - { - if ( index % itemsPerPage == 0 ) - { - PageIndex pageIndex = index / itemsPerPage; - value = arrayAllocator()->allocateArrayPage(); - pages_[pageIndex] = value; - } - new (value) Value( dereference( itOther ) ); - } -} - - -ValueInternalArray & -ValueInternalArray::operator =( const ValueInternalArray &other ) -{ - ValueInternalArray temp( other ); - swap( temp ); - return *this; -} - - -ValueInternalArray::~ValueInternalArray() -{ - // destroy all constructed items - IteratorState it; - IteratorState itEnd; - makeBeginIterator( it); - makeEndIterator( itEnd ); - for ( ; !equals(it,itEnd); increment(it) ) - { - Value *value = &dereference(it); - value->~Value(); - } - // release all pages - PageIndex lastPageIndex = size_ / itemsPerPage; - for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) - arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); - // release pages index - arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); -} - - -void -ValueInternalArray::swap( ValueInternalArray &other ) -{ - Value **tempPages = pages_; - pages_ = other.pages_; - other.pages_ = tempPages; - ArrayIndex tempSize = size_; - size_ = other.size_; - other.size_ = tempSize; - PageIndex tempPageCount = pageCount_; - pageCount_ = other.pageCount_; - other.pageCount_ = tempPageCount; -} - -void -ValueInternalArray::clear() -{ - ValueInternalArray dummy; - swap( dummy ); -} - - -void -ValueInternalArray::resize( ArrayIndex newSize ) -{ - if ( newSize == 0 ) - clear(); - else if ( newSize < size_ ) - { - IteratorState it; - IteratorState itEnd; - makeIterator( it, newSize ); - makeIterator( itEnd, size_ ); - for ( ; !equals(it,itEnd); increment(it) ) - { - Value *value = &dereference(it); - value->~Value(); - } - PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; - PageIndex lastPageIndex = size_ / itemsPerPage; - for ( ; pageIndex < lastPageIndex; ++pageIndex ) - arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); - size_ = newSize; - } - else if ( newSize > size_ ) - resolveReference( newSize ); -} - - -void -ValueInternalArray::makeIndexValid( ArrayIndex index ) -{ - // Need to enlarge page index ? - if ( index >= pageCount_ * itemsPerPage ) - { - PageIndex minNewPages = (index + 1) / itemsPerPage; - arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); - JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); - } - - // Need to allocate new pages ? - ArrayIndex nextPageIndex = - (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage - : size_; - if ( nextPageIndex <= index ) - { - PageIndex pageIndex = nextPageIndex / itemsPerPage; - PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; - for ( ; pageToAllocate-- > 0; ++pageIndex ) - pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); - } - - // Initialize all new entries - IteratorState it; - IteratorState itEnd; - makeIterator( it, size_ ); - size_ = index + 1; - makeIterator( itEnd, size_ ); - for ( ; !equals(it,itEnd); increment(it) ) - { - Value *value = &dereference(it); - new (value) Value(); // Construct a default value using placement new - } -} - -Value & -ValueInternalArray::resolveReference( ArrayIndex index ) -{ - if ( index >= size_ ) - makeIndexValid( index ); - return pages_[index/itemsPerPage][index%itemsPerPage]; -} - -Value * -ValueInternalArray::find( ArrayIndex index ) const -{ - if ( index >= size_ ) - return 0; - return &(pages_[index/itemsPerPage][index%itemsPerPage]); -} - -ValueInternalArray::ArrayIndex -ValueInternalArray::size() const -{ - return size_; -} - -int -ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) -{ - return indexOf(y) - indexOf(x); -} - - -ValueInternalArray::ArrayIndex -ValueInternalArray::indexOf( const IteratorState &iterator ) -{ - if ( !iterator.array_ ) - return ArrayIndex(-1); - return ArrayIndex( - (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage - + iterator.currentItemIndex_ ); -} - - -int -ValueInternalArray::compare( const ValueInternalArray &other ) const -{ - int sizeDiff( size_ - other.size_ ); - if ( sizeDiff != 0 ) - return sizeDiff; - - for ( ArrayIndex index =0; index < size_; ++index ) - { - int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( - other.pages_[index/itemsPerPage][index%itemsPerPage] ); - if ( diff != 0 ) - return diff; - } - return 0; -} diff --git a/thirdparty/jsoncpp/src/lib_json/json_internalmap.inl b/thirdparty/jsoncpp/src/lib_json/json_internalmap.inl deleted file mode 100644 index 19771488..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_internalmap.inl +++ /dev/null @@ -1,607 +0,0 @@ -// included by json_value.cpp -// everything is within Json namespace - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueInternalMap -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); - * This optimization is used by the fast allocator. - */ -ValueInternalLink::ValueInternalLink() - : previous_( 0 ) - , next_( 0 ) -{ -} - -ValueInternalLink::~ValueInternalLink() -{ - for ( int index =0; index < itemPerLink; ++index ) - { - if ( !items_[index].isItemAvailable() ) - { - if ( !items_[index].isMemberNameStatic() ) - free( keys_[index] ); - } - else - break; - } -} - - - -ValueMapAllocator::~ValueMapAllocator() -{ -} - -#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -class DefaultValueMapAllocator : public ValueMapAllocator -{ -public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - return new ValueInternalMap(); - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - return new ValueInternalMap( other ); - } - - virtual void destructMap( ValueInternalMap *map ) - { - delete map; - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - return new ValueInternalLink(); - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - delete link; - } -}; -#else -/// @todo make this thread-safe (lock when accessign batch allocator) -class DefaultValueMapAllocator : public ValueMapAllocator -{ -public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - ValueInternalMap *map = mapsAllocator_.allocate(); - new (map) ValueInternalMap(); // placement new - return map; - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - ValueInternalMap *map = mapsAllocator_.allocate(); - new (map) ValueInternalMap( other ); // placement new - return map; - } - - virtual void destructMap( ValueInternalMap *map ) - { - if ( map ) - { - map->~ValueInternalMap(); - mapsAllocator_.release( map ); - } - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - ValueInternalLink *link = linksAllocator_.allocate(); - memset( link, 0, sizeof(ValueInternalLink) ); - return link; - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - link->~ValueInternalLink(); - linksAllocator_.release( link ); - } -private: - BatchAllocator mapsAllocator_; - BatchAllocator linksAllocator_; -}; -#endif - -static ValueMapAllocator *&mapAllocator() -{ - static DefaultValueMapAllocator defaultAllocator; - static ValueMapAllocator *mapAllocator = &defaultAllocator; - return mapAllocator; -} - -static struct DummyMapAllocatorInitializer { - DummyMapAllocatorInitializer() - { - mapAllocator(); // ensure mapAllocator() statics are initialized before main(). - } -} dummyMapAllocatorInitializer; - - - -// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. - -/* -use linked list hash map. -buckets array is a container. -linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) -value have extra state: valid, available, deleted -*/ - - -ValueInternalMap::ValueInternalMap() - : buckets_( 0 ) - , tailLink_( 0 ) - , bucketsSize_( 0 ) - , itemCount_( 0 ) -{ -} - - -ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) - : buckets_( 0 ) - , tailLink_( 0 ) - , bucketsSize_( 0 ) - , itemCount_( 0 ) -{ - reserve( other.itemCount_ ); - IteratorState it; - IteratorState itEnd; - other.makeBeginIterator( it ); - other.makeEndIterator( itEnd ); - for ( ; !equals(it,itEnd); increment(it) ) - { - bool isStatic; - const char *memberName = key( it, isStatic ); - const Value &aValue = value( it ); - resolveReference(memberName, isStatic) = aValue; - } -} - - -ValueInternalMap & -ValueInternalMap::operator =( const ValueInternalMap &other ) -{ - ValueInternalMap dummy( other ); - swap( dummy ); - return *this; -} - - -ValueInternalMap::~ValueInternalMap() -{ - if ( buckets_ ) - { - for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) - { - ValueInternalLink *link = buckets_[bucketIndex].next_; - while ( link ) - { - ValueInternalLink *linkToRelease = link; - link = link->next_; - mapAllocator()->releaseMapLink( linkToRelease ); - } - } - mapAllocator()->releaseMapBuckets( buckets_ ); - } -} - - -void -ValueInternalMap::swap( ValueInternalMap &other ) -{ - ValueInternalLink *tempBuckets = buckets_; - buckets_ = other.buckets_; - other.buckets_ = tempBuckets; - ValueInternalLink *tempTailLink = tailLink_; - tailLink_ = other.tailLink_; - other.tailLink_ = tempTailLink; - BucketIndex tempBucketsSize = bucketsSize_; - bucketsSize_ = other.bucketsSize_; - other.bucketsSize_ = tempBucketsSize; - BucketIndex tempItemCount = itemCount_; - itemCount_ = other.itemCount_; - other.itemCount_ = tempItemCount; -} - - -void -ValueInternalMap::clear() -{ - ValueInternalMap dummy; - swap( dummy ); -} - - -ValueInternalMap::BucketIndex -ValueInternalMap::size() const -{ - return itemCount_; -} - -bool -ValueInternalMap::reserveDelta( BucketIndex growth ) -{ - return reserve( itemCount_ + growth ); -} - -bool -ValueInternalMap::reserve( BucketIndex newItemCount ) -{ - if ( !buckets_ && newItemCount > 0 ) - { - buckets_ = mapAllocator()->allocateMapBuckets( 1 ); - bucketsSize_ = 1; - tailLink_ = &buckets_[0]; - } -// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; - return true; -} - - -const Value * -ValueInternalMap::find( const char *key ) const -{ - if ( !bucketsSize_ ) - return 0; - HashKey hashedKey = hash( key ); - BucketIndex bucketIndex = hashedKey % bucketsSize_; - for ( const ValueInternalLink *current = &buckets_[bucketIndex]; - current != 0; - current = current->next_ ) - { - for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) - { - if ( current->items_[index].isItemAvailable() ) - return 0; - if ( strcmp( key, current->keys_[index] ) == 0 ) - return ¤t->items_[index]; - } - } - return 0; -} - - -Value * -ValueInternalMap::find( const char *key ) -{ - const ValueInternalMap *constThis = this; - return const_cast( constThis->find( key ) ); -} - - -Value & -ValueInternalMap::resolveReference( const char *key, - bool isStatic ) -{ - HashKey hashedKey = hash( key ); - if ( bucketsSize_ ) - { - BucketIndex bucketIndex = hashedKey % bucketsSize_; - ValueInternalLink **previous = 0; - BucketIndex index; - for ( ValueInternalLink *current = &buckets_[bucketIndex]; - current != 0; - previous = ¤t->next_, current = current->next_ ) - { - for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) - { - if ( current->items_[index].isItemAvailable() ) - return setNewItem( key, isStatic, current, index ); - if ( strcmp( key, current->keys_[index] ) == 0 ) - return current->items_[index]; - } - } - } - - reserveDelta( 1 ); - return unsafeAdd( key, isStatic, hashedKey ); -} - - -void -ValueInternalMap::remove( const char *key ) -{ - HashKey hashedKey = hash( key ); - if ( !bucketsSize_ ) - return; - BucketIndex bucketIndex = hashedKey % bucketsSize_; - for ( ValueInternalLink *link = &buckets_[bucketIndex]; - link != 0; - link = link->next_ ) - { - BucketIndex index; - for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) - { - if ( link->items_[index].isItemAvailable() ) - return; - if ( strcmp( key, link->keys_[index] ) == 0 ) - { - doActualRemove( link, index, bucketIndex ); - return; - } - } - } -} - -void -ValueInternalMap::doActualRemove( ValueInternalLink *link, - BucketIndex index, - BucketIndex bucketIndex ) -{ - // find last item of the bucket and swap it with the 'removed' one. - // set removed items flags to 'available'. - // if last page only contains 'available' items, then desallocate it (it's empty) - ValueInternalLink *&lastLink = getLastLinkInBucket( index ); - BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 - for ( ; - lastItemIndex < ValueInternalLink::itemPerLink; - ++lastItemIndex ) // may be optimized with dicotomic search - { - if ( lastLink->items_[lastItemIndex].isItemAvailable() ) - break; - } - - BucketIndex lastUsedIndex = lastItemIndex - 1; - Value *valueToDelete = &link->items_[index]; - Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; - if ( valueToDelete != valueToPreserve ) - valueToDelete->swap( *valueToPreserve ); - if ( lastUsedIndex == 0 ) // page is now empty - { // remove it from bucket linked list and delete it. - ValueInternalLink *linkPreviousToLast = lastLink->previous_; - if ( linkPreviousToLast != 0 ) // can not deleted bucket link. - { - mapAllocator()->releaseMapLink( lastLink ); - linkPreviousToLast->next_ = 0; - lastLink = linkPreviousToLast; - } - } - else - { - Value dummy; - valueToPreserve->swap( dummy ); // restore deleted to default Value. - valueToPreserve->setItemUsed( false ); - } - --itemCount_; -} - - -ValueInternalLink *& -ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) -{ - if ( bucketIndex == bucketsSize_ - 1 ) - return tailLink_; - ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; - if ( !previous ) - previous = &buckets_[bucketIndex]; - return previous; -} - - -Value & -ValueInternalMap::setNewItem( const char *key, - bool isStatic, - ValueInternalLink *link, - BucketIndex index ) -{ - char *duplicatedKey = valueAllocator()->makeMemberName( key ); - ++itemCount_; - link->keys_[index] = duplicatedKey; - link->items_[index].setItemUsed(); - link->items_[index].setMemberNameIsStatic( isStatic ); - return link->items_[index]; // items already default constructed. -} - - -Value & -ValueInternalMap::unsafeAdd( const char *key, - bool isStatic, - HashKey hashedKey ) -{ - JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); - BucketIndex bucketIndex = hashedKey % bucketsSize_; - ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); - ValueInternalLink *link = previousLink; - BucketIndex index; - for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) - { - if ( link->items_[index].isItemAvailable() ) - break; - } - if ( index == ValueInternalLink::itemPerLink ) // need to add a new page - { - ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); - index = 0; - link->next_ = newLink; - previousLink = newLink; - link = newLink; - } - return setNewItem( key, isStatic, link, index ); -} - - -ValueInternalMap::HashKey -ValueInternalMap::hash( const char *key ) const -{ - HashKey hash = 0; - while ( *key ) - hash += *key++ * 37; - return hash; -} - - -int -ValueInternalMap::compare( const ValueInternalMap &other ) const -{ - int sizeDiff( itemCount_ - other.itemCount_ ); - if ( sizeDiff != 0 ) - return sizeDiff; - // Strict order guaranty is required. Compare all keys FIRST, then compare values. - IteratorState it; - IteratorState itEnd; - makeBeginIterator( it ); - makeEndIterator( itEnd ); - for ( ; !equals(it,itEnd); increment(it) ) - { - if ( !other.find( key( it ) ) ) - return 1; - } - - // All keys are equals, let's compare values - makeBeginIterator( it ); - for ( ; !equals(it,itEnd); increment(it) ) - { - const Value *otherValue = other.find( key( it ) ); - int valueDiff = value(it).compare( *otherValue ); - if ( valueDiff != 0 ) - return valueDiff; - } - return 0; -} - - -void -ValueInternalMap::makeBeginIterator( IteratorState &it ) const -{ - it.map_ = const_cast( this ); - it.bucketIndex_ = 0; - it.itemIndex_ = 0; - it.link_ = buckets_; -} - - -void -ValueInternalMap::makeEndIterator( IteratorState &it ) const -{ - it.map_ = const_cast( this ); - it.bucketIndex_ = bucketsSize_; - it.itemIndex_ = 0; - it.link_ = 0; -} - - -bool -ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) -{ - return x.map_ == other.map_ - && x.bucketIndex_ == other.bucketIndex_ - && x.link_ == other.link_ - && x.itemIndex_ == other.itemIndex_; -} - - -void -ValueInternalMap::incrementBucket( IteratorState &iterator ) -{ - ++iterator.bucketIndex_; - JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, - "ValueInternalMap::increment(): attempting to iterate beyond end." ); - if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) - iterator.link_ = 0; - else - iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); - iterator.itemIndex_ = 0; -} - - -void -ValueInternalMap::increment( IteratorState &iterator ) -{ - JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); - ++iterator.itemIndex_; - if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) - { - JSON_ASSERT_MESSAGE( iterator.link_ != 0, - "ValueInternalMap::increment(): attempting to iterate beyond end." ); - iterator.link_ = iterator.link_->next_; - if ( iterator.link_ == 0 ) - incrementBucket( iterator ); - } - else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) - { - incrementBucket( iterator ); - } -} - - -void -ValueInternalMap::decrement( IteratorState &iterator ) -{ - if ( iterator.itemIndex_ == 0 ) - { - JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); - if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) - { - JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); - --(iterator.bucketIndex_); - } - iterator.link_ = iterator.link_->previous_; - iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; - } -} - - -const char * -ValueInternalMap::key( const IteratorState &iterator ) -{ - JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); - return iterator.link_->keys_[iterator.itemIndex_]; -} - -const char * -ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) -{ - JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); - isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); - return iterator.link_->keys_[iterator.itemIndex_]; -} - - -Value & -ValueInternalMap::value( const IteratorState &iterator ) -{ - JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); - return iterator.link_->items_[iterator.itemIndex_]; -} - - -int -ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) -{ - int offset = 0; - IteratorState it = x; - while ( !equals( it, y ) ) - increment( it ); - return offset; -} diff --git a/thirdparty/jsoncpp/src/lib_json/json_reader.cpp b/thirdparty/jsoncpp/src/lib_json/json_reader.cpp deleted file mode 100644 index 93fbe262..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_reader.cpp +++ /dev/null @@ -1,883 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. -#endif - -namespace Json { - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() - : allowComments_( true ) - , strictRoot_( false ) -{ -} - - -Features -Features::all() -{ - return Features(); -} - - -Features -Features::strictMode() -{ - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) -{ - return c == c1 || c == c2 || c == c3 || c == c4; -} - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) -{ - return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; -} - - -static bool -containsNewLine( Reader::Location begin, - Reader::Location end ) -{ - for ( ;begin < end; ++begin ) - if ( *begin == '\n' || *begin == '\r' ) - return true; - return false; -} - -static std::string codePointToUTF8(unsigned int cp) -{ - std::string result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) - { - result.resize(1); - result[0] = static_cast(cp); - } - else if (cp <= 0x7FF) - { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } - else if (cp <= 0xFFFF) - { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); - } - else if (cp <= 0x10FFFF) - { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() - : features_( Features::all() ) -{ -} - - -Reader::Reader( const Features &features ) - : features_( features ) -{ -} - - -bool -Reader::parse( const std::string &document, - Value &root, - bool collectComments ) -{ - document_ = document; - const char *begin = document_.c_str(); - const char *end = begin + document_.length(); - return parse( begin, end, root, collectComments ); -} - - -bool -Reader::parse( std::istream& sin, - Value &root, - bool collectComments ) -{ - //std::istream_iterator begin(sin); - //std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since std::string is reference-counted, this at least does not - // create an extra copy. - std::string doc; - std::getline(sin, doc, (char)EOF); - return parse( doc, root, collectComments ); -} - -bool -Reader::parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments ) -{ - if ( !features_.allowComments_ ) - { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while ( !nodes_.empty() ) - nodes_.pop(); - nodes_.push( &root ); - - bool successful = readValue(); - Token token; - skipCommentTokens( token ); - if ( collectComments_ && !commentsBefore_.empty() ) - root.setComment( commentsBefore_, commentAfter ); - if ( features_.strictRoot_ ) - { - if ( !root.isArray() && !root.isObject() ) - { - // Set error location to start of doc, ideally should be first token found in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( "A valid JSON document must be either an array or an object value.", - token ); - return false; - } - } - return successful; -} - - -bool -Reader::readValue() -{ - Token token; - skipCommentTokens( token ); - bool successful = true; - - if ( collectComments_ && !commentsBefore_.empty() ) - { - currentValue().setComment( commentsBefore_, commentBefore ); - commentsBefore_ = ""; - } - - - switch ( token.type_ ) - { - case tokenObjectBegin: - successful = readObject( token ); - break; - case tokenArrayBegin: - successful = readArray( token ); - break; - case tokenNumber: - successful = decodeNumber( token ); - break; - case tokenString: - successful = decodeString( token ); - break; - case tokenTrue: - currentValue() = true; - break; - case tokenFalse: - currentValue() = false; - break; - case tokenNull: - currentValue() = Value(); - break; - default: - return addError( "Syntax error: value, object or array expected.", token ); - } - - if ( collectComments_ ) - { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - - -void -Reader::skipCommentTokens( Token &token ) -{ - if ( features_.allowComments_ ) - { - do - { - readToken( token ); - } - while ( token.type_ == tokenComment ); - } - else - { - readToken( token ); - } -} - - -bool -Reader::expectToken( TokenType type, Token &token, const char *message ) -{ - readToken( token ); - if ( token.type_ != type ) - return addError( message, token ); - return true; -} - - -bool -Reader::readToken( Token &token ) -{ - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch ( c ) - { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match( "rue", 3 ); - break; - case 'f': - token.type_ = tokenFalse; - ok = match( "alse", 4 ); - break; - case 'n': - token.type_ = tokenNull; - ok = match( "ull", 3 ); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if ( !ok ) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - - -void -Reader::skipSpaces() -{ - while ( current_ != end_ ) - { - Char c = *current_; - if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) - ++current_; - else - break; - } -} - - -bool -Reader::match( Location pattern, - int patternLength ) -{ - if ( end_ - current_ < patternLength ) - return false; - int index = patternLength; - while ( index-- ) - if ( current_[index] != pattern[index] ) - return false; - current_ += patternLength; - return true; -} - - -bool -Reader::readComment() -{ - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if ( c == '*' ) - successful = readCStyleComment(); - else if ( c == '/' ) - successful = readCppStyleComment(); - if ( !successful ) - return false; - - if ( collectComments_ ) - { - CommentPlacement placement = commentBefore; - if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) - { - if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) - placement = commentAfterOnSameLine; - } - - addComment( commentBegin, current_, placement ); - } - return true; -} - - -void -Reader::addComment( Location begin, - Location end, - CommentPlacement placement ) -{ - assert( collectComments_ ); - if ( placement == commentAfterOnSameLine ) - { - assert( lastValue_ != 0 ); - lastValue_->setComment( std::string( begin, end ), placement ); - } - else - { - if ( !commentsBefore_.empty() ) - commentsBefore_ += "\n"; - commentsBefore_ += std::string( begin, end ); - } -} - - -bool -Reader::readCStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '*' && *current_ == '/' ) - break; - } - return getNextChar() == '/'; -} - - -bool -Reader::readCppStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '\r' || c == '\n' ) - break; - } - return true; -} - - -void -Reader::readNumber() -{ - while ( current_ != end_ ) - { - if ( !(*current_ >= '0' && *current_ <= '9') && - !in( *current_, '.', 'e', 'E', '+', '-' ) ) - break; - ++current_; - } -} - -bool -Reader::readString() -{ - Char c = 0; - while ( current_ != end_ ) - { - c = getNextChar(); - if ( c == '\\' ) - getNextChar(); - else if ( c == '"' ) - break; - } - return c == '"'; -} - - -bool -Reader::readObject( Token &tokenStart ) -{ - Token tokenName; - std::string name; - currentValue() = Value( objectValue ); - while ( readToken( tokenName ) ) - { - bool initialTokenOk = true; - while ( tokenName.type_ == tokenComment && initialTokenOk ) - initialTokenOk = readToken( tokenName ); - if ( !initialTokenOk ) - break; - if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object - return true; - if ( tokenName.type_ != tokenString ) - break; - - name = ""; - if ( !decodeString( tokenName, name ) ) - return recoverFromError( tokenObjectEnd ); - - Token colon; - if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) - { - return addErrorAndRecover( "Missing ':' after object member name", - colon, - tokenObjectEnd ); - } - Value &value = currentValue()[ name ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenObjectEnd ); - - Token comma; - if ( !readToken( comma ) - || ( comma.type_ != tokenObjectEnd && - comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment ) ) - { - return addErrorAndRecover( "Missing ',' or '}' in object declaration", - comma, - tokenObjectEnd ); - } - bool finalizeTokenOk = true; - while ( comma.type_ == tokenComment && - finalizeTokenOk ) - finalizeTokenOk = readToken( comma ); - if ( comma.type_ == tokenObjectEnd ) - return true; - } - return addErrorAndRecover( "Missing '}' or object member name", - tokenName, - tokenObjectEnd ); -} - - -bool -Reader::readArray( Token &tokenStart ) -{ - currentValue() = Value( arrayValue ); - skipSpaces(); - if ( *current_ == ']' ) // empty array - { - Token endArray; - readToken( endArray ); - return true; - } - int index = 0; - while ( true ) - { - Value &value = currentValue()[ index++ ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenArrayEnd ); - - Token token; - // Accept Comment after last item in the array. - ok = readToken( token ); - while ( token.type_ == tokenComment && ok ) - { - ok = readToken( token ); - } - bool badTokenType = ( token.type_ == tokenArraySeparator && - token.type_ == tokenArrayEnd ); - if ( !ok || badTokenType ) - { - return addErrorAndRecover( "Missing ',' or ']' in array declaration", - token, - tokenArrayEnd ); - } - if ( token.type_ == tokenArrayEnd ) - break; - } - return true; -} - - -bool -Reader::decodeNumber( Token &token ) -{ - bool isDouble = false; - for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) - { - isDouble = isDouble - || in( *inspect, '.', 'e', 'E', '+' ) - || ( *inspect == '-' && inspect != token.start_ ); - } - if ( isDouble ) - return decodeDouble( token ); - Location current = token.start_; - bool isNegative = *current == '-'; - if ( isNegative ) - ++current; - Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) - : Value::maxUInt) / 10; - Value::UInt value = 0; - while ( current < token.end_ ) - { - Char c = *current++; - if ( c < '0' || c > '9' ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - if ( value >= threshold ) - return decodeDouble( token ); - value = value * 10 + Value::UInt(c - '0'); - } - if ( isNegative ) - currentValue() = -Value::Int( value ); - else if ( value <= Value::UInt(Value::maxInt) ) - currentValue() = Value::Int( value ); - else - currentValue() = value; - return true; -} - - -bool -Reader::decodeDouble( Token &token ) -{ - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - if ( length <= bufferSize ) - { - Char buffer[bufferSize]; - memcpy( buffer, token.start_, length ); - buffer[length] = 0; - count = sscanf( buffer, "%lf", &value ); - } - else - { - std::string buffer( token.start_, token.end_ ); - count = sscanf( buffer.c_str(), "%lf", &value ); - } - - if ( count != 1 ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - currentValue() = value; - return true; -} - - -bool -Reader::decodeString( Token &token ) -{ - std::string decoded; - if ( !decodeString( token, decoded ) ) - return false; - currentValue() = decoded; - return true; -} - - -bool -Reader::decodeString( Token &token, std::string &decoded ) -{ - decoded.reserve( token.end_ - token.start_ - 2 ); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while ( current != end ) - { - Char c = *current++; - if ( c == '"' ) - break; - else if ( c == '\\' ) - { - if ( current == end ) - return addError( "Empty escape sequence in string", token, current ); - Char escape = *current++; - switch ( escape ) - { - case '"': decoded += '"'; break; - case '/': decoded += '/'; break; - case '\\': decoded += '\\'; break; - case 'b': decoded += '\b'; break; - case 'f': decoded += '\f'; break; - case 'n': decoded += '\n'; break; - case 'r': decoded += '\r'; break; - case 't': decoded += '\t'; break; - case 'u': - { - unsigned int unicode; - if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) - return false; - decoded += codePointToUTF8(unicode); - } - break; - default: - return addError( "Bad escape sequence in string", token, current ); - } - } - else - { - decoded += c; - } - } - return true; -} - -bool -Reader::decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - - if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) - { - // surrogate pairs - if (end - current < 6) - return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++)== 'u') - { - if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) - { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } - else - return false; - } - else - return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); - } - return true; -} - -bool -Reader::decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - if ( end - current < 4 ) - return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); - unicode = 0; - for ( int index =0; index < 4; ++index ) - { - Char c = *current++; - unicode *= 16; - if ( c >= '0' && c <= '9' ) - unicode += c - '0'; - else if ( c >= 'a' && c <= 'f' ) - unicode += c - 'a' + 10; - else if ( c >= 'A' && c <= 'F' ) - unicode += c - 'A' + 10; - else - return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); - } - return true; -} - - -bool -Reader::addError( const std::string &message, - Token &token, - Location extra ) -{ - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back( info ); - return false; -} - - -bool -Reader::recoverFromError( TokenType skipUntilToken ) -{ - int errorCount = int(errors_.size()); - Token skip; - while ( true ) - { - if ( !readToken(skip) ) - errors_.resize( errorCount ); // discard errors caused by recovery - if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) - break; - } - errors_.resize( errorCount ); - return false; -} - - -bool -Reader::addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ) -{ - addError( message, token ); - return recoverFromError( skipUntilToken ); -} - - -Value & -Reader::currentValue() -{ - return *(nodes_.top()); -} - - -Reader::Char -Reader::getNextChar() -{ - if ( current_ == end_ ) - return 0; - return *current_++; -} - - -void -Reader::getLocationLineAndColumn( Location location, - int &line, - int &column ) const -{ - Location current = begin_; - Location lastLineStart = current; - line = 0; - while ( current < location && current != end_ ) - { - Char c = *current++; - if ( c == '\r' ) - { - if ( *current == '\n' ) - ++current; - lastLineStart = current; - ++line; - } - else if ( c == '\n' ) - { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - - -std::string -Reader::getLocationLineAndColumn( Location location ) const -{ - int line, column; - getLocationLineAndColumn( location, line, column ); - char buffer[18+16+16+1]; - sprintf( buffer, "Line %d, Column %d", line, column ); - return buffer; -} - - -std::string -Reader::getFormatedErrorMessages() const -{ - std::string formattedMessage; - for ( Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError ) - { - const ErrorInfo &error = *itError; - formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if ( error.extra_ ) - formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; - } - return formattedMessage; -} - - -std::istream& operator>>( std::istream &sin, Value &root ) -{ - Json::Reader reader; - bool ok = reader.parse(sin, root, true); - //JSON_ASSERT( ok ); - if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); - return sin; -} - - -} // namespace Json diff --git a/thirdparty/jsoncpp/src/lib_json/json_value.cpp b/thirdparty/jsoncpp/src/lib_json/json_value.cpp deleted file mode 100644 index 0c387599..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_value.cpp +++ /dev/null @@ -1,1717 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#ifdef JSON_USE_CPPTL -# include -#endif -#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -# include "json_batchallocator.h" -#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR - -#define JSON_ASSERT_UNREACHABLE assert( false ) -#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw -#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); - -namespace Json { - -const Value Value::null; -const Int Value::minInt = Int( ~(UInt(-1)/2) ); -const Int Value::maxInt = Int( UInt(-1)/2 ); -const UInt Value::maxUInt = UInt(-1); - -// A "safe" implementation of strdup. Allow null pointer to be passed. -// Also avoid warning on msvc80. -// -//inline char *safeStringDup( const char *czstring ) -//{ -// if ( czstring ) -// { -// const size_t length = (unsigned int)( strlen(czstring) + 1 ); -// char *newString = static_cast( malloc( length ) ); -// memcpy( newString, czstring, length ); -// return newString; -// } -// return 0; -//} -// -//inline char *safeStringDup( const std::string &str ) -//{ -// if ( !str.empty() ) -// { -// const size_t length = str.length(); -// char *newString = static_cast( malloc( length + 1 ) ); -// memcpy( newString, str.c_str(), length ); -// newString[length] = 0; -// return newString; -// } -// return 0; -//} - -ValueAllocator::~ValueAllocator() -{ -} - -class DefaultValueAllocator : public ValueAllocator -{ -public: - virtual ~DefaultValueAllocator() - { - } - - virtual char *makeMemberName( const char *memberName ) - { - return duplicateStringValue( memberName ); - } - - virtual void releaseMemberName( char *memberName ) - { - releaseStringValue( memberName ); - } - - virtual char *duplicateStringValue( const char *value, - unsigned int length = unknown ) - { - //@todo invesgate this old optimization - //if ( !value || value[0] == 0 ) - // return 0; - - if ( length == unknown ) - length = (unsigned int)strlen(value); - char *newString = static_cast( malloc( length + 1 ) ); - memcpy( newString, value, length ); - newString[length] = 0; - return newString; - } - - virtual void releaseStringValue( char *value ) - { - if ( value ) - free( value ); - } -}; - -static ValueAllocator *&valueAllocator() -{ - static DefaultValueAllocator defaultAllocator; - static ValueAllocator *valueAllocator = &defaultAllocator; - return valueAllocator; -} - -static struct DummyValueAllocatorInitializer { - DummyValueAllocatorInitializer() - { - valueAllocator(); // ensure valueAllocator() statics are initialized before main(). - } -} dummyValueAllocatorInitializer; - - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#ifdef JSON_VALUE_USE_INTERNAL_MAP -# include "json_internalarray.inl" -# include "json_internalmap.inl" -#endif // JSON_VALUE_USE_INTERNAL_MAP - -# include "json_valueiterator.inl" - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - - -Value::CommentInfo::CommentInfo() - : comment_( 0 ) -{ -} - -Value::CommentInfo::~CommentInfo() -{ - if ( comment_ ) - valueAllocator()->releaseStringValue( comment_ ); -} - - -void -Value::CommentInfo::setComment( const char *text ) -{ - if ( comment_ ) - valueAllocator()->releaseStringValue( comment_ ); - JSON_ASSERT( text ); - JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = valueAllocator()->duplicateStringValue( text ); -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -# ifndef JSON_VALUE_USE_INTERNAL_MAP - -// Notes: index_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString( int index ) - : cstr_( 0 ) - , index_( index ) -{ -} - -Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) - : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) - : cstr ) - , index_( allocate ) -{ -} - -Value::CZString::CZString( const CZString &other ) -: cstr_( other.index_ != noDuplication && other.cstr_ != 0 - ? valueAllocator()->makeMemberName( other.cstr_ ) - : other.cstr_ ) - , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) - : other.index_ ) -{ -} - -Value::CZString::~CZString() -{ - if ( cstr_ && index_ == duplicate ) - valueAllocator()->releaseMemberName( const_cast( cstr_ ) ); -} - -void -Value::CZString::swap( CZString &other ) -{ - std::swap( cstr_, other.cstr_ ); - std::swap( index_, other.index_ ); -} - -Value::CZString & -Value::CZString::operator =( const CZString &other ) -{ - CZString temp( other ); - swap( temp ); - return *this; -} - -bool -Value::CZString::operator<( const CZString &other ) const -{ - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) < 0; - return index_ < other.index_; -} - -bool -Value::CZString::operator==( const CZString &other ) const -{ - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) == 0; - return index_ == other.index_; -} - - -int -Value::CZString::index() const -{ - return index_; -} - - -const char * -Value::CZString::c_str() const -{ - return cstr_; -} - -bool -Value::CZString::isStaticString() const -{ - return index_ == noDuplication; -} - -#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value( ValueType type ) - : type_( type ) - , allocated_( 0 ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - switch ( type ) - { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArray(); - break; - case objectValue: - value_.map_ = mapAllocator()->newMap(); - break; -#endif - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - - -Value::Value( Int value ) - : type_( intValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.int_ = value; -} - - -Value::Value( UInt value ) - : type_( uintValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.uint_ = value; -} - -Value::Value( double value ) - : type_( realValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.real_ = value; -} - -Value::Value( const char *value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( value ); -} - - -Value::Value( const char *beginValue, - const char *endValue ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( beginValue, - UInt(endValue - beginValue) ); -} - - -Value::Value( const std::string &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), - (unsigned int)value.length() ); - -} - -Value::Value( const StaticString &value ) - : type_( stringValue ) - , allocated_( false ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = const_cast( value.c_str() ); -} - - -# ifdef JSON_USE_CPPTL -Value::Value( const CppTL::ConstString &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); -} -# endif - -Value::Value( bool value ) - : type_( booleanValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.bool_ = value; -} - - -Value::Value( const Value &other ) - : type_( other.type_ ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if ( other.value_.string_ ) - { - value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); - allocated_ = true; - } - else - value_.string_ = 0; - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues( *other.value_.map_ ); - break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); - break; - case objectValue: - value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); - break; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - if ( other.comments_ ) - { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) - { - const CommentInfo &otherComment = other.comments_[comment]; - if ( otherComment.comment_ ) - comments_[comment].setComment( otherComment.comment_ ); - } - } -} - - -Value::~Value() -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if ( allocated_ ) - valueAllocator()->releaseStringValue( value_.string_ ); - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - delete value_.map_; - break; -#else - case arrayValue: - arrayAllocator()->destructArray( value_.array_ ); - break; - case objectValue: - mapAllocator()->destructMap( value_.map_ ); - break; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - - if ( comments_ ) - delete[] comments_; -} - -Value & -Value::operator=( const Value &other ) -{ - Value temp( other ); - swap( temp ); - return *this; -} - -void -Value::swap( Value &other ) -{ - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap( value_, other.value_ ); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2; -} - -ValueType -Value::type() const -{ - return type_; -} - - -int -Value::compare( const Value &other ) -{ - /* - int typeDelta = other.type_ - type_; - switch ( type_ ) - { - case nullValue: - - return other.type_ == type_; - case intValue: - if ( other.type_.isNumeric() - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue, - break; - case arrayValue: - delete value_.array_; - break; - case objectValue: - delete value_.map_; - default: - JSON_ASSERT_UNREACHABLE; - } - */ - return 0; // unreachable -} - -bool -Value::operator <( const Value &other ) const -{ - int typeDelta = type_ - other.type_; - if ( typeDelta ) - return typeDelta < 0 ? true : false; - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - return ( value_.string_ == 0 && other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) < 0 ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - { - int delta = int( value_.map_->size() - other.value_.map_->size() ); - if ( delta ) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } -#else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) < 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) < 0; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable -} - -bool -Value::operator <=( const Value &other ) const -{ - return !(other > *this); -} - -bool -Value::operator >=( const Value &other ) const -{ - return !(*this < other); -} - -bool -Value::operator >( const Value &other ) const -{ - return other < *this; -} - -bool -Value::operator ==( const Value &other ) const -{ - //if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if ( type_ != temp ) - return false; - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - return ( value_.string_ == other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) == 0 ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() - && (*value_.map_) == (*other.value_.map_); -#else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) == 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) == 0; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable -} - -bool -Value::operator !=( const Value &other ) const -{ - return !( *this == other ); -} - -const char * -Value::asCString() const -{ - JSON_ASSERT( type_ == stringValue ); - return value_.string_; -} - - -std::string -Value::asString() const -{ - switch ( type_ ) - { - case nullValue: - return ""; - case stringValue: - return value_.string_ ? value_.string_ : ""; - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - case uintValue: - case realValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return ""; // unreachable -} - -# ifdef JSON_USE_CPPTL -CppTL::ConstString -Value::asConstString() const -{ - return CppTL::ConstString( asString().c_str() ); -} -# endif - -Value::Int -Value::asInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - return value_.int_; - case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); - return Int( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -Value::UInt -Value::asUInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); - return UInt( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -double -Value::asDouble() const -{ - switch ( type_ ) - { - case nullValue: - return 0.0; - case intValue: - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - return value_.real_; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -bool -Value::asBool() const -{ - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - case uintValue: - return value_.int_ != 0; - case realValue: - return value_.real_ != 0.0; - case booleanValue: - return value_.bool_; - case stringValue: - return value_.string_ && value_.string_[0] != 0; - case arrayValue: - case objectValue: - return value_.map_->size() != 0; - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -bool -Value::isConvertibleTo( ValueType other ) const -{ - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return ( other == nullValue && value_.int_ == 0 ) - || other == intValue - || ( other == uintValue && value_.int_ >= 0 ) - || other == realValue - || other == stringValue - || other == booleanValue; - case uintValue: - return ( other == nullValue && value_.uint_ == 0 ) - || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case realValue: - return ( other == nullValue && value_.real_ == 0.0 ) - || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) - || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) - || other == realValue - || other == stringValue - || other == booleanValue; - case booleanValue: - return ( other == nullValue && value_.bool_ == false ) - || other == intValue - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case stringValue: - return other == stringValue - || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); - case arrayValue: - return other == arrayValue - || ( other == nullValue && value_.map_->size() == 0 ); - case objectValue: - return other == objectValue - || ( other == nullValue && value_.map_->size() == 0 ); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -/// Number of values in array or object -Value::UInt -Value::size() const -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: // size of the array is highest index + 1 - if ( !value_.map_->empty() ) - { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index()+1; - } - return 0; - case objectValue: - return Int( value_.map_->size() ); -#else - case arrayValue: - return Int( value_.array_->size() ); - case objectValue: - return Int( value_.map_->size() ); -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - - -bool -Value::empty() const -{ - if ( isNull() || isArray() || isObject() ) - return size() == 0u; - else - return false; -} - - -bool -Value::operator!() const -{ - return isNull(); -} - - -void -Value::clear() -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); - - switch ( type_ ) - { -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_->clear(); - break; -#else - case arrayValue: - value_.array_->clear(); - break; - case objectValue: - value_.map_->clear(); - break; -#endif - default: - break; - } -} - -void -Value::resize( UInt newSize ) -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - UInt oldSize = size(); - if ( newSize == 0 ) - clear(); - else if ( newSize > oldSize ) - (*this)[ newSize - 1 ]; - else - { - for ( UInt index = newSize; index < oldSize; ++index ) - value_.map_->erase( index ); - assert( size() == newSize ); - } -#else - value_.array_->resize( newSize ); -#endif -} - - -Value & -Value::operator[]( UInt index ) -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::iterator it = value_.map_->lower_bound( key ); - if ( it != value_.map_->end() && (*it).first == key ) - return (*it).second; - - ObjectValues::value_type defaultValue( key, null ); - it = value_.map_->insert( it, defaultValue ); - return (*it).second; -#else - return value_.array_->resolveReference( index ); -#endif -} - - -const Value & -Value::operator[]( UInt index ) const -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::const_iterator it = value_.map_->find( key ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; -#else - Value *value = value_.array_->find( index ); - return value ? *value : null; -#endif -} - - -Value & -Value::operator[]( const char *key ) -{ - return resolveReference( key, false ); -} - - -Value & -Value::resolveReference( const char *key, - bool isStatic ) -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - *this = Value( objectValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, isStatic ? CZString::noDuplication - : CZString::duplicateOnCopy ); - ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); - if ( it != value_.map_->end() && (*it).first == actualKey ) - return (*it).second; - - ObjectValues::value_type defaultValue( actualKey, null ); - it = value_.map_->insert( it, defaultValue ); - Value &value = (*it).second; - return value; -#else - return value_.map_->resolveReference( key, isStatic ); -#endif -} - - -Value -Value::get( UInt index, - const Value &defaultValue ) const -{ - const Value *value = &((*this)[index]); - return value == &null ? defaultValue : *value; -} - - -bool -Value::isValidIndex( UInt index ) const -{ - return index < size(); -} - - - -const Value & -Value::operator[]( const char *key ) const -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::const_iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; -#else - const Value *value = value_.map_->find( key ); - return value ? *value : null; -#endif -} - - -Value & -Value::operator[]( const std::string &key ) -{ - return (*this)[ key.c_str() ]; -} - - -const Value & -Value::operator[]( const std::string &key ) const -{ - return (*this)[ key.c_str() ]; -} - -Value & -Value::operator[]( const StaticString &key ) -{ - return resolveReference( key, true ); -} - - -# ifdef JSON_USE_CPPTL -Value & -Value::operator[]( const CppTL::ConstString &key ) -{ - return (*this)[ key.c_str() ]; -} - - -const Value & -Value::operator[]( const CppTL::ConstString &key ) const -{ - return (*this)[ key.c_str() ]; -} -# endif - - -Value & -Value::append( const Value &value ) -{ - return (*this)[size()] = value; -} - - -Value -Value::get( const char *key, - const Value &defaultValue ) const -{ - const Value *value = &((*this)[key]); - return value == &null ? defaultValue : *value; -} - - -Value -Value::get( const std::string &key, - const Value &defaultValue ) const -{ - return get( key.c_str(), defaultValue ); -} - -Value -Value::removeMember( const char* key ) -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - Value old(it->second); - value_.map_->erase(it); - return old; -#else - Value *value = value_.map_->find( key ); - if (value){ - Value old(*value); - value_.map_.remove( key ); - return old; - } else { - return null; - } -#endif -} - -Value -Value::removeMember( const std::string &key ) -{ - return removeMember( key.c_str() ); -} - -# ifdef JSON_USE_CPPTL -Value -Value::get( const CppTL::ConstString &key, - const Value &defaultValue ) const -{ - return get( key.c_str(), defaultValue ); -} -# endif - -bool -Value::isMember( const char *key ) const -{ - const Value *value = &((*this)[key]); - return value != &null; -} - - -bool -Value::isMember( const std::string &key ) const -{ - return isMember( key.c_str() ); -} - - -# ifdef JSON_USE_CPPTL -bool -Value::isMember( const CppTL::ConstString &key ) const -{ - return isMember( key.c_str() ); -} -#endif - -Value::Members -Value::getMemberNames() const -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return Value::Members(); - Members members; - members.reserve( value_.map_->size() ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for ( ; it != itEnd; ++it ) - members.push_back( std::string( (*it).first.c_str() ) ); -#else - ValueInternalMap::IteratorState it; - ValueInternalMap::IteratorState itEnd; - value_.map_->makeBeginIterator( it ); - value_.map_->makeEndIterator( itEnd ); - for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) - members.push_back( std::string( ValueInternalMap::key( it ) ) ); -#endif - return members; -} -// -//# ifdef JSON_USE_CPPTL -//EnumMemberNames -//Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -//EnumValues -//Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type() ); -// return EnumValues(); -//} -// -//# endif - - -bool -Value::isNull() const -{ - return type_ == nullValue; -} - - -bool -Value::isBool() const -{ - return type_ == booleanValue; -} - - -bool -Value::isInt() const -{ - return type_ == intValue; -} - - -bool -Value::isUInt() const -{ - return type_ == uintValue; -} - - -bool -Value::isIntegral() const -{ - return type_ == intValue - || type_ == uintValue - || type_ == booleanValue; -} - - -bool -Value::isDouble() const -{ - return type_ == realValue; -} - - -bool -Value::isNumeric() const -{ - return isIntegral() || isDouble(); -} - - -bool -Value::isString() const -{ - return type_ == stringValue; -} - - -bool -Value::isArray() const -{ - return type_ == nullValue || type_ == arrayValue; -} - - -bool -Value::isObject() const -{ - return type_ == nullValue || type_ == objectValue; -} - - -void -Value::setComment( const char *comment, - CommentPlacement placement ) -{ - if ( !comments_ ) - comments_ = new CommentInfo[numberOfCommentPlacement]; - comments_[placement].setComment( comment ); -} - - -void -Value::setComment( const std::string &comment, - CommentPlacement placement ) -{ - setComment( comment.c_str(), placement ); -} - - -bool -Value::hasComment( CommentPlacement placement ) const -{ - return comments_ != 0 && comments_[placement].comment_ != 0; -} - -std::string -Value::getComment( CommentPlacement placement ) const -{ - if ( hasComment(placement) ) - return comments_[placement].comment_; - return ""; -} - - -std::string -Value::toStyledString() const -{ - StyledWriter writer; - return writer.write( *this ); -} - - -Value::const_iterator -Value::begin() const -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->begin() ); - break; -#endif - default: - break; - } - return const_iterator(); -} - -Value::const_iterator -Value::end() const -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return const_iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->end() ); - break; -#endif - default: - break; - } - return const_iterator(); -} - - -Value::iterator -Value::begin() -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->begin() ); - break; -#endif - default: - break; - } - return iterator(); -} - -Value::iterator -Value::end() -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->end() ); - break; -#endif - default: - break; - } - return iterator(); -} - - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() - : kind_( kindNone ) -{ -} - - -PathArgument::PathArgument( Value::UInt index ) - : index_( index ) - , kind_( kindIndex ) -{ -} - - -PathArgument::PathArgument( const char *key ) - : key_( key ) - , kind_( kindKey ) -{ -} - - -PathArgument::PathArgument( const std::string &key ) - : key_( key.c_str() ) - , kind_( kindKey ) -{ -} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path( const std::string &path, - const PathArgument &a1, - const PathArgument &a2, - const PathArgument &a3, - const PathArgument &a4, - const PathArgument &a5 ) -{ - InArgs in; - in.push_back( &a1 ); - in.push_back( &a2 ); - in.push_back( &a3 ); - in.push_back( &a4 ); - in.push_back( &a5 ); - makePath( path, in ); -} - - -void -Path::makePath( const std::string &path, - const InArgs &in ) -{ - const char *current = path.c_str(); - const char *end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while ( current != end ) - { - if ( *current == '[' ) - { - ++current; - if ( *current == '%' ) - addPathInArg( path, in, itInArg, PathArgument::kindIndex ); - else - { - Value::UInt index = 0; - for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) - index = index * 10 + Value::UInt(*current - '0'); - args_.push_back( index ); - } - if ( current == end || *current++ != ']' ) - invalidPath( path, int(current - path.c_str()) ); - } - else if ( *current == '%' ) - { - addPathInArg( path, in, itInArg, PathArgument::kindKey ); - ++current; - } - else if ( *current == '.' ) - { - ++current; - } - else - { - const char *beginName = current; - while ( current != end && !strchr( "[.", *current ) ) - ++current; - args_.push_back( std::string( beginName, current ) ); - } - } -} - - -void -Path::addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ) -{ - if ( itInArg == in.end() ) - { - // Error: missing argument %d - } - else if ( (*itInArg)->kind_ != kind ) - { - // Error: bad argument type - } - else - { - args_.push_back( **itInArg ); - } -} - - -void -Path::invalidPath( const std::string &path, - int location ) -{ - // Error: invalid path. -} - - -const Value & -Path::resolve( const Value &root ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - { - // Error: unable to resolve path (array value expected at position... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: unable to resolve path (object value expected at position...) - } - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - { - // Error: unable to resolve path (object has no member named '' at position...) - } - } - } - return *node; -} - - -Value -Path::resolve( const Value &root, - const Value &defaultValue ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - return defaultValue; - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - return defaultValue; - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - return defaultValue; - } - } - return *node; -} - - -Value & -Path::make( Value &root ) const -{ - Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() ) - { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - - -} // namespace Json diff --git a/thirdparty/jsoncpp/src/lib_json/json_valueiterator.inl b/thirdparty/jsoncpp/src/lib_json/json_valueiterator.inl deleted file mode 100644 index 736e260e..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_valueiterator.inl +++ /dev/null @@ -1,292 +0,0 @@ -// included by json_value.cpp -// everything is within Json namespace - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() -#ifndef JSON_VALUE_USE_INTERNAL_MAP - : current_() - , isNull_( true ) -{ -} -#else - : isArray_( true ) - , isNull_( true ) -{ - iterator_.array_ = ValueInternalArray::IteratorState(); -} -#endif - - -#ifndef JSON_VALUE_USE_INTERNAL_MAP -ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) - : current_( current ) - , isNull_( false ) -{ -} -#else -ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) - : isArray_( true ) -{ - iterator_.array_ = state; -} - - -ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) - : isArray_( false ) -{ - iterator_.map_ = state; -} -#endif - -Value & -ValueIteratorBase::deref() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - return current_->second; -#else - if ( isArray_ ) - return ValueInternalArray::dereference( iterator_.array_ ); - return ValueInternalMap::value( iterator_.map_ ); -#endif -} - - -void -ValueIteratorBase::increment() -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - ++current_; -#else - if ( isArray_ ) - ValueInternalArray::increment( iterator_.array_ ); - ValueInternalMap::increment( iterator_.map_ ); -#endif -} - - -void -ValueIteratorBase::decrement() -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - --current_; -#else - if ( isArray_ ) - ValueInternalArray::decrement( iterator_.array_ ); - ValueInternalMap::decrement( iterator_.map_ ); -#endif -} - - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance( const SelfType &other ) const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP -# ifdef JSON_USE_CPPTL_SMALLMAP - return current_ - other.current_; -# else - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if ( isNull_ && other.isNull_ ) - { - return 0; - } - - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) - { - ++myDistance; - } - return myDistance; -# endif -#else - if ( isArray_ ) - return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); - return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); -#endif -} - - -bool -ValueIteratorBase::isEqual( const SelfType &other ) const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - if ( isNull_ ) - { - return other.isNull_; - } - return current_ == other.current_; -#else - if ( isArray_ ) - return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); - return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); -#endif -} - - -void -ValueIteratorBase::copy( const SelfType &other ) -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - current_ = other.current_; -#else - if ( isArray_ ) - iterator_.array_ = other.iterator_.array_; - iterator_.map_ = other.iterator_.map_; -#endif -} - - -Value -ValueIteratorBase::key() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - const Value::CZString czstring = (*current_).first; - if ( czstring.c_str() ) - { - if ( czstring.isStaticString() ) - return Value( StaticString( czstring.c_str() ) ); - return Value( czstring.c_str() ); - } - return Value( czstring.index() ); -#else - if ( isArray_ ) - return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); - bool isStatic; - const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); - if ( isStatic ) - return Value( StaticString( memberName ) ); - return Value( memberName ); -#endif -} - - -UInt -ValueIteratorBase::index() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - const Value::CZString czstring = (*current_).first; - if ( !czstring.c_str() ) - return czstring.index(); - return Value::UInt( -1 ); -#else - if ( isArray_ ) - return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); - return Value::UInt( -1 ); -#endif -} - - -const char * -ValueIteratorBase::memberName() const -{ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - const char *name = (*current_).first.c_str(); - return name ? name : ""; -#else - if ( !isArray_ ) - return ValueInternalMap::key( iterator_.map_ ); - return ""; -#endif -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() -{ -} - - -#ifndef JSON_VALUE_USE_INTERNAL_MAP -ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) - : ValueIteratorBase( current ) -{ -} -#else -ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} - -ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} -#endif - -ValueConstIterator & -ValueConstIterator::operator =( const ValueIteratorBase &other ) -{ - copy( other ); - return *this; -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() -{ -} - - -#ifndef JSON_VALUE_USE_INTERNAL_MAP -ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) - : ValueIteratorBase( current ) -{ -} -#else -ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} - -ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) - : ValueIteratorBase( state ) -{ -} -#endif - -ValueIterator::ValueIterator( const ValueConstIterator &other ) - : ValueIteratorBase( other ) -{ -} - -ValueIterator::ValueIterator( const ValueIterator &other ) - : ValueIteratorBase( other ) -{ -} - -ValueIterator & -ValueIterator::operator =( const SelfType &other ) -{ - copy( other ); - return *this; -} diff --git a/thirdparty/jsoncpp/src/lib_json/json_writer.cpp b/thirdparty/jsoncpp/src/lib_json/json_writer.cpp deleted file mode 100644 index e96a5e98..00000000 --- a/thirdparty/jsoncpp/src/lib_json/json_writer.cpp +++ /dev/null @@ -1,828 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. -#endif - -namespace Json { - -static bool isControlCharacter(char ch) -{ - return ch > 0 && ch <= 0x1F; -} - -static bool containsControlCharacter( const char* str ) -{ - while ( *str ) - { - if ( isControlCharacter( *(str++) ) ) - return true; - } - return false; -} -static void uintToString( unsigned int value, - char *¤t ) -{ - *--current = 0; - do - { - *--current = (value % 10) + '0'; - value /= 10; - } - while ( value != 0 ); -} - -std::string valueToString( Int value ) -{ - char buffer[32]; - char *current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if ( isNegative ) - value = -value; - uintToString( UInt(value), current ); - if ( isNegative ) - *--current = '-'; - assert( current >= buffer ); - return current; -} - - -std::string valueToString( UInt value ) -{ - char buffer[32]; - char *current = buffer + sizeof(buffer); - uintToString( value, current ); - assert( current >= buffer ); - return current; -} - -std::string valueToString( double value ) -{ - char buffer[32]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. - sprintf_s(buffer, sizeof(buffer), "%#.16g", value); -#else - sprintf(buffer, "%#.16g", value); -#endif - char* ch = buffer + strlen(buffer) - 1; - if (*ch != '0') return buffer; // nothing to truncate, so save time - while(ch > buffer && *ch == '0'){ - --ch; - } - char* last_nonzero = ch; - while(ch >= buffer){ - switch(*ch){ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - --ch; - continue; - case '.': - // Truncate zeroes to save bytes in output, but keep one. - *(last_nonzero+2) = '\0'; - return buffer; - default: - return buffer; - } - } - return buffer; -} - - -std::string valueToString( bool value ) -{ - return value ? "true" : "false"; -} - -std::string valueToQuotedString( const char *value ) -{ - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c=value; *c != 0; ++c) - { - switch(*c) - { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - //case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } - else - { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() -{ -} - - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - : yamlCompatiblityEnabled_( false ) -{ -} - - -void -FastWriter::enableYAMLCompatibility() -{ - yamlCompatiblityEnabled_ = true; -} - - -std::string -FastWriter::write( const Value &root ) -{ - document_ = ""; - writeValue( root ); - document_ += "\n"; - return document_; -} - - -void -FastWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - document_ += "null"; - break; - case intValue: - document_ += valueToString( value.asInt() ); - break; - case uintValue: - document_ += valueToString( value.asUInt() ); - break; - case realValue: - document_ += valueToString( value.asDouble() ); - break; - case stringValue: - document_ += valueToQuotedString( value.asCString() ); - break; - case booleanValue: - document_ += valueToString( value.asBool() ); - break; - case arrayValue: - { - document_ += "["; - int size = value.size(); - for ( int index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ","; - writeValue( value[index] ); - } - document_ += "]"; - } - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - document_ += "{"; - for ( Value::Members::iterator it = members.begin(); - it != members.end(); - ++it ) - { - const std::string &name = *it; - if ( it != members.begin() ) - document_ += ","; - document_ += valueToQuotedString( name.c_str() ); - document_ += yamlCompatiblityEnabled_ ? ": " - : ":"; - writeValue( value[name] ); - } - document_ += "}"; - } - break; - } -} - - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() - : rightMargin_( 74 ) - , indentSize_( 3 ) -{ -} - - -std::string -StyledWriter::write( const Value &root ) -{ - document_ = ""; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - document_ += "\n"; - return document_; -} - - -void -StyledWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - while ( true ) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - document_ += " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - while ( true ) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - document_ += "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - - -bool -StyledWriter::isMultineArray( const Value &value ) -{ - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - - -void -StyledWriter::pushValue( const std::string &value ) -{ - if ( addChildValues_ ) - childValues_.push_back( value ); - else - document_ += value; -} - - -void -StyledWriter::writeIndent() -{ - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - - -void -StyledWriter::writeWithIndent( const std::string &value ) -{ - writeIndent(); - document_ += value; -} - - -void -StyledWriter::indent() -{ - indentString_ += std::string( indentSize_, ' ' ); -} - - -void -StyledWriter::unindent() -{ - assert( int(indentString_.size()) >= indentSize_ ); - indentString_.resize( indentString_.size() - indentSize_ ); -} - - -void -StyledWriter::writeCommentBeforeValue( const Value &root ) -{ - if ( !root.hasComment( commentBefore ) ) - return; - document_ += normalizeEOL( root.getComment( commentBefore ) ); - document_ += "\n"; -} - - -void -StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) -{ - if ( root.hasComment( commentAfterOnSameLine ) ) - document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); - - if ( root.hasComment( commentAfter ) ) - { - document_ += "\n"; - document_ += normalizeEOL( root.getComment( commentAfter ) ); - document_ += "\n"; - } -} - - -bool -StyledWriter::hasCommentForValue( const Value &value ) -{ - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); -} - - -std::string -StyledWriter::normalizeEOL( const std::string &text ) -{ - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; -} - - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter( std::string indentation ) - : document_(NULL) - , rightMargin_( 74 ) - , indentation_( indentation ) -{ -} - - -void -StyledStreamWriter::write( std::ostream &out, const Value &root ) -{ - document_ = &out; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. -} - - -void -StyledStreamWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - while ( true ) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - *document_ << " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledStreamWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - while ( true ) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - *document_ << "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - - -bool -StyledStreamWriter::isMultineArray( const Value &value ) -{ - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - - -void -StyledStreamWriter::pushValue( const std::string &value ) -{ - if ( addChildValues_ ) - childValues_.push_back( value ); - else - *document_ << value; -} - - -void -StyledStreamWriter::writeIndent() -{ - /* - Some comments in this method would have been nice. ;-) - - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - *document_ << '\n'; - } - */ - *document_ << '\n' << indentString_; -} - - -void -StyledStreamWriter::writeWithIndent( const std::string &value ) -{ - writeIndent(); - *document_ << value; -} - - -void -StyledStreamWriter::indent() -{ - indentString_ += indentation_; -} - - -void -StyledStreamWriter::unindent() -{ - assert( indentString_.size() >= indentation_.size() ); - indentString_.resize( indentString_.size() - indentation_.size() ); -} - - -void -StyledStreamWriter::writeCommentBeforeValue( const Value &root ) -{ - if ( !root.hasComment( commentBefore ) ) - return; - *document_ << normalizeEOL( root.getComment( commentBefore ) ); - *document_ << "\n"; -} - - -void -StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) -{ - if ( root.hasComment( commentAfterOnSameLine ) ) - *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); - - if ( root.hasComment( commentAfter ) ) - { - *document_ << "\n"; - *document_ << normalizeEOL( root.getComment( commentAfter ) ); - *document_ << "\n"; - } -} - - -bool -StyledStreamWriter::hasCommentForValue( const Value &value ) -{ - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); -} - - -std::string -StyledStreamWriter::normalizeEOL( const std::string &text ) -{ - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; -} - - -std::ostream& operator<<( std::ostream &sout, const Value &root ) -{ - Json::StyledStreamWriter writer; - writer.write(sout, root); - return sout; -} - - -} // namespace Json diff --git a/thirdparty/jsoncpp/src/lib_json/sconscript b/thirdparty/jsoncpp/src/lib_json/sconscript deleted file mode 100644 index f6520d18..00000000 --- a/thirdparty/jsoncpp/src/lib_json/sconscript +++ /dev/null @@ -1,8 +0,0 @@ -Import( 'env buildLibrary' ) - -buildLibrary( env, Split( """ - json_reader.cpp - json_value.cpp - json_writer.cpp - """ ), - 'json' ) From 744a4f3ec1b3c123e4628c7ec45be2fe430d7e9c Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Jun 2019 21:20:04 -0400 Subject: [PATCH 177/186] Remove Json:Reader `Json::Reader` has been deprecated for some time, so we replace it with `Json::CharReader` generated by a `Json::CharReaderBuilder`, or (in the one instance where we have a stream as input) `Json::parseFromStream();` --- src/CacheDisk.cpp | 16 ++++++++++++---- src/CacheMemory.cpp | 17 +++++++++++++---- src/ChunkReader.cpp | 14 ++++++++++---- src/Clip.cpp | 8 ++++++-- src/Color.cpp | 8 ++++++-- src/Coordinate.cpp | 8 ++++++-- src/DecklinkReader.cpp | 8 ++++++-- src/DummyReader.cpp | 8 ++++++-- src/EffectBase.cpp | 8 ++++++-- src/FFmpegReader.cpp | 8 ++++++-- src/FrameMapper.cpp | 8 ++++++-- src/ImageReader.cpp | 10 +++++++--- src/KeyFrame.cpp | 8 ++++++-- src/Point.cpp | 8 ++++++-- src/Profiles.cpp | 8 ++++++-- src/QtImageReader.cpp | 8 ++++++-- src/TextReader.cpp | 8 ++++++-- src/Timeline.cpp | 16 ++++++++++++---- src/WriterBase.cpp | 8 ++++++-- src/effects/Bars.cpp | 8 ++++++-- src/effects/Blur.cpp | 8 ++++++-- src/effects/Brightness.cpp | 8 ++++++-- src/effects/ChromaKey.cpp | 8 ++++++-- src/effects/ColorShift.cpp | 8 ++++++-- src/effects/Crop.cpp | 9 ++++++--- src/effects/Deinterlace.cpp | 8 ++++++-- src/effects/Hue.cpp | 8 ++++++-- src/effects/Mask.cpp | 8 ++++++-- src/effects/Negate.cpp | 8 ++++++-- src/effects/Pixelate.cpp | 8 ++++++-- src/effects/Saturation.cpp | 8 ++++++-- src/effects/Shift.cpp | 8 ++++++-- src/effects/Wave.cpp | 8 ++++++-- tests/Clip_Tests.cpp | 16 +++++++++++----- 34 files changed, 233 insertions(+), 81 deletions(-) diff --git a/src/CacheDisk.cpp b/src/CacheDisk.cpp index 23854f3a..148dc1db 100644 --- a/src/CacheDisk.cpp +++ b/src/CacheDisk.cpp @@ -486,8 +486,12 @@ Json::Value CacheDisk::JsonValue() { // Parse and append range data (if any) Json::Value ranges; - Json::Reader reader; - bool success = reader.parse( json_ranges, ranges ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( json_ranges.c_str(), + json_ranges.c_str() + json_ranges.size(), &ranges, &errors ); if (success) root["ranges"] = ranges; @@ -500,8 +504,12 @@ void CacheDisk::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/CacheMemory.cpp b/src/CacheMemory.cpp index f830d74e..2cc79e7b 100644 --- a/src/CacheMemory.cpp +++ b/src/CacheMemory.cpp @@ -340,8 +340,13 @@ Json::Value CacheMemory::JsonValue() { // Parse and append range data (if any) Json::Value ranges; - Json::Reader reader; - bool success = reader.parse( json_ranges, ranges ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( json_ranges.c_str(), + json_ranges.c_str() + json_ranges.size(), &ranges, &errors ); + if (success) root["ranges"] = ranges; @@ -354,8 +359,12 @@ void CacheMemory::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp index fe552243..44f887b7 100644 --- a/src/ChunkReader.cpp +++ b/src/ChunkReader.cpp @@ -76,8 +76,10 @@ void ChunkReader::load_json() // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( json_string.str(), root ); + Json::CharReaderBuilder rbuilder; + + string errors; + bool success = Json::parseFromStream(rbuilder, json_string, &root, &errors); if (!success) // Raise exception throw InvalidJSON("Chunk folder could not be opened.", path); @@ -278,8 +280,12 @@ void ChunkReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/Clip.cpp b/src/Clip.cpp index 2099705d..0cb88cfe 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -786,8 +786,12 @@ void Clip::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/Color.cpp b/src/Color.cpp index df2cf097..e9bf438a 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -107,8 +107,12 @@ void Color::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp index 60ea90b2..835cbbf0 100644 --- a/src/Coordinate.cpp +++ b/src/Coordinate.cpp @@ -70,8 +70,12 @@ void Coordinate::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp index 1d9b70b9..7e491424 100644 --- a/src/DecklinkReader.cpp +++ b/src/DecklinkReader.cpp @@ -265,8 +265,12 @@ void DecklinkReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index dc77db5b..bb079abb 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -143,8 +143,12 @@ void DummyReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp index c0afded8..48dd266f 100644 --- a/src/EffectBase.cpp +++ b/src/EffectBase.cpp @@ -99,8 +99,12 @@ void EffectBase::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 6aa0938e..0e28971d 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -2422,8 +2422,12 @@ void FFmpegReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse(value, root); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse(value.c_str(), value.c_str() + value.size(), + &root, &errors); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 113171a2..22cf4a97 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -694,8 +694,12 @@ void FrameMapper::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index f535666a..3c1d334a 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -106,7 +106,7 @@ void ImageReader::Close() { // Mark as "closed" is_open = false; - + // Delete the image image.reset(); } @@ -153,8 +153,12 @@ void ImageReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 2b0389de..f585333d 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -366,8 +366,12 @@ void Keyframe::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/Point.cpp b/src/Point.cpp index e55e6453..e41883bf 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -133,8 +133,12 @@ void Point::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/Profiles.cpp b/src/Profiles.cpp index 390e5765..53a3424b 100644 --- a/src/Profiles.cpp +++ b/src/Profiles.cpp @@ -164,8 +164,12 @@ void Profile::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index 502ddb9a..7630a693 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -286,8 +286,12 @@ void QtImageReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/TextReader.cpp b/src/TextReader.cpp index 8234aa5d..a24f26e4 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -201,8 +201,12 @@ void TextReader::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 37d3f71c..1758479b 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -990,8 +990,12 @@ void Timeline::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); @@ -1083,8 +1087,12 @@ void Timeline::ApplyJsonDiff(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success || !root.isArray()) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid).", ""); diff --git a/src/WriterBase.cpp b/src/WriterBase.cpp index 3697c52a..3aedec67 100644 --- a/src/WriterBase.cpp +++ b/src/WriterBase.cpp @@ -196,8 +196,12 @@ void WriterBase::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Bars.cpp b/src/effects/Bars.cpp index a4a72c19..f7219215 100644 --- a/src/effects/Bars.cpp +++ b/src/effects/Bars.cpp @@ -138,8 +138,12 @@ void Bars::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Blur.cpp b/src/effects/Blur.cpp index 6eafc2a1..dbbfbdbf 100644 --- a/src/effects/Blur.cpp +++ b/src/effects/Blur.cpp @@ -275,8 +275,12 @@ void Blur::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp index 591bce6a..e817a062 100644 --- a/src/effects/Brightness.cpp +++ b/src/effects/Brightness.cpp @@ -129,8 +129,12 @@ void Brightness::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp index 2c3008f2..fe6a2687 100644 --- a/src/effects/ChromaKey.cpp +++ b/src/effects/ChromaKey.cpp @@ -122,8 +122,12 @@ void ChromaKey::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/ColorShift.cpp b/src/effects/ColorShift.cpp index 00300561..e2a72d7e 100644 --- a/src/effects/ColorShift.cpp +++ b/src/effects/ColorShift.cpp @@ -221,8 +221,12 @@ void ColorShift::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Crop.cpp b/src/effects/Crop.cpp index 53953ec2..245307ef 100644 --- a/src/effects/Crop.cpp +++ b/src/effects/Crop.cpp @@ -137,8 +137,12 @@ void Crop::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); @@ -193,4 +197,3 @@ string Crop::PropertiesJSON(int64_t requested_frame) { // Return formatted string return root.toStyledString(); } - diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp index bf34d13f..dc35cd9a 100644 --- a/src/effects/Deinterlace.cpp +++ b/src/effects/Deinterlace.cpp @@ -116,8 +116,12 @@ void Deinterlace::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Hue.cpp b/src/effects/Hue.cpp index ae401a8b..4ea3bcd5 100644 --- a/src/effects/Hue.cpp +++ b/src/effects/Hue.cpp @@ -123,8 +123,12 @@ void Hue::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index f8f34ac6..95dd3489 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -176,8 +176,12 @@ void Mask::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp index 8ff6e0d6..98b79213 100644 --- a/src/effects/Negate.cpp +++ b/src/effects/Negate.cpp @@ -77,8 +77,12 @@ void Negate::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Pixelate.cpp b/src/effects/Pixelate.cpp index 78030283..bad0fa15 100644 --- a/src/effects/Pixelate.cpp +++ b/src/effects/Pixelate.cpp @@ -134,8 +134,12 @@ void Pixelate::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp index ecb3165f..0393ed0b 100644 --- a/src/effects/Saturation.cpp +++ b/src/effects/Saturation.cpp @@ -134,8 +134,12 @@ void Saturation::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Shift.cpp b/src/effects/Shift.cpp index 80a7b2d7..89ad36d1 100644 --- a/src/effects/Shift.cpp +++ b/src/effects/Shift.cpp @@ -154,8 +154,12 @@ void Shift::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/src/effects/Wave.cpp b/src/effects/Wave.cpp index 0a1c5273..2325213f 100644 --- a/src/effects/Wave.cpp +++ b/src/effects/Wave.cpp @@ -137,8 +137,12 @@ void Wave::SetJson(string value) { // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( value, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + + string errors; + bool success = reader->parse( value.c_str(), + value.c_str() + value.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); diff --git a/tests/Clip_Tests.cpp b/tests/Clip_Tests.cpp index 1134e8ab..0ae00d65 100644 --- a/tests/Clip_Tests.cpp +++ b/tests/Clip_Tests.cpp @@ -110,8 +110,11 @@ TEST(Clip_Properties) // Parse JSON string into JSON objects Json::Value root; - Json::Reader reader; - bool success = reader.parse( properties, root ); + Json::CharReaderBuilder rbuilder; + Json::CharReader* reader(rbuilder.newCharReader()); + string errors; + bool success = reader->parse( properties.c_str(), + properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); @@ -135,7 +138,8 @@ TEST(Clip_Properties) // Parse JSON string into JSON objects root.clear(); - success = reader.parse( properties, root ); + success = reader->parse( properties.c_str(), + properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); @@ -159,7 +163,8 @@ TEST(Clip_Properties) // Parse JSON string into JSON objects root.clear(); - success = reader.parse( properties, root ); + success = reader->parse( properties.c_str(), + properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); @@ -182,7 +187,8 @@ TEST(Clip_Properties) // Parse JSON string into JSON objects root.clear(); - success = reader.parse( properties, root ); + success = reader->parse( properties.c_str(), + properties.c_str() + properties.size(), &root, &errors ); if (!success) // Raise exception throw InvalidJSON("JSON could not be parsed (or is invalid)", ""); From 9378225d76dce86222c7aa6684bc916b6a292598 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Jun 2019 22:21:50 -0400 Subject: [PATCH 178/186] Add -no-integrated-cpp for G++ < 9 --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e3a49c3..03c5a761 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,13 @@ Generating build files for OpenShot SO/API/ABI Version: ${SO_VERSION} ") +#### Work around a GCC < 9 bug with handling of _Pragma() in macros +#### See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 +if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND + (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS "9.0.0")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-integrated-cpp") +endif() + #### Enable C++11 (for std::shared_ptr support) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) From ddd78215bb356d29986e4477a6ccd2fe2ad45441 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Jun 2019 22:53:42 -0400 Subject: [PATCH 179/186] Also adjust tests for new jsoncpp --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e358fb44..da04c0da 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -194,7 +194,7 @@ if (USE_SYSTEM_JSONCPP) find_package(JsonCpp REQUIRED) include_directories(${JSONCPP_INCLUDE_DIRS}) else() - include_directories("../thirdparty/jsoncpp/include") + include_directories("../thirdparty/jsoncpp") endif(USE_SYSTEM_JSONCPP) IF (NOT DISABLE_TESTS) From 40b9891d8a02458beb4528ec734d88f399b32661 Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 20 Jun 2019 13:32:30 -0700 Subject: [PATCH 180/186] Update FFmpegWriter.cpp Reverse 1st attempt --- src/FFmpegWriter.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 64618ce5..072ac6d7 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -992,14 +992,7 @@ AVStream *FFmpegWriter::add_audio_stream() { throw InvalidCodec("A valid audio codec could not be found for this file.", path); // Create a new audio stream -#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) -_Pragma ("GCC diagnostic push") -_Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#endif AV_FORMAT_NEW_STREAM(oc, audio_codec, codec, st) -#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) -_Pragma ("GCC diagnostic pop") -#endif c->codec_id = codec->id; #if LIBAVFORMAT_VERSION_MAJOR >= 53 @@ -1082,14 +1075,7 @@ AVStream *FFmpegWriter::add_video_stream() { throw InvalidCodec("A valid video codec could not be found for this file.", path); // Create a new video stream -#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) -_Pragma ("GCC diagnostic push") -_Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#endif AV_FORMAT_NEW_STREAM(oc, video_codec, codec, st) -#if (IS_FFMPEG_3_2 && (LIBAVFORMAT_VERSION_MAJOR < 58)) -_Pragma ("GCC diagnostic pop") -#endif c->codec_id = codec->id; #if LIBAVFORMAT_VERSION_MAJOR >= 53 From c54a3705ff00e72b7c08cb153da2f56c4aa063ba Mon Sep 17 00:00:00 2001 From: eisneinechse <42617957+eisneinechse@users.noreply.github.com> Date: Thu, 20 Jun 2019 13:41:03 -0700 Subject: [PATCH 181/186] Update FFmpegUtilities.h Warnings are now silenced in FFmpegUtilities.h, where it should be. --- include/FFmpegUtilities.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h index 0d12ba72..4ac8b158 100644 --- a/include/FFmpegUtilities.h +++ b/include/FFmpegUtilities.h @@ -209,9 +209,12 @@ #define AV_FORMAT_NEW_STREAM(oc, st_codec, av_codec, av_st) av_st = avformat_new_stream(oc, NULL);\ if (!av_st) \ throw OutOfMemory("Could not allocate memory for the video stream.", path); \ - c = avcodec_alloc_context3(av_codec); \ - st_codec = c; \ - av_st->codecpar->codec_id = av_codec->id; + _Pragma ("GCC diagnostic push"); \ + _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \ + avcodec_get_context_defaults3(av_st->codec, av_codec); \ + c = av_st->codec; \ + _Pragma ("GCC diagnostic pop"); \ + st_codec = c; #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) avcodec_parameters_from_context(av_stream->codecpar, av_codec); #elif LIBAVFORMAT_VERSION_MAJOR >= 55 #define AV_REGISTER_ALL av_register_all(); From a47d5b58fd4b55a3fd3cce451f8839a830baf203 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Fri, 21 Jun 2019 01:07:49 -0400 Subject: [PATCH 182/186] Add backwards-compatible Imagemagick 7 support (#252) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ImageMagick 7 compatibility A new header, `imclude/MagickUtilities.h`, is created to hold the compatibility `#define`s. The image-conversion code in `src/Frame.cpp` received the only major changes — instead of doing the export by hand (and having to account for changes in the underlying API), it uses the `MagickCore::ExportImagePixels()` function which does basically the same work, but accounts for all of the API changes for us. The API of that function is _unchanged_ from IM6 to IM7. TODO: `MagickCore::ExportImagePixels()` will return an `exception` struct if it encounters any problems. Currently the code ignores that, which it should not. * Add ImageMagick 7 compatibility A new header, `imclude/MagickUtilities.h`, is created to hold the compatibility `#define`s. The image-conversion code in `src/Frame.cpp` received the only major changes — instead of doing the export by hand (and having to account for changes in the underlying API), it uses the `MagickCore::ExportImagePixels()` function which does basically the same work, but accounts for all of the API changes for us. The API of that function is _unchanged_ from IM6 to IM7. TODO: `MagickCore::ExportImagePixels()` will return an `exception` struct if it encounters any problems. Currently the code ignores that, which it should not. Thanks @ferdnyc --- include/Frame.h | 6 ++-- include/ImageReader.h | 8 +++-- include/ImageWriter.h | 9 +++--- include/MagickUtilities.h | 61 +++++++++++++++++++++++++++++++++++++++ include/TextReader.h | 10 +++++-- include/effects/Mask.h | 7 +++-- src/Frame.cpp | 20 ++++--------- src/ImageReader.cpp | 7 ++++- src/ImageWriter.cpp | 6 +++- src/TextReader.cpp | 5 ++++ src/effects/Mask.cpp | 9 +++--- 11 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 include/MagickUtilities.h diff --git a/include/Frame.h b/include/Frame.h index 6b682edb..1c4dd26c 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -53,14 +53,14 @@ #include #include #include "ZmqLogger.h" -#ifdef USE_IMAGEMAGICK - #include "Magick++.h" -#endif #include "ChannelLayouts.h" #include "AudioBufferSource.h" #include "AudioResampler.h" #include "Fraction.h" #include "JuceHeader.h" +#ifdef USE_IMAGEMAGICK + #include "MagickUtilities.h" +#endif #pragma SWIG nowarn=362 using namespace std; diff --git a/include/ImageReader.h b/include/ImageReader.h index e698e0c1..7ad23173 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -28,6 +28,9 @@ #ifndef OPENSHOT_IMAGE_READER_H #define OPENSHOT_IMAGE_READER_H +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "ReaderBase.h" #include @@ -36,9 +39,9 @@ #include #include #include -#include "Magick++.h" #include "CacheMemory.h" #include "Exceptions.h" +#include "MagickUtilities.h" using namespace std; @@ -113,4 +116,5 @@ namespace openshot } -#endif +#endif //USE_IMAGEMAGICK +#endif //OPENSHOT_IMAGE_READER_H diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 25177134..b7dd7dc2 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -32,10 +32,11 @@ * along with OpenShot Library. If not, see . */ - #ifndef OPENSHOT_IMAGE_WRITER_H #define OPENSHOT_IMAGE_WRITER_H +#ifdef USE_IMAGEMAGICK + #include "ReaderBase.h" #include "WriterBase.h" @@ -44,11 +45,10 @@ #include #include #include -#include "Magick++.h" #include "CacheMemory.h" #include "Exceptions.h" #include "OpenMPUtilities.h" - +#include "MagickUtilities.h" using namespace std; @@ -145,4 +145,5 @@ namespace openshot } -#endif +#endif //USE_IMAGEMAGICK +#endif //OPENSHOT_IMAGE_WRITER_H diff --git a/include/MagickUtilities.h b/include/MagickUtilities.h new file mode 100644 index 00000000..f3b7ea12 --- /dev/null +++ b/include/MagickUtilities.h @@ -0,0 +1,61 @@ +/** + * @file + * @brief Header file for MagickUtilities (IM6/IM7 compatibility overlay) + * @author Jonathan Thomas + * @author FeRD (Frank Dana) + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) 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 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . + */ + +#ifndef OPENSHOT_MAGICK_UTILITIES_H +#define OPENSHOT_MAGICK_UTILITIES_H + +#ifdef USE_IMAGEMAGICK + + #include "Magick++.h" + + // Determine ImageMagick version, as IM7 isn't fully + // backwards compatible + #ifndef NEW_MAGICK + #define NEW_MAGICK (MagickLibVersion >= 0x700) + #endif + + // IM7: ->alpha(bool) + // IM6: ->matte(bool) + #if NEW_MAGICK + #define MAGICK_IMAGE_ALPHA(im, a) im->alpha((a)) + #else + #define MAGICK_IMAGE_ALPHA(im, a) im->matte((a)) + #endif + + // IM7: vector + // IM6: list + // (both have the push_back() method which is all we use) + #if NEW_MAGICK + #define MAGICK_DRAWABLE vector + #else + #define MAGICK_DRAWABLE list + #endif + +#endif +#endif diff --git a/include/TextReader.h b/include/TextReader.h index d7d653d2..bb4bdc22 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -28,6 +28,9 @@ #ifndef OPENSHOT_TEXT_READER_H #define OPENSHOT_TEXT_READER_H +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "ReaderBase.h" #include @@ -36,10 +39,10 @@ #include #include #include -#include "Magick++.h" #include "CacheMemory.h" #include "Enums.h" #include "Exceptions.h" +#include "MagickUtilities.h" using namespace std; @@ -91,7 +94,7 @@ namespace openshot string text_color; string background_color; std::shared_ptr image; - list lines; + MAGICK_DRAWABLE lines; bool is_open; GravityType gravity; @@ -144,4 +147,5 @@ namespace openshot } -#endif +#endif //USE_IMAGEMAGICK +#endif //OPENSHOT_TEXT_READER_H diff --git a/include/effects/Mask.h b/include/effects/Mask.h index ef707f5f..e5b8f649 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -25,8 +25,8 @@ * along with OpenShot Library. If not, see . */ -#ifndef OPENSHOT_WIPE_EFFECT_H -#define OPENSHOT_WIPE_EFFECT_H +#ifndef OPENSHOT_MASK_EFFECT_H +#define OPENSHOT_MASK_EFFECT_H #include "../EffectBase.h" @@ -45,6 +45,7 @@ #include "../QtImageReader.h" #include "../ChunkReader.h" #ifdef USE_IMAGEMAGICK + #include "../MagickUtilities.h" #include "../ImageReader.h" #endif @@ -54,7 +55,7 @@ namespace openshot { /** - * @brief This class uses the ImageMagick++ libraries, to apply alpha (or transparency) masks + * @brief This class uses the image libraries to apply alpha (or transparency) masks * to any frame. It can also be animated, and used as a powerful Wipe transition. * * These masks / wipes can also be combined, such as a transparency mask on top of a clip, which diff --git a/src/Frame.cpp b/src/Frame.cpp index aa7c0d87..5e06e61e 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -926,7 +926,7 @@ std::shared_ptr Frame::GetMagickImage() // Give image a transparent background color magick_image->backgroundColor(Magick::Color("none")); magick_image->virtualPixelMethod(Magick::TransparentVirtualPixelMethod); - magick_image->matte(true); + MAGICK_IMAGE_ALPHA(magick_image, true); return magick_image; } @@ -945,20 +945,12 @@ void Frame::AddMagickImage(std::shared_ptr new_image) qbuffer = new unsigned char[bufferSize](); unsigned char *buffer = (unsigned char*)qbuffer; - // Iterate through the pixel packets, and load our own buffer - // Each color needs to be scaled to 8 bit (using the ImageMagick built-in ScaleQuantumToChar function) - int numcopied = 0; - Magick::PixelPacket *pixels = new_image->getPixels(0,0, new_image->columns(), new_image->rows()); - for (int n = 0, i = 0; n < new_image->columns() * new_image->rows(); n += 1, i += 4) { - buffer[i+0] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].red); - buffer[i+1] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].green); - buffer[i+2] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].blue); - buffer[i+3] = 255 - MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].opacity); - numcopied+=4; - } + MagickCore::ExceptionInfo exception; + // TODO: Actually do something, if we get an exception here + MagickCore::ExportImagePixels(new_image->constImage(), 0, 0, new_image->columns(), new_image->rows(), "RGBA", Magick::CharPixel, buffer, &exception); - // Create QImage of frame data - image = std::shared_ptr(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer)); + // Create QImage of frame data + image = std::shared_ptr(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer)); // Update height and width width = image->width(); diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index 3c1d334a..491e1c5d 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -25,6 +25,9 @@ * along with OpenShot Library. If not, see . */ +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "../include/ImageReader.h" using namespace openshot; @@ -59,7 +62,7 @@ void ImageReader::Open() // Give image a transparent background color image->backgroundColor(Magick::Color("none")); - image->matte(true); + MAGICK_IMAGE_ALPHA(image, true); } catch (Magick::Exception e) { // raise exception @@ -192,3 +195,5 @@ void ImageReader::SetJsonValue(Json::Value root) { Open(); } } + +#endif //USE_IMAGEMAGICK diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 41626b09..5bc0367a 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -28,6 +28,9 @@ * along with OpenShot Library. If not, see . */ +//Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "../include/ImageWriter.h" using namespace openshot; @@ -97,7 +100,7 @@ void ImageWriter::WriteFrame(std::shared_ptr frame) std::shared_ptr frame_image = frame->GetMagickImage(); frame_image->magick( info.vcodec ); frame_image->backgroundColor(Magick::Color("none")); - frame_image->matte(true); + MAGICK_IMAGE_ALPHA(frame_image, true); frame_image->quality(image_quality); frame_image->animationDelay(info.video_timebase.ToFloat() * 100); frame_image->animationIterations(number_of_loops); @@ -153,3 +156,4 @@ void ImageWriter::Close() ZmqLogger::Instance()->AppendDebugMethod("ImageWriter::Close", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } +#endif //USE_IMAGEMAGICK diff --git a/src/TextReader.cpp b/src/TextReader.cpp index a24f26e4..b38c5f18 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -25,6 +25,9 @@ * along with OpenShot Library. If not, see . */ +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "../include/TextReader.h" using namespace openshot; @@ -258,3 +261,5 @@ void TextReader::SetJsonValue(Json::Value root) { Open(); } } + +#endif //USE_IMAGEMAGICK diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index 95dd3489..e1c2db4d 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -238,11 +238,11 @@ void Mask::SetJsonValue(Json::Value root) { reader->SetJsonValue(root["reader"]); #ifdef USE_IMAGEMAGICK - } else if (type == "ImageReader") { + } else if (type == "ImageReader") { - // Create new reader - reader = new ImageReader(root["reader"]["path"].asString()); - reader->SetJsonValue(root["reader"]); + // Create new reader + reader = new ImageReader(root["reader"]["path"].asString()); + reader->SetJsonValue(root["reader"]); #endif } else if (type == "QtImageReader") { @@ -294,4 +294,3 @@ string Mask::PropertiesJSON(int64_t requested_frame) { // Return formatted string return root.toStyledString(); } - From bf9e45b5725ec19703df2a5534a5451711eaeacf Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 21 Jun 2019 02:02:55 -0500 Subject: [PATCH 183/186] Make docs on Linux builder, and auto-update doc files for develop branch --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 42656302..0d044dd8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,6 +20,8 @@ linux-builder: - cmake -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -D"CMAKE_BUILD_TYPE:STRING=Release" ../ - make - make install + - make doc + - ~/.auto-update-docs "$CI_PROJECT_DIR/build" "$CI_COMMIT_REF_NAME" - mv install-x64/lib/python3.4/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" From c7371bc7f14b481151dff0bd4a7e86bd21b53c36 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 21 Jun 2019 02:18:23 -0500 Subject: [PATCH 184/186] Fixing invalid script path --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d044dd8..d74c1ef6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ linux-builder: - make - make install - make doc - - ~/.auto-update-docs "$CI_PROJECT_DIR/build" "$CI_COMMIT_REF_NAME" + - ~/auto-update-docs "$CI_PROJECT_DIR/build" "$CI_COMMIT_REF_NAME" - mv install-x64/lib/python3.4/site-packages/*openshot* install-x64/python - echo -e "CI_PROJECT_NAME:$CI_PROJECT_NAME\nCI_COMMIT_REF_NAME:$CI_COMMIT_REF_NAME\nCI_COMMIT_SHA:$CI_COMMIT_SHA\nCI_JOB_ID:$CI_JOB_ID" > "install-x64/share/$CI_PROJECT_NAME" - git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:"%C(auto,yellow)%h%C(auto,magenta)% %C(auto,blue)%>(12,trunc)%ad %C(auto,green)%<(25,trunc)%aN%C(auto,reset)%s%C(auto,red)% gD% D" --date=short > "install-x64/share/$CI_PROJECT_NAME.log" From ac8876f81051f69074bc50f21d66ba2706620a2f Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 21 Jun 2019 15:57:41 -0500 Subject: [PATCH 185/186] Removing duplicated destructor definitions and implementations... so our virtual destructors will not break on older toolchains. --- include/CacheBase.h | 2 -- include/ClipBase.h | 1 - include/ReaderBase.h | 2 -- src/CacheBase.cpp | 3 --- src/ClipBase.cpp | 3 --- src/ReaderBase.cpp | 3 --- 6 files changed, 14 deletions(-) diff --git a/include/CacheBase.h b/include/CacheBase.h index 12108680..3760e84b 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -63,8 +63,6 @@ namespace openshot { /// @param max_bytes The maximum bytes to allow in the cache. Once exceeded, the cache will purge the oldest frames. CacheBase(int64_t max_bytes); - virtual ~CacheBase(); - /// @brief Add a Frame to the cache /// @param frame The openshot::Frame object needing to be cached. virtual void Add(std::shared_ptr frame) = 0; diff --git a/include/ClipBase.h b/include/ClipBase.h index 05f2747e..ab3f0637 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -72,7 +72,6 @@ namespace openshot { /// Constructor for the base clip ClipBase() { }; - virtual ~ClipBase(); // Compare a clip using the Position() property bool operator< ( ClipBase& a) { return (Position() < a.Position()); } diff --git a/include/ReaderBase.h b/include/ReaderBase.h index b2e8f19e..0d14ea19 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -110,8 +110,6 @@ namespace openshot /// Constructor for the base reader, where many things are initialized. ReaderBase(); - virtual ~ReaderBase(); - /// Information about the current media file ReaderInfo info; diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp index 8270b393..0016694a 100644 --- a/src/CacheBase.cpp +++ b/src/CacheBase.cpp @@ -45,9 +45,6 @@ CacheBase::CacheBase(int64_t max_bytes) : max_bytes(max_bytes) { cacheCriticalSection = new CriticalSection(); }; -CacheBase::~CacheBase() { -}; - // Set maximum bytes to a different amount based on a ReaderInfo struct void CacheBase::SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels) { diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp index 1517a7e3..60bdb633 100644 --- a/src/ClipBase.cpp +++ b/src/ClipBase.cpp @@ -32,9 +32,6 @@ using namespace openshot; -ClipBase::~ClipBase() { -} - // Generate Json::JsonValue for this object Json::Value ClipBase::JsonValue() { diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index ece0684f..30706866 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -66,9 +66,6 @@ ReaderBase::ReaderBase() parent = NULL; } -ReaderBase::~ReaderBase() { -} - // Display file information void ReaderBase::DisplayInfo() { cout << fixed << setprecision(2) << boolalpha; From 9d09b65e70ef242bfbc673e4b337c3b64534b4bd Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 21 Jun 2019 16:47:37 -0500 Subject: [PATCH 186/186] Revert "Don't break Python install path detection on Debian" --- src/bindings/python/CMakeLists.txt | 50 ++++++++++++------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/bindings/python/CMakeLists.txt b/src/bindings/python/CMakeLists.txt index 0496bef6..eb7c989a 100644 --- a/src/bindings/python/CMakeLists.txt +++ b/src/bindings/python/CMakeLists.txt @@ -65,39 +65,29 @@ if (PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND) target_link_libraries(${SWIG_MODULE_pyopenshot_REAL_NAME} ${PYTHON_LIBRARIES} openshot) - ### FIND THE PYTHON INTERPRETER (AND THE SITE PACKAGES FOLDER) - if (UNIX AND NOT APPLE) - ### Special-case for Debian's crazy, by checking to see if pybuild - ### is available. We don't use it, except as a canary in a coal mine - find_program(PYBUILD_EXECUTABLE pybuild - DOC "Path to Debian's pybuild utility") - if (PYBUILD_EXECUTABLE) - # We're on a Debian derivative, fall back to old path detection - set(py_detection "import site; print(site.getsitepackages()[0])") - set(PY_INSTALL_PREFIX "/usr/local") # An assumption (bad one?) - else() - # Use distutils to detect install path - set (py_detection "\ + ### Check if the following Debian-friendly python module path exists + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages") + if (NOT EXISTS ${PYTHON_MODULE_PATH}) + + ### Check if another Debian-friendly python module path exists + SET(PYTHON_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/dist-packages") + if (NOT EXISTS ${PYTHON_MODULE_PATH}) + + ### Calculate the python module path (using distutils) + execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "\ from distutils.sysconfig import get_python_lib; \ -print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )") - set(PY_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) +print( get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )" + OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE ) + + GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH + "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) + FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH + ${CMAKE_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) + SET(PYTHON_MODULE_PATH ${_ABS_PYTHON_MODULE_PATH}) endif() endif() - - if (NOT PYTHON_MODULE_PATH) - execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "${py_detection}" - OUTPUT_VARIABLE _ABS_PYTHON_MODULE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE ) - - GET_FILENAME_COMPONENT(_ABS_PYTHON_MODULE_PATH - "${_ABS_PYTHON_MODULE_PATH}" ABSOLUTE) - FILE(RELATIVE_PATH _REL_PYTHON_MODULE_PATH - ${PY_INSTALL_PREFIX} ${_ABS_PYTHON_MODULE_PATH}) - SET(PYTHON_MODULE_PATH ${_REL_PYTHON_MODULE_PATH} - CACHE PATH "Install path for Python modules (relative to prefix)") - endif() - - message(STATUS "Will install Python module to: ${PYTHON_MODULE_PATH}") + message("PYTHON_MODULE_PATH: ${PYTHON_MODULE_PATH}") ############### INSTALL HEADERS & LIBRARY ################ ### Install Python bindings