Skip to content

Instantly share code, notes, and snippets.

@lisamelton
Last active March 2, 2020 10:26
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save lisamelton/7679368 to your computer and use it in GitHub Desktop.
Save lisamelton/7679368 to your computer and use it in GitHub Desktop.
Convert MP4 video file into Matroska format without transcoding.
#!/bin/bash
#
# convert-video.sh
#
# Copyright (c) 2013-2014 Don Melton
#
about() {
cat <<EOF
$program 2.0 of December 3, 2014
Copyright (c) 2013-2014 Don Melton
EOF
exit 0
}
usage() {
cat <<EOF
Convert video file from Matroska to MP4 format or from MP4 to Matroksa format
WITHOUT TRANSCODING VIDEO.
Usage: $program [OPTION]... [FILE]
--help display this help and exit
--version output version information and exit
Requires \`mkvmerge\`, \`ffmpeg\` and \`mp4track\` executables in \$PATH
Output is written to current working directory.
EOF
exit 0
}
syntax_error() {
echo "$program: $1" >&2
echo "Try \`$program --help\` for more information." >&2
exit 1
}
die() {
echo "$program: $1" >&2
exit ${2:-1}
}
readonly program="$(basename "$0")"
case $1 in
--help)
usage
;;
--version)
about
;;
esac
readonly input="$1"
if [ ! "$input" ]; then
syntax_error 'too few arguments'
fi
if [ ! -f "$input" ]; then
die "input file not found: $input"
fi
for tool in mkvmerge ffmpeg mp4track; do
if ! $(which $tool >/dev/null); then
die "executable not in \$PATH: $tool"
fi
done
readonly identification="$(mkvmerge --identify-verbose "$input")"
readonly input_container="$(echo "$identification" | sed -n 's/^File .*: container: \(.*\) \[.*\]$/\1/p')"
if [ ! "$input_container" ]; then
die "unknown input container format: $input"
fi
case $input_container in
'Matroska')
container_format='mp4'
;;
'QuickTime/MP4')
container_format='mkv'
;;
*)
die "unsupported input container format: $input"
;;
esac
readonly output="$(basename "$input" | sed 's/\.[^.]*$//').$container_format"
if [ -e "$output" ]; then
die "output file already exists: $output"
fi
video_track=''
ac3_audio_track=''
aac_audio_track=''
extra_aac_audio_track_list=''
other_audio_track=''
index='0'
while read format; do
if [ ! "$video_track" ] && [ "$format" == 'video (MPEG-4p10/AVC/h.264)' ]; then
video_track="$index"
fi
if [[ "$format" =~ ^'audio ' ]]; then
case $format in
'audio (AC3/EAC3)')
if [ ! "$ac3_audio_track" ] && [ ! "$other_audio_track" ]; then
ac3_audio_track="$index"
fi
;;
'audio (AAC)')
if [ ! "$other_audio_track" ]; then
if [ ! "$aac_audio_track" ]; then
aac_audio_track="$index"
else
extra_aac_audio_track_list="$extra_aac_audio_track_list,$index"
fi
fi
;;
*)
if [ "$input_container" == 'Matroska' ] && [ ! "$other_audio_track" ] && [ ! "$ac3_audio_track" ] && [ ! "$aac_audio_track" ]; then
other_audio_track="$index"
fi
;;
esac
fi
index="$((index + 1))"
done < <(echo "$identification" | sed -n '/^Track ID /s/^Track ID [0-9]\{1,\}: \(.*\) \[.*\]$/\1/p')
if [ ! "$video_track" ]; then
die "missing H.264 format video track: $input"
fi
if [ "$input_container" == 'Matroska' ]; then
map_options="-map 0:$video_track"
codec_options='-c copy'
if [ "$aac_audio_track" ]; then
map_options="$map_options -map 0:$aac_audio_track"
fi
if $(ffmpeg -version | grep enable-libfdk-aac >/dev/null); then
aac_encoder='libfdk_aac'
else
aac_encoder='libfaac'
fi
if [ "$ac3_audio_track" ]; then
map_options="$map_options -map 0:$ac3_audio_track"
if [ ! "$aac_audio_track" ]; then
map_options="$map_options -map 0:$ac3_audio_track"
codec_options="-c:v copy -ac 2 -c:a:0 $aac_encoder -b:a:0 160k -c:a:1 copy"
fi
fi
if [ "$extra_aac_audio_track_list" ]; then
map_options="$map_options$(echo "$extra_aac_audio_track_list" | sed 's/,/ -map 0:/g')"
fi
if [ "$other_audio_track" ]; then
map_options="$map_options -map 0:$other_audio_track"
readonly channels="$(echo "$identification" |
sed -n '/^Track ID '$other_audio_track': /s/^.* audio_channels:\([0-9]\{1,\}\).*$/\1/p')"
if [ "$channels" ] && (($channels > 2)); then
map_options="$map_options -map 0:$other_audio_track"
codec_options="-c:v copy -ac 2 -c:a:0 $aac_encoder -b:a:0 160k -ac 6 -c:a:1 ac3 -b:a:1 384k"
else
codec_options="-c:v copy -ac 2 -c:a $aac_encoder -b:a 160k"
fi
fi
echo "Converting to MP4 format: $input" >&2
time {
ffmpeg \
-i "$input" \
$map_options \
$codec_options \
"$output" \
|| exit 1
if [ "$aac_audio_track" ] || [ "$ac3_audio_track" ] || [ "$other_audio_track" ]; then
flag='true'
index='1'
while read enabled_flag; do
if [ "$enabled_flag" != "$flag" ]; then
mp4track --track-index $index --enabled $flag "$output" || exit 1
fi
flag='false'
index="$((index + 1))"
done < <(mp4track --list "$output" | sed -n '/enabled/p' | sed 1d | sed 's/^[^=]*= //')
fi
}
else
track_order="0:$video_track"
audio_tracks=''
if [ "$ac3_audio_track" ]; then
track_order="$track_order,0:$ac3_audio_track"
audio_tracks="$ac3_audio_track"
fi
if [ "$aac_audio_track" ]; then
track_order="$track_order,0:$aac_audio_track"
if [ "$ac3_audio_track" ]; then
audio_tracks="$audio_tracks,$aac_audio_track"
else
audio_tracks="$aac_audio_track"
fi
if [ "$extra_aac_audio_track_list" ]; then
track_order="$track_order$(echo "$extra_aac_audio_track_list" | sed 's/,/,0:/g')"
audio_tracks="$audio_tracks$extra_aac_audio_track_list"
fi
fi
track_name_options=()
if [ "$audio_tracks" ]; then
audio_tracks_option="--audio-tracks $audio_tracks"
readonly track_names="$(mp4track --list "$input" |
sed -n '/userDataName/p' |
sed 1d |
sed 's/^[^=]*= //;s/^<absent>$//')"
for index in $(echo "$audio_tracks" | sed 's/,/ /g'); do
name="$(echo "$track_names" | sed -n ${index}p)"
if [ "$name" ]; then
track_name_options=("${track_name_options[@]}" --track-name "$index:$name")
fi
done
else
audio_tracks_option='--no-audio'
fi
echo "Converting to Matroska format: $input" >&2
time mkvmerge \
--output "$output" \
--track-order $track_order \
--disable-track-statistics-tags \
$audio_tracks_option \
"${track_name_options[@]}" \
"$input" \
|| exit 1
fi
@stevensegui
Copy link

Another method is to add mp4 to iDealshare VideoGo, click Profile drop down button to select MKV from General Video category and click Convert button. Here is the detailed guide: https://www.idealshare.net/video-converter/convert-mp4-to-mkv.html

@mminko
Copy link

mminko commented Mar 2, 2020

It is a bit difficult for a beginner. Maybe use a video converter to convert MP4 to MKV is a good choice, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment