video_converter 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,9 +13,9 @@ module VideoConverter
|
|
13
13
|
|
14
14
|
self.one_pass_command = "%{bin} -i %{input} -y -acodec copy -vcodec %{video_codec} -g 100 -keyint_min 50 -b:v %{video_bitrate}k -bt %{video_bitrate}k %{vf} %{frame_rate} -progress %{progressfile} -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
|
15
15
|
|
16
|
-
self.first_pass_command = "%{bin} -i %{input} -y -an -vcodec %{video_codec} -g %{keyframe_interval} -keyint_min 25 -pass 1 -passlogfile %{passlogfile} -progress %{progressfile} -b:v 3000k %{vf} %{frame_rate} -threads %{threads} -f mp4 /dev/null 1>>%{log} 2>&1 || exit 1"
|
16
|
+
self.first_pass_command = "%{bin} -i %{input} -y -an -vcodec %{video_codec} -g %{keyframe_interval} -keyint_min 25 -pass 1 -passlogfile %{passlogfile} -progress %{progressfile} -b:v 3000k %{vf} %{frame_rate} -threads %{threads} -pix_fmt yuv420p -f mp4 /dev/null 1>>%{log} 2>&1 || exit 1"
|
17
17
|
|
18
|
-
self.second_pass_command = "%{bin} -i %{input} -y -pass 2 -passlogfile %{passlogfile} -progress %{progressfile} -c:a %{audio_codec} -b:a %{audio_bitrate}k -c:v %{video_codec} -g %{keyframe_interval} -keyint_min 25 %{frame_rate} -b:v %{video_bitrate}k %{vf} -threads %{threads} -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
|
18
|
+
self.second_pass_command = "%{bin} -i %{input} -y -pass 2 -passlogfile %{passlogfile} -progress %{progressfile} -c:a %{audio_codec} -b:a %{audio_bitrate}k -ac 2 -c:v %{video_codec} -g %{keyframe_interval} -keyint_min 25 %{frame_rate} -b:v %{video_bitrate}k %{vf} -threads %{threads} -pix_fmt yuv420p -f mp4 %{local_path} 1>%{log} 2>&1 || exit 1"
|
19
19
|
|
20
20
|
attr_accessor :input_array, :output_array, :one_pass, :paral, :log, :process
|
21
21
|
|
data/lib/video_converter/hls.rb
CHANGED
@@ -24,7 +24,8 @@ module VideoConverter
|
|
24
24
|
`mkdir -p #{output_dir}` unless Dir.exists?(output_dir)
|
25
25
|
concat_file = File.join(output_dir, 'concat.ts')
|
26
26
|
`rm #{concat_file}` if File.exists? concat_file
|
27
|
-
|
27
|
+
need_reconvert = false
|
28
|
+
chunks.each_with_index do |chunk, chunk_index|
|
28
29
|
local_chunk = if chunks_dir
|
29
30
|
File.join(chunks_dir, chunk)
|
30
31
|
elsif replace_in_chunk
|
@@ -36,6 +37,9 @@ module VideoConverter
|
|
36
37
|
yield message if block_given?
|
37
38
|
`cat #{local_chunk} >> #{concat_file}`
|
38
39
|
else
|
40
|
+
# NOTE because of troubles with timestamps
|
41
|
+
need_reconvert = true unless [0,chunks.count-1].include?(chunk_index)
|
42
|
+
|
39
43
|
chunk = File.join(File.dirname(input), chunk) unless chunk.match(/(^https?:\/\/)|(^\/)/)
|
40
44
|
message = "Download #{chunk} to #{concat_file}"
|
41
45
|
puts message if verbose
|
@@ -45,7 +49,10 @@ module VideoConverter
|
|
45
49
|
end
|
46
50
|
raise "Cannot download chunks from #{input}" unless File.exists?(concat_file) && File.size(concat_file) > 0
|
47
51
|
puts "Convert #{concat_file}" if verbose
|
48
|
-
|
52
|
+
cmd = "#{ffmpeg_bin} -i #{concat_file} -vcodec copy -acodec copy -f mpegts pipe:1 2>>/dev/null | #{ffmpeg_bin} -y -i - -acodec copy -vcodec #{need_reconvert ? 'libx264' : 'copy'} -absf aac_adtstoasc -f mp4 #{output} 1>>#{log} 2>&1"
|
53
|
+
puts cmd if verbose
|
54
|
+
yield cmd if block_given?
|
55
|
+
`#{cmd}`
|
49
56
|
`rm #{concat_file}`
|
50
57
|
output
|
51
58
|
end
|
@@ -38,7 +38,7 @@ module VideoConverter
|
|
38
38
|
def metadata
|
39
39
|
metadata = {}
|
40
40
|
s = `#{Command.new self.class.metadata_command, common_params}`.encode!('UTF-8', 'UTF-8', :invalid => :replace)
|
41
|
-
if (m = s.match(/Stream.*?Audio:\s*(\w+).*?(\d+)\s*Hz.*?(\d+)\s*kb\/s
|
41
|
+
if (m = s.match(/Stream.*?Audio:\s*(\w+).*?(\d+)\s*Hz.*?(\d+)\s*kb\/s.*?$/).to_a).any?
|
42
42
|
metadata[:audio_codec] = m[1]
|
43
43
|
metadata[:audio_sample_rate] = m[2].to_i
|
44
44
|
metadata[:audio_bitrate_in_kbps] = m[3].to_i
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module VideoConverter
|
4
4
|
class LiveSegmenter
|
5
5
|
class << self
|
6
|
-
attr_accessor :bin, :ffprobe_bin, :chunks_command, :chunk_prefix, :encoding_profile, :log, :paral
|
6
|
+
attr_accessor :bin, :ffprobe_bin, :chunks_command, :chunk_prefix, :encoding_profile, :log, :paral, :select_streams
|
7
7
|
end
|
8
8
|
|
9
9
|
self.bin = '/usr/local/bin/live_segmenter'
|
@@ -12,6 +12,7 @@ module VideoConverter
|
|
12
12
|
self.encoding_profile = 's'
|
13
13
|
self.log = '/dev/null'
|
14
14
|
self.paral = true
|
15
|
+
self.select_streams = 'v'
|
15
16
|
|
16
17
|
self.chunks_command = '%{ffmpeg_bin} -f mp4 -i %{local_path} -vcodec copy -acodec copy -f mpegts -bsf h264_mp4toannexb pipe:1 2>>/dev/null | %{bin} %{segment_seconds} %{chunks_dir} %{chunk_prefix} %{encoding_profile} 1>>%{log} 2>&1'
|
17
18
|
|
@@ -53,10 +54,20 @@ module VideoConverter
|
|
53
54
|
def gen_quality_playlist output
|
54
55
|
res = ''
|
55
56
|
durations = []
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
# order desc
|
58
|
+
chunks = Dir::glob(File.join(output.chunks_dir, "#{chunk_prefix}-*[0-9].ts")).sort do |c1, c2|
|
59
|
+
File.basename(c2).match(/\d+/).to_s.to_i <=> File.basename(c1).match(/\d+/).to_s.to_i
|
60
|
+
end
|
61
|
+
# chunk duration = (pts of first frame of the next chunk - pts of first frame of current chunk) / time_base
|
62
|
+
# for the last chunks the last two pts are used
|
63
|
+
prl_pts, l_pts = `#{self.class.ffprobe_bin} -show_frames -select_streams #{self.class.select_streams} -print_format csv -loglevel fatal #{chunks.first} | tail -n2 2>&1`.split("\n").map { |l| l.split(',')[3].to_i }
|
64
|
+
next_chunk_pts = 2 * l_pts - prl_pts
|
65
|
+
chunks.each do |chunk|
|
66
|
+
durations << (duration = (next_chunk_pts - (next_chunk_pts =
|
67
|
+
`#{self.class.ffprobe_bin} -show_frames -select_streams #{self.class.select_streams} -print_format csv -loglevel fatal #{chunk} | head -n1 2>&1`.split(',')[3].to_i
|
68
|
+
)) / `#{self.class.ffprobe_bin} -show_streams -select_streams #{self.class.select_streams} -loglevel fatal #{chunk} 2>&1`.match(/\ntime_base=1\/(\d+)/)[1].to_f)
|
69
|
+
res = File.join(File.basename(output.chunks_dir), File.basename(chunk)) + "\n" + res
|
70
|
+
res = "#EXTINF:%0.2f,\n" % duration + res
|
60
71
|
end
|
61
72
|
res = "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:#{durations.max}\n#EXT-X-MEDIA-SEQUENCE:0\n" + res + "#EXT-X-ENDLIST"
|
62
73
|
File.open(File.join(output.work_dir, output.filename), 'w') { |f| f.write res }
|
@@ -76,9 +87,5 @@ module VideoConverter
|
|
76
87
|
def common_params
|
77
88
|
{ :ffmpeg_bin => Ffmpeg.bin, :bin => self.class.bin, :log => log, :chunk_prefix => chunk_prefix, :encoding_profile => encoding_profile }
|
78
89
|
end
|
79
|
-
|
80
|
-
def chunk_duration chunk
|
81
|
-
s = `#{self.class.ffprobe_bin} #{chunk} 2>&1`.match(/Duration:.*(?:[0-9]{2}):(?:[0-9]{2}):([0-9]{2}(?:\.[0-9]{2})?)/).to_a[1].to_f
|
82
|
-
end
|
83
90
|
end
|
84
91
|
end
|
@@ -11,7 +11,7 @@ module VideoConverter
|
|
11
11
|
self.collect_progress_interval = 10
|
12
12
|
|
13
13
|
def self.find uid
|
14
|
-
if Dir.exists?(File.join(process_dir, uid))
|
14
|
+
if Dir.exists?(File.join(process_dir, uid.to_s))
|
15
15
|
new uid
|
16
16
|
else
|
17
17
|
nil
|
@@ -19,7 +19,7 @@ module VideoConverter
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def initialize uid, output_array = nil
|
22
|
-
self.uid = uid
|
22
|
+
self.uid = uid.to_s
|
23
23
|
self.process_dir = File.join(self.class.process_dir, uid)
|
24
24
|
|
25
25
|
unless Dir.exists? process_dir
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: video_converter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-03-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: video_screenshoter
|
@@ -137,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
137
137
|
version: '0'
|
138
138
|
segments:
|
139
139
|
- 0
|
140
|
-
hash:
|
140
|
+
hash: 3814024992440192523
|
141
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
142
|
none: false
|
143
143
|
requirements:
|
@@ -146,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
146
|
version: '0'
|
147
147
|
segments:
|
148
148
|
- 0
|
149
|
-
hash:
|
149
|
+
hash: 3814024992440192523
|
150
150
|
requirements:
|
151
151
|
- ffmpeg, version 1.2 or greated configured with libx264 and libfaac
|
152
152
|
- live_segmenter to convert to hls
|