bitmovin-ruby 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +1 -1
- data/examples/create_encoding_finished_webhook.rb +21 -0
- data/examples/dash_hls_mp4_encoding_with_manifests.rb +502 -0
- data/examples/hls_multi_codec.rb +205 -0
- data/examples/simple_dash_with_http_input.rb +216 -0
- data/examples/simple_hls_with_aes128.rb +197 -0
- data/lib/bitmovin/encoding/codec_configurations/h265_configuration.rb +1 -0
- data/lib/bitmovin/encoding/encodings/muxings/drms/drm_muxing_resource.rb +54 -0
- data/lib/bitmovin/encoding/encodings/muxings/drms/drm_muxings.rb +6 -0
- data/lib/bitmovin/encoding/encodings/muxings/drms/ts_muxing_aes_encryption.rb +5 -0
- data/lib/bitmovin/encoding/encodings/muxings/drms/ts_muxing_aes_encryption_list.rb +15 -0
- data/lib/bitmovin/encoding/encodings/muxings/drms/ts_muxing_drm_list.rb +11 -0
- data/lib/bitmovin/encoding/encodings/muxings/mp4_muxing_list.rb +1 -1
- data/lib/bitmovin/encoding/encodings/muxings/ts_muxing.rb +15 -0
- data/lib/bitmovin/encoding/encodings/stream.rb +6 -1
- data/lib/bitmovin/encoding/encodings.rb +4 -0
- data/lib/bitmovin/encoding/inputs.rb +18 -0
- data/lib/bitmovin/encoding/manifests/hls_audio_media.rb +27 -0
- data/lib/bitmovin/encoding/manifests/hls_manifest.rb +43 -0
- data/lib/bitmovin/encoding/manifests/hls_variant_stream.rb +20 -0
- data/lib/bitmovin/encoding/manifests/hls_variant_stream_list.rb +22 -0
- data/lib/bitmovin/encoding/manifests/list.rb +39 -0
- data/lib/bitmovin/encoding/manifests.rb +3 -0
- data/lib/bitmovin/encoding/outputs.rb +2 -0
- data/lib/bitmovin/version.rb +1 -1
- data/lib/bitmovin/webhooks/encoding_finished_webhook.rb +5 -0
- data/lib/bitmovin/webhooks/webhook_encryption.rb +45 -0
- data/lib/bitmovin/webhooks/webhook_resource.rb +5 -0
- data/lib/bitmovin/webhooks/webhook_signature.rb +45 -0
- data/lib/bitmovin/webhooks.rb +8 -0
- data/lib/bitmovin-ruby.rb +1 -0
- metadata +22 -3
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'bitmovin-ruby'
|
2
|
+
|
3
|
+
# CONFIGURATION
|
4
|
+
BITMOVIN_API_KEY = "YOUR API KEY HERE"
|
5
|
+
|
6
|
+
S3_INPUT_ID = "The ID of the Input"
|
7
|
+
S3_OUTPUT_ID = "The ID of the Output"
|
8
|
+
OUTPUT_PATH = "/encoding_test/bitmovin-ruby/#{Time.now.strftime("%v-%H-%M")}/"
|
9
|
+
M3U8_NAME = "playlist.m3u8"
|
10
|
+
|
11
|
+
Bitmovin.init(BITMOVIN_API_KEY)
|
12
|
+
|
13
|
+
# This will create a Input Bucket you can reuse in future encodings
|
14
|
+
# To get a list of all your S3Inputs do:
|
15
|
+
# Bitmovin::Encoding::Inputs::S3Input.list
|
16
|
+
s3_input = Bitmovin::Encoding::Inputs::S3Input.find(S3_INPUT_ID)
|
17
|
+
|
18
|
+
# This will create a Output Bucket you can reuse in future encodings
|
19
|
+
# To get a list of all your Output do:
|
20
|
+
# Bitmovin::Encoding::Outputs::S3Output.list
|
21
|
+
s3_output = Bitmovin::Encoding::Outputs::S3Output.find(S3_OUTPUT_ID)
|
22
|
+
|
23
|
+
# Please note inputs/outputs are not individual files but rather the
|
24
|
+
# Bucket you are reading/writing files to and they can be reused between encodings.
|
25
|
+
|
26
|
+
|
27
|
+
# This hash contains the H264 Codec Configurations we want to create
|
28
|
+
# Codec Configurations are similar to Inputs/Outputs in that they are configured once
|
29
|
+
# and can be reused for future encodings.
|
30
|
+
video_configs = [
|
31
|
+
{ name: "h264_360p_600", profile: "HIGH", height: 360, bitrate: 600000 },
|
32
|
+
{ name: "h264_432p_700", profile: "HIGH", height: 432, bitrate: 700000 },
|
33
|
+
{ name: "h264_576p_1050", profile: "HIGH", height: 576, bitrate: 1050000 },
|
34
|
+
{ name: "h264_720p_1380", profile: "HIGH", height: 720, bitrate: 1380000 },
|
35
|
+
{ name: "h264_720p_1800", profile: "HIGH", height: 720, bitrate: 1800000 },
|
36
|
+
{ name: "h264_1080p_2150", profile: "HIGH", height: 1080, bitrate: 2150000 },
|
37
|
+
{ name: "h264_1080p_2900", profile: "HIGH", height: 1080, bitrate: 2900000 },
|
38
|
+
{ name: "h264_2160p_4000", profile: "HIGH", height: 2160, bitrate: 4000000 },
|
39
|
+
{ name: "h264_2160p_6000", profile: "HIGH", height: 2160, bitrate: 6000000 },
|
40
|
+
{ name: "h264_2160p_8500", profile: "HIGH", height: 2160, bitrate: 8500000 },
|
41
|
+
{ name: "h264_2160p_10000", profile: "HIGH", height: 2160, bitrate: 10000000 },
|
42
|
+
|
43
|
+
{ name: "h265_360p_420", profile: "main", height: 360, bitrate: 420000 },
|
44
|
+
{ name: "h265_432p_490", profile: "main", height: 432, bitrate: 490000 },
|
45
|
+
{ name: "h265_576p_735", profile: "main", height: 576, bitrate: 735000 },
|
46
|
+
{ name: "h265_720p_966", profile: "main", height: 720, bitrate: 966000 },
|
47
|
+
{ name: "h265_720p_1260", profile: "main", height: 720, bitrate: 1260000 },
|
48
|
+
{ name: "h265_1080p_1505", profile: "main", height: 1080, bitrate: 1505000 },
|
49
|
+
{ name: "h265_1080p_2030", profile: "main", height: 1080, bitrate: 2030000 },
|
50
|
+
{ name: "h265_2160p_2800", profile: "main", height: 2160, bitrate: 2800000 },
|
51
|
+
{ name: "h265_2160p_4200", profile: "main", height: 2160, bitrate: 4200000 },
|
52
|
+
{ name: "h265_2160p_5950", profile: "main", height: 2160, bitrate: 5950000 },
|
53
|
+
{ name: "h265_2160p_7000", profile: "main", height: 2160, bitrate: 7000000 }
|
54
|
+
]
|
55
|
+
|
56
|
+
# The actual instance of the encoding task you are about to start
|
57
|
+
enc = Bitmovin::Encoding::Encodings::EncodingTask.new({
|
58
|
+
name: "VOD h264/h265 Encoding HLS"
|
59
|
+
})
|
60
|
+
enc.save!
|
61
|
+
|
62
|
+
|
63
|
+
# Let's also start the Manifest generation
|
64
|
+
manifest = Bitmovin::Encoding::Manifests::HlsManifest.new({
|
65
|
+
name: 'Test Ruby Manifest',
|
66
|
+
description: "Test encoding with ruby",
|
67
|
+
manifest_name: M3U8_NAME
|
68
|
+
})
|
69
|
+
|
70
|
+
manifest.outputs << Bitmovin::Encoding::StreamOutput.new({
|
71
|
+
output_id: s3_output.id,
|
72
|
+
output_path: OUTPUT_PATH
|
73
|
+
})
|
74
|
+
manifest.save!
|
75
|
+
|
76
|
+
create_audio!(enc, manifest, s3_input, s3_output)
|
77
|
+
|
78
|
+
# Adding Video Streams to Encoding
|
79
|
+
video_configs.each do |config|
|
80
|
+
if (config[:name].start_with?("h264"))
|
81
|
+
codec_config = Bitmovin::Encoding::CodecConfigurations::H264Configuration.new(config)
|
82
|
+
else
|
83
|
+
codec_config = Bitmovin::Encoding::CodecConfigurations::H265Configuration.new(config)
|
84
|
+
end
|
85
|
+
codec_config.save!
|
86
|
+
config = OpenStruct.new(config)
|
87
|
+
|
88
|
+
str = enc.streams.build(name: codec_config.name)
|
89
|
+
str.codec_configuration = codec_config
|
90
|
+
str.build_input_stream(input_path: INPUT_FILE_PATH, input_id: s3_input.id, selection_mode: 'AUTO')
|
91
|
+
str.conditions = {
|
92
|
+
type: "CONDITION",
|
93
|
+
attribute: "HEIGHT",
|
94
|
+
operator: "<=",
|
95
|
+
value: codec_config.height
|
96
|
+
}
|
97
|
+
str.save!
|
98
|
+
|
99
|
+
muxing = enc.muxings.fmp4.build(name: "#{codec_config.name} muxing", segment_length: 4)
|
100
|
+
muxing.streams << str.id
|
101
|
+
muxing.build_output({
|
102
|
+
output_id: s3_output.id,
|
103
|
+
output_path: File.join(OUTPUT_PATH, config.name),
|
104
|
+
acl: [{
|
105
|
+
permission: "PUBLIC_READ"
|
106
|
+
}]
|
107
|
+
})
|
108
|
+
muxing.save!
|
109
|
+
puts "Finished muxing #{muxing.name}"
|
110
|
+
|
111
|
+
# Add the Stream to the Manifest too
|
112
|
+
hls_stream = manifest.build_stream({
|
113
|
+
audio: 'audio_group',
|
114
|
+
closed_captions: 'NONE',
|
115
|
+
segmentPath: config.name,
|
116
|
+
encoding_id: enc.id,
|
117
|
+
muxing_id: muxing.id,
|
118
|
+
stream_id: str.id,
|
119
|
+
#drm_id: aes_muxing.id,
|
120
|
+
uri: config.name + '.m3u8'
|
121
|
+
})
|
122
|
+
hls_stream.save!
|
123
|
+
end
|
124
|
+
|
125
|
+
# Starting an encoding and monitoring it's status
|
126
|
+
enc.start!
|
127
|
+
|
128
|
+
while(enc.status != 'FINISHED')
|
129
|
+
puts "Encoding Status is #{enc.status}"
|
130
|
+
progress = enc.progress
|
131
|
+
if (progress > 0)
|
132
|
+
puts "Progress: #{enc.progress} %"
|
133
|
+
end
|
134
|
+
sleep 2
|
135
|
+
end
|
136
|
+
puts "Encoding finished!"
|
137
|
+
|
138
|
+
# Now that the encoding is finished we can start writing the m3u8 Manifest
|
139
|
+
manifest.start!
|
140
|
+
|
141
|
+
while(manifest.status != 'FINISHED')
|
142
|
+
puts "manifestoding Status is #{manifest.status}"
|
143
|
+
progress = manifest.progress
|
144
|
+
if (progress > 0)
|
145
|
+
puts "Progress: #{manifest.progress} %"
|
146
|
+
end
|
147
|
+
sleep 2
|
148
|
+
end
|
149
|
+
|
150
|
+
BEGIN {
|
151
|
+
# Begin is a hack to have this method available but define it at the end of the file
|
152
|
+
def create_audio!(enc, manifest, s3_input, s3_output)
|
153
|
+
|
154
|
+
# Create or load the Audio Config
|
155
|
+
#audio_config = Bitmovin::Encoding::CodecConfigurations::AacConfiguration.find("<EXISTING_AAC_CONFIG_ID>")
|
156
|
+
audio_config = Bitmovin::Encoding::CodecConfigurations::AacConfiguration.new({
|
157
|
+
name: "AAC_PROFILE_128k",
|
158
|
+
bitrate: 128000,
|
159
|
+
rate: 48000
|
160
|
+
})
|
161
|
+
audio_config.save!
|
162
|
+
#
|
163
|
+
# Adding Audio Stream to Encoding
|
164
|
+
stream_aac = enc.streams.build(name: 'audio stream')
|
165
|
+
stream_aac.codec_configuration = audio_config
|
166
|
+
stream_aac.build_input_stream(input_path: INPUT_FILE_PATH, input_id: s3_input.id, selection_mode: 'AUTO')
|
167
|
+
stream_aac.conditions = {
|
168
|
+
type: "CONDITION",
|
169
|
+
attribute: "INPUTSTREAM",
|
170
|
+
operator: "==",
|
171
|
+
value: "TRUE"
|
172
|
+
}
|
173
|
+
puts stream_aac.conditions.to_json
|
174
|
+
stream_aac.save!
|
175
|
+
|
176
|
+
# Audio Muxing
|
177
|
+
audio_muxing = enc.muxings.fmp4.build(name: 'audio-muxing', segment_length: 4)
|
178
|
+
audio_muxing.build_output({
|
179
|
+
output_id: s3_output.id,
|
180
|
+
output_path: File.join(OUTPUT_PATH, "audio/aac")
|
181
|
+
})
|
182
|
+
audio_muxing.build_output({
|
183
|
+
output_id: s3_output.id,
|
184
|
+
output_path: File.join(OUTPUT_PATH, "audio/aac"),
|
185
|
+
acl: [{
|
186
|
+
permission: "PUBLIC_READ"
|
187
|
+
}]
|
188
|
+
})
|
189
|
+
audio_muxing.streams << stream_aac.id
|
190
|
+
audio_muxing.save!
|
191
|
+
|
192
|
+
# Adding Audio Stream to HLS Manifest
|
193
|
+
audio_stream_medium = manifest.build_audio_medium({
|
194
|
+
name: "HLS Audio Media",
|
195
|
+
group_id: "audio_group",
|
196
|
+
segment_path: "audio/aac",
|
197
|
+
encoding_id: enc.id,
|
198
|
+
stream_id: stream_aac.id,
|
199
|
+
muxing_id: audio_muxing.id,
|
200
|
+
language: "en",
|
201
|
+
uri: "audio_media.m3u8"
|
202
|
+
})
|
203
|
+
audio_stream_medium.save!
|
204
|
+
end
|
205
|
+
}
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# CONFIGURATION
|
2
|
+
BITMOVIN_API_KEY = 'YOUR API KEY HERE'
|
3
|
+
|
4
|
+
HTTP_INPUT_HOST = 'your.host.com'
|
5
|
+
HTTP_INPUT_FILE_PATH = '/path/to/your/input/file.mkv'
|
6
|
+
|
7
|
+
OUTPUT_AWS_ACCESS_KEY = 'YOUR AWS_ACCESS_KEY'
|
8
|
+
OUTPUT_AWS_SECRET_KEY = 'YOUR AWS_SECRET_KEY'
|
9
|
+
|
10
|
+
BUCKET_NAME = 'YOUR BUCKET NAME HERE'
|
11
|
+
OUTPUT_PATH = 'path/to/output'
|
12
|
+
MPD_NAME = 'manifest.mpd'
|
13
|
+
|
14
|
+
# Please refer to our API spec to get available cloud regions
|
15
|
+
# https://bitmovin.com/encoding-documentation/bitmovin-api/#/reference/encoding/encodings/create-encoding
|
16
|
+
ENCODING_CLOUD_REGION = 'GOOGLE_EUROPE_WEST_1'
|
17
|
+
|
18
|
+
Bitmovin.init(BITMOVIN_API_KEY)
|
19
|
+
|
20
|
+
# This will create a http input
|
21
|
+
# To get a list of all your HTTP outputs do:
|
22
|
+
# Bitmovin::Encoding::Outputs::HttpOutput.list
|
23
|
+
http_input = Bitmovin::Encoding::Inputs::HttpInput.new({
|
24
|
+
host: HTTP_INPUT_HOST
|
25
|
+
}).save!
|
26
|
+
|
27
|
+
# For reuse set http_input_id = '<YOUR HTTP INPUT ID>' and omit creation
|
28
|
+
http_input_id = http_input.id
|
29
|
+
|
30
|
+
# This will create a Output Bucket you can reuse in future encodings
|
31
|
+
# To get a list of all your Output do:
|
32
|
+
# Bitmovin::Encoding::Outputs::S3Output.list
|
33
|
+
s3_output = Bitmovin::Encoding::Outputs::S3Output.new({
|
34
|
+
accessKey: OUTPUT_AWS_ACCESS_KEY,
|
35
|
+
secretKey: OUTPUT_AWS_SECRET_KEY,
|
36
|
+
bucketName: BUCKET_NAME
|
37
|
+
}).save!
|
38
|
+
|
39
|
+
# For reuse set s3_output_id = '<YOUR S3 OUTPUT ID>' and omit creation
|
40
|
+
s3_output_id = s3_output.id
|
41
|
+
|
42
|
+
# Codec Configurations are similar to Inputs/Outputs in that they are configured once
|
43
|
+
# and can be reused for future encodings.
|
44
|
+
codec_config_720_700 = Bitmovin::Encoding::CodecConfigurations::H264Configuration.new({
|
45
|
+
name: 'H264 1280x720 700kb/s',
|
46
|
+
profile: 'MAIN',
|
47
|
+
width: 1280,
|
48
|
+
height: 720,
|
49
|
+
bitrate: 700000
|
50
|
+
})
|
51
|
+
codec_config_720_700.save!
|
52
|
+
codec_config_720_1500 = Bitmovin::Encoding::CodecConfigurations::H264Configuration.new({
|
53
|
+
name: 'H264 1280x720 1500kb/s',
|
54
|
+
profile: 'MAIN',
|
55
|
+
width: 1280,
|
56
|
+
height: 720,
|
57
|
+
bitrate: 1500000
|
58
|
+
})
|
59
|
+
codec_config_720_1500.save!
|
60
|
+
codec_config_720_2400 = Bitmovin::Encoding::CodecConfigurations::H264Configuration.new({
|
61
|
+
name: 'H264 1280x720 2400kb/s',
|
62
|
+
profile: 'MAIN',
|
63
|
+
width: 1280,
|
64
|
+
height: 720,
|
65
|
+
bitrate: 2400000
|
66
|
+
})
|
67
|
+
codec_config_720_2400.save!
|
68
|
+
|
69
|
+
audio_config = Bitmovin::Encoding::CodecConfigurations::AacConfiguration.new({
|
70
|
+
name: 'AAC_PROFILE_128k',
|
71
|
+
bitrate: 128000,
|
72
|
+
rate: 48000
|
73
|
+
})
|
74
|
+
audio_config.save!
|
75
|
+
|
76
|
+
|
77
|
+
# The actual instance of the encoding task you are about to start
|
78
|
+
enc = Bitmovin::Encoding::Encodings::EncodingTask.new({
|
79
|
+
name: 'VOD Encoding Ruby',
|
80
|
+
cloud_region: ENCODING_CLOUD_REGION
|
81
|
+
})
|
82
|
+
enc.save!
|
83
|
+
|
84
|
+
# Stream Configuration
|
85
|
+
|
86
|
+
stream_720_700 = enc.streams.build(name: 'H264 1280x720 700kb/s')
|
87
|
+
stream_720_700.codec_configuration = codec_config_720_700
|
88
|
+
stream_720_700.build_input_stream(input_path: INPUT_FILE_PATH, input_id: http_input_id, selection_mode: 'AUTO')
|
89
|
+
stream_720_700.save!
|
90
|
+
|
91
|
+
stream_720_1500 = enc.streams.build(name: 'H264 1280x720 1500/s')
|
92
|
+
stream_720_1500.codec_configuration = codec_config_720_1500
|
93
|
+
stream_720_1500.build_input_stream(input_path: INPUT_FILE_PATH, input_id: http_input_id, selection_mode: 'AUTO')
|
94
|
+
stream_720_1500.save!
|
95
|
+
|
96
|
+
stream_720_2400 = enc.streams.build(name: 'H264 1280x720 2400/s')
|
97
|
+
stream_720_2400.codec_configuration = codec_config_720_2400
|
98
|
+
stream_720_2400.build_input_stream(input_path: INPUT_FILE_PATH, input_id: http_input_id, selection_mode: 'AUTO')
|
99
|
+
stream_720_2400.save!
|
100
|
+
|
101
|
+
stream_aac = enc.streams.build(name: 'audio stream')
|
102
|
+
stream_aac.codec_configuration = audio_config
|
103
|
+
stream_aac.build_input_stream(input_path: INPUT_FILE_PATH, input_id: http_input_id, selection_mode: 'AUTO')
|
104
|
+
stream_aac.save!
|
105
|
+
|
106
|
+
# Muxing Configuration
|
107
|
+
|
108
|
+
fmp4_muxing_720_700 = enc.muxings.fmp4.build(name: 'H264 1280x720 700kb/s', segment_length: 4)
|
109
|
+
fmp4_muxing_720_700.build_output({
|
110
|
+
output_id: s3_output_id,
|
111
|
+
output_path: File.join(OUTPUT_PATH, 'video/720_700')
|
112
|
+
})
|
113
|
+
fmp4_muxing_720_700.streams << stream_720_700.id
|
114
|
+
fmp4_muxing_720_700.save!
|
115
|
+
|
116
|
+
fmp4_muxing_720_1500 = enc.muxings.fmp4.build(name: 'H264 1280x720 1500kb/s', segment_length: 4)
|
117
|
+
fmp4_muxing_720_1500.build_output({
|
118
|
+
output_id: s3_output_id,
|
119
|
+
output_path: File.join(OUTPUT_PATH, 'video/720_1500')
|
120
|
+
})
|
121
|
+
fmp4_muxing_720_1500.streams << stream_720_1500.id
|
122
|
+
fmp4_muxing_720_1500.save!
|
123
|
+
|
124
|
+
fmp4_muxing_720_2400 = enc.muxings.fmp4.build(name: 'H264 1280x720 2400kb/s', segment_length: 4)
|
125
|
+
fmp4_muxing_720_2400.build_output({
|
126
|
+
output_id: s3_output_id,
|
127
|
+
output_path: File.join(OUTPUT_PATH, 'video/720_2400')
|
128
|
+
})
|
129
|
+
fmp4_muxing_720_2400.streams << stream_720_2400.id
|
130
|
+
fmp4_muxing_720_2400.save!
|
131
|
+
|
132
|
+
audio_muxing = enc.muxings.fmp4.build(name: 'audio-muxing', segment_length: 4)
|
133
|
+
audio_muxing.build_output({
|
134
|
+
output_id: s3_output_id,
|
135
|
+
output_path: File.join(OUTPUT_PATH, 'audio/aac')
|
136
|
+
})
|
137
|
+
audio_muxing.streams << stream_aac.id
|
138
|
+
audio_muxing.save!
|
139
|
+
|
140
|
+
|
141
|
+
# Starting an encoding and monitoring it's status
|
142
|
+
enc.start!
|
143
|
+
|
144
|
+
while enc.status != 'FINISHED' && enc.status != 'ERROR'
|
145
|
+
puts "Encoding Status is #{enc.status}"
|
146
|
+
progress = enc.progress
|
147
|
+
if progress > 0
|
148
|
+
puts "Progress: #{enc.progress} %"
|
149
|
+
end
|
150
|
+
sleep 2
|
151
|
+
end
|
152
|
+
puts "Encoding finished with status #{enc.status}!"
|
153
|
+
|
154
|
+
|
155
|
+
# Generating a DASH Manifest
|
156
|
+
puts 'Starting Manifest generation'
|
157
|
+
manifest = Bitmovin::Encoding::Manifests::DashManifest.new({
|
158
|
+
name: 'Test Ruby Manifest',
|
159
|
+
description: 'Test encoding with ruby',
|
160
|
+
manifest_name: MPD_NAME
|
161
|
+
})
|
162
|
+
|
163
|
+
manifest.outputs << Bitmovin::Encoding::StreamOutput.new({
|
164
|
+
output_id: s3_output_id,
|
165
|
+
output_path: OUTPUT_PATH
|
166
|
+
})
|
167
|
+
manifest.save!
|
168
|
+
|
169
|
+
period = manifest.build_period()
|
170
|
+
period.save!
|
171
|
+
|
172
|
+
video_adaptationset = period.build_video_adaptationset()
|
173
|
+
video_adaptationset.save!
|
174
|
+
|
175
|
+
audio_adaptationset = period.build_audio_adaptationset({lang: 'en'})
|
176
|
+
audio_adaptationset.save!
|
177
|
+
|
178
|
+
video_adaptationset.build_fmp4_representation({
|
179
|
+
encoding_id: enc.id,
|
180
|
+
muxing_id: fmp4_muxing_720_2400.id,
|
181
|
+
type: 'TEMPLATE',
|
182
|
+
segment_path: 'video/720_2400'
|
183
|
+
}).save!
|
184
|
+
video_adaptationset.build_fmp4_representation({
|
185
|
+
encoding_id: enc.id,
|
186
|
+
muxing_id: fmp4_muxing_720_1500.id,
|
187
|
+
type: 'TEMPLATE',
|
188
|
+
segment_path: 'video/720_1500'
|
189
|
+
}).save!
|
190
|
+
video_adaptationset.build_fmp4_representation({
|
191
|
+
encoding_id: enc.id,
|
192
|
+
muxing_id: fmp4_muxing_720_700.id,
|
193
|
+
type: 'TEMPLATE',
|
194
|
+
segment_path: 'video/720_700'
|
195
|
+
}).save!
|
196
|
+
|
197
|
+
audio_adaptationset.build_fmp4_representation({
|
198
|
+
encoding_id: enc.id,
|
199
|
+
muxing_id: audio_muxing.id,
|
200
|
+
name: 'Audio representation',
|
201
|
+
type: 'TEMPLATE',
|
202
|
+
segment_path: 'audio/aac'
|
203
|
+
}).save!
|
204
|
+
|
205
|
+
manifest.start!
|
206
|
+
|
207
|
+
while manifest.status != 'FINISHED' && manifest.status != 'ERROR'
|
208
|
+
puts "Manifest Status is #{manifest.status}"
|
209
|
+
progress = manifest.progress
|
210
|
+
if progress > 0
|
211
|
+
puts "Progress: #{manifest.progress} %"
|
212
|
+
end
|
213
|
+
sleep 2
|
214
|
+
end
|
215
|
+
|
216
|
+
puts "Manifest generation finished with status #{manifest.status}!"
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'bitmovin-ruby'
|
2
|
+
|
3
|
+
# CONFIGURATION
|
4
|
+
BITMOVIN_API_KEY = "YOUR API KEY HERE"
|
5
|
+
|
6
|
+
S3_INPUT_ID = "The ID of the Input"
|
7
|
+
S3_OUTPUT_ID = "The ID of the Output"
|
8
|
+
INPUT_FILE_PATH = "encoding/awolnation.mkv"
|
9
|
+
OUTPUT_PATH = "/encoding_test/bitmovin-ruby/#{Time.now.strftime("%v-%H-%M")}/"
|
10
|
+
M3U8_NAME = "playlist.m3u8"
|
11
|
+
|
12
|
+
DRM_AES_KEY = "759678DC403B3CB84125E8E0F0824CD6" # Change this to something else
|
13
|
+
DRM_AES_IV = "196E6EB871BBC09191A3995318406198"
|
14
|
+
|
15
|
+
Bitmovin.init(BITMOVIN_API_KEY)
|
16
|
+
|
17
|
+
# This will create a Input Bucket you can reuse in future encodings
|
18
|
+
# To get a list of all your S3Inputs do:
|
19
|
+
# Bitmovin::Encoding::Inputs::S3Input.list
|
20
|
+
s3_input = Bitmovin::Encoding::Inputs::S3Input.find(S3_INPUT_ID)
|
21
|
+
|
22
|
+
# This will create a Output Bucket you can reuse in future encodings
|
23
|
+
# To get a list of all your Output do:
|
24
|
+
# Bitmovin::Encoding::Outputs::S3Output.list
|
25
|
+
s3_output = Bitmovin::Encoding::Outputs::S3Output.find(S3_OUTPUT_ID)
|
26
|
+
|
27
|
+
# Please note inputs/outputs are not individual files but rather the
|
28
|
+
# Bucket you are reading/writing files to and they can be reused between encodings.
|
29
|
+
|
30
|
+
|
31
|
+
# This hash contains the H264 Codec Configurations we want to create
|
32
|
+
# Codec Configurations are similar to Inputs/Outputs in that they are configured once
|
33
|
+
# and can be reused for future encodings.
|
34
|
+
video_configs = [
|
35
|
+
{ name: "h264_720p_700",
|
36
|
+
profile: "MAIN",
|
37
|
+
height: 720,
|
38
|
+
bitrate: 700000
|
39
|
+
}, {
|
40
|
+
name: "h264_540p_500",
|
41
|
+
profile: "MAIN",
|
42
|
+
height: 540,
|
43
|
+
bitrate: 500000
|
44
|
+
}
|
45
|
+
]
|
46
|
+
|
47
|
+
# The actual instance of the encoding task you are about to start
|
48
|
+
enc = Bitmovin::Encoding::Encodings::EncodingTask.new({
|
49
|
+
name: "VOD Encoding HLS AES128 Ruby"
|
50
|
+
})
|
51
|
+
enc.save!
|
52
|
+
|
53
|
+
|
54
|
+
# Let's also start the Manifest generation
|
55
|
+
manifest = Bitmovin::Encoding::Manifests::HlsManifest.new({
|
56
|
+
name: 'Test Ruby Manifest',
|
57
|
+
description: "Test encoding with ruby",
|
58
|
+
manifest_name: M3U8_NAME
|
59
|
+
})
|
60
|
+
|
61
|
+
manifest.outputs << Bitmovin::Encoding::StreamOutput.new({
|
62
|
+
output_id: s3_output.id,
|
63
|
+
output_path: OUTPUT_PATH
|
64
|
+
})
|
65
|
+
manifest.save!
|
66
|
+
|
67
|
+
create_audio!(enc, manifest, s3_input, s3_output)
|
68
|
+
|
69
|
+
# Adding Video Streams to Encoding
|
70
|
+
video_configs.each do |config|
|
71
|
+
h264_config = Bitmovin::Encoding::CodecConfigurations::H264Configuration.new(config)
|
72
|
+
h264_config.save!
|
73
|
+
config = OpenStruct.new(config)
|
74
|
+
|
75
|
+
str = enc.streams.build(name: h264_config.name)
|
76
|
+
str.codec_configuration = h264_config
|
77
|
+
str.build_input_stream(input_path: INPUT_FILE_PATH, input_id: s3_input.id, selection_mode: 'AUTO')
|
78
|
+
str.save!
|
79
|
+
|
80
|
+
muxing = enc.muxings.ts.build(name: "#{h264_config.name} muxing", segment_length: 4)
|
81
|
+
muxing.streams << str.id
|
82
|
+
muxing.save!
|
83
|
+
|
84
|
+
aes_muxing = muxing.drms.aes.build({
|
85
|
+
key: DRM_AES_KEY,
|
86
|
+
iv: DRM_AES_IV,
|
87
|
+
method: 'AES_128',
|
88
|
+
name: "AES DRM for #{muxing.name}"
|
89
|
+
})
|
90
|
+
aes_muxing.build_output({
|
91
|
+
output_id: s3_output.id,
|
92
|
+
output_path: File.join(OUTPUT_PATH, config.name),
|
93
|
+
acl: [{
|
94
|
+
permission: "PUBLIC_READ"
|
95
|
+
}]
|
96
|
+
})
|
97
|
+
aes_muxing.save!
|
98
|
+
puts "Finished DRM Muxing"
|
99
|
+
|
100
|
+
# Add the Stream to the Manifest too
|
101
|
+
hls_stream = manifest.build_stream({
|
102
|
+
audio: 'audio_group',
|
103
|
+
closed_captions: 'NONE',
|
104
|
+
segmentPath: config.name,
|
105
|
+
encoding_id: enc.id,
|
106
|
+
muxing_id: muxing.id,
|
107
|
+
stream_id: str.id,
|
108
|
+
drm_id: aes_muxing.id,
|
109
|
+
uri: config.name + '.m3u8'
|
110
|
+
})
|
111
|
+
hls_stream.save!
|
112
|
+
end
|
113
|
+
|
114
|
+
# Starting an encoding and monitoring it's status
|
115
|
+
enc.start!
|
116
|
+
|
117
|
+
while(enc.status != 'FINISHED')
|
118
|
+
puts "Encoding Status is #{enc.status}"
|
119
|
+
progress = enc.progress
|
120
|
+
if (progress > 0)
|
121
|
+
puts "Progress: #{enc.progress} %"
|
122
|
+
end
|
123
|
+
sleep 2
|
124
|
+
end
|
125
|
+
puts "Encoding finished!"
|
126
|
+
|
127
|
+
# Now that the encoding is finished we can start writing the m3u8 Manifest
|
128
|
+
manifest.start!
|
129
|
+
|
130
|
+
while(manifest.status != 'FINISHED')
|
131
|
+
puts "manifestoding Status is #{manifest.status}"
|
132
|
+
progress = manifest.progress
|
133
|
+
if (progress > 0)
|
134
|
+
puts "Progress: #{manifest.progress} %"
|
135
|
+
end
|
136
|
+
sleep 2
|
137
|
+
end
|
138
|
+
|
139
|
+
BEGIN {
|
140
|
+
# Begin is a hack to have this method available but define it at the end of the file
|
141
|
+
def create_audio!(enc, manifest, s3_input, s3_output)
|
142
|
+
|
143
|
+
# Create or load the Audio Config
|
144
|
+
#audio_config = Bitmovin::Encoding::CodecConfigurations::AacConfiguration.find("<EXISTING_AAC_CONFIG_ID>")
|
145
|
+
audio_config = Bitmovin::Encoding::CodecConfigurations::AacConfiguration.new({
|
146
|
+
name: "AAC_PROFILE_128k",
|
147
|
+
bitrate: 128000,
|
148
|
+
rate: 48000
|
149
|
+
})
|
150
|
+
audio_config.save!
|
151
|
+
#
|
152
|
+
# Adding Audio Stream to Encoding
|
153
|
+
stream_aac = enc.streams.build(name: 'audio stream')
|
154
|
+
stream_aac.codec_configuration = audio_config
|
155
|
+
stream_aac.build_input_stream(input_path: INPUT_FILE_PATH, input_id: s3_input.id, selection_mode: 'AUTO')
|
156
|
+
stream_aac.save!
|
157
|
+
|
158
|
+
# Audio Muxing
|
159
|
+
audio_muxing = enc.muxings.ts.build(name: 'audio-muxing', segment_length: 4)
|
160
|
+
audio_muxing.build_output({
|
161
|
+
output_id: s3_output.id,
|
162
|
+
output_path: File.join(OUTPUT_PATH, "audio/aac")
|
163
|
+
})
|
164
|
+
audio_muxing.streams << stream_aac.id
|
165
|
+
audio_muxing.save!
|
166
|
+
|
167
|
+
aes_audio_muxing = audio_muxing.drms.aes.build({
|
168
|
+
key: DRM_AES_KEY,
|
169
|
+
iv: DRM_AES_IV,
|
170
|
+
method: 'AES_128',
|
171
|
+
name: "AES DRM for Audio"
|
172
|
+
})
|
173
|
+
aes_audio_muxing.build_output({
|
174
|
+
output_id: s3_output.id,
|
175
|
+
output_path: File.join(OUTPUT_PATH, "audio/aac"),
|
176
|
+
acl: [{
|
177
|
+
permission: "PUBLIC_READ"
|
178
|
+
}]
|
179
|
+
})
|
180
|
+
aes_audio_muxing.save!
|
181
|
+
puts "Finished DRM Muxing"
|
182
|
+
|
183
|
+
# Adding Audio Stream to HLS Manifest
|
184
|
+
audio_stream_medium = manifest.build_audio_medium({
|
185
|
+
name: "HLS Audio Media",
|
186
|
+
group_id: "audio_group",
|
187
|
+
segment_path: "audio/aac",
|
188
|
+
encoding_id: enc.id,
|
189
|
+
stream_id: stream_aac.id,
|
190
|
+
muxing_id: audio_muxing.id,
|
191
|
+
drm_id: aes_audio_muxing.id,
|
192
|
+
language: "en",
|
193
|
+
uri: "audio_media.m3u8"
|
194
|
+
})
|
195
|
+
audio_stream_medium.save!
|
196
|
+
end
|
197
|
+
}
|
@@ -3,6 +3,7 @@ module Bitmovin::Encoding::CodecConfigurations
|
|
3
3
|
init 'encoding/configurations/video/h265'
|
4
4
|
|
5
5
|
attr_accessor :id, :name, :description, :created_at, :modified_at
|
6
|
+
attr_accessor :width, :height
|
6
7
|
attr_accessor :name, :description, :bitrate, :rate, :profile, :bframes, :ref_frames, :qp, :max_bitrate, :min_bitrate, :bufsize, :min_gop, :max_gop, :level, :rc_lookahead, :b_adapt, :max_ctu_size, :tu_intra_depth, :tu_inter_depth, :motion_search, :sub_me, :motion_search_range, :weight_prediction_on_p_slice, :weight_prediction_on_b_slice, :sao
|
7
8
|
end
|
8
9
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Bitmovin::Encoding::Encodings::Muxings::Drms
|
2
|
+
class DrmMuxingResource < Bitmovin::Resource
|
3
|
+
attr_accessor :name, :description, :created_at, :modified_at
|
4
|
+
attr_accessor :encoding_id, :muxing_id
|
5
|
+
attr_accessor :id
|
6
|
+
attr_accessor :outputs
|
7
|
+
|
8
|
+
def initialize(encoding_id, muxing_id, hash = {})
|
9
|
+
hsh = ActiveSupport::HashWithIndifferentAccess.new(underscore_hash(hash))
|
10
|
+
@encoding_id = encoding_id
|
11
|
+
@muxing_id = muxing_id
|
12
|
+
muxing_type = self.class.name.demodulize.gsub(/(.*)Muxing.*/, '\1').downcase
|
13
|
+
encryption_type = self.class.name.demodulize.gsub(/.*Muxing(.*)Encryption/, '\1').downcase
|
14
|
+
self.class.init(File.join("/v1/encoding/encodings/", encoding_id, "muxings", muxing_type, muxing_id, "drm", encryption_type))
|
15
|
+
super(hsh)
|
16
|
+
@outputs = (hsh[:outputs] || []).map do |output|
|
17
|
+
Bitmovin::Encoding::StreamOutput.new(output)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_output(opts = {})
|
22
|
+
output = Bitmovin::Encoding::StreamOutput.new(opts)
|
23
|
+
@outputs << output
|
24
|
+
output
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def collect_attributes
|
30
|
+
val = Hash.new
|
31
|
+
ignored_variables = []
|
32
|
+
if (self.respond_to?(:ignore_fields))
|
33
|
+
ignored_variables = self.ignore_fields
|
34
|
+
end
|
35
|
+
instance_variables.each do |name|
|
36
|
+
if ignored_variables.include?(name)
|
37
|
+
next
|
38
|
+
end
|
39
|
+
if name == :@outputs
|
40
|
+
val["outputs"] = @outputs.map { |o| o.send(:collect_attributes) }
|
41
|
+
next
|
42
|
+
end
|
43
|
+
|
44
|
+
if name == :@streams
|
45
|
+
val["streams"] = @streams.map { |s| { "streamId" => s } }
|
46
|
+
next
|
47
|
+
end
|
48
|
+
json_name = ActiveSupport::Inflector.camelize(name.to_s.gsub(/@/, ''), false)
|
49
|
+
val[json_name] = instance_variable_get(name)
|
50
|
+
end
|
51
|
+
val
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|