在Rails应用程序中使用CarrierWave和Amazon Elastic Transcoder

我之前在Stack Overflow上问了两个额外的问题,但得到了很少的帮助,我想我会问一个未解决的后代问题。 我花了一些时间来解析AWS-SDK API文档,但很少直接找到我的需求。 我也在AWS论坛上发布过,但未能在那里得到很好的回复。 一个简单,全面,循序渐进的解决方案似乎无法找到。

我完成了什么:

  • 使用CarrierWave直接上传到s3。 我按照Railscast#383进行了调整,并根据我的需要进行了调整。
  • 我能够从我的s3存储桶中“检索”我的文件。

关于我到目前为止所做的事情的详细信息:

我使用Carrierwave-Direct直接上传到s3(这利用雾来处理直接上传到s3)。 使用Sidekiq在后台作业中处理上载。 将文件放入存储桶后,我只需通过迭代用户上传来检索它,然后通过上传的URL从s3调用该文件。

这是我迷路的地方:

  • 我需要使用AWS提供的Elastic Transcoder对video进行转码。
  • 我需要从输出桶中调出上传/转换的video。 如何链接到“output-bucket”中的URL? 它是新的url引用还是url与原始“上传url”保持一致?
  • 我需要将转码器中的转码video集成到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 

我的看法:

显示所有用户的上传内容:

    

显示上传(现在它只是一个下载链接):

 

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

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

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

  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

我觉得让你的文件进入S3,CarrierWave是最难的部分,你已经完成了! 接下来的部分看起来像是在攀登一座山,但它更像是在公园散步:)……实际上你真的很少,因为AWS将会处理很多我们正在做的事情我们的一个输入(两个,如果你算上初始上传)是create_job请求……在我们开始之前,我只是说从你的代码中引用的模块看起来你确实有gem 'aws-sdk'在你的gemfile中,这在使用AWS资源时很重要(我们不会在问题范围之外进行适当的配置,但你可以按照github repo上的说明进行操作),我也会说很明显你已经完成了一些这样的步骤,比如创建一个管道。 尽管如此,我还是为未来的读者提供了这些步骤,他们可能会偶然发现这个答案……让我们开始吧:

  1. 首先要做的事情。 创建一个S3存储桶,您的管道将放置转码后的文件。 你不需要两个水桶,你可以只使用相同的水桶,但是两个可以使东西更清洁,并且水桶本身不会花费任何额外的费用(尽管你会支付存储桶中的存储空间)。

  2. 创建CloudFront分配以分发转码后的文件。 对于Origin Domain Name,单击输入字段,您将获得一个包含您帐户的S3存储桶的下拉列表; 选择用于OUTPUTS的S3存储桶,即您在步骤1中创建的转码文件,作为分发源。 请注意创建发行版后您将收到的唯一URL,它将类似于https://d111111abcdef8.cloudfront.net ,您可以在此处查找文件。

  3. 在您能够创建转码作业之前,您需要有一个管道。 管道基本上是保存转码作业的队列。 当用户上传文件时,您将向您在此步骤中创建的管道添加转码作业。 您只需创建一次管道,就可以将所有作业添加到此管道中进行转码。 您告诉管道哪个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

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

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

    5.1在第3步中,我们创建了一个管道,在第4步中,我们为该管道创建了一个作业。 管道要求我们告诉它将作业输出的文件放在何处。 显然,因为我们告诉管道将文件放在哪里,我们知道它将在哪里。 不是因为我们使用CloudFront来分发该文件,而不是使用我们的S3存储桶位置,我们将使用我们的CloudFronturl。 如果我们不使用CloudFront并且只使用S3存储桶,我们将使用S3存储桶URL。 接下来,就像管道要求我们告诉它输出文件的位置一样,作业要求我们告诉它输出哪种格式,因为我们告诉作业转码为AVI格式,我们知道输出格式正在进行是AVI。 最后,由于我们知道上传文件的名称,并且我们没有更改文件的名称,因此我们知道输出文件的名称。 我们正在提供所有信息 ,并告诉Elastic Transcoder如何处理输出文件…因此,显然,我们知道存储桶位置,文件名和文件扩展名,我们可以很容易地找出访问该url的urlfile:它将是https:///. 。 我们可以将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保存它。 然后,您可以按标准方式访问这些记录…要检索特定用户的所有video列表,您可以执行类似@videos = Upload.where(:user_id => current_user.id) 。 如果user_id与current_user_id匹配,这将返回Upload模型中所有对象的数组。

  6. 可选的下一步是让SNS在转码完成时向您的应用发送通知。 该通知可用于了解新文件何时可用的确切内容。 如果您选择使用SNS通知,我们现在已经完成了转码,除了创建由SDK发布到AWS资源的作业之外,我们不必从代码角度做很多事情。

  7. 下一步是通过CloudFront分发输出文件。 由于我们已将我们的发行版的Origin设置为我们输出转码文件的S3存储桶,因此您无需做任何其他事情。 添加到存储桶的任何新文件都将自动添加到您的分发中。 阅读更多相关信息,请访问: http : //docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AddingObjects.html 。

  8. 为了播放你通过JPlayer分发的文件,你需要做任何你需要做的事情来使用播放器,然后通过文件的Cloudfront URL从CDN加载文件(这种格式: https://d111111abcdef8.cloudfront.net/myvideo.avihttps://d111111abcdef8.cloudfront.net/myvideo.avi ),播放器需要的时间/地点。

  9. 要启动转码过程(您所谓的将API代码与上传过程集成在一起),您唯一需要做的就是在您的Sidekiq工作人员的对象上使用简单的create_job方法……一旦发生这种情况,真的不会有更多除了在等待输出文件在CloudFront分配中可用时获取cuppa之外,您可以这样做。

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

希望有所帮助!

Interesting Posts