From f66ccb11c456fbd8932b9b2bb73e7a2e6a25d3e9 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 26 Jan 2019 17:56:15 -0600 Subject: [PATCH 1/3] Set video bit rate to 0 if an invalid bit rate detected (which happens when using crf) (#191) --- src/FFmpegWriter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d8f07c83..6bea8000 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -148,6 +148,8 @@ 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; info.interlaced_frame = interlaced; info.top_field_first = top_field_first; @@ -968,9 +970,12 @@ 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; + } //TODO: Implement variable bitrate feature (which actually works). This implementation throws //invalid bitrate errors and rc buffer underflow errors, etc... From eeeec316758a0288427a11bf798a2b1f0341f1b3 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sat, 26 Jan 2019 22:15:18 -0600 Subject: [PATCH 2/3] Add git log file with commits up to the previous release (#192) --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 12365c0d..f8b13908 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,6 +22,7 @@ linux-builder: - make install - mv /usr/local/lib/python3.4/dist-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 except: - tags @@ -48,6 +49,7 @@ mac-builder: - make install - mv /Library/Frameworks/Python.framework/Versions/3.6/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 except: - tags @@ -77,6 +79,8 @@ windows-builder-x86: - Move-Item -Force -path "C:\msys32\mingw32\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) + - 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-x86/share/$CI_PROJECT_NAME.log" when: always except: - tags @@ -105,6 +109,8 @@ windows-builder-x64: - 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 From 1bf3e3756719d377e34c236a5d01b2d363ab5c8f Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 28 Jan 2019 12:28:35 -0600 Subject: [PATCH 3/3] Refactor FFmpegWriter Open() and PrepareStreams() methods, so that SetOption() is can be called between them, and allowed to adjust the codecs bit_rate and options before we call open_video(). This was primarily to allow CRF options to work. (#193) --- src/FFmpegWriter.cpp | 78 ++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 6bea8000..b9b6ba76 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -55,16 +55,24 @@ FFmpegWriter::FFmpegWriter(string path) : // Open the writer void FFmpegWriter::Open() { - // Open the writer - is_open = true; + if (!is_open) { + // Open the writer + is_open = true; - // Prepare streams (if needed) - if (!prepare_streams) - PrepareStreams(); + // Prepare streams (if needed) + if (!prepare_streams) + PrepareStreams(); - // Write header (if needed) - if (!write_header) - WriteHeader(); + // Now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers + if (info.has_video && video_st) + open_video(oc, video_st); + if (info.has_audio && audio_st) + open_audio(oc, audio_st); + + // Write header (if needed) + if (!write_header) + WriteHeader(); + } } // auto detect format (from path) @@ -148,8 +156,8 @@ 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 crf + info.video_bit_rate = bit_rate; info.interlaced_frame = interlaced; info.top_field_first = top_field_first; @@ -293,29 +301,50 @@ void FFmpegWriter::SetOption(StreamType stream, string name, string value) // and way to set quality are possible #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 39, 101) switch (c->codec_id) { - case AV_CODEC_ID_VP8 : + #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 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); + 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); + 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); + 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; - #ifdef AV_CODEC_ID_AV1 - case AV_CODEC_ID_AV1 : - av_opt_set_int(c->priv_data, "crf", min(stoi(value),63), 0); - break; - #endif + 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 = 380.0; + } + else { + mbs *= pow(0.912,info.video_bit_rate); + } + } + c->bit_rate = (int)(mbs); } #endif } @@ -355,12 +384,6 @@ void FFmpegWriter::PrepareStreams() // Initialize the streams (i.e. add the streams) initialize_streams(); - // Now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers - if (info.has_video && video_st) - open_video(oc, video_st); - if (info.has_audio && audio_st) - open_audio(oc, audio_st); - // Mark as 'prepared' prepare_streams = true; } @@ -973,9 +996,6 @@ 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...