Skip to content

Instantly share code, notes, and snippets.

@adithya2306
Last active April 26, 2025 15:21
Show Gist options
  • Save adithya2306/4c94f4a2ed064ce5cabe52f769358288 to your computer and use it in GitHub Desktop.
Save adithya2306/4c94f4a2ed064ce5cabe52f769358288 to your computer and use it in GitHub Desktop.
Convert dolby vision profile 8 mkv to dolby vision profile 5 mp4
#!/bin/bash
# Script to convert MKV files with dolby vision video (any profile), dolby audio (AC3 or EAC3)
# and subtitles, to MP4 with dolby vision profile 5 and SRT file.
# Default settings
video_id=0
audio_id=0
subtitle_id=0
skip_extraction=false
audio_codec="eac3"
audio_ext="ec3"
# Usage message
usage() {
echo "Usage: $0 [-v video_id] [-a audio_id] [-s subtitle_id] [-k] [-c] [-h] input.mkv"
echo "Options:"
echo " -v <id> Video stream ID to extract (default 0)"
echo " -a <id> Audio stream ID to extract (default 0)"
echo " -s <id> Subtitle stream ID to extract (default 0)"
echo " -k Skip ffmpeg extraction, run only mp4muxer"
echo " -c Use AC3 audio instead of EAC3"
echo " -h Show this help message and exit"
exit 0
}
# Parse options
while getopts ":v:a:s:kch" opt; do
case ${opt} in
v ) video_id=$OPTARG ;;
a ) audio_id=$OPTARG ;;
s ) subtitle_id=$OPTARG ;;
k ) skip_extraction=true ;;
c )
audio_codec="ac3"
audio_ext="ac3"
;;
h ) usage ;;
\? )
echo -e "\nInvalid option: -$OPTARG\n" >&2
usage
;;
esac
done
# Shift processed options
shift $((OPTIND -1))
# Check input file
input_file="$1"
if [[ -z "$input_file" ]]; then
echo "Error: No input file provided."
usage
fi
# Function to format seconds to mm:ss
format_time() {
local total_seconds=$1
printf "%d min %02d sec" $((total_seconds / 60)) $((total_seconds % 60))
}
# Record total start time
total_start_time=$(date +%s)
# Remove path and extension for naming
base_name="$(basename "$input_file" .mkv)"
# Create a new folder based on the base name
output_dir="./$base_name"
mkdir -p "$output_dir"
# Extract the video and audio into separate files
if ! $skip_extraction; then
start_time=$(date +%s)
set -x
if ! ffmpeg -i "$input_file" \
-map 0:v:"$video_id" -c:v copy "$output_dir/${base_name}.hevc" \
-map 0:a:"$audio_id" -c:a copy -f "$audio_codec" "$output_dir/${base_name}.${audio_ext}" \
-map 0:s:"$subtitle_id" -c:s copy "$output_dir/${base_name}.srt"; then
set +x
echo -e "\nError: ffmpeg extraction failed."
exit 1
fi
set +x
end_time=$(date +%s)
duration=$((end_time - start_time))
echo -e "\nffmpeg extraction successful. Time taken: $(format_time $duration)"
fi
start_time=$(date +%s)
set -x
if ! mp4muxer -o "$output_dir/${base_name}.mp4" \
-i "$output_dir/${base_name}.hevc" \
-i "$output_dir/${base_name}.${audio_ext}" \
--dv-profile 5; then
set +x
echo -e "\nError: mp4muxer failed."
exit 1
fi
set +x
end_time=$(date +%s)
duration=$((end_time - start_time))
echo -e "\nmp4muxer muxing successful. Time taken: $(format_time $duration)"
# Always cleanup intermediate files
echo -e "\nCleaning up intermediate files..."
rm -f "$output_dir/${base_name}.hevc" "$output_dir/${base_name}.${audio_ext}"
echo -e "\nCleanup done. Final output: $output_dir/${base_name}.mp4"
# Total time
total_end_time=$(date +%s)
total_duration=$((total_end_time - total_start_time))
echo "Total time taken: $(format_time $total_duration)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment