Membrane VideoMerger Plugin

Hex.pmAPI DocsCircleCI

Plugin containing elements for cutting and merging raw video. By using this plugin you can

For most cases, the VideoCutAndMerge bin should be your first choice.

Implementations of the VideoCutter and the VideoMerger are using presentation timestamps, so every Buffer should have the pts field in the metadata map.

It is part of Membrane Multimedia Framework.

Installation

The package can be installed by adding membrane_video_merger_plugin to your list of dependencies in mix.exs:

def deps do
  [
    {:membrane_video_merger_plugin, "~> 0.1.0"}
  ]
end

Sample Usage

Both pipelines will result in creating /tmp/output.raw file with the first 5 seconds of the input_1 track and everything but the first 5 seconds of the input_2 track.

/tmp/input_1.h264 and /tmp/input_2.h264 should be an H264 video files.

CutAndMerge bin

defmodule VideoCutAndMerge.Pipeline do
  use Membrane.Pipeline
  alias Membrane.VideoCutAndMerge
  alias Membrane.H264.FFmpeg.{Parser, Decoder}
  alias Membrane.File.{Sink, Source}

  @impl true
  def handle_init(_) do
    children = [
      file_src_1: %Source{chunk_size: 40_960, location: "/tmp/input_1.h264"},
      parser_1: %Parser{framerate: {30, 1}},
      decoder_1: Decoder,
      file_src_2: %Source{chunk_size: 40_960, location: "/tmp/input_2.h264"},
      parser_2: %Parser{framerate: {30, 1}},
      decoder_2: Decoder,
      cut_and_merge: VideoCutAndMerge,
      sink: %Sink{location: "/tmp/output.raw"}
    ]

    stream_1 = %VideoCutAndMerge.Stream{intervals: [{0, Membrane.Time.seconds(5)}]}
    stream_2 = %VideoCutAndMerge.Stream{intervals: [{Membrane.Time.seconds(5), :infinity}]}

    links = [
      link(:file_src_1)
      |> to(:parser_1)
      |> to(:decoder_1)
      |> via_in(Pad.ref(:input, 1), options: [stream: stream_1])
      |> to(:cut_and_merge),
      link(:file_src_2)
      |> to(:parser_2)
      |> to(:decoder_2)
      |> via_in(Pad.ref(:input, 2), options: [stream: stream_2])
      |> to(:cut_and_merge),
      link(:cut_and_merge)
      |> to(:sink)
    ]

    {{:ok, spec: %ParentSpec{children: children, links: links}}, %{}}
  end
end

VideoCutter and VideoMerger

defmodule VideoMerger.Pipeline do
  use Membrane.Pipeline
  alias Membrane.H264.FFmpeg.{Parser, Decoder}
  alias Membrane.File.{Sink, Source}
  alias Membrane.{VideoCutter, VideoMerger}

  @impl true
  def handle_init(_) do
    children = [
      file_src_1: %Source{chunk_size: 40_960, location: "/tmp/input_1.h264"},
      parser_1: %Parser{framerate: {30, 1}},
      decoder_1: Decoder,
      cutter_1: %VideoCutter{intervals: [{0, Membrane.Time.seconds(5)}]},
      file_src_2: %Source{chunk_size: 40_960, location: "/tmp/input_2.h264"},
      parser_2: %Parser{framerate: {30, 1}},
      decoder_2: Decoder,
      cutter_2: %VideoCutter{intervals: [{Membrane.Time.seconds(5), :infinity}]},
      merger: VideoMerger,
      sink: %Sink{location: "/tmp/output.raw"}
    ]

    links = [
      link(:file_src_1)
      |> to(:parser_1)
      |> to(:decoder_1)
      |> to(:cutter_1)
      |> via_in(Pad.ref(:input, 1))
      |> to(:merger),
      link(:file_src_2)
      |> to(:parser_2)
      |> to(:decoder_2)
      |> to(:cutter_2)
      |> via_in(Pad.ref(:input, 2))
      |> to(:merger),
      link(:merger)
      |> to(:sink)
    ]

    {{:ok, spec: %ParentSpec{children: children, links: links}}, %{}}
  end
end

Copyright and License

Copyright 2021, Software Mansion

Software Mansion

Licensed under the Apache License, Version 2.0