Score:2

How to merge multiple video files with different codecs? MP4/H.265

cn flag

I have a very very very ugly script to merge multiple files of my football games (I have 10 cameras a game) and now I am starting to make highlights of each game. But some of the cameras have different frame rates and use different codecs. So now I am completely at a loss on how to get these working in linux. I would be ok with a GUI or some other video editing software if that is what it would take.

Ugly script (for context)

#!/bin/bash

#filesList=""
#for file in $(ls -1v *.MP4);do #lists even numbered file
#    filesList="${filesList}${file}|"
#done
#filesList=${filesList%?} # removes trailing pipe
#ffmpeg -i "concat:$filesList" -c copy ../$(date +%Y%m%d_%H%M%S)_merged.mp4
# customize with your own.


simpleCopy(){    
    printf "Would you like to have a thumbnail:\n"
    select answer in Yes No Mkv
    do
        break;
    done
}

checkFolders(){ 
    d=$(zenity  --file-selection --title="Choose a directory and merge all .MP4s inside folder" --directory)
}

simpleCopy
checkFolders

cd "$d"
echo $(pwd)
howManyFolders=$(ls -l -tr "$(pwd)" | grep -c ^d)

if [ $howManyFolders -gt 1 ] 
then
    checkFolders
fi

currentDate=$(date +'%m.%d.%Y_%H.%M')
safeVideoName="${d/ /_}"
safeVideoName="${safeVideoName////}"
echo "safeVideoName: ${safeVideoName}"
videoName="../${safeVideoName}_${currentDate}_merged"


if [ "$answer" = "Yes" ] 
    then
        numberOfVideos=0
        videoFilter=""
        filesList=""
        for file in $(ls -1v | grep -i mp4);do 
            filesList="${filesList} -i ${file}"
            videoFilter="${videoFilter}[${numberOfVideos}:v][${numberOfVideos}:a]"
            
            let "numberOfVideos=numberOfVideos+1"
        done
        echo "videoFilter: ${videoFilter}"
        ffmpeg $filesList -vf "transpose=2,transpose=2,transpose=2" -filter_complex "${videoFilter}concat=n=${numberOfVideos}:v=1:a=1[vv][a];[vv]overlay=main_w-overlay_w-5:main_h-overlay_h-5[v]:" -map "[v]" -map "[a]" ${videoName%/}.mp4
    elif [ "$answer" = "Mkv" ]
    then
        ffmpeg -safe 0 -f concat -i <(find . -type f -name '*.MP4' -printf "file '$PWD/%p'\n" | sort) -c copy ${videoName%/}.mkv
    else
        ls -1v -tr | grep -i mp4 | perl -ne '$_ =~ s/\n$//; print "file '"'"'$_'"'"'\n"' | ffmpeg -safe 0 -protocol_whitelist file,tcp,http,pipe -f concat -i - -c copy "${videoName%/}.mp4"
fi

When I do merge the files, the H.265 files play fine, but when it gets to the MP4's it just has the last frame from the H.265 files and audio from the MP4.

error seen when merging

// cmd -         echo ls -1v -tr | grep -i mp4 | perl -ne '$_ =~ s/\n$//; print "file '"'"'$_'"'"'\n"' | ffmpeg -safe 0 -protocol_whitelist file,tcp,http,pipe -f concat -i - -c copy "${videoName%/}.mp4"

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x55f528e4d3c0] Auto-inserting h264_mp4toannexb bitstream filter
[mp4 @ 0x55f528e4fb40] Non-monotonous DTS in output stream 0:1; previous: 655360, current: 626560; changing to 655361. This may result in incorrect timestamps in the output file.
[concat @ 0x55f528e436c0] DTS 1116270 < 1167534 out of order
[mp4 @ 0x55f528e4fb40] Non-monotonous DTS in output stream 0:0; previous: 1226574, current: 1175310; changing to 1226575. This may result in incorrect timestamps in the output file.
[mp4 @ 0x55f528e4fb40] Non-monotonous DTS in output stream 0:1; previous: 655361, current: 627584; changing to 655362. This may result in incorrect timestamps in the output file.
[mp4 @ 0x55f528e4fb40] Non-monotonous DTS in output stream 0:0; previous: 1226575, current: 1178313; changing to 1226576. This may result in incorrect timestamps in the output file.
[mp4 @ 0x55f528e4fb40] Non-monotonous DTS in output stream 0:1; previous: 655362, current: 628608; changing to 655363. This may result in incorrect timestamps in the output file.

enter image description here

I can provide example clips if required :)

raj avatar
cn flag
raj
Your script uses `ffmpeg` to merge the files using just `copy` pseudo-codec. If the files are differently encoded, you have to do actual recoding with `ffmpeg`, ie. you have to provide some actual output codec name instead of `copy`. Then `ffmpeg` should recode all the clips to the format you specify. You may need to add some additional parameters specifying the coding details, as `ffmpeg` is a complicated software you have to experiment and test which options give the best output.
raj avatar
cn flag
raj
Also, you also probably need to provide some actual output format instead of `concat`.
cn flag
Ah interesting. So it would take much longer, but it would work. I wonder if I could just reencode files that were MP4 and not 265? I guess you can do a check in `ffmpeg` to check what the file is?
raj avatar
cn flag
raj
I don't think `ffmpeg` has a parameter that can tell it "if the format is the same, then don't recode". If you don't tell it to `copy`, then it always recodes, even from the same to the same format. So you have probably to first recode H265 clips to MP4 (also using `ffmpeg`) and then merge all MP4 files using your script. But you must ensure that you convert them to MP4 with exactly the same parameters (codec, framerate, size etc.) as the MP4s you already have.
raj avatar
cn flag
raj
But you can probably tell `ffmpeg` explicitly to `copy` the files that are already MP4 and recode the others. But you have to identify first which are which. You can use `ffprobe` that comes with `ffmpeg` to identify the video files.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.