3

在此之前,我在 Stack Overflow 上问了另外两个问题,但得到的帮助很少,我想我会问一个悬而未决的问题。我花时间解析 AWS-SDK API 文档,但几乎没有找到直接满足我需求的答案。我也在 AWS 论坛上发过帖子,但在那里没有得到很好的回应。似乎不可能找到一个简单、全面、循序渐进的解决方案。

我完成了什么:

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

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

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

这是我迷路的地方:

  • 我需要使用 AWS 提供的 Elastic Transcoder 对视频进行转码。
  • 我需要从输出存储桶中调用上传/转换的视频。如何从“输出桶”链接到 URL?它是新的 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 工作程序中,但我不确定我是否正确执行此操作。我也不确定如何将我的“上传”连接到“转换后的上传”。

 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

4

1 回答 1

9

我觉得使用 CarrierWave 将您的文件放入 S3 是最难的部分,而您已经完成了!下一部分看起来像是在爬山,但更像是在公园里散步 :)... 令人惊讶的是,您实际上要做的事情很少,因为 AWS 将处理我们正在做的很多事情,实际上只是我们的一个输入(如果您计算初始上传,则为两个)是 create_job 请求...在我们开始之前,我只想说,从您的代码中引用的模块来看,您确实有gem 'aws-sdk'在您的 gemfile 中,这在使用 AWS 资源时很重要(我们不会正确配置 SDK,因为这超出了问题的范围,但您可以按照 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. 由于我怀疑这将是一个“标准”过程(即所有上传的文件都将被转码为相同的格式并且您的管道不会改变),我建议您创建您的管道与图形用户界面。你可以在这里阅读如何做到这一点: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 对此答案的评论,可能还有其他要求,即用户可以上传许多视频,并且您应该能够列出用户上传的所有视频。Rails 让这一切变得超级简单。你有一个用户模型,你有一个上传模型。您belongs_to :user在上传模型上有关联,这是完美的。由于用户可以有许多上传,您需要添加has_many :uploads关联到您的用户模型(ActiveRecord 关联有两种方式)。我将假设您使用 Rails 生成器创建 Upload 模型,如果您这样做了,您会注意到它为您创建了一个迁移,该迁移在您的数据库中创建了一个 Upload 表。我不清楚您的架构是什么样的,但我假设您运行了在生成模型时创建的迁移,而没有进行任何更改(即仅生成关联的表),并且您的 Uploads 表不包括列“user_id”或“url”。我们将通过Rails g migration AddColumnsToUploadsTable从您的终端运行来添加它们。从那里我们将去编辑yourApp/db/migrations文件夹中的迁移。我们将在迁移中的 change 方法中添加两行add_column :uploads, :url, :stringadd_reference :uploads, :user, :index => true然后我们rake db:migrate. 这些列现在已添加到数据库中的 Upload 表中。

    5.1 在第 3 步中,我们创建了一个管道,在第 4 步中,我们为该管道创建了一个作业。管道要求我们告诉它将作业输出的文件放在哪里。显然,因为我们已经告诉管道将该文件放在哪里,所以我们知道它将在哪里。并不是因为我们使用 CloudFront 来分发该文件,而不是使用我们的 S3 存储桶位置,我们将使用我们的 CloudFront url。如果我们不使用 CloudFront 而只是使用 S3 存储桶,我们将使用 S3 存储桶 URL。继续前进,就像管道需要我们告诉它把输出文件放在哪里,作业需要我们告诉它要输出到哪种格式,因为我们告诉作业转码为 AVI 格式,我们知道输出格式是什么成为AVI。最后,由于我们知道上传文件的名称,并且我们'我们正在提供所有信息,并准确地告诉 Elastic Transcoder如何处理输出文件……因此,很明显,我们知道存储桶的位置、文件名和文件扩展名,我们可以很容易地找出访问文件:它将是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). 如果 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.avi:),播放器需要的时间/地点。

  9. 要启动转码过程(您称之为将 API 代码与上传过程集成),您唯一需要做的就是create_job在您的 Sidekiq 工作人员上对您的对象使用简单的方法......一旦发生这种情况,真的没有更多在等待输出文件在 CloudFront 分配中可用时,您要做的只是拿一杯茶。

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

希望有帮助!

于 2016-04-14T05:26:51.733 回答