Skip to content

Commit

Permalink
Support easily testing with custom input files and different segment …
Browse files Browse the repository at this point in the history
…lengths.
  • Loading branch information
MaxPower15 committed Feb 11, 2024
1 parent b290490 commit 7fb28b6
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 11 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers

## Usage

Split and stitch:
Split and stitch with the defaults:

ruby run.rb

Test with your own input files and different target segment durations:

ruby run.rb 0.5 <path-or-url>

You can find all artifacts in the "out" directory:

ls out
Expand Down
4 changes: 2 additions & 2 deletions calculations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def get_closest_aligned_time(target_time)
nearest_frame_index_for_target_time * frame_duration
end

def generate_command_and_directives_for_segment(index, target_start, target_end, is_last)
def generate_command_and_directives_for_segment(input_file, index, target_start, target_end, is_last)
puts "--- segment #{index + 1} ---"

start_time = get_closest_aligned_time(target_start)
Expand Down Expand Up @@ -60,7 +60,7 @@ def generate_command_and_directives_for_segment(index, target_start, target_end,

puts "inpoint: #{inpoint}, outpoint: #{outpoint}"

command = "ffmpeg -hide_banner -loglevel error -nostats -y -ss #{start_time_with_padding}us -t #{padded_duration}us -i out/#{SINE_WAVE_FILE_NAME} -c:a libfdk_aac -ar 44100 -f adts out/seg#{index + 1}.aac"
command = "ffmpeg -hide_banner -loglevel error -nostats -y -ss #{start_time_with_padding}us -t #{padded_duration}us -i #{input_file} -c:a libfdk_aac -ar 44100 -f adts out/seg#{index + 1}.aac"
directives = [
"file 'seg#{index + 1}.aac'",
"inpoint #{inpoint}us",
Expand Down
48 changes: 40 additions & 8 deletions run.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,57 @@
require "fileutils"
require "uri"
require "net/http"
require_relative "./calculations"

# Feel free to change these constants for your own testing.
SINE_WAVE_DURATION = 10.to_f
SINE_FREQUENCY = 10.to_f
TARGET_SEGMENT_DURATION = 1.0.to_f
DEFAULT_SEGMENT_DURATION = 1.0.to_f
SINE_WAVE_FILE_NAME = "sine-wave-#{SINE_WAVE_DURATION.to_i}-seconds.wav"

FileUtils.rm_rf "out"
FileUtils.mkdir_p "out"

# generate the sine wave we'll use as input
system("ffmpeg -hide_banner -loglevel error -nostats -y -f lavfi -i \"sine=frequency=#{SINE_FREQUENCY}:duration=#{SINE_WAVE_DURATION}\" out/#{SINE_WAVE_FILE_NAME}")
input_file = nil

if ARGV.count == 1 && ARGV[0] !~ /\A\d+(\.\d+)?\z/
input_file = ARGV[0]
target_segment_duration = DEFAULT_SEGMENT_DURATION
else
target_segment_duration = (ARGV[0] || DEFAULT_SEGMENT_DURATION).to_f
end

if ARGV.count == 2
input_file = ARGV[1]
end

if input_file&.start_with?(/^https?:\/\//)
uri = URI.parse(input_file)
puts "Downloading file from #{uri}..."
resp = Net::HTTP.get_response(uri)
if resp.code.to_i != 200
raise "Failed to download file: #{resp.code.inspect}"
end
File.write("out/downloaded-file", resp.body)
input_file = "out/downloaded-file"
else
# generate the sine wave we'll use as input
system("ffmpeg -hide_banner -loglevel error -nostats -y -f lavfi -i \"sine=frequency=#{SINE_FREQUENCY}:duration=#{SINE_WAVE_DURATION}\" out/#{SINE_WAVE_FILE_NAME}")
input_file = "out/#{SINE_WAVE_FILE_NAME}"
end

duration_cmd = "ffprobe -hide_banner -loglevel error -select_streams v:0 -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 #{input_file}"
puts duration_cmd
duration = `#{duration_cmd}`.to_f
puts "Input file duration: #{duration}"

# Generate the commands we'll use to slice the sine wave into segments and the
# directives we'll use to recombine them later.
commands_and_directives = (SINE_WAVE_DURATION / TARGET_SEGMENT_DURATION).ceil.to_i.times.map do |i|
start_time = (i * TARGET_SEGMENT_DURATION * 1000000).round.to_i
end_time = [((i + 1) * TARGET_SEGMENT_DURATION * 1000000).round, SINE_WAVE_DURATION * 1000000].min.to_i
is_last = i == (SINE_WAVE_DURATION / TARGET_SEGMENT_DURATION).ceil.to_i - 1
generate_command_and_directives_for_segment(i, start_time, end_time, is_last)
commands_and_directives = (duration / target_segment_duration).ceil.to_i.times.map do |i|
start_time = (i * target_segment_duration * 1000000).round.to_i
end_time = [((i + 1) * target_segment_duration * 1000000).round, duration * 1000000].min.to_i
is_last = i == (duration / target_segment_duration).ceil.to_i - 1
generate_command_and_directives_for_segment(input_file, i, start_time, end_time, is_last)
end

all_directives = commands_and_directives.map { |cmd, directives| directives }.join("\n")
Expand Down

0 comments on commit 7fb28b6

Please sign in to comment.