Last active
March 10, 2021 09:43
-
-
Save abautu/fcd3a1cf8b5f5665d16fd07d623808ef to your computer and use it in GitHub Desktop.
Change to BigBlueButton recording processing (includes new processing workflow, lower framerate and lower filesize)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -urN core-default/lib/recordandplayback/generators/audio_processor.rb core-andrei/lib/recordandplayback/generators/audio_processor.rb | |
--- core-default/lib/recordandplayback/generators/audio_processor.rb 2021-03-03 00:05:00.000000000 +0200 | |
+++ core-andrei/lib/recordandplayback/generators/audio_processor.rb 2021-03-08 10:30:21.004763090 +0200 | |
@@ -60,13 +60,13 @@ | |
ogg_format = { | |
:extension => 'ogg', | |
- :parameters => [ [ '-c:a', 'libvorbis', '-q:a', '2', '-f', 'ogg' ] ] | |
+ :parameters => [ [ '-c:a', 'copy', '-f', 'ogg' ] ] | |
} | |
BigBlueButton::EDL.encode(@audio_file, nil, ogg_format, file_basename) | |
webm_format = { | |
:extension => 'webm', | |
- :parameters => [ [ '-c:a', 'libvorbis', '-q:a', '2', '-f', 'webm' ] ], | |
+ :parameters => [ [ '-c:a', 'copy', '-f', 'webm' ] ], | |
:postprocess => [ [ 'mkclean', '--quiet', ':input', ':output' ] ] | |
} | |
BigBlueButton::EDL.encode(@audio_file, nil, webm_format, file_basename) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -urN core-default/lib/recordandplayback/edl/audio.rb core-andrei/lib/recordandplayback/edl/audio.rb | |
--- core-default/lib/recordandplayback/edl/audio.rb 2021-03-03 00:05:00.000000000 +0200 | |
+++ core-andrei/lib/recordandplayback/edl/audio.rb 2021-01-09 23:57:55.864891875 +0200 | |
@@ -22,9 +22,9 @@ | |
module Audio | |
FFMPEG_AEVALSRC = "aevalsrc=s=48000:c=stereo:exprs=0|0" | |
FFMPEG_AFORMAT = "aformat=sample_fmts=s16:sample_rates=48000:channel_layouts=stereo" | |
- FFMPEG_WF_CODEC = 'flac' | |
- FFMPEG_WF_ARGS = ['-c:a', FFMPEG_WF_CODEC, '-f', 'flac'] | |
- WF_EXT = 'flac' | |
+ FFMPEG_WF_CODEC = 'libvorbis' | |
+ FFMPEG_WF_ARGS = ['-c:a', FFMPEG_WF_CODEC, '-q:a', '2', '-f', 'ogg'] | |
+ WF_EXT = 'ogg' | |
def self.dump(edl) | |
BigBlueButton.logger.debug "EDL Dump:" | |
diff -urN core-default/lib/recordandplayback/edl/video.rb core-andrei/lib/recordandplayback/edl/video.rb | |
--- core-default/lib/recordandplayback/edl/video.rb 2021-03-03 00:05:00.000000000 +0200 | |
+++ core-andrei/lib/recordandplayback/edl/video.rb 2021-03-10 11:41:20.012439020 +0200 | |
@@ -23,10 +23,9 @@ | |
module BigBlueButton | |
module EDL | |
module Video | |
- FFMPEG_WF_CODEC = 'mpeg2video' | |
- FFMPEG_WF_FRAMERATE = 24 | |
- FFMPEG_WF_ARGS = ['-an', '-codec', FFMPEG_WF_CODEC.to_s, '-q:v', '2', '-g', (FFMPEG_WF_FRAMERATE * 10).to_s, '-pix_fmt', 'yuv420p', '-r', FFMPEG_WF_FRAMERATE.to_s, '-f', 'mpegts'] | |
- WF_EXT = 'ts' | |
+ FFMPEG_WF_CODEC = 'libx264' | |
+ FFMPEG_WF_ARGS = ['-an', '-codec', FFMPEG_WF_CODEC.to_s, '-preset', 'veryfast', '-crf', '30', '-force_key_frames', 'expr:gte(t,n_forced*10)', '-pix_fmt', 'yuv420p', '-bsf:v', 'h264_mp4toannexb'] | |
+ WF_EXT = 'mp4' | |
def self.dump(edl) | |
BigBlueButton.logger.debug "EDL Dump:" | |
@@ -254,12 +253,31 @@ | |
BigBlueButton.logger.info "Compositing cuts" | |
render = "#{output_basename}.#{WF_EXT}" | |
+ concat = [] | |
for i in 0...(edl.length - 1) | |
if edl[i][:timestamp] == edl[i][:next_timestamp] | |
warn 'Skipping 0-length edl entry' | |
next | |
end | |
- composite_cut(render, edl[i], layout, videoinfo) | |
+ segment = "#{output_basename}_#{i}.#{WF_EXT}" | |
+ composite_cut(segment, edl[i], layout, videoinfo) | |
+ concat += [segment] unless video_info(segment).empty? | |
+ end | |
+ | |
+ concat_file = "#{output_basename}.txt" | |
+ File.open(concat_file, 'w') do |outio| | |
+ concat.each do |segment| | |
+ outio.write("file #{segment}\n") | |
+ end | |
+ end | |
+ | |
+ ffmpeg_cmd = [*FFMPEG] | |
+ ffmpeg_cmd += ['-safe', '0', '-f', 'concat', '-i', concat_file , '-c', 'copy', render] | |
+ exitstatus = BigBlueButton.exec_ret(*ffmpeg_cmd) | |
+ raise "ffmpeg failed, exit code #{exitstatus}" if exitstatus != 0 | |
+ | |
+ concat.each do |segment| | |
+ File.delete(segment) | |
end | |
return render | |
@@ -375,7 +393,7 @@ | |
duration = cut[:next_timestamp] - cut[:timestamp] | |
BigBlueButton.logger.info " Cut start time #{cut[:timestamp]}, duration #{duration}" | |
- ffmpeg_filter = "color=c=white:s=#{layout[:width]}x#{layout[:height]}:r=24" | |
+ ffmpeg_filter = "color=c=white:s=#{layout[:width]}x#{layout[:height]}:r=#{layout[:framerate]}" | |
layout[:areas].each do |layout_area| | |
area = cut[:areas][layout_area[:name]] | |
@@ -488,7 +506,7 @@ | |
ffmpeg_filter << ",setpts=PTS-#{ms_to_s(seek_offset)}/TB" | |
# fps filter fills in frames up to the desired start point, and | |
# cuts the video there | |
- ffmpeg_filter << ",fps=#{FFMPEG_WF_FRAMERATE}:start_time=#{ms_to_s(video[:timestamp])}" | |
+ ffmpeg_filter << ",fps=#{layout[:framerate]}:start_time=#{ms_to_s(video[:timestamp])}" | |
# Reset the timestamps to start at 0 so that everything is synced | |
# for the video tiling, and scale to the desired size. | |
ffmpeg_filter << ",setpts=PTS-STARTPTS,scale=#{scale_width}:#{scale_height},setsar=1" | |
@@ -500,7 +518,7 @@ | |
# it to length. do that by concatenating a video generated by the | |
# color filter. (It would be nice to repeat the last frame instead, | |
# but there's no easy way to do that.) | |
- ffmpeg_filter << "color=c=white:s=#{tile_width}x#{tile_height}:r=#{FFMPEG_WF_FRAMERATE}" | |
+ ffmpeg_filter << "color=c=white:s=#{tile_width}x#{tile_height}:r=#{layout[:framerate]}" | |
ffmpeg_filter << "[#{pad_name}_pad];" | |
ffmpeg_filter << "[#{pad_name}_movie][#{pad_name}_pad]concat=n=2:v=1:a=0[#{pad_name}];" | |
@@ -542,12 +560,10 @@ | |
ffmpeg_filter << ",trim=end=#{ms_to_s(duration)}" | |
ffmpeg_cmd = [*FFMPEG] | |
- ffmpeg_cmd += ['-filter_complex', ffmpeg_filter, *FFMPEG_WF_ARGS, '-'] | |
+ ffmpeg_cmd += ['-filter_complex', ffmpeg_filter, *FFMPEG_WF_ARGS, '-r', layout[:framerate].to_s, output] | |
- File.open(output, 'a') do |outio| | |
- exitstatus = BigBlueButton.exec_redirect_ret(outio, *ffmpeg_cmd) | |
- raise "ffmpeg failed, exit code #{exitstatus}" if exitstatus != 0 | |
- end | |
+ exitstatus = BigBlueButton.exec_ret(*ffmpeg_cmd) | |
+ raise "ffmpeg failed, exit code #{exitstatus}" if exitstatus != 0 | |
return output | |
end | |
diff -urN core-default/lib/recordandplayback/edl.rb core-andrei/lib/recordandplayback/edl.rb | |
--- core-default/lib/recordandplayback/edl.rb 2021-03-03 00:05:00.000000000 +0200 | |
+++ core-andrei/lib/recordandplayback/edl.rb 2021-02-24 13:34:57.369981192 +0200 | |
@@ -70,6 +70,7 @@ | |
exitstatus = BigBlueButton.exec_ret(*cmd) | |
raise "postprocess failed, exit code #{exitstatus}" if exitstatus != 0 | |
end | |
+ FileUtils.rm(lastoutput) | |
lastoutput = ppoutput | |
end | |
end | |
diff -urN core-default/lib/recordandplayback/generators/video.rb core-andrei/lib/recordandplayback/generators/video.rb | |
--- core-default/lib/recordandplayback/generators/video.rb 2021-03-03 00:05:00.000000000 +0200 | |
+++ core-andrei/lib/recordandplayback/generators/video.rb 2021-03-07 00:09:16.220272663 +0200 | |
@@ -1,3 +1,4 @@ | |
+ | |
# Set encoding to utf-8 | |
# encoding: UTF-8 | |
@@ -27,7 +28,7 @@ | |
module BigBlueButton | |
- def BigBlueButton.process_webcam_videos(target_dir, temp_dir, meeting_id, output_width, output_height, audio_offset, processed_audio_file, video_formats=['webm']) | |
+ def BigBlueButton.process_webcam_videos(target_dir, temp_dir, meeting_id, output_width, output_height, output_framerate, audio_offset, processed_audio_file, video_formats=['webm']) | |
BigBlueButton.logger.info("Processing webcam videos") | |
events = Nokogiri::XML(File.open("#{temp_dir}/#{meeting_id}/events.xml")) | |
@@ -42,7 +43,7 @@ | |
BigBlueButton::EDL::Video.dump(user_video_edl) | |
user_video_layout = { | |
- width: output_width, height: output_height, | |
+ width: output_width, height: output_height, framerate: output_framerate, | |
areas: [ { name: :webcam, x: 0, y: 0, width: output_width, height: output_height } ] | |
} | |
user_video_file = BigBlueButton::EDL::Video.render( | |
@@ -55,8 +56,8 @@ | |
# These settings are appropriate for 640x480 medium quality, and should be tweaked for other resolutions | |
# See https://developers.google.com/media/vp9/settings/vod/ | |
# Increase -threads to max of 4 or increase -speed to max of 4 to speed up processing | |
- %w[-c:v libvpx-vp9 -b:v 750K -minrate 375K -maxrate 1088K -crf 33 -quality good -speed 1 -g 240 -tile-columns 1 -threads 2 | |
- -c:a libopus -b:a 48K | |
+ %w[-c:v libvpx-vp9 -crf 32 -deadline realtime -cpu-used 8 -force_key_frames expr:gte(t,n_forced*10) -tile-columns 2 -tile-rows 2 -threads 4 | |
+ -c:a copy | |
-f webm] | |
# Google recommends doing a 2-pass encode for better quality, but it's a lot slower. If you want to do this, | |
# comment the lines above, and uncomment the lines below. | |
@@ -76,7 +77,7 @@ | |
# Increase -threads (or remove it, to use all cpu cores) to speed up processing | |
# You can also change the preset: try 'fast' or 'faster' | |
# To change quality, adjust the -crf value. Lower numbers are higher quality. | |
- %w[-c:v libx264 -crf 23 -threads 2 -preset medium -g 240 | |
+ %w[-c:v copy | |
-c:a aac -b:a 64K | |
-f mp4 -movflags faststart] | |
], | |
@@ -90,7 +91,7 @@ | |
end | |
end | |
- def BigBlueButton.process_deskshare_videos(target_dir, temp_dir, meeting_id, output_width, output_height, video_formats=['webm']) | |
+ def BigBlueButton.process_deskshare_videos(target_dir, temp_dir, meeting_id, output_width, output_height, output_framerate, video_formats=['webm']) | |
BigBlueButton.logger.info("Processing deskshare videos") | |
events = Nokogiri::XML(File.open("#{temp_dir}/#{meeting_id}/events.xml")) | |
@@ -107,7 +108,7 @@ | |
BigBlueButton::EDL::Video.dump(deskshare_video_edl) | |
deskshare_layout = { | |
- width: output_width, height: output_height, | |
+ width: output_width, height: output_height, framerate: output_framerate, | |
areas: [ { name: :deskshare, x: 0, y: 0, width: output_width, height: output_height } ] | |
} | |
@@ -121,8 +122,8 @@ | |
# These settings are appropriate for 1280x720 medium quality, and should be tweaked for other resolutions | |
# See https://developers.google.com/media/vp9/settings/vod/ | |
# Increase -threads to max of 8 or increase -speed to max of 4 to speed up processing | |
- %w[-c:v libvpx-vp9 -b:v 1024K -minrate 512K -maxrate 1485K -crf 32 -quality good -speed 2 -g 240 -tile-columns 2 -threads 2 | |
- -c:a libopus -b:a 48K | |
+ %w[-c:v libvpx-vp9 -crf 32 -deadline realtime -cpu-used 8 -force_key_frames expr:gte(t,n_forced*10) -tile-columns 2 -tile-rows 2 -threads 4 | |
+ -c:a copy | |
-f webm] | |
# Google recommends doing a 2-pass encode for better quality, but it's a lot slower. If you want to do this, | |
# comment the lines above, and uncomment the lines below. | |
@@ -142,7 +143,7 @@ | |
# Increase -threads (or remove it, to use all cpu cores) to speed up processing | |
# You can also change the preset: try 'fast' or 'faster' | |
# To change quality, adjust the -crf value. Lower numbers are higher quality. | |
- %w[-c:v libx264 -crf 23 -threads 2 -preset medium -g 240 | |
+ %w[-c:v copy | |
-c:a aac -b:a 64K | |
-f mp4 -movflags faststart] | |
], | |
diff -urN core-default/scripts/presentation.yml core-andrei/scripts/presentation.yml | |
--- core-default/scripts/presentation.yml 2020-12-09 03:08:00.000000000 +0200 | |
+++ core-andrei/scripts/presentation.yml 2021-03-08 10:44:07.707601985 +0200 | |
@@ -1,9 +1,11 @@ | |
video_output_width: 640 | |
video_output_height: 480 | |
+video_output_framerate: 15 | |
# Alternate output size to use when deskshare videos are present | |
# Set higher so that deskshare output is higher quality, but uses more space. | |
deskshare_output_width: 1280 | |
deskshare_output_height: 720 | |
+deskshare_output_framerate: 5 | |
# offset applied to audio in the output video file | |
# audio_offset = 1200 means that the audio will be delayed by 1200ms | |
audio_offset: 0 | |
diff -urN core-default/scripts/process/presentation.rb core-andrei/scripts/process/presentation.rb | |
--- core-default/scripts/process/presentation.rb 2020-12-09 03:08:00.000000000 +0200 | |
+++ core-andrei/scripts/process/presentation.rb 2021-03-06 16:33:05.452330114 +0200 | |
@@ -220,21 +220,27 @@ | |
captions.length > 0 | |
webcam_width = presentation_props['video_output_width'] | |
webcam_height = presentation_props['video_output_height'] | |
+ webcam_framerate = presentation_props['video_output_framerate'] | |
# Use a higher resolution video canvas if there's broadcast video streams | |
if !Dir["#{raw_archive_dir}/video-broadcast/*"].empty? | |
webcam_width = presentation_props['deskshare_output_width'] | |
webcam_height = presentation_props['deskshare_output_height'] | |
+ webcam_framerate = presentation_props['deskshare_output_framerate'] | |
end | |
+ webcam_framerate = 15 if webcam_framerate.nil? | |
processed_audio_file = BigBlueButton::AudioProcessor.get_processed_audio_file("#{temp_dir}/#{meeting_id}", "#{target_dir}/audio") | |
- BigBlueButton.process_webcam_videos(target_dir, temp_dir, meeting_id, webcam_width, webcam_height, presentation_props['audio_offset'], processed_audio_file, presentation_props['video_formats']) | |
+ BigBlueButton.process_webcam_videos(target_dir, temp_dir, meeting_id, webcam_width, webcam_height, webcam_framerate, presentation_props['audio_offset'], processed_audio_file, presentation_props['video_formats']) | |
end | |
if !Dir["#{raw_archive_dir}/deskshare/*"].empty? and presentation_props['include_deskshare'] | |
deskshare_width = presentation_props['deskshare_output_width'] | |
deskshare_height = presentation_props['deskshare_output_height'] | |
- BigBlueButton.process_deskshare_videos(target_dir, temp_dir, meeting_id, deskshare_width, deskshare_height, presentation_props['video_formats']) | |
+ deskshare_framerate = presentation_props['deskshare_output_framerate'] | |
+ deskshare_framerate = 5 if deskshare_framerate.nil? | |
+ | |
+ BigBlueButton.process_deskshare_videos(target_dir, temp_dir, meeting_id, deskshare_width, deskshare_height, deskshare_framerate, presentation_props['video_formats']) | |
end | |
# Copy shared notes from raw files |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment