Generate an image thumbnail grid using FFmpex

Success! The key was to use option_vf/1, not option_filter_complex/1 (and it accepts a string as argument).

Full command as follows


  def get_video_framecount(file_path) do
    case FFprobe.streams(file_path) do
      {:ok, streams} ->
        streams
        |> Enum.find(fn stream -> stream["codec_type"] == "video" end)
        |> case do
          nil -> {:error, "No video stream found"}
          video_stream ->
            nb_frames =
              video_stream
              |> Map.get("nb_frames", %{})

            case nb_frames do
              nil -> {:error, "nb_frames not found"}
              %{} -> {:error, "nb_frames not found. (empty map)"}
              nb_frames ->
                case Integer.parse(nb_frames) do
                  {number, _} -> {:ok, number}
                end
            end
        end

      {:error, reason} -> {:error, reason}
    end
  end


  def create_thumbnail(input_file, output_file) do

    case get_video_framecount(input_file) do
      {:error, reason} -> {:error, reason}
      {:ok, framecount} ->

        frame_interval = div(framecount, 25)
        scale_width = 160
        tile_grid = "5x5"

        # ffmpeg -y -i ~/Videos/moose-encounter_75.mp4 -frames:v 1 -vf 'select=not(mod(n\,257)),scale=160:-1,tile=5x5' -update 1 -fps_mode passthrough ~/Videos/thumb.jpg
        command =
          FFmpex.new_command
          |> add_global_option(option_y())
          |> add_input_file(input_file)
          |> add_output_file(output_file)
            |> add_file_option(option_vframes(1))
            |> add_file_option(option_vf("select=not(mod(n\\,#{frame_interval})),scale=#{scale_width}:-1,tile=#{tile_grid}"))
            |> add_file_option(option_vsync(1))                  # -vsync is deprecated in ffmpeg but ffmpex doesn't have the modern replacement, -fps_mode
            # |> add_file_option(option_update(1))               # ffmpeg complains but it doesn't necessarily need this. I'm omitting because ffmpex doesn't know this function
            # |> add_file_option(option_fps_mode("passthrough")) # -fps_mode is the modern replacement for -vsync

        execute(command)
    end
  end
1 Like