/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.frame.h264; import java.nio.ByteBuffer; import org.apache.log4j.Logger; import com.ttProject.frame.IFrame; import com.ttProject.nio.channels.IReadChannel; import com.ttProject.util.BufferUtil; /** * analyzer for h264 nal. * ex:mpegts 00 00 01 64 ...... * @author taktod */ public class NalAnalyzer extends H264FrameAnalyzer { /** logger */ @SuppressWarnings("unused") private Logger logger = Logger.getLogger(NalAnalyzer.class); /** * {@inheritDoc} */ @Override public IFrame analyze(IReadChannel channel) throws Exception { if(channel.position() == channel.size()) { return null; } Short lastData = null; ByteBuffer buffer = ByteBuffer.allocate(channel.size() - channel.position()); // load data. while(channel.size() - channel.position() > 1) { short data = BufferUtil.safeRead(channel, 2).getShort(); // 00 00 00 01 or 00 00 01 is the sign for nal. // so check deeply in the case of 00 00(short == 0) if(data == 0) { byte firstByte, secondByte; firstByte = BufferUtil.safeRead(channel, 1).get(); if(firstByte == 1) { checkLastData(buffer, lastData); buffer.flip(); if(buffer.remaining() == 0) { buffer = ByteBuffer.allocate(channel.size() - channel.position()); continue; } return setupFrame(buffer); } else if(firstByte == 0) { secondByte = BufferUtil.safeRead(channel, 1).get(); if(secondByte == 1) { checkLastData(buffer, lastData); buffer.flip(); if(buffer.remaining() == 0) { buffer = ByteBuffer.allocate(channel.size() - channel.position()); continue; } return setupFrame(buffer); } else { if(lastData != null) { buffer.putShort(lastData); } buffer.putShort(data); buffer.put(firstByte); buffer.put(secondByte); } } else { if(lastData != null) { buffer.putShort(lastData); } buffer.putShort(data); buffer.put(firstByte); } lastData = null; } else { // not 0(cannot be sign of nal.) if(lastData != null && data == 1 && (lastData & 0x00FF) == 0) { checkLastData(buffer, lastData); buffer.flip(); if(buffer.remaining() == 0) { buffer = ByteBuffer.allocate(channel.size() - channel.position()); continue; } return setupFrame(buffer); } setLastData(buffer, lastData); lastData = data; } } setLastData(buffer, lastData); if(channel.size() - channel.position() == 1) { buffer.put(BufferUtil.safeRead(channel, 1).get()); } buffer.flip(); if(buffer.remaining() == 0) { return null; } return setupFrame(buffer); } /** * set the last data of nal. * @param buffer * @param lastData */ private void setLastData(ByteBuffer buffer, Short lastData) { if(lastData != null) { buffer.putShort(lastData); } } /** * check the last data of nal. * @param buffer * @param lastData */ private void checkLastData(ByteBuffer buffer, Short lastData) { if(lastData != null) { if((lastData & 0x00FF) == 0) { buffer.put((byte)(lastData >>> 8)); } else { buffer.putShort(lastData); } } } }