active_encode 0.8.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +26 -17
  3. data/.rubocop.yml +7 -3
  4. data/.rubocop_todo.yml +8 -1
  5. data/CONTRIBUTING.md +42 -12
  6. data/Gemfile +11 -11
  7. data/README.md +64 -10
  8. data/active_encode.gemspec +2 -4
  9. data/app/controllers/active_encode/encode_record_controller.rb +1 -1
  10. data/app/jobs/active_encode/polling_job.rb +1 -1
  11. data/app/models/active_encode/encode_record.rb +1 -1
  12. data/guides/media_convert_adapter.md +208 -0
  13. data/lib/active_encode/base.rb +1 -1
  14. data/lib/active_encode/core.rb +14 -14
  15. data/lib/active_encode/engine_adapter.rb +13 -13
  16. data/lib/active_encode/engine_adapters/elastic_transcoder_adapter.rb +158 -158
  17. data/lib/active_encode/engine_adapters/ffmpeg_adapter.rb +14 -3
  18. data/lib/active_encode/engine_adapters/matterhorn_adapter.rb +204 -202
  19. data/lib/active_encode/engine_adapters/media_convert_adapter.rb +421 -217
  20. data/lib/active_encode/engine_adapters/media_convert_output.rb +67 -5
  21. data/lib/active_encode/engine_adapters/pass_through_adapter.rb +3 -3
  22. data/lib/active_encode/engine_adapters/zencoder_adapter.rb +114 -114
  23. data/lib/active_encode/errors.rb +1 -1
  24. data/lib/active_encode/persistence.rb +19 -19
  25. data/lib/active_encode/version.rb +1 -1
  26. data/lib/file_locator.rb +6 -6
  27. data/spec/fixtures/ffmpeg/cancelled-id/exit_status.code +1 -0
  28. data/spec/fixtures/ffmpeg/completed-id/exit_status.code +1 -0
  29. data/spec/fixtures/ffmpeg/completed-with-warnings-id/error.log +3 -0
  30. data/spec/fixtures/ffmpeg/completed-with-warnings-id/exit_status.code +1 -0
  31. data/spec/fixtures/ffmpeg/completed-with-warnings-id/input_metadata +102 -0
  32. data/spec/fixtures/ffmpeg/completed-with-warnings-id/output_metadata-high +90 -0
  33. data/spec/fixtures/ffmpeg/completed-with-warnings-id/output_metadata-low +90 -0
  34. data/spec/fixtures/ffmpeg/completed-with-warnings-id/pid +1 -0
  35. data/spec/fixtures/ffmpeg/completed-with-warnings-id/progress +11 -0
  36. data/spec/fixtures/ffmpeg/completed-with-warnings-id/video-high.mp4 +0 -0
  37. data/spec/fixtures/ffmpeg/completed-with-warnings-id/video-low.mp4 +0 -0
  38. data/spec/fixtures/ffmpeg/failed-id/exit_status.code +1 -0
  39. data/spec/integration/ffmpeg_adapter_spec.rb +50 -1
  40. data/spec/integration/matterhorn_adapter_spec.rb +1 -2
  41. data/spec/integration/media_convert_adapter_spec.rb +91 -0
  42. data/spec/integration/pass_through_adapter_spec.rb +2 -2
  43. data/spec/integration/zencoder_adapter_spec.rb +3 -3
  44. data/spec/units/core_spec.rb +1 -1
  45. data/spec/units/file_locator_spec.rb +3 -3
  46. data/spec/units/status_spec.rb +1 -1
  47. metadata +50 -19
@@ -30,13 +30,32 @@ module ActiveEncode
30
30
  "XAVC" => :xavc_settings
31
31
  }.freeze
32
32
 
33
- def tech_metadata(settings, output)
34
- url = output.dig('outputFilePaths', 0)
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: output.dig('videoDetails', 'widthInPx'),
37
- height: output.dig('videoDetails', 'heightInPx'),
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: output['durationInMs'],
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.decode(input_url) if input_url.starts_with? "file:///"
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
- return new_encode
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
- return encode
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
- def get_job_details(job_id)
23
- Zencoder::Job.details(job_id)
24
- end
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
- def get_job_progress(job_id)
27
- Zencoder::Job.progress(job_id)
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
- 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])
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
- encode
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
- 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
68
- end
69
- end
71
+ def get_job_state(job_details)
72
+ job_details.body["job"]["state"]
73
+ end
70
74
 
71
- def get_job_state(job_details)
72
- job_details.body["job"]["state"]
73
- end
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
- 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
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
- 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
88
+ def convert_input(job_details)
89
+ job_details.body["job"]["input_media_file"]["url"]
90
+ end
87
91
 
88
- def convert_input(job_details)
89
- job_details.body["job"]["input_media_file"]["url"]
90
- end
92
+ def convert_options(_job_details)
93
+ {}
94
+ end
91
95
 
92
- def convert_options(_job_details)
93
- {}
94
- end
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
- 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"])
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
- def convert_input_errors(job_details)
118
- Array(job_details.body["job"]["input_media_file"]["error_message"])
119
- end
117
+ def convert_input_errors(job_details)
118
+ Array(job_details.body["job"]["input_media_file"]["error_message"])
119
+ end
120
120
 
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
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module ActiveEncode #:nodoc:
2
+ module ActiveEncode # :nodoc:
3
3
  class NotFound < RuntimeError; end
4
4
  class NotRunningError < RuntimeError; end
5
5
  class CancelError < RuntimeError; end
@@ -27,25 +27,25 @@ module ActiveEncode
27
27
 
28
28
  private
29
29
 
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
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
- 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
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ActiveEncode
3
- VERSION = '0.8.2'
3
+ VERSION = '1.0.0'
4
4
  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.decode(uri.host)
14
- @key = URI.decode(uri.path).sub(%r{^/*(.+)/*$}, '\1')
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.decode(uri.path)
54
+ Addressable::URI.unencode(uri.path)
55
55
  else
56
56
  @uri.to_s
57
57
  end
@@ -0,0 +1,3 @@
1
+ [mpeg2video @ 0x6e48440] slice mismatch
2
+ [mpeg2video @ 0x6e48440] Warning MVs not available
3
+ [mpeg2video @ 0x8f89a0] concealing 45 DC, 45 AC, 45 MV errors in P frame
@@ -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>