Class: ActiveEncode::EngineAdapters::MediaConvertAdapter

Inherits:
Object
  • Object
show all
Defined in:
lib/active_encode/engine_adapters/media_convert_adapter.rb

Constant Summary collapse

JOB_STATES =

[AWS Elemental MediaConvert](aws.amazon.com/mediaconvert/) doesn’t provide detailed output information in the job description that can be pulled directly from the service. Instead, it provides that information along with the job status notification when the job status changes to ‘COMPLETE`. The only way to capture that notification is through an [Amazon Eventbridge](aws.amazon.com/eventbridge/) rule that forwards the status change notification to another service for capture and/or handling.

‘ActiveEncode::EngineAdapters::MediaConvert` does this by creating a [CloudWatch Logs] (aws.amazon.com/cloudwatch/) log group and an EventBridge rule to forward status change notifications to the log group. It can then find the log entry containing the output details later when the job is complete. This is accomplished by calling the idempotent `#setup!` method.

The AWS user/role calling the ‘#setup!` method will require permissions to create the necessary CloudWatch and EventBridge resources, and the role passed to the engine adapter will need access to any S3 buckets where files will be read from or written to during transcoding.

Configuration example:

ActiveEncode::Base.engine_adapter = :media_convert
ActiveEncode::Base.engine_adapter.role = 'arn:aws:iam::123456789012:role/service-role/MediaConvert_Default_Role'
ActiveEncode::Base.engine_adapter.output_bucket = 'output-bucket'
ActiveEncode::Base.engine_adapter.setup!
{
  "SUBMITTED" => :running, "PROGRESSING" => :running, "CANCELED" => :cancelled,
  "ERROR" => :failed, "COMPLETE" => :completed
}.freeze
OUTPUT_GROUP_TEMPLATES =
{
  hls: { min_segment_length: 0, segment_control: "SEGMENTED_FILES", segment_length: 10 },
  dash_iso: { fragment_length: 2, segment_control: "SEGMENTED_FILES", segment_length: 30 },
  file: {},
  ms_smooth: { fragment_length: 2 },
  cmaf: { fragment_length: 2, segment_control: "SEGMENTED_FILES", segment_length: 10 }
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#log_groupObject



149
150
151
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 149

def log_group
  @log_group ||= "/aws/events/active-encode/mediaconvert/#{queue}"
end

#output_bucketObject

Returns the value of attribute output_bucket.



54
55
56
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 54

def output_bucket
  @output_bucket
end

#queueObject



153
154
155
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 153

def queue
  @queue ||= "Default"
end

#roleObject

Returns the value of attribute role.



54
55
56
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 54

def role
  @role
end

Instance Method Details

#cancel(id) ⇒ Object



144
145
146
147
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 144

def cancel(id)
  mediaconvert.cancel_job(id: id)
  find(id)
end

#create(input_url, options = {}) ⇒ Object

Required options:

  • ‘output_prefix`: The S3 key prefix to use as the base for all outputs.

  • ‘outputs`: An array of `modifier` options defining how to transcode and name the outputs.

Optional options:

  • ‘masterfile_bucket`: The bucket to which file-based inputs will be copied before

    being passed to MediaConvert. Also used for S3-based inputs
    unless `use_original_url` is specified.
    
  • ‘use_original_url`: If `true`, any S3 URL passed in as input will be passed directly to

    MediaConvert as the file input instead of copying the source to
    the `masterfile_bucket`.
    

Example:

output_prefix: "path/to/output/files",
outputs: [
    {preset: "System-Avc_16x9_1080p_29_97fps_8500kbps", modifier: "-1080",
    "System-Avc_16x9_720p_29_97fps_5000kbps", modifier: "-720",
    "System-Avc_16x9_540p_29_97fps_3500kbps", modifier: "-540"
  ]
}

}



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 118

def create(input_url, options = {})
  input_url = s3_uri(input_url, options)

  input = options[:media_type] == :audio ? make_audio_input(input_url) : make_video_input(input_url)

  create_job_params = {
    role: role,
    settings: {
      inputs: [input],
      output_groups: make_output_groups(options)
    }
  }

  response = mediaconvert.create_job(create_job_params)
  job = response.job
  build_encode(job)
end

#find(id, _opts = {}) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 136

def find(id, _opts = {})
  response = mediaconvert.get_job(id: id)
  job = response.job
  build_encode(job)
rescue Aws::MediaConvert::Errors::NotFound
  raise ActiveEncode::NotFound, "Job #{id} not found"
end

#setup!Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/active_encode/engine_adapters/media_convert_adapter.rb', line 57

def setup!
  rule_name = "active-encode-mediaconvert-#{queue}"
  return true if event_rule_exists?(rule_name)

  queue_arn = mediaconvert.get_queue(name: queue).queue.arn

  event_pattern = {
    source: ["aws.mediaconvert"],
    "detail-type": ["MediaConvert Job State Change"],
    detail: {
      queue: [queue_arn]
    }
  }

  log_group_arn = create_log_group(log_group).arn

  cloudwatch_events.put_rule(
    name: rule_name,
    event_pattern: event_pattern.to_json,
    state: "ENABLED",
    description: "Forward MediaConvert job state changes from queue #{queue} to #{log_group}"
  )

  cloudwatch_events.put_targets(
    rule: rule_name,
    targets: [
      {
        id: "Id#{SecureRandom.uuid}",
        arn: log_group_arn
      }
    ]
  )
  true
end