ruby-on-rails - 在Rails应用程序中将CarrierWave与Amazon Elastic Transcoder一起使用

标签 ruby-on-rails amazon-web-services carrierwave sidekiq amazon-elastic-transcoder

在此之前,我在Stack Overflow上又问了两个问题,但得到的帮助很少,我想就后代提出一个开放性问题。我花了很多时间来解析AWS-SDK API文档,却发现很少有直接答案可以满足我的需求。我也曾在AWS论坛上发帖,但未能在那里获得良好的回应。似乎找不到简单,全面,分步的解决方案。

我已完成的工作:


使用CarrierWave直接上传到s3。我遵循了Railscast#383,并使其适应了我的需求。
我可以从s3存储桶中“检索”我的文件。


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

我使用了Carrierwave-Direct直接上传到s3(这利用雾处理了直接上传到s3的问题)。使用Sidekiq在后台作业中处理上载。将文件放入存储桶后,我只需遍历用户上传的文件即可检索它,并通过s3中的上传网址调用文件。

这是我迷路的地方:


我需要使用AWS提供的Elastic Transcoder对视频进行转码。
我需要从输出存储桶中调用上传/转换的视频。如何从“输出桶”链接到URL?它是新的URL引用,还是与原始的“上传URL”相同?
我需要将转码后的视频从转码器集成到Cloudfront并使用JWPlayer进行显示。
如何在后台将API代码集成到我的上传过程中?


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

我的上传者:

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 %>


要显示上载(目前仅是一个下载链接):

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


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

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

我会将这段代码添加到Sidekiq worker中,但是我不确定是否这样做正确。我也不确定如何将我的“上传”连接到“转换后的上传”。

 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请求...在开始之前,我只是说,从代码中引用的模块来看,您的gemfile中确实确实有gem 'aws-sdk' ,这在使用AWS资源时很重要(我们不会适当地配置SDK,因为这不在问题的范围之内,但是您可以按照github存储库上的说明进行操作),我也会说很明显,您已经完成了其中一些步骤,例如创建管道。尽管如此,我还是为那些可能偶然发现此答案的读者提供了这些步骤。让我们开始:


首先是第一件事。在管道将放置转码文件的位置创建一个S3存储桶。您严格不需要两个存储桶,您可以只使用同一个存储桶,但是两个存储桶使事情变得更加清洁,拥有存储桶本身并不会花费任何额外费用(不过您需要为存储在存储桶中的存储空间付费)。
创建一个CloudFront分发以分发您的转码文件。对于原始域名,单击输入字段,您将获得一个下拉列表,其中包括您帐户的S3存储桶;选择OUTPUTS的S3存储桶,即您在其中放置了在步骤1中创建的转码文件的存储桶,作为分发源。注意创建发行版后将收到的唯一URL,它类似于https://d111111abcdef8.cloudfront.net,这是以后要查找文件的位置。
在创建转码作业之前,您需要具有管道。管道基本上是保存您的转码作业的队列。当用户上传文件时,您将在此步骤中将转码作业添加到您创建的管道中。您只需创建一个管道即可,并且可以将所有作业进行转码添加到该管道。您告诉管道从哪个S3存储桶中获取作业的文件,然后告诉S3存储桶将作业中的输出文件放置在什么位置。输出文件可以具有相同的名称,并且具有新的扩展名,因此,如果您上传myvideo.mp4并将其转码为.avi格式,则输出文件将为myvideo.avi(您也可以更改名称,但这很复杂事情和您的问题范围之外)。由于您知道作业中的文件名以及输出存储桶,因此只需将它们放在一起即可获取访问文件的URL(您必须确保已对​​存储桶设置了正确的访问权限以访问该文件)。如果我的输出文件是myvideo.avi,并且我知道它已经输出到特定的存储桶(属于CloudFront发行版),那么我知道可以在myCloudFrontURL/myvideo.avi处访问它了。类似于https://d111111abcdef8.cloudfront.net/myvideo.avi。由于我怀疑这将是一个“标准”过程(即所有上传的文件都将被转码成相同的格式,并且您的管道也不会改变),所以我建议您创建管道与GUI。您可以在这里阅读操作方法:
http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/creating-pipelines.html
现在我们有了管道,为了对上传的文件进行转码,我们需要在管道中创建一个作业。您正在与您的工作人员一起创建工作,这是正确的轨道,这是纯香草哈希:http://docs.aws.amazon.com/sdkforruby/api/Aws/ElasticTranscoder/Types/CreateJobRequest.html。一旦SDK将其发布,则ET管道将接管工作,该作业将添加到您的管道中,并将按照添加到ET管道中的顺序进行转码。
编辑根据OP对这个答案的评论,可能还有其他要求,即用户可以上传许多视频,并且您应该能够列出用户已上传的所有视频。 Rails使这个超级容易。您有一个用户模型,并且有一个上载模型。您的上载模型上具有belongs_to :user关联,这是完美的。由于用户可以上传许多文件,因此您需要将has_many :uploads关联添加到用户模型中(ActiveRecord关联有两种方式)。我假设您使用Rails生成器创建了上载模型,如果这样做了,您会注意到它为您创建了一个迁移,该迁移在数据库中创建了一个上载表。我不清楚您的模式是什么样子,但是我假设您运行的是在生成模型时创建的迁移,而没有进行任何更改(即仅生成关联表),并且您的Uploads表不包含列“ user_id”或“ url”。我们将通过在您的终端上运行Rails g migration AddColumnsToUploadsTable来添加它们。从那里,我们将在yourApp/db/migrations文件夹中编辑迁移。我们将在迁移add_column :uploads, :url, :stringadd_reference :uploads, :user, :index => true的change方法中添加两行,然后回到终端并运行rake db:migrate。这些列现在已添加到数据库中的Upload表中。

5.1在步骤3中,我们创建了一个管道,在步骤4中,我们为该管道创建了一个作业。管道要求我们告诉它将从作业输出的文件放在何处。显然,因为我们已经告知管道将文件放置在何处,所以我们知道该文件在哪里。并不是因为我们使用CloudFront分发该文件,而不是使用我们的S3存储桶位置,所以我们将使用CloudFront网址。如果我们不使用CloudFront而仅使用S3存储桶,则将使用S3存储桶URL。继续前进,就像管道需要我们告诉它将输出文件放在哪里,作业需要我们告诉它输出哪种格式,因为我们告诉作业将代码转码为AVI格式,所以我们知道输出格式正在成为AVI。最后,由于我们知道上载文件的名称,并且我们没有更改文件名,因此我们知道将要命名输出文件。我们正在提供所有信息,并确切地告诉Elastic Transcoder如何处理输出文件...因此,显然,我们知道存储桶的位置,文件名和文件扩展名,并且我们可以很容易地找出访问该URL的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,然后设置新对象video.url = urlname+filename+newextension的网址。我们已经设置了user_id并设置了记录的url,我们要做的就是用video.save保存它。然后,您可以按照标准方式按要求访问这些记录...要检索特定用户的所有视频的列表,可以执行@videos = Upload.where(:user_id => current_user.id)之类的操作。如果user_id与current_user_id匹配,则将返回Upload模型中所有对象的数组。
可选的下一步是让SNS在转码完成后向您的应用发送通知。该通知对于准确了解新文件何时可用等情况可能很有用。如果您选择是否使用SNS通知,那么我们现在已经完成了转码,并且从代码角度而言,我们无需做很多事情,只需创建一个由SDK发布到AWS资源的作业即可。
下一步是通过CloudFront分发输出文件。由于我们已经将我们发行版的Origin设置为输出转码文件的S3存储桶,因此您无需执行其他任何操作。添加到存储桶的所有新文件都将自动添加到您的分发中。在此处阅读有关其工作原理的更多信息:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AddingObjects.html
为了播放通过JPlayer通过发行版发行的文件,您需要做任何事情以使用播放器,然后通过Cloudfront URL从CDN加载该文件(播放器要求的时间/位置:https://d111111abcdef8.cloudfront.net/myvideo.avi)。
要启动代码转换过程(您将API代码与上传过程集成在一起),您唯一需要做的就是在Sidekiq worker上的对象上使用简单的create_job方法...一旦发生,实际上就不是一个完整的过程了。除了在等待输出文件在CloudFront发行版中可用时抓取一杯咖啡以外,还有很多事情要做。


就这样...您已经创建了输出S3存储桶,创建了发行​​版,创建了管道,从S3抓取了一个文件,使用该文件创建了一个作业,然后将该作业添加到了ET管道中。您已将该作业的结果输出到另一个S3存储桶,有选择地收到了作业完成的SNS通知,将该文件分发到了CloudFront CDN上,最后您将该文件从CloudFront分发中加载到了浏览器的JPlayer中。 。

希望有帮助!

关于ruby-on-rails - 在Rails应用程序中将CarrierWave与Amazon Elastic Transcoder一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36605438/

相关文章:

ruby-on-rails - 从 S3 下载 Carrierwave 上传

ruby-on-rails - 用于 RubyOnRails 应用程序的 Thin + Nginx 生产就绪组合

ruby-on-rails - Heroku:连接中出现未知的 SSL 协议(protocol)错误

ruby-on-rails - 向 ActiveRecord 序列化添加更多属性?

amazon-web-services - 如何使用 EMR 上的 HiveQL 将 DynamoDB 上的 Map 数据类型列导出到具有 JSON 数据类型的 S3?

ruby-on-rails-3 - 载波+ mini_magick gem =没有图像错误

ruby-on-rails - Rails - Action Cable 是否需要 Rails 5?

amazon-web-services - 如何获取 SNS 主题中的最新消息?

amazon-web-services - 自动接受来自另一个 AWS 账户的 Transit Gateway 附件

ruby-on-rails - 将 base64 图像转换为用于 Carrierwave 的 StringIO