protected void parse() {
		// Sync byte
		int marker = buffer.get() & 0xff;
		Preconditions.checkArgument(Constants.TS_MARKER == marker);

		// Second/Third byte
		int secondAndThirdBytes = buffer.getShort();

		// Transport Error Indicator (TEI)
		boolean transportErrorIndicator = (secondAndThirdBytes & 0x8000) != 0;

		// Payload Unit Start Indicator
		boolean payloadUnitStartIndicator = (secondAndThirdBytes & 0x4000) != 0;

		// Transport Priority
		boolean transportPriority = (secondAndThirdBytes & 0x2000) != 0;

		// Packet Identifier (PID)
		int pid = secondAndThirdBytes & 0x1fff;

		// Fourth byte
		int fourthByte = buffer.get() & 0xff;

		// Scrambling control
		int scramblingControl = fourthByte & 0xc0;

		// Adaptation field exist
		boolean adaptationFieldExist = (fourthByte & 0x20) != 0;

		// Contains payload
		boolean containsPayload = (fourthByte & 0x10) != 0;

		// Continuity counter
		int continuityCounter = fourthByte & 0x0f;

		MTSPacket.AdaptationField adaptationField = null;
		if (adaptationFieldExist) {
			// Adaptation Field Length
			int adaptationFieldLength = buffer.get() & 0xff;
			if (adaptationFieldLength != 0) {

				int remainingBytes = adaptationFieldLength;

				// Get next byte
				int nextByte = buffer.get() & 0xff;
				remainingBytes--;

				// Discontinuity indicator
				boolean discontinuityIndicator = (nextByte & 0x80) != 0;

				// Random Access indicator
				boolean randomAccessIndicator = (nextByte & 0x40) != 0;

				// Elementary stream priority indicator
				boolean elementaryStreamPriorityIndicator = (nextByte & 0x20) != 0;

				// PCR flag
				boolean pcrFlag = (nextByte & 0x10) != 0;

				// OPCR flag
				boolean opcrFlag = (nextByte & 0x08) != 0;

				// Splicing point flag
				boolean splicingPointFlag = (nextByte & 0x04) != 0;

				// Transport private data flag
				boolean transportPrivateDataFlag = (nextByte & 0x2) != 0;

				// Adaptation field extension flag
				boolean adaptationFieldExtensionFlag = (nextByte & 0x01) != 0;

				// PCR
				MTSPacket.AdaptationField.PCR pcr = null;
				if (pcrFlag) {
					pcr = parsePCR();
					remainingBytes -= 6;
				}

				// OPCR
				MTSPacket.AdaptationField.PCR opcr = null;
				if (opcrFlag) {
					opcr = parsePCR();
					remainingBytes -= 6;
				}

				// Splice countdown
				byte spliceCountdown = 0;
				if (splicingPointFlag) {
					spliceCountdown = buffer.get();
					remainingBytes--;
				}

				byte[] privateData = null;
				if (transportPrivateDataFlag) {
					int transportPrivateDataLength = buffer.get() & 0xff;
					privateData = new byte[transportPrivateDataLength];
					buffer.get(privateData);
					remainingBytes -= transportPrivateDataLength;
				}

				byte[] extension = null;
				if (adaptationFieldExtensionFlag) {
					int extensionLength = buffer.get() & 0xff;
					extension = new byte[extensionLength];
					buffer.get(extension);
					remainingBytes -= extensionLength;
				}

				// Skip remaining bytes
				NIOUtils.skip(buffer, remainingBytes);

				adaptationField = new MTSPacket.AdaptationField(this, discontinuityIndicator, randomAccessIndicator, elementaryStreamPriorityIndicator, pcrFlag, opcrFlag, splicingPointFlag, transportPrivateDataFlag, adaptationFieldExtensionFlag, pcr, opcr, spliceCountdown, privateData, extension);
			}
		}

		this.transportErrorIndicator = transportErrorIndicator;
		this.payloadUnitStartIndicator = payloadUnitStartIndicator;
		this.transportPriority = transportPriority;
		this.pid = pid;
		this.scramblingControl = scramblingControl;
		this.adaptationFieldExist = adaptationFieldExist;
		this.containsPayload = containsPayload;
		this.continuityCounter = continuityCounter;
		this.adaptationField = adaptationField;

		// Payload
		this.payload = containsPayload ? buffer.slice() : null;
	}