Interaktywnie łącz pliki wideo

9

Jak interaktywnie łączyć (łączyć) wiele plików wideo MP4 w jeden plik?

Istnieje wiele programów, które robią to dla dwóch plików z wiersza poleceń. Na przykład:

  • ffmpeg
  • avconv
  • MP4Box

Ale często potrzebujemy rozwiązania, aby zrobić to interaktywnie.

Slyx
źródło
1
Czy możesz opisać, co masz na myśli przez interaktywne?
slm
@slm Mam na myśli program, który prosi użytkownika o wprowadzanie plików wejściowych jeden po drugim, a następnie o utworzenie pliku wyjściowego. a następnie dokonaj konkatenacji.
Slyx,
Nigdy nie widziałem programu, który robi to bezpośrednio, to tak jak zostałeś stworzony, skrypt powłoki, który zbiera informacje, a następnie tworzy wiersz poleceń. Czy szukasz ulepszeń w stosunku do tego, co masz?
slm
@slm opublikowałem to, ponieważ jest to częsta potrzeba dla użytkowników multimediów takich jak ja. Mam nadzieję, że pomoże to komuś innemu. Oczywiście wszelkie ulepszenia są mile widziane!
Slyx
1
@gold Umieściłem edycję w kolejce. ffmpegnie jest wcale martwy ani przestarzały: ostatnie gitzatwierdzenie mastermiało miejsce 15 minut temu i używam go codziennie.
Anko

Odpowiedzi:

8

Ostatnio nie próbowałem tej metody, ale nie rozumiem, dlaczego nadal nie działa. Uważam, że możesz po prostu cat .mp4złożyć razem pliki, jeśli nie chcesz robić nic innego niż ich łączenie.

1. Korzystanie z kat

$ cat file1.mp4 file2.mp4 > file3.mp4
$ ffmpeg -i file3.mp4 -qscale:v 2 output.avi

Nadal używam ffmpegcały czas, to też może łączyć pliki.

2. Korzystanie z ffmpeg

  1. Zrób listę plików do połączenia

    $ cat inputs.txt 
    file sample_mpeg4.mp4
    file sample_mpeg4.mp4
    
  2. powiązać

    $ ffmpeg -f concat -i inputs.txt -c copy out.mp4
    
    $ ll |grep -E "sample|out"
    -rw-rw-r--. 1 saml saml 491860 Feb 19 23:36 out.mp4
    -rw-r--r--. 1 saml saml 245779 Feb 19 23:32 sample_mpeg4.mp4
    

    Inne metody są omówione na wiki FFmpeg: Jak łączyć (łączyć, scalać) pliki multimedialne .

    UWAGA: Wydaje się, że Ubuntu nie obsługuje tego concatformatu. Musisz użyć protokołu concat. Ponadto ma opcje kodeka strumienia. Zatem użycie protokołu concat daje następujące wyniki:

    $ ffmpeg -i input1.mp4 -vcodec copy -acodec copy \
         -vbsf h264_mp4toannexb -f mpegts intermediate1.ts
    
    $ ffmpeg -i input2.mp4 -vcodec copy -acodec copy \
         -vbsf h264_mp4toannexb -f mpegts intermediate2.ts
    
    $ ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" \
         -vcodec copy -acodec copy -absf aac_adtstoasc output.mp4
    

    Opcje Ubuntu ffmpeg są tutaj udokumentowane .

slm
źródło
Ciekawy ! Nie wiedziałem, że catto wystarczy na pliki MP4! rozwiązanie nie jest jednak interaktywne!
Slyx
@Slyx - tak, dlatego zapytałem, co masz na myśli przez interaktywne. Pokaż mi, co o tym powiedziałeś, i zobacz, co mogę do tego dodać. Sprawdź, czy to catdziała. Ostatni raz użyłem go z .mpgplikami i to def. pracował z nimi.
slm
2
Zweryfikowałem to. Używanie catnie jest prawidłowym rozwiązaniem. Wygenerowany plik przez cating dwa pliki pokazuje tylko zawartość pierwszego pliku wejściowego!
Slyx
@Slyx - cat działa, ale znaczniki czasu są niepoprawne, więc kiedy próbujesz go odtworzyć, odtwarzacz wideo jest zdezorientowany skokiem znacznika czasu od 00 do końca, a następnie z powrotem do 00. Jeśli miałbyś transkodować wideo, to zostanie naprawiony w ramach tego procesu. Istnieją również sposoby na zregenerowanie znaczników czasu.
slm
To też mam na myśli. Istnieją dwie treści, ale odtwarzacz multimediów po prostu wykrywa pierwszy.
Slyx
4

Używam MP4Box jako podstawy pracy.
Sugerowany przeze mnie skrypt czyta wszystkie pliki jeden po drugim, weryfikując każdy z nich (niezależnie od tego, czy jest to zwykły plik), prosi użytkownika o utworzenie pliku wejściowego.

#!/bin/bash
printf "###  Concatenate Media files ###\n"
fInputCount=0
# Reading input files
IFS=''
while (true)
do
    let currentNumber=$fInputCount+1 
    printf "File n°%s (\"ok\" to finish): " $currentNumber
    read inputFile
    [ "$inputFile" == "ok" ] && break
    [ ! -e "$inputFile" ] || [ ! -f "$inputFile" ] && printf "\"%s\" : Invalid filename. Skipped !\n" "$inputFile" && continue
    ((fInputCount++))
    inputFileList[$fInputCount]=$inputFile
    printf "\"%s\" : Added to queue !\n" "$inputFile"
done
[ "$fInputCount" == "0" ] || [ "$fInputCount" == "1" ] && echo "No enough input data. BYE ! " && exit
# Listing the input file list 
for ((i=1;i<=$fInputCount;i++))
do
    printf "%2d : %s\n" $i ${inputFileList[$i]}
done
# Reading the output filename
while (true)
do
    printf "Output file without extention (\"none\" to dismiss) : "
    read outputRead
    [ "$outputRead" == "none" ] && echo "Dismissed. BYE ! " && exit
    [ "$outputRead" == "" ] && echo "Try again ! " && continue
    [ -e "$outputRead" ] && echo "\"$outputRead\" exists. Try again !" && continue
    outputFile=$outputRead.mp4
    echo "Output to \"$outputFile\". Go !" && break
done
# Creating a random temporary filename
tmpOutFile="/tmp/concatMedia"`date +"%s%N"| sha1sum | awk '{print $1}'`".mp4"
# Joining the two first input files
MP4Box -cat "${inputFileList[1]}" -cat "${inputFileList[2]}" $tmpOutFile
# Adding all other files
for ((i=3;i<=$fInputCount;i++))
do
    tmpIntermediateFile=$tmpOutFile
    tmpOutFile="/tmp/concatMedia"`date +"%s%N"| sha1sum | awk '{print $1}'`".mp4"
    MP4Box -cat $tmpIntermediateFile -cat "${inputFileList[$i]}" $tmpOutFile
    rm $tmpIntermediateFile
done
mv $tmpOutFile "$outputFile"
# Finished
echo "\"$outputFile\" Saved !"
Slyx
źródło