title: Background version of uploaded video creation in Elixir with Arc and FFmpeg
body: <p>I tried to make video uploading on Elixir phoenix project using Arc. I need to have different size versions of video. So I used FFmpeg to do this:</p>
  
  <pre><code>def transform(:large, {file, scope}) do
    {:ffmpeg, fn(input, output) -&gt; "-i #{input} -c:a copy -s 1920x1080 -f mp4 #{output}" end, :mp4}
  end
  </code></pre>
  
  <p>However, it takes a lot of time to create this versions even to small videos. So, I decided to make version creation on background. I want Arc to upload video, then I give the response with uploaded original while other versions are creating.</p>
  
  <p>I was hoping to find such option at <a href="https://github.com/stavro/arc" rel="nofollow noreferrer">https://github.com/stavro/arc</a> but I didn't succed. I only found "To disable asynchronous processing, add @async false to your upload definition" but I don't want to disable it, right? </p>
  
  <p>I tried to use Exq <a href="https://github.com/akira/exq" rel="nofollow noreferrer">https://github.com/akira/exq</a> for background processing but I didn't menage to use it in uploader.</p>
  
  <p>Could anybody tell me how it should be made in a proper way or give me some dirty hack advice to make it work. Thanks.</p>
  
  <p>I tried Task as was advised in comments, but I am not sure how to use them in this case. When I try</p>
  
  <pre><code>{:ffmpeg, fn(input, output) -&gt; Task.async(fn -&gt; "-i #{input} -c:a copy -s 1920x1080 -f mp4 #{output}" end) end, :mp4}
  </code></pre>
  
  <p>or</p>
  
  <pre><code>{:ffmpeg, Task.async(fn -&gt; fn(input, output) -&gt;  "-i #{input} -c:a copy -s 1920x1080 -f mp4 #{output}" end end), :mp4}
  </code></pre>
  
  <p>I got "protocol String.Chars not implemented for %Task".</p>
  
  <p>When I try </p>
  
  <pre><code>{:ffmpeg, Task.async(fn(input, output) -&gt;  "-i #{input} -c:a copy -s 1920x1080 -f mp4 #{output}" end), :mp4}
  </code></pre>
  
  <p>I got "#Function&lt;20.83953603/2 in MyWebSite.Content.transform/2> with arity 2 called with no arguments". I tried to pass function as an argument with "&amp;" but it fails as well.</p>
  
  <p>My uploader:</p>
  
  <pre><code>defmodule MyWebSite.Content do
  use Arc.Definition
  use Arc.Ecto.Definition
  
  @acl :public_read
  
  @versions [:original,  :huge]
  
  def transform(:huge, {file, scope}) do
    {:ffmpeg, Task.async(fn(input, output) -&gt;  "-i #{input} -c:a copy -s 1920x1080 -f mp4 #{output}" end), :mp4}
  end
  
  def s3_object_headers(version, {file, scope}) do
    [timeout: 3_000_00, content_type: Plug.MIME.path(file.file_name)]
  end
  end
  </code></pre>