Code I/O

A topnotch WordPress.com site


8 Comments

5 Minutes on Linux: How to join/merge M4V files in ubuntu?

What is M4V, how is it different from MP4? This is something that needs an understanding, click here to lean more.

 

Do you have multiple .m4v files and is looking forward to join them?  Then, I hope this post will help you.

What is required?
ubuntu 9.10 Karmic

Install gpac packages to install MP4Box tools.

sudo apt-get install gpac

Once you’ve done it, you can use the Mp4Box command to concatenate the files together:

MP4Box -cat file_01.m4v -cat file_02.m4v -cat file_03.m4v -new final.m4v

This will create a merged m4v file ready do be used.

NOTE: MP4Box will be able to concatenate only 20 files at a time.

DISCLAIMER: The script helps in processing more files, which is handy.  However, note that I still find multiple tracks in the target (sporadically), which I presume is a bug in MP4Box.  Otherwise, most of the time, this script has helped me.

Here is the script that will handy to merge many files.

#!/bin/bash

##################################################################
# mergeM4V.sh
# Merges multiple m4v files
#
# USAGE: mergeM4V.sh -d "dir1 dir2"
#
# OUTPUT: final.m4v (override this with -o new_target_name.m4v)
#
# The tracks (audio and video) are processed separately,
# if you want to avoid this, use -i option to ignore such
# processing.
##################################################################

DIRS="."
OFILE=""
TARGET="final.m4v"
USE_PARAMS=1

while getopts "d:o:i" opt; do
	case $opt in
		d)
			DIRS=$OPTARG
		;;

		o)
			TARGET=$OPTARG
		;;

		i)
			USE_PARAMS=0
		;;

		*)
			echo "USAGE: $0 -d dir_list [-o output_file] [-i]"
			exit 1
		;;
	esac
done

MP4BOX_PARAMS=""
PARAMS_1="#1:fps=23.976"
PARAMS_2="#2"

MP4BOX_OPT=""

first=0
scale=4
page_size=10

listing=""
for dir in $DIRS; do
	listing="$listing $dir/*.m4v"
done

# convert to an array for easy access
count=1
for item in $listing; do
	array_listing[$count]=$item
	count=$((count + 1))
done

page_size=10
total_files=`echo $listing | wc -w`
page=1;
pages=$(($total_files / page_size))
last_items=$(($total_files % page_size))

# Work on the array
index=1

while [ $page -le $pages ]; do
	count=1
	mp4box_args=""
	while [ $count -le $page_size ]; do
		if [ $USE_PARAMS == 1 ]; then
			mp4box_args="$mp4box_args -cat ${array_listing[$index]}$PARAMS_1 -cat ${array_listing[$index]}$PARAMS_2"
		else
			mp4box_args="$mp4box_args -cat ${array_listing[$index]}"
		fi

		count=$((count + 1))
		index=$((index + 1))
	done

	OFILE="ofile_${page}.m4v"
	MP4Box $MP4BOX_PARAMS $mp4box_args -new $OFILE
	page=$((page + 1))
done

if [ $last_items -gt 0 ]; then
	count=1
	OFILE="ofile_${page}.m4v"
	mp4box_args=""

	while [ $count -le $last_items ]; do
		if [ $USE_PARAMS == 1 ]; then
			mp4box_args="$mp4box_args -cat ${array_listing[$index]}$PARAMS_1 -cat ${array_listing[$index]}$PARAMS_2"
		else
			mp4box_args="$mp4box_args -cat ${array_listing[$index]}"
		fi
		count=$((count + 1))
		index=$((index + 1))
	done

	MP4Box $MP4BOX_PARAMS $mp4box_args -new $OFILE
fi

mp4box_args=""
for ofile in `ls ofile*`; do
	if [ $USE_PARAMS == 1 ]; then
		mp4box_args="$mp4box_args -cat $ofile$PARAMS_1 -cat $ofile$PARAMS_2"
	else
	    mp4box_args="$mp4box_args -cat $ofile"
	fi
done

MP4Box $MP4BOX_PARAMS $mp4box_args -new $TARGET
rm ofile*.m4v

exit 0
Advertisements