active_encode 0.8.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +26 -17
- data/.rubocop.yml +7 -3
- data/.rubocop_todo.yml +8 -1
- data/CONTRIBUTING.md +42 -12
- data/Gemfile +11 -11
- data/README.md +64 -10
- data/active_encode.gemspec +2 -4
- data/app/controllers/active_encode/encode_record_controller.rb +1 -1
- data/app/jobs/active_encode/polling_job.rb +1 -1
- data/app/models/active_encode/encode_record.rb +1 -1
- data/guides/media_convert_adapter.md +208 -0
- data/lib/active_encode/base.rb +1 -1
- data/lib/active_encode/core.rb +14 -14
- data/lib/active_encode/engine_adapter.rb +13 -13
- data/lib/active_encode/engine_adapters/elastic_transcoder_adapter.rb +158 -158
- data/lib/active_encode/engine_adapters/ffmpeg_adapter.rb +14 -3
- data/lib/active_encode/engine_adapters/matterhorn_adapter.rb +204 -202
- data/lib/active_encode/engine_adapters/media_convert_adapter.rb +435 -203
- data/lib/active_encode/engine_adapters/media_convert_output.rb +67 -5
- data/lib/active_encode/engine_adapters/pass_through_adapter.rb +3 -3
- data/lib/active_encode/engine_adapters/zencoder_adapter.rb +114 -114
- data/lib/active_encode/errors.rb +1 -1
- data/lib/active_encode/persistence.rb +19 -19
- data/lib/active_encode/version.rb +1 -1
- data/lib/file_locator.rb +6 -6
- data/spec/fixtures/ffmpeg/cancelled-id/exit_status.code +1 -0
- data/spec/fixtures/ffmpeg/completed-id/exit_status.code +1 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/error.log +3 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/exit_status.code +1 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/input_metadata +102 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/output_metadata-high +90 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/output_metadata-low +90 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/pid +1 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/progress +11 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/video-high.mp4 +0 -0
- data/spec/fixtures/ffmpeg/completed-with-warnings-id/video-low.mp4 +0 -0
- data/spec/fixtures/ffmpeg/failed-id/exit_status.code +1 -0
- data/spec/fixtures/media_convert/job_completed_empty_detail.json +1 -0
- data/spec/integration/ffmpeg_adapter_spec.rb +50 -1
- data/spec/integration/matterhorn_adapter_spec.rb +1 -2
- data/spec/integration/media_convert_adapter_spec.rb +144 -0
- data/spec/integration/pass_through_adapter_spec.rb +2 -2
- data/spec/integration/zencoder_adapter_spec.rb +3 -3
- data/spec/units/core_spec.rb +1 -1
- data/spec/units/file_locator_spec.rb +3 -3
- data/spec/units/status_spec.rb +1 -1
- metadata +52 -19
@@ -30,13 +30,32 @@ module ActiveEncode
|
|
30
30
|
"XAVC" => :xavc_settings
|
31
31
|
}.freeze
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
# @param output_url [String] url, expected to be `s3://`
|
34
|
+
# @param output_settings [Aws::MediaConvert::Types::Output]
|
35
|
+
# @param output_detail_settings [Aws::MediaConvert::Types::OutputDetail]
|
36
|
+
def tech_metadata_from_settings(output_url:, output_settings:, output_detail_settings:)
|
35
37
|
{
|
36
|
-
width:
|
37
|
-
height:
|
38
|
+
width: output_detail_settings.video_details.width_in_px,
|
39
|
+
height: output_detail_settings.video_details.height_in_px,
|
40
|
+
frame_rate: extract_video_frame_rate(output_settings),
|
41
|
+
duration: output_detail_settings.duration_in_ms,
|
42
|
+
audio_codec: extract_audio_codec(output_settings),
|
43
|
+
video_codec: extract_video_codec(output_settings),
|
44
|
+
audio_bitrate: extract_audio_bitrate(output_settings),
|
45
|
+
video_bitrate: extract_video_bitrate(output_settings),
|
46
|
+
url: output_url,
|
47
|
+
label: (output_url ? File.basename(output_url) : output_settings.name_modifier),
|
48
|
+
suffix: output_settings.name_modifier
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def tech_metadata_from_logged(settings, logged_output)
|
53
|
+
url = logged_output.dig('outputFilePaths', 0)
|
54
|
+
{
|
55
|
+
width: logged_output.dig('videoDetails', 'widthInPx'),
|
56
|
+
height: logged_output.dig('videoDetails', 'heightInPx'),
|
38
57
|
frame_rate: extract_video_frame_rate(settings),
|
39
|
-
duration:
|
58
|
+
duration: logged_output['durationInMs'],
|
40
59
|
audio_codec: extract_audio_codec(settings),
|
41
60
|
video_codec: extract_video_codec(settings),
|
42
61
|
audio_bitrate: extract_audio_bitrate(settings),
|
@@ -47,6 +66,49 @@ module ActiveEncode
|
|
47
66
|
}
|
48
67
|
end
|
49
68
|
|
69
|
+
# constructs an `s3:` output URL from the MediaConvert job params, the same
|
70
|
+
# way MediaConvert will.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# construct_output_filename(
|
74
|
+
# destination: "s3://bucket/base_name",
|
75
|
+
# original_filename: "foo.mp3",
|
76
|
+
# name_modifier: "-1080",
|
77
|
+
# suffix: "m3u8")
|
78
|
+
# # => "s3://bucket/base_name-1080.m3u8"
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# construct_output_filename(
|
82
|
+
# destination: "s3://bucket/directory_end_in_slash/",
|
83
|
+
# original_filename: "original-filename.mp3",
|
84
|
+
# name_modifier: "-1080",
|
85
|
+
# suffix: "m3u8")
|
86
|
+
# # => "s3://bucket/directory_end_in_slash/original_filename-1080.m3u8"
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# construct_output_filename(
|
90
|
+
# destination: "s3://bucket/directory_end_in_slash/",
|
91
|
+
# original_filename: "original-filename.mp3",
|
92
|
+
# name_modifier: nil,
|
93
|
+
# suffix: "m3u8")
|
94
|
+
# # => "s3://bucket/directory_end_in_slash/original_filename.m3u8"
|
95
|
+
def construct_output_url(destination:, file_input_url:, name_modifier:, file_suffix:)
|
96
|
+
output = destination
|
97
|
+
|
98
|
+
# MediaConvert operates such that if you give a destination ending in '/',
|
99
|
+
# it'll use the original file name as part of output url.
|
100
|
+
if output.end_with?('/')
|
101
|
+
# ".*" on the end will strip extension off
|
102
|
+
output += File.basename(file_input_url, '.*')
|
103
|
+
end
|
104
|
+
|
105
|
+
output += name_modifier if name_modifier
|
106
|
+
|
107
|
+
output += "." + file_suffix
|
108
|
+
|
109
|
+
output
|
110
|
+
end
|
111
|
+
|
50
112
|
def extract_audio_codec(settings)
|
51
113
|
settings.audio_descriptions.first.codec_settings.codec
|
52
114
|
rescue
|
@@ -18,7 +18,7 @@ module ActiveEncode
|
|
18
18
|
|
19
19
|
def create(input_url, options = {})
|
20
20
|
# Decode file uris for ffmpeg (mediainfo works either way)
|
21
|
-
input_url = URI.
|
21
|
+
input_url = Addressable::URI.unencode(input_url) if input_url.starts_with? "file:///"
|
22
22
|
|
23
23
|
new_encode = ActiveEncode::Base.new(input_url, options)
|
24
24
|
new_encode.id = SecureRandom.uuid
|
@@ -73,7 +73,7 @@ module ActiveEncode
|
|
73
73
|
new_encode.percent_complete = 1
|
74
74
|
new_encode.errors = [e.full_message]
|
75
75
|
write_errors new_encode
|
76
|
-
|
76
|
+
new_encode
|
77
77
|
end
|
78
78
|
|
79
79
|
# Return encode object from file system
|
@@ -110,7 +110,7 @@ module ActiveEncode
|
|
110
110
|
encode.percent_complete = 1
|
111
111
|
encode.errors = [e.full_message]
|
112
112
|
write_errors encode
|
113
|
-
|
113
|
+
encode
|
114
114
|
end
|
115
115
|
|
116
116
|
# Cancel ongoing encode using pid file
|
@@ -19,138 +19,138 @@ module ActiveEncode
|
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
def get_job_details(job_id)
|
23
|
+
Zencoder::Job.details(job_id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_job_progress(job_id)
|
27
|
+
Zencoder::Job.progress(job_id)
|
28
|
+
end
|
25
29
|
|
26
|
-
|
27
|
-
|
30
|
+
def build_encode(job_details)
|
31
|
+
return nil if job_details.nil?
|
32
|
+
encode = ActiveEncode::Base.new(convert_input(job_details), convert_options(job_details))
|
33
|
+
encode.id = job_details.body["job"]["id"].to_s
|
34
|
+
encode.state = convert_state(get_job_state(job_details))
|
35
|
+
job_progress = get_job_progress(encode.id)
|
36
|
+
encode.current_operations = convert_current_operations(job_progress)
|
37
|
+
encode.percent_complete = convert_percent_complete(job_progress, job_details)
|
38
|
+
encode.created_at = job_details.body["job"]["created_at"]
|
39
|
+
encode.updated_at = job_details.body["job"]["updated_at"]
|
40
|
+
encode.errors = []
|
41
|
+
|
42
|
+
encode.output = convert_output(job_details, job_progress)
|
43
|
+
|
44
|
+
encode.input.id = job_details.body["job"]["input_media_file"]["id"].to_s
|
45
|
+
encode.input.errors = convert_input_errors(job_details)
|
46
|
+
tech_md = convert_tech_metadata(job_details.body["job"]["input_media_file"])
|
47
|
+
[:width, :height, :frame_rate, :duration, :checksum, :audio_codec, :video_codec,
|
48
|
+
:audio_bitrate, :video_bitrate, :file_size].each do |field|
|
49
|
+
encode.input.send("#{field}=", tech_md[field])
|
28
50
|
end
|
51
|
+
encode.input.state = convert_state(job_details.body["job"]["input_media_file"]["state"])
|
52
|
+
encode.input.created_at = job_details.body["job"]["input_media_file"]["created_at"]
|
53
|
+
encode.input.updated_at = job_details.body["job"]["input_media_file"]["updated_at"]
|
29
54
|
|
30
|
-
|
31
|
-
|
32
|
-
encode = ActiveEncode::Base.new(convert_input(job_details), convert_options(job_details))
|
33
|
-
encode.id = job_details.body["job"]["id"].to_s
|
34
|
-
encode.state = convert_state(get_job_state(job_details))
|
35
|
-
job_progress = get_job_progress(encode.id)
|
36
|
-
encode.current_operations = convert_current_operations(job_progress)
|
37
|
-
encode.percent_complete = convert_percent_complete(job_progress, job_details)
|
38
|
-
encode.created_at = job_details.body["job"]["created_at"]
|
39
|
-
encode.updated_at = job_details.body["job"]["updated_at"]
|
40
|
-
encode.errors = []
|
41
|
-
|
42
|
-
encode.output = convert_output(job_details, job_progress)
|
43
|
-
|
44
|
-
encode.input.id = job_details.body["job"]["input_media_file"]["id"].to_s
|
45
|
-
encode.input.errors = convert_input_errors(job_details)
|
46
|
-
tech_md = convert_tech_metadata(job_details.body["job"]["input_media_file"])
|
47
|
-
[:width, :height, :frame_rate, :duration, :checksum, :audio_codec, :video_codec,
|
48
|
-
:audio_bitrate, :video_bitrate, :file_size].each do |field|
|
49
|
-
encode.input.send("#{field}=", tech_md[field])
|
50
|
-
end
|
51
|
-
encode.input.state = convert_state(job_details.body["job"]["input_media_file"]["state"])
|
52
|
-
encode.input.created_at = job_details.body["job"]["input_media_file"]["created_at"]
|
53
|
-
encode.input.updated_at = job_details.body["job"]["input_media_file"]["updated_at"]
|
55
|
+
encode
|
56
|
+
end
|
54
57
|
|
55
|
-
|
58
|
+
def convert_state(state)
|
59
|
+
case state
|
60
|
+
when "assigning", "pending", "waiting", "processing" # Should there be a queued state?
|
61
|
+
:running
|
62
|
+
when "cancelled"
|
63
|
+
:cancelled
|
64
|
+
when "failed", "no_input"
|
65
|
+
:failed
|
66
|
+
when "finished"
|
67
|
+
:completed
|
56
68
|
end
|
69
|
+
end
|
57
70
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
:running
|
62
|
-
when "cancelled"
|
63
|
-
:cancelled
|
64
|
-
when "failed", "no_input"
|
65
|
-
:failed
|
66
|
-
when "finished"
|
67
|
-
:completed
|
68
|
-
end
|
69
|
-
end
|
71
|
+
def get_job_state(job_details)
|
72
|
+
job_details.body["job"]["state"]
|
73
|
+
end
|
70
74
|
|
71
|
-
|
72
|
-
|
73
|
-
|
75
|
+
def convert_current_operations(job_progress)
|
76
|
+
current_ops = []
|
77
|
+
job_progress.body["outputs"].each { |output| current_ops << output["current_event"] unless output["current_event"].nil? }
|
78
|
+
current_ops
|
79
|
+
end
|
74
80
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
def convert_percent_complete(job_progress, job_details)
|
82
|
+
percent = job_progress.body["progress"]
|
83
|
+
percent ||= 100 if convert_state(get_job_state(job_details)) == :completed
|
84
|
+
percent ||= 0
|
85
|
+
percent
|
86
|
+
end
|
80
87
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
percent ||= 0
|
85
|
-
percent
|
86
|
-
end
|
88
|
+
def convert_input(job_details)
|
89
|
+
job_details.body["job"]["input_media_file"]["url"]
|
90
|
+
end
|
87
91
|
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
def convert_options(_job_details)
|
93
|
+
{}
|
94
|
+
end
|
91
95
|
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
def convert_output(job_details, job_progress)
|
97
|
+
job_details.body["job"]["output_media_files"].collect do |o|
|
98
|
+
output = ActiveEncode::Output.new
|
99
|
+
output.id = o["id"].to_s
|
100
|
+
output.label = o["label"]
|
101
|
+
output.url = o["url"]
|
102
|
+
output.errors = Array(o["error_message"])
|
95
103
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
output.
|
100
|
-
output.label = o["label"]
|
101
|
-
output.url = o["url"]
|
102
|
-
output.errors = Array(o["error_message"])
|
103
|
-
|
104
|
-
tech_md = convert_tech_metadata(o)
|
105
|
-
[:width, :height, :frame_rate, :duration, :checksum, :audio_codec, :video_codec,
|
106
|
-
:audio_bitrate, :video_bitrate, :file_size].each do |field|
|
107
|
-
output.send("#{field}=", tech_md[field])
|
108
|
-
end
|
109
|
-
output_progress = job_progress.body["outputs"].find { |out_prog| out_prog["id"] = output.id }
|
110
|
-
output.state = convert_state(output_progress["state"])
|
111
|
-
output.created_at = o["created_at"]
|
112
|
-
output.updated_at = o["updated_at"]
|
113
|
-
output
|
104
|
+
tech_md = convert_tech_metadata(o)
|
105
|
+
[:width, :height, :frame_rate, :duration, :checksum, :audio_codec, :video_codec,
|
106
|
+
:audio_bitrate, :video_bitrate, :file_size].each do |field|
|
107
|
+
output.send("#{field}=", tech_md[field])
|
114
108
|
end
|
109
|
+
output_progress = job_progress.body["outputs"].find { |out_prog| out_prog["id"] = output.id }
|
110
|
+
output.state = convert_state(output_progress["state"])
|
111
|
+
output.created_at = o["created_at"]
|
112
|
+
output.updated_at = o["updated_at"]
|
113
|
+
output
|
115
114
|
end
|
115
|
+
end
|
116
116
|
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
def convert_input_errors(job_details)
|
118
|
+
Array(job_details.body["job"]["input_media_file"]["error_message"])
|
119
|
+
end
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
121
|
+
def convert_tech_metadata(media_file)
|
122
|
+
return {} if media_file.nil?
|
123
|
+
|
124
|
+
metadata = {}
|
125
|
+
media_file.each_pair do |key, value|
|
126
|
+
next if value.blank?
|
127
|
+
case key
|
128
|
+
when "md5_checksum"
|
129
|
+
metadata[:checksum] = value
|
130
|
+
when "format"
|
131
|
+
metadata[:mime_type] = value
|
132
|
+
when "duration_in_ms"
|
133
|
+
metadata[:duration] = value
|
134
|
+
when "audio_codec"
|
135
|
+
metadata[:audio_codec] = value
|
136
|
+
when "channels"
|
137
|
+
metadata[:audio_channels] = value
|
138
|
+
when "audio_bitrate_in_kbps"
|
139
|
+
metadata[:audio_bitrate] = value
|
140
|
+
when "video_codec"
|
141
|
+
metadata[:video_codec] = value
|
142
|
+
when "frame_rate"
|
143
|
+
metadata[:frame_rate] = value
|
144
|
+
when "video_bitrate_in_kbps"
|
145
|
+
metadata[:video_bitrate] = value
|
146
|
+
when "width"
|
147
|
+
metadata[:width] = value
|
148
|
+
when "height"
|
149
|
+
metadata[:height] = value
|
151
150
|
end
|
152
|
-
metadata
|
153
151
|
end
|
152
|
+
metadata
|
153
|
+
end
|
154
154
|
end
|
155
155
|
end
|
156
156
|
end
|
data/lib/active_encode/errors.rb
CHANGED
@@ -27,25 +27,25 @@ module ActiveEncode
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def persist(encode_attributes)
|
31
|
+
model = ActiveEncode::EncodeRecord.find_or_initialize_by(global_id: encode_attributes[:global_id])
|
32
|
+
model.update(encode_attributes) # Don't fail if persisting doesn't succeed?
|
33
|
+
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
35
|
+
def persistence_model_attributes(encode, create_options = nil)
|
36
|
+
attributes = {
|
37
|
+
global_id: encode.to_global_id.to_s,
|
38
|
+
state: encode.state,
|
39
|
+
adapter: encode.class.engine_adapter.class.name,
|
40
|
+
title: encode.input.url.to_s,
|
41
|
+
# Need to ensure that these values come through or else validations will fail
|
42
|
+
created_at: encode.created_at,
|
43
|
+
updated_at: encode.updated_at,
|
44
|
+
raw_object: encode.to_json,
|
45
|
+
progress: encode.percent_complete
|
46
|
+
}
|
47
|
+
attributes[:create_options] = create_options.to_json if create_options.present?
|
48
|
+
attributes
|
49
|
+
end
|
50
50
|
end
|
51
51
|
end
|
data/lib/file_locator.rb
CHANGED
@@ -10,8 +10,8 @@ class FileLocator
|
|
10
10
|
|
11
11
|
def initialize(uri)
|
12
12
|
uri = Addressable::URI.parse(uri)
|
13
|
-
@bucket = URI.
|
14
|
-
@key = URI.
|
13
|
+
@bucket = Addressable::URI.unencode(uri.host)
|
14
|
+
@key = Addressable::URI.unencode(uri.path).sub(%r{^/*(.+)/*$}, '\1')
|
15
15
|
end
|
16
16
|
|
17
17
|
def object
|
@@ -26,21 +26,21 @@ class FileLocator
|
|
26
26
|
def uri
|
27
27
|
if @uri.nil?
|
28
28
|
if source.is_a? File
|
29
|
-
@uri = Addressable::URI.parse("file://#{URI.encode(File.expand_path(source))}")
|
29
|
+
@uri = Addressable::URI.parse("file://#{Addressable::URI.encode(File.expand_path(source))}")
|
30
30
|
else
|
31
31
|
encoded_source = source
|
32
32
|
begin
|
33
33
|
@uri = Addressable::URI.parse(encoded_source)
|
34
34
|
rescue URI::InvalidURIError
|
35
35
|
if encoded_source == source
|
36
|
-
encoded_source = URI.encode(encoded_source)
|
36
|
+
encoded_source = Addressable::URI.encode(encoded_source)
|
37
37
|
retry
|
38
38
|
else
|
39
39
|
raise
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
@uri = Addressable::URI.parse("file://#{URI.encode(File.expand_path(source))}") if @uri.scheme.nil?
|
43
|
+
@uri = Addressable::URI.parse("file://#{Addressable::URI.encode(File.expand_path(source))}") if @uri.scheme.nil?
|
44
44
|
end
|
45
45
|
end
|
46
46
|
@uri
|
@@ -51,7 +51,7 @@ class FileLocator
|
|
51
51
|
when 's3'
|
52
52
|
S3File.new(uri).object.presigned_url(:get)
|
53
53
|
when 'file'
|
54
|
-
URI.
|
54
|
+
Addressable::URI.unencode(uri.path)
|
55
55
|
else
|
56
56
|
@uri.to_s
|
57
57
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
143
|
@@ -0,0 +1 @@
|
|
1
|
+
0
|
@@ -0,0 +1 @@
|
|
1
|
+
0
|
@@ -0,0 +1,102 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<MediaInfo
|
3
|
+
xmlns="https://mediaarea.net/mediainfo"
|
4
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
5
|
+
xsi:schemaLocation="https://mediaarea.net/mediainfo https://mediaarea.net/mediainfo/mediainfo_2_0.xsd"
|
6
|
+
version="2.0">
|
7
|
+
<creatingLibrary version="18.05" url="https://mediaarea.net/MediaInfo">MediaInfoLib</creatingLibrary>
|
8
|
+
<media ref="/home/pdinh/Downloads/videoshort.mp4">
|
9
|
+
<track type="General">
|
10
|
+
<VideoCount>1</VideoCount>
|
11
|
+
<AudioCount>1</AudioCount>
|
12
|
+
<FileExtension>mp4</FileExtension>
|
13
|
+
<Format>MPEG-4</Format>
|
14
|
+
<Format_Profile>Base Media</Format_Profile>
|
15
|
+
<CodecID>mp42</CodecID>
|
16
|
+
<FileSize>199160</FileSize>
|
17
|
+
<Duration>6.315</Duration>
|
18
|
+
<OverallBitRate_Mode>VBR</OverallBitRate_Mode>
|
19
|
+
<OverallBitRate>252301</OverallBitRate>
|
20
|
+
<FrameRate>23.719</FrameRate>
|
21
|
+
<FrameCount>149</FrameCount>
|
22
|
+
<StreamSize>5679</StreamSize>
|
23
|
+
<HeaderSize>160</HeaderSize>
|
24
|
+
<DataSize>193489</DataSize>
|
25
|
+
<FooterSize>5511</FooterSize>
|
26
|
+
<IsStreamable>No</IsStreamable>
|
27
|
+
<Encoded_Date>UTC 2010-09-23 00:37:25</Encoded_Date>
|
28
|
+
<Tagged_Date>UTC 2010-09-23 00:37:27</Tagged_Date>
|
29
|
+
<File_Modified_Date>UTC 2017-12-14 19:29:35</File_Modified_Date>
|
30
|
+
<File_Modified_Date_Local>2017-12-14 14:29:35</File_Modified_Date_Local>
|
31
|
+
<Encoded_Application>HandBrake 0.9.4 2009112300</Encoded_Application>
|
32
|
+
</track>
|
33
|
+
<track type="Video">
|
34
|
+
<StreamOrder>0</StreamOrder>
|
35
|
+
<ID>1</ID>
|
36
|
+
<Format>AVC</Format>
|
37
|
+
<Format_Profile>Main</Format_Profile>
|
38
|
+
<Format_Level>1.1</Format_Level>
|
39
|
+
<Format_Settings_CABAC>Yes</Format_Settings_CABAC>
|
40
|
+
<Format_Settings_RefFrames>2</Format_Settings_RefFrames>
|
41
|
+
<CodecID>avc1</CodecID>
|
42
|
+
<Duration>6.282</Duration>
|
43
|
+
<BitRate>74477</BitRate>
|
44
|
+
<Width>200</Width>
|
45
|
+
<Height>110</Height>
|
46
|
+
<Stored_Width>208</Stored_Width>
|
47
|
+
<Stored_Height>112</Stored_Height>
|
48
|
+
<Sampled_Width>200</Sampled_Width>
|
49
|
+
<Sampled_Height>110</Sampled_Height>
|
50
|
+
<PixelAspectRatio>1.000</PixelAspectRatio>
|
51
|
+
<DisplayAspectRatio>1.818</DisplayAspectRatio>
|
52
|
+
<Rotation>0.000</Rotation>
|
53
|
+
<FrameRate_Mode>VFR</FrameRate_Mode>
|
54
|
+
<FrameRate>23.719</FrameRate>
|
55
|
+
<FrameRate_Minimum>12.500</FrameRate_Minimum>
|
56
|
+
<FrameRate_Maximum>24.390</FrameRate_Maximum>
|
57
|
+
<FrameRate_Original>24.000</FrameRate_Original>
|
58
|
+
<FrameCount>149</FrameCount>
|
59
|
+
<ColorSpace>YUV</ColorSpace>
|
60
|
+
<ChromaSubsampling>4:2:0</ChromaSubsampling>
|
61
|
+
<BitDepth>8</BitDepth>
|
62
|
+
<ScanType>Progressive</ScanType>
|
63
|
+
<StreamSize>58482</StreamSize>
|
64
|
+
<Encoded_Library>x264 - core 79 r1347 5ddd61b</Encoded_Library>
|
65
|
+
<Encoded_Library_Name>x264</Encoded_Library_Name>
|
66
|
+
<Encoded_Library_Version>core 79 r1347 5ddd61b</Encoded_Library_Version>
|
67
|
+
<Encoded_Library_Settings>cabac=1 / ref=2 / deblock=1:0:0 / analyse=0x1:0x111 / me=hex / subme=6 / psy=1 / psy_rd=1.0:0.0 / mixed_ref=0 / me_range=16 / chroma_me=1 / trellis=0 / 8x8dct=0 / cqm=0 / deadzone=21,11 / chroma_qp_offset=-2 / threads=3 / nr=0 / decimate=1 / mbaff=0 / constrained_intra=0 / bframes=2 / b_pyramid=0 / b_adapt=1 / b_bias=0 / direct=1 / wpredb=0 / wpredp=2 / keyint=240 / keyint_min=24 / scenecut=40 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=25.5 / qcomp=0.60 / qpmin=10 / qpmax=51 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00</Encoded_Library_Settings>
|
68
|
+
<Encoded_Date>UTC 2010-09-23 00:37:25</Encoded_Date>
|
69
|
+
<Tagged_Date>UTC 2010-09-23 00:37:27</Tagged_Date>
|
70
|
+
<colour_range>Limited</colour_range>
|
71
|
+
<colour_description_present>Yes</colour_description_present>
|
72
|
+
<colour_primaries>BT.601 NTSC</colour_primaries>
|
73
|
+
<transfer_characteristics>BT.709</transfer_characteristics>
|
74
|
+
<matrix_coefficients>BT.601</matrix_coefficients>
|
75
|
+
</track>
|
76
|
+
<track type="Audio">
|
77
|
+
<StreamOrder>1</StreamOrder>
|
78
|
+
<ID>2</ID>
|
79
|
+
<Format>AAC</Format>
|
80
|
+
<Format_Profile>LC</Format_Profile>
|
81
|
+
<CodecID>mp4a-40-2</CodecID>
|
82
|
+
<Duration>6.315</Duration>
|
83
|
+
<BitRate_Mode>VBR</BitRate_Mode>
|
84
|
+
<BitRate>171030</BitRate>
|
85
|
+
<BitRate_Maximum>201736</BitRate_Maximum>
|
86
|
+
<Channels>1</Channels>
|
87
|
+
<ChannelPositions>Front: C</ChannelPositions>
|
88
|
+
<ChannelLayout>C</ChannelLayout>
|
89
|
+
<SamplesPerFrame>1024</SamplesPerFrame>
|
90
|
+
<SamplingRate>48000</SamplingRate>
|
91
|
+
<SamplingCount>303120</SamplingCount>
|
92
|
+
<FrameRate>46.875</FrameRate>
|
93
|
+
<FrameCount>296</FrameCount>
|
94
|
+
<Compression_Mode>Lossy</Compression_Mode>
|
95
|
+
<StreamSize>134999</StreamSize>
|
96
|
+
<StreamSize_Proportion>0.67784</StreamSize_Proportion>
|
97
|
+
<Title>Stereo</Title>
|
98
|
+
<Encoded_Date>UTC 2010-09-23 00:37:25</Encoded_Date>
|
99
|
+
<Tagged_Date>UTC 2010-09-23 00:37:27</Tagged_Date>
|
100
|
+
</track>
|
101
|
+
</media>
|
102
|
+
</MediaInfo>
|