将两个视频剪辑合并为一个,将它们并排放置

将两个视频剪辑合并为一个,将它们并排放置

我有两个视频剪辑。两者都是 640x480,最后 10 分钟。一个包含背景音频,另一个包含歌唱演员。我想创建一个尺寸为 1280x480 的 10 分钟视频剪辑(换句话说,我想将视频彼此相邻放置并同时播放它们,混合两个剪辑的音频)。我试图弄清楚如何使用 ffmpeg/avidemux 来做到这一点,但到目前为止我一无所获。当我搜索合并时,它们都指的是连接。

有什么建议吗?

答案1

老实说,使用接受的答案导致我丢了很多帧。

然而,使用hstackfilter_complex 产生了完美的流体输出:

ffmpeg -i left.mp4 -i right.mp4 -filter_complex hstack output.mp4

答案2

ffmpeg \
  -i input1.mp4 \
  -i input2.mp4 \
  -filter_complex '[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]' \
  -map '[vid]' \
  -c:v libx264 \
  -crf 23 \
  -preset veryfast \
  output.mp4

input1.mp4这实际上是通过用与原始视频大小相同的黑色填充右侧来使大小加倍,然后input2.mp4使用覆盖过滤器放置在该黑色区域的顶部。

来源:https://superuser.com/questions/153160/join-videos-split-screen

答案3

只需两个滤波器即可完成此操作,并且来自两个输入的音频也将被包括在内。

ffmpeg -i left.mp4 -i right.mp4 -filter_complex \
"[0:v][1:v]hstack=inputs=2[v]; \
 [0:a][1:a]amerge[a]" \
-map "[v]" -map "[a]" -ac 2 output.mp4
  • 将并排放置每个视频。
  • 阿默格将来自两个输入的音频组合成单个多通道音频流,并-ac 2使其成为立体声;如果没有此选项,如果两个输入都是立体声,音频流可能最终会变成 4 个通道。

答案4

等级依赖

implementation "com.writingminds:FFmpegAndroid:0.3.2"

代码

将两个视频并排连接成一个的命令

val cmd : arrayOf("-y", "-i", videoFile!!.path, "-i", videoFileTwo!!.path, "-filter_complex", "hstack", outputFile.path)

将两个视频(一个接一个)附加到一个视频中的命令

  val cmd : arrayOf("-y", "-i", videoFile!!.path, "-i", videoFileTwo!!.path, "-strict", "experimental", "-filter_complex",
                        "[0:v]scale=iw*min(1920/iw\\,1080/ih):ih*min(1920/iw\\,1080/ih), pad=1920:1080:(1920-iw*min(1920/iw\\,1080/ih))/2:(1080-ih*min(1920/iw\\,1080/ih))/2,setsar=1:1[v0];[1:v] scale=iw*min(1920/iw\\,1080/ih):ih*min(1920/iw\\,1080/ih), pad=1920:1080:(1920-iw*min(1920/iw\\,1080/ih))/2:(1080-ih*min(1920/iw\\,1080/ih))/2,setsar=1:1[v1];[v0][0:a][v1][1:a] concat=n=2:v=1:a=1",
                        "-ab", "48000", "-ac", "2", "-ar", "22050", "-s", "1920x1080", "-vcodec", "libx264", "-crf", "27",
                        "-q", "4", "-preset", "ultrafast", outputFile.path)

笔记:

“videoFile”是您的第一个视频路径。
“videoFileTwo”是您的第二个视频路径。
“outputFile”是您的组合视频路径,这是我们的最终输出路径

创建视频输出路径

fun createVideoPath(context: Context): File {
        val timeStamp: String = SimpleDateFormat(Constant.DATE_FORMAT, Locale.getDefault()).format(Date())
        val imageFileName: String = "APP_NAME_"+ timeStamp + "_"
        val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)
        if (storageDir != null) {
            if (!storageDir.exists()) storageDir.mkdirs()
        }
        return File.createTempFile(imageFileName, Constant.VIDEO_FORMAT, storageDir)
    }

执行命令的代码

try {
            FFmpeg.getInstance(context).execute(cmd, object : ExecuteBinaryResponseHandler() {
                override fun onStart() {

                }

                override fun onProgress(message: String?) {
                    callback!!.onProgress(message!!)
                }

                override fun onSuccess(message: String?) {
                    callback!!.onSuccess(outputFile)
                }

                override fun onFailure(message: String?) {
                    if (outputFile.exists()) {
                        outputFile.delete()
                    }
                    callback!!.onFailure(IOException(message))
                }

                override fun onFinish() {
                    callback!!.onFinish()
                }
            })
        } catch (e: Exception) {
            
        } catch (e2: FFmpegCommandAlreadyRunningException) {
           
        }

相关内容