AVCHD MPL File Format
AVCHD MPL file format/structure/specification as determined from Panasonic and JVC video cams
Comments and corrections are welcome at http://www.knotless.com/contact-us.html

MPLFile {
	header
A:	uint playitems_size  	// bytes to location B:
	uint playitemcount	// number of playitems
	ushort pad
	playitem[playitemcount]	// array of playlist items
B:	uint logicalplayitems_size
	logicalplayitems
C:	uint size		// bytes to end of file
	byte unk[16] = 00 00 00 18 00 00 00 01 10 00 01 00 00 00 00 18 // apparent constant
	uint size2		// bytes to end of file
	plex
}

header {			// size = 0x3A
	char[8] = "MPLS0100"	// version 1.00 of the Bluray playlist spec
	uint ndx1		// file index of location A:
	uint ndx2  		// file index of location B:
	uint ndx3 		// file index of location C:
	byte[20] reserved
	uint 0x0E 		// size of following
	byte[0x0E] 00 01 00 00 00 00 01 CF 40 00 00 00 00 00  // apparent constant
}

playitem {			
	ushort size		// bytes remaining in this playitem
	byte[9] name 		// Bluray file name of playitem, e.g. "00000M2TS" (AVCHD "00000.MTS")
	byte
	byte typecode 		// 1 = first clip, 5 = new clip, 6 = continuation clip (logical item exceeds 4GB FAT32 limit)
	byte
	uint startaddr		// starting point in file
	uint endaddr		// ending point in file
	byte[12] reserved
	uint size2		// bytes remaining in this playitem
	ushort unknown
	byte videopresent	// guess.  0 = no, 1 = yes
	byte audiopresent	// guess
	byte textpresent	// guess
	byte igpresent		// guess
	byte[8] reserved
	descriptor[count of 'present' bits above]	// array of descriptor
}

descriptor {  
	byte[16] unknown, but the last 3 bytes of the audio and text descriptors is the language, e.g. "eng" for English
}

// "Logical items" are composed of contatenated playitems previously defined, but 
// there's no law that says a camera must use this feature.  Panasonic uses it but
// JVC does not- their logical entries always correspond to physical even if they
// represent a single giant clip
logicalplayitems {
	logicalitem[logicalitemcount] // array
	ushort = 0		// padding
}

logicalitem {			// size = 0x0E
	ushort count		// on the first logical item this value contains the count of logical items, else zero
	ushort 0x01		// ?
	ushort index		// the playitem this logical item starts with
	uint startaddr
	uint endaddr    	// 0xFFFF0000 means 'play to the end'
}

// Vendor-defined
plex {
	byte[4] sectionname	// "PLEX" (Playlist Extension?)
	byte[4] reserved
	uint plexheadsize	// 0x144, bytes from sectionname to end of plexhead
	plexhead
	uint plexlogicals_size
	plexlogical[logicalitemcount] // array of plexlogical

#if Panasonic
E:	uint unk
	uint size		// bytes remaining in this file.
	byte[]			// more info for each logical, including both start and end times, ...
				// ... but this section is mostly inscrutable
#else
	byte[]
#endif

D:	tail 
}
 
plexhead {
	uint size		// JVC (bytes to location D:), Pana (bytes to location E:)
	byte[24] reserved
	uint size2		// bytes remaining to end of plexhead
	mysterycode 
	uint = 0		
	ushort = 0xFFFF
	timestamp most_recent_recording_stop // ?
	byte[2] unk		// 00 90
#if Panasonic
	byte size3		
	char[size3] recording_mode // e.g. "P 1080 29.97p AC3"
#endif
	byte[] reserved 	// 
	ushort size4		// JVC (bytes to location D:), Pana (bytes to location E:)
}

// Present in several places.
// Appears to encode vendor and camera model.   Pana HMC150=0x01030410 AC130=0x01030416, JVC=0x11048941
mysterycode {
	uint code
}

plexlogical PANASONIC {		// size = 0x42
	ushort count  		// on first plexlogical it's the count of plexlogicals, else zero
	uint mysterycode
	uint = 0x2		// ?
	ushort index		// incrementing count of plexlogicals
	timestamp starttime
	byte[2] = 0x0105	// ?
	char[5] name	  	// starting filename, e.g. "00003"
	byte[0x27] unk		// contains various unknown things
}

plexlogical JVC {		// size = 0x42
	ushort count  		// on first plexlogical it's the count of plexlogicals, else zero
	uint mysterycode
	uint = 0
	ushort 0xFFFF
	timestamp starttime
	byte[0x2E] unknown	// contains various unknown things
}

tail {
	byte[] unk
}

timestamp {
	byte timezone		// guess
	byte[7] time 		// bcd encoding of year, month, day, hour, minute, second
}