在 Rails 个应用程序中将 CarrierWave 与 Amazon Elastic Transcoder 结合使用

Using CarrierWave with Amazon Elastic Transcoder in a Rails app

在此之前,我在 Stack Overflow 上问了两个额外的问题,但得到的帮助很少,我想我会为后代问一个开放性问题。我花时间解析了 AWS-SDK API 文档,但几乎没有找到满足我需求的直接答案。我还在 AWS 论坛上发帖,但没有得到很好的回应。似乎找不到简单、全面、循序渐进的解决方案。

我完成的内容:

到目前为止我所做的详细信息:

我使用 Carrierwave-Direct 直接上传到 s3(这利用 fog 来处理直接上传到 s3)。使用 Sidekiq 在后台作业中处理上传。将文件放入存储桶后,我只是通过遍历用户上传来检索它,并通过来自 s3 的上传 url 调用文件。

这是我迷路的地方:

到目前为止,这是我的代码:

我的上传者:

class VideoUploader < CarrierWave::Uploader::Base
 include CarrierWaveDirect::Uploader
end

我处理 s3 细节的初始化程序:

CarrierWave.configure do |config|

 config.fog_credentials = {
 provider:              'AWS',
 aws_access_key_id:     'AWS_ACCESS_KEY_ID',
 aws_secret_access_key: 'AWS_SECRET_ACCESS_KEY',
 region:                'us-west-1'}

 config.fog_directory  = 'video-input'
 config.fog_public     = false                                        # optional, defaults to true
 config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {}
end

我的上传模型:

class Upload < ActiveRecord::Base
 belongs_to :user
 mount_uploader :video, VideoUploader


 after_save :enqueue_video

 def enqueue_video
  VideoWorker.perform_async(id, key) if key.present?
 end

 class VideoWorker
  include Sidekiq::Worker

  def perform(id, key)
    upload = Upload.find(id)
    upload.key = key
    video.remote_video_url = upload.video.direct_fog_url(with_path: true)
    upload.save!
  end
 end
end

我的看法:

显示所有用户的上传:

<% @user.uploads.each do |upload| %>
  <%= link_to upload.title, upload_url(upload) %>
<% end %>

显示上传(目前只有下载link):

<h1><%= @upload.title %></h1>
<p><%= link_to @upload.video_url %></p>

我认为我的架构或表单不相关。

我认为代码可能如何工作的类似示例:

我会把这段代码添加到 Sidekiq worker 中,但我不确定我这样做是否正确。我也不确定如何将我的 "upload" 连接到 "converted upload"。

 upload.update_column 'converted_video', 
 File.basename(upload.video.path)

transcoder = AWS::ElasticTranscoder::Client.new
transcoder.create_job(
  pipeline_id: APP_CONFIG[Rails.env][:pipeline_id],
  input: {
    key: upload.video.path,
    frame_rate: 'auto',
    resolution: 'auto',
    aspect_ratio: 'auto',
    interlaced: 'auto',
    container: 'auto'
  },
  output: {
    key: upload.converted_video.path,
    preset_id: WEB_M4_PRESET_ID,
    thumbnail_pattern: "",
    rotate: '0'
  }
)

有关 Elastic Transcoder 的有用文章和文档的链接:

http://www.techdarkside.com/getting-started-with-the-aws-elastic-transcoder-api-in-rails

http://docs.aws.amazon.com/sdkforruby/api/Aws/ElasticTranscoder.html

我觉得使用 CarrierWave 将文件导入 S3 是最难的部分,而您已经做到了!下一部分看起来像是在爬山,但它更像是在公园里散步 :)...实际上您可以做的事情很少,因为 AWS 将处理我们正在做的很多事情,实际上只需要我们的一个输入(如果算上初始上传,则为两个)是 create_job 请求...在我们开始之前,我只想说,从您的代码中引用的模块来看,您确实有 gem 'aws-sdk' 在您的 gemfile 中,这在使用 AWS 资源时很重要(我们不会适当地配置 SDK,因为这超出了问题的范围,但您可以按照 github 存储库中的说明进行操作),我还要说的是,很明显您已经完成了其中的一些步骤,例如创建管道。尽管如此,我还是为可能偶然发现此答案的未来读者包括了这些步骤...让我们开始吧:

  1. 要事第一。创建一个 S3 存储桶,您的管道将在其中放置 t运行scoded 文件。你并不严格需要两个桶,你可以只使用同一个桶,但是两个桶会让事情变得更干净,而且拥有一个桶本身不会花费任何额外的费用(尽管你会为桶中的存储付费)。

  2. 创建一个 CloudFront 分发来分发您的 t运行scoded 文件。对于源域名,单击输入字段,您将获得一个下拉列表,其中包含您帐户的 S3 存储桶; select OUTPUTS 的 S3 存储桶,您将在其中放置您在步骤 1 中创建的 t运行scoded 文件的存储桶,作为分发的源。请注意您在创建分发后将收到的唯一 URL,它类似于 https://d111111abcdef8.cloudfront.net,稍后您将在此处查找文件。

  3. 在您能够创建 t运行scoding 作业之前,您需要有一个管道。管道基本上是保存 t运行scoding 作业的队列。当用户上传文件时,您将向在此步骤中创建的管道中添加一个 t运行scoding 作业。您只需创建一次管道,就可以将 t运行scoding 的所有作业添加到该管道中。您告诉管道从哪个 S3 存储桶中获取作业的文件,然后告诉它 S3 存储桶用于放置作业的输出文件。输出文件可以具有相同的名称,并且将具有新的扩展名,因此如果您上传 myvideo.mp4 并且您 t运行 将其编码为 .avi 格式,则输出文件将为 myvideo.avi(您也可以更改名称,但这会使事情复杂化并且超出您的问题范围)。由于您知道作业中的文件名,并且知道输出存储桶,因此您只需将它们放在一起以获得 URL 来访问文件(您必须确保设置了正确的访问权限存储桶的权限以便访问文件)。如果我的输出文件是 myvideo.avi 并且我知道它已输出到特定存储桶,这是我的 CloudFront 分配的一部分,我知道我将能够在 myCloudFrontURL/myvideo.avi 访问它...它看起来像 https://d111111abcdef8.cloudfront.net/myvideo.avi。因为我怀疑这将是一个 "standard" 过程(即所有上传的文件都将被 t运行 编码为相同的格式并且您的管道不会改变),我将建议您使用 GUI 创建管道。您可以在此处阅读操作方法: http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/creating-pipelines.html

  4. 现在我们有了管道,为了对上传的文件进行编码,我们需要在管道中创建一个作业。你和你的工人一起创造工作是正确的,它是一个纯粹的香草哈希:http://docs.aws.amazon.com/sdkforruby/api/Aws/ElasticTranscoder/Types/CreateJobRequest.html。一旦由 SDK 发布,ET 管道将接管,作业将添加到您的管道,并且将按照它添加到您的 ET 管道的顺序进行 t运行scoded。

  5. EDIT 根据 OP 对此答案的评论,可能还有其他要求,即用户可以上传许多视频并且您应该能够列出用户上传的所有视频。 Rails 让这变得超级简单。你有一个用户模型,你有一个上传模型。您的上传模型上有 belongs_to :user 关联,这是完美的。由于一个用户可以有很多上传,您需要将 has_many :uploads 关联添加到您的用户模型(ActiveRecord 关联有两种方式)。我假设您使用 Rails 生成器来创建您的上传模型,如果您这样做了,您会注意到它为您创建了一个迁移,在您的数据库中创建了一个上传 table。我不清楚你的模式是什么样的,但我假设你 运行 在你生成模型时创建的迁移没有做任何更改(即只生成关联的 table)和您的上传 table 不包含 "user_id" 或 "url" 列。我们将通过 运行ning Rails g migration AddColumnsToUploadsTable 从您的终端添加这些。从那里我们将在 yourApp/db/migrations 文件夹中编辑我们的迁移。我们将在我们的迁移 add_column :uploads, :url, :stringadd_reference :uploads, :user, :index => true 中向 change 方法添加两行,然后我们将返回我们的终端和 运行 rake db:migrate。这些列现已添加到我们的上传 table 数据库中。

    5.1 在第 3 步中,我们创建了一个管道,在第 4 步中,我们为该管道创建了一个作业。管道要求我们告诉它把作业输出的文件放在哪里。显然,因为我们已经告诉管道将该文件放在哪里,所以我们知道它会放在哪里。并不是因为我们使用 CloudFront 来分发该文件,而不是使用我们的 S3 存储桶位置,我们将使用我们的 CloudFront url。如果我们不使用 CloudFront 而只是使用 S3 存储桶,我们将使用 S3 存储桶 URL。继续,就像管道需要我们告诉它把输出文件放在哪里一样,作业需要我们告诉它输出到哪种格式,因为我们告诉作业将 t运行scode 转换为 AVI 格式,我们知道输出格式将是 AVI。最后,因为我们知道上传文件的名称,而且我们没有更改文件的名称,所以我们知道输出文件的名称。 我们正在提供所有信息,并告诉 Elastic T运行scoder 确切地 如何处理输出文件...因此,显然,我们知道存储桶位置、文件名和文件扩展名,我们可以很容易地找出访问文件的 url:它将是 https://<yourCloudFrontURL>/<videoName>.<extension>。我们可以将 yourCloudFrontURL、videoName 和扩展名(我们知道)转换为变量,供我们在其他地方使用。 urlname = https://d111111abcdef8.cloudfront.net/ \ filename = File.basename(params[:file].original_filename, ".*") \ newextension = ".avi" 可以使用标准 Ruby/Rails 过程将其保存到您的数据库:实例化一个新对象 video = Upload.new,设置 user_id 到 current_user video.user_id = current_user_id 然后设置新对象 url video.url = urlname+filename+newextension。我们已经设置了 user_id 并且我们已经设置了记录的 url ,我们需要做的就是用 video.save 保存它。然后,您可以按要求以标准方式访问这些记录...要检索特定用户的所有视频列表,您可以执行类似 @videos = Upload.where(:user_id => current_user.id) 的操作。这将 return 上传模型中所有对象的数组 user_id 匹配 current_user_id.

  6. 可选的下一步是让 SNS 在 t运行编码完成时向您的应用程序发送通知。该通知对于准确了解新文件何时可用等信息可能很有用。无论您是否选择使用 SNS 通知,我们现在已经完成了 t运行scoding,除了创建一个发布到 AWS 资源的作业之外,我们不需要从代码的角度做很多事情通过 SDK。

  7. 下一步是通过 CloudFront 分发输出文件。由于我们已经为我们的分发设置了 Origin 作为我们在其中输出 t运行scoded 文件的 S3 存储桶,因此您无需执行任何其他操作。添加到存储桶中的任何新文件都将自动添加到您的分发中。在此处阅读有关其工作原理的更多信息:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AddingObjects.html

  8. 为了播放您通过 JPlayer 分发的文件,您需要做任何您需要做的事情才能使用播放器,然后从通过 Cloudfront URL 的 CDN 文件(此格式:https://d111111abcdef8.cloudfront.net/myvideo.avi),播放器所需的 when/where。

  9. 要启动 t运行scoding 过程(你称之为将 API 代码与你的上传过程集成),你唯一需要做的就是这么简单 [= Sidekiq worker 上对象的 31=] 方法... 一旦发生这种情况,除了在等待输出文件在 CloudFront 发行版中可用时拿杯咖啡外,您真的没有太多事情要做。

就是这样...您已经创建了输出 S3 存储桶,创建了分配,创建了管道,从 S3 中获取了一个文件,使用该文件创建了一个作业并将该作业添加到您的 ET 管道中。您将该作业的结果输出到不同的 S3 存储桶,可选择接收作业完成的 SNS 通知,将该文件分发到 CloudFront CDN,最后您将该文件从 CloudFront 分发加载到浏览器中的 JPlayer .

希望对您有所帮助!