User Tools

Site Tools


howto:merge-video

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
howto:merge-video [2022/08/30 22:31] Wulf Rajekhowto:merge-video [2025/04/03 23:58] (current) Wulf Rajek
Line 1: Line 1:
 ====== Merge/Combine/Join Video ====== ====== Merge/Combine/Join Video ======
 +
 +GUI tool for mkv files. Older version is in default debian/ubuntu repositories, but latest can be installed in Mint using, afterwards associate mkv files with mktoolnix:
 +<code>
 +sudo wget -O /usr/share/keyrings/gpg-pub-moritzbunkus.gpg https://mkvtoolnix.download/gpg-pub-moritzbunkus.gpg
 +cat <<EOF | sudo tee /etc/apt/sources.list.d/mkvtoolnix.list
 +deb [arch=amd64 signed-by=/usr/share/keyrings/gpg-pub-moritzbunkus.gpg] https://mkvtoolnix.download/linuxmint/ vanessa main
 +deb-src [arch=amd64 signed-by=/usr/share/keyrings/gpg-pub-moritzbunkus.gpg] https://mkvtoolnix.download/linuxmint/ vanessa main
 +EOF
 +sudo apt update
 +sudo apt install mkvtoolnix mkvtoolnix-gui
 +</code>
 +
 +{{:howto:pasted:20241124-224334.png}}
 +
  
 MPG/MPEG files: MPG/MPEG files:
Line 7: Line 21:
 </code> </code>
  
-WMV files (same codec/properties):+WMV/MP4 files (same codec/properties):
 <code> <code>
 ls -la > list.txt ls -la > list.txt
Line 20: Line 34:
  
 ffmpeg -f concat -safe 0 -i list.txt -c copy outputfilename.wmv ffmpeg -f concat -safe 0 -i list.txt -c copy outputfilename.wmv
 +
 +#or
 +
 +ffmpeg -f concat -safe 0 -i video1.wmv video2.wmv video3.wmv -c copy outputfilename.wmv
 +
 </code> </code>
 https://stackoverflow.com/questions/49371422/how-to-merge-two-videos-without-re-encoding/49373401#49373401 https://stackoverflow.com/questions/49371422/how-to-merge-two-videos-without-re-encoding/49373401#49373401
 +
 +Script for multiple conversions based on filename pattern. Converts all related files that have a number at the end and start with 1:
 +<code>
 +#!/bin/bash
 +SAVEIFS=$IFS
 +IFS=$(echo -en "\n\b")
 +for f in *1.wmv
 +do
 +  shortfile=${f::-5}
 +  echo "file '"$shortfile"1.wmv" > list.txt
 +  echo "file '"$shortfile"2.wmv" >> list.txt
 +  echo "file '"$shortfile"3.wmv" >> list.txt
 +  ffmpeg -f concat -safe 0 -i list.txt -c copy $shortfile.wmv
 +  rm list.txt
 +done
 +IFS=$SAVEIFS
 +
 +</code>
 +
 +Script to merge files:
 +<code bash video_merge.sh>
 +#!/bin/bash
 +
 +# Check if a parameter is provided
 +if [ -z "$1" ]; then
 +    echo "Usage: "$(basename $0)" <files>"
 +    exit 1
 +fi
 +
 +TMPFILE=$(mktemp)
 +
 +for input in "$@";
 +do
 +    if [ -f "$input" ]; then
 +        if [ "$container" == "" ]; then
 +            container="${input##*.}"
 +        fi
 +        if [ "$container" != "${input##*.}" ]; then
 +            echo "Files need to be in same format to merge!"
 +            echo "Abandoning merge"
 +            if [ -f "$TMPFILE" ]; then
 +                rm $TMPFILE
 +            fi
 +            echo;read -rsn1 -p "Press any key to continue . . .";echo
 +            exit
 +        fi
 +        echo "file '$input'" >> $TMPFILE
 +        container="${input##*.}"
 +        filename=${input%.*}
 +    fi
 +done
 +
 +output="$filename.mergedprogress.$container"
 +sort -n -o $TMPFILE"_sort" $TMPFILE
 +
 +echo "The following files will be merged in this order:"
 +cat $TMPFILE"_sort"
 +echo;read -rsn1 -p "Press any key to continue . . .";echo
 +
 +cmd='ffmpeg -f concat -safe 0 -i "'"$TMPFILE"'_sort" -c copy "'"$output"'"'
 +eval $cmd
 +if [ $? -eq 0 ];
 +then
 +    actualheight=$(ffprobe -v error -select_streams v -show_entries stream=height -of csv=p=0:s=x "$output")
 +    #output2="${output%.*}."$actualheight"p.$container"
 +    output2="${output//.mergedprogress./.$actualheight""p.merged.}"
 +    mv "$output" "$output2"
 +    echo "Output file: $output2"
 +    rm $TMPFILE
 +    rm $TMPFILE"_sort"
 +else
 +    echo "An error occured. File not converted properly!"
 +    echo "Full ffmpeg command:"
 +    echo "$cmd"
 +fi
 +
 +echo;read -rsn1 -p "Press any key to continue . . .";echo
 +</code>
 +
 +Nemo action to call this merge script (to be put in ~/.local/share/nemo/actions:
 +<code - video_merge.nemo_action>
 +[Nemo Action]
 +Name=Video Merge
 +Comment=Video Merge
 +Exec=video_merge.sh %F
 +Icon-Name=stock_down
 +Selection=m
 +Extensions=mp4;wmv;avi;mkv;mov
 +Quote=double
 +EscapeSpaces=true
 +Terminal=true
 +</code>
 +
 +alternative merge script with chapters, inspired by https://gist.github.com/bdurrow/b51470869dd72b2333407dbfcb947801 has some issues with single quotes in filenames or paths.
 +<code bash video_mergechapters.sh>
 +#!/bin/bash
 +#http://redsymbol.net/articles/unofficial-bash-strict-mode/
 +set -euo pipefail
 +IFS=$'\n\t'
 +
 +cd "$1"
 +echo "$1"
 +## Script to merge all mp4 videos in current directory (recursively 2 levels)
 +## And update chapter marks to retain the folder/filename
 +
 +## Script for merging videos
 +
 +temp_dir=$(mktemp -d)
 +function finish {
 +  rc=$?
 +  if [[ $rc != 0 ]]; then
 +    echo
 +    echo "FAILED!"
 +  fi
 +  echo -n "Cleaning up "
 +  rm -rf "${temp_dir}"
 +  echo "..........[ DONE ]"
 +  exit $rc
 +}
 +trap finish SIGHUP EXIT
 +
 +current_dir=$(pwd)
 +bname=$(basename ${current_dir})
 +final_mp4=${bname}.mp4
 +input_list=${temp_dir}/${bname}-input_list.txt
 +file_list=${temp_dir}/${bname}-file_list
 +meta_file=${temp_dir}/${bname}-metadata.txt
 +
 +#Hopefully this will work for either BSD or GNU sed
 +extended_match="-r"
 +echo "" | sed ${extended_match} 's|foo|bar|' 2>/dev/null || extended_match="-E"
 +
 +if [ -e "${final_mp4}" ]; then
 +    echo "${final_mp4} already exists, please remove it."
 +    echo;read -rsn1 -p "Press any key to continue . . .";echo
 +    exit 1
 +fi
 +
 +echo -n "Generating file lists "
 +find . -maxdepth 2 -type f -iname '*.mp4' | sort -V |
 +    sed -e 's|^./||' | sed -e "s|'|'\"'\"'|" |
 +    tee "${file_list}" |
 +    awk "{printf \"file '${current_dir}/%s'\n\", \$0}" > "${input_list}"
 +echo "..........[ DONE ]"  
 +
 +cat "${input_list}"
 +echo;read -rsn1 -p "Press any key to continue . . .";echo
 +
 +## chapter marks
 +#Do this first so we fail early
 +#TODO: Test (‘=’, ‘;’, ‘#’, ‘\’) are escaped
 +ts=0
 +echo -n "Generating chapter marks "
 +ffmpeg -i "$(head -1 "${file_list}")" -f ffmetadata "${meta_file}" -v quiet
 +
 +cat "${file_list}" | while read file
 +do
 +    ds=$(ffprobe -v quiet -of csv=p=0 -show_entries format=duration "${file}")
 +    # echo "$ds"
 +    escaped_title=$(echo ${file} | sed ${extended_match} -e 's|([=;#\])|\\\1|g' -e 's|.[Mm][Pp]4$||' )
 +    echo "[CHAPTER]" >> "${meta_file}"
 +    echo "TIMEBASE=1/1" >> "${meta_file}"
 +    echo "START=${ts}" >> "${meta_file}"
 +    ts=$(awk "BEGIN {print ${ts}+${ds}; exit}")
 +    echo "END=${ts}" >> "${meta_file}"
 +    echo "TITLE=${escaped_title}" >> "${meta_file}"
 +done
 +echo "..........[ DONE ]"
 +
 +echo -n "Merging the files "
 +ffmpeg -f concat -safe 0 -i "${input_list}" -i "${meta_file}" -map_metadata 1 -codec copy "${final_mp4}" -v quiet
 +echo "..........[ DONE ]"
 +
 +echo "Job Completed."
 +
 +echo;read -rsn1 -p "Press any key to continue . . .";echo
 +</code>
 +
 +Notes re subtitles:
 +note: mp4 format does not support ass or srt subtitles, but mov_text subtitles. ffmpeg can convert them. formatting from ass subtitles will be lost.
 +
 +Embed srt subtitle file into mp4 as additional user-controllable track:
 +<code>ffmpeg -i infile.mp4 -i infile.srt -c copy -c:s mov_text outfile.mp4</code>
 +
 +set metadata of first subtitle stream to english:
 +<code>ffmpeg -i infile.mp4 -i infile.srt -c copy -c:s mov_text -metadata:s:s:0 language=eng outfile.mp4
 +ffmpeg -i infile.mp4 -i infile.ass -c copy -c:s mov_text -metadata:s:s:0 language=eng outfile.mp4
 +</code>
 +
 +extract subtitle from video:
 +<code>ffmpeg -i Movie.mkv -map 0:s:0 subs.srt</code>
 +
 +Multiple subs require mapping, otherwise first sub will be overwritten
 +First add another input: -i input2.srt. Second, map that as 2nd stream: -map 2:0. Finally, select encoder for 2nd subtitle stream (the same as the first one): -c:s srt. The complete example\ <code>ffmpeg -i input.mp4 -f srt -i input.srt -i input2.srt -map 0:0 -map 0:1 -map 1:0 -map 2:0 -c:v copy -c:a copy -c:s srt -c:s srt output.mkv </code>
 +
 +convert srt to ass or ass to srt:
 +<code>ffmpeg -i input.srt input.ass
 +ffmpeg -i input.ass input.srt
 +</code>
 +
 +Remove audio from a video file:
 +<code>
 +ffmpeg -i input_file -c copy -an output_file
 +
 +# remove all but a specific language audio streams
 +ffmpeg -i input_file -map 0 -map -0:a -map 0:a:m:language:fre -c copy output_file
 +</code>
 +
 +
howto/merge-video.1661895068.txt.gz · Last modified: 2023/05/29 11:53 (external edit)