Skip to content

Instantly share code, notes, and snippets.

@abautu
Last active March 10, 2021 09:43
Show Gist options
  • Save abautu/fcd3a1cf8b5f5665d16fd07d623808ef to your computer and use it in GitHub Desktop.
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)
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)
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