diff --git a/record-and-playback/core/lib/recordandplayback/edl/video.rb b/record-and-playback/core/lib/recordandplayback/edl/video.rb
index 898d86a65cc1d560319d0035aa753dbcffe2358b..8faa73814638225dce8f5d014e35557c0b3b8d8f 100644
--- a/record-and-playback/core/lib/recordandplayback/edl/video.rb
+++ b/record-and-playback/core/lib/recordandplayback/edl/video.rb
@@ -189,11 +189,11 @@ module BigBlueButton
         videoinfo.keys.each do |videofile|
           BigBlueButton.logger.debug "  #{videofile}"
           info = video_info(videofile)
-          BigBlueButton.logger.debug "    width: #{info[:width]}, height: #{info[:height]}, duration: #{info[:duration]}"
           if !info[:video]
             BigBlueButton.logger.warn "    This video file is corrupt! It will be removed from the output."
             corrupt_videos << videofile
           else
+            BigBlueButton.logger.debug "    width: #{info[:width]}, height: #{info[:height]}, duration: #{info[:duration]}, start_time: #{info[:start_time]}"
             if info[:video][:deskshare_timestamp_bug]
               BigBlueButton.logger.debug("    has early 1.1 deskshare timestamp bug")
             end
@@ -264,6 +264,14 @@ module BigBlueButton
           # Convert the duration to milliseconds
           info[:duration] = (info[:format][:duration].to_r * 1000).to_i
 
+          # Red5 writes video files with the first frame often having a pts
+          # much greater than 0.
+          # We can compensate for this during decoding if we know the
+          # timestamp offset, which ffprobe handily finds. Convert the units
+          # to ms.
+          info[:start_time] = (info[:format][:start_time].to_r * 1000).to_i
+          info[:video][:start_time] = (info[:video][:start_time].to_r * 1000).to_i
+
           return info
         end
         {}
@@ -368,9 +376,10 @@ module BigBlueButton
           ffmpeg_filter << "[#{layout_area[:name]}_in];"
 
           area.each do |video|
+            this_videoinfo = videoinfo[video[:filename]]
             BigBlueButton.logger.debug "    tile location (#{tile_x}, #{tile_y})"
-            video_width = videoinfo[video[:filename]][:width]
-            video_height = videoinfo[video[:filename]][:height]
+            video_width = this_videoinfo[:width]
+            video_height = this_videoinfo[:height]
             BigBlueButton.logger.debug "      original size: #{video_width}x#{video_height}"
 
             scale_width, scale_height = aspect_scale(video_width, video_height, tile_width, tile_height)
@@ -379,11 +388,13 @@ module BigBlueButton
             offset_x, offset_y = pad_offset(scale_width, scale_height, tile_width, tile_height)
             BigBlueButton.logger.debug "      offset: left: #{offset_x}, top: #{offset_y}"
 
-            BigBlueButton.logger.debug "      start timestamp: #{video[:timestamp]}"
-            BigBlueButton.logger.debug("      codec: #{videoinfo[video[:filename]][:video][:codec_name].inspect}")
-            BigBlueButton.logger.debug("      duration: #{videoinfo[video[:filename]][:duration]}, original duration: #{video[:original_duration]}")
+            BigBlueButton.logger.debug("      start timestamp: #{video[:timestamp]}")
+            seek_offset = this_videoinfo[:video][:start_time]
+            BigBlueButton.logger.debug("      seek offset: #{seek_offset}")
+            BigBlueButton.logger.debug("      codec: #{this_videoinfo[:video][:codec_name].inspect}")
+            BigBlueButton.logger.debug("      duration: #{this_videoinfo[:duration]}, original duration: #{video[:original_duration]}")
 
-            if videoinfo[video[:filename]][:video][:codec_name] == "flashsv2"
+            if this_videoinfo[:video][:codec_name] == "flashsv2"
               # Desktop sharing videos in flashsv2 do not have regular
               # keyframes, so seeking in them doesn't really work.
               # To make processing more reliable, always decode them from the
@@ -403,8 +414,8 @@ module BigBlueButton
             # actually be...) and scale the video length.
             scale = nil
             if !video[:original_duration].nil? and
-                  videoinfo[video[:filename]][:video][:deskshare_timestamp_bug]
-              scale = video[:original_duration].to_f / videoinfo[video[:filename]][:duration]
+                  this_videoinfo[:video][:deskshare_timestamp_bug]
+              scale = video[:original_duration].to_f / this_videoinfo[:duration]
               # Rather than attempt to recalculate seek...
               seek = 0
               BigBlueButton.logger.debug("      Early 1.1 deskshare timestamp bug: scaling video length by #{scale}")
@@ -412,12 +423,28 @@ module BigBlueButton
 
             pad_name = "#{layout_area[:name]}_x#{tile_x}_y#{tile_y}"
 
+            # Apply the video start time offset to seek to the correct point.
+            # Only actually apply the offset if we're already seeking so we
+            # don't start seeking in a file where we've overridden the seek
+            # behaviour.
+            if seek > 0
+              seek = seek + seek_offset
+            end
             ffmpeg_filter << "movie=#{video[:filename]}:sp=#{ms_to_s(seek)}"
+            # Scale the video length for the deskshare timestamp workaround
             if !scale.nil?
               ffmpeg_filter << ",setpts=PTS*#{scale}"
             end
+            # Subtract away the offset from the timestamps, so the trimming
+            # in the fps filter is accurate
+            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])}"
+            # 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}"
+            # And finally, pad the video to the desired aspect ratio
             ffmpeg_filter << ",pad=w=#{tile_width}:h=#{tile_height}:x=#{offset_x}:y=#{offset_y}:color=white"
             ffmpeg_filter << "[#{pad_name}];"
 
@@ -428,6 +455,7 @@ module BigBlueButton
             end
           end
 
+          # Create the video rows
           remaining = video_count
           (0...tiles_v).each do |tile_y|
             this_tiles_h = [tiles_h, remaining].min
@@ -443,6 +471,7 @@ module BigBlueButton
             ffmpeg_filter << "[#{layout_area[:name]}_y#{tile_y}];"
           end
 
+          # Stack the video rows
           (0...tiles_v).each do |tile_y|
             ffmpeg_filter << "[#{layout_area[:name]}_y#{tile_y}]"
           end