package cn.org.hentai.jtt1078.flv; import cn.org.hentai.jtt1078.util.Packet; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; /** * Created by matrixy on 2020/1/3. */ public final class FlvEncoder { Packet flvHeader; Packet videoHeader; Packet SPS, PPS; int SPSSize, PPSSize; boolean writeAVCSeqHeader; int prevTagSize; int streamID; int videoTimeStamp; byte[] lastIFrame; Packet _pAudioSpecificConfig; int _nAudioConfigSize; int _aacProfile; int _sampleRateIndex; int _channelConfig; int _bWriteAACSeqHeader; boolean haveAudio, haveVideo; ByteArrayOutputStream videoFrame; public FlvEncoder(boolean haveVideo, boolean haveAudio) { this.haveVideo = haveVideo; // this.haveAudio = haveAudio; flvHeader = Packet.create(16); videoFrame = new ByteArrayOutputStream(2048 * 100); makeFlvHeader(); } public Packet getHeader() { return flvHeader; } public Packet getVideoHeader() { return videoHeader; } public boolean videoReady() { return writeAVCSeqHeader; } public byte[] getLastIFrame() { return this.lastIFrame; } public byte[] write(byte[] nalu, int nTimeStamp) { this.videoTimeStamp = nTimeStamp; if (nalu == null || nalu.length <= 4) return null; int naluType = nalu[4] & 0x1f; // skip SEI if (naluType == 0x06) return null; if (naluType == 0x01 || naluType == 0x02 || naluType == 0x03 || naluType == 0x04 || naluType == 0x05 || naluType == 0x07 || naluType == 0x08) ; else return null; if (SPS == null && naluType == 0x07) { SPS = Packet.create(nalu); SPSSize = nalu.length; } if (PPS == null && naluType == 0x08) { PPS = Packet.create(nalu); PPSSize = nalu.length; } if (SPS != null && PPS != null && writeAVCSeqHeader == false) { writeH264Header(nTimeStamp); writeAVCSeqHeader = true; } if (writeAVCSeqHeader == false) return null; videoFrame.reset(); writeH264Frame(nalu, nTimeStamp); if (videoFrame.size() == 0) return null; // 如果当前NAL单元为I祯,则缓存一个 if (naluType == 0x05) { lastIFrame = videoFrame.toByteArray(); } return videoFrame.toByteArray(); } void makeFlvHeader() { flvHeader.addByte((byte)'F'); flvHeader.addByte((byte)'L'); flvHeader.addByte((byte)'V'); flvHeader.addByte((byte)0x01); // version flvHeader.addByte((byte)(0x00 | (haveVideo ? 0x01 : 0x00) | (haveAudio ? 0x04 : 0x00))); flvHeader.addInt(0x09); flvHeader.addInt(0x00); } void writeH264Header(int nTimeStamp) { int nDataSize = 1 + 1 + 3 + 6 + 2 + (SPSSize - 4) + 1 + 2 + (PPSSize - 4); videoHeader = Packet.create(nDataSize + 32); byte cTagType = 0x09; videoHeader.addByte(cTagType); videoHeader.add3Bytes(nDataSize); videoHeader.add3Bytes(nTimeStamp); videoHeader.addByte((byte)(nTimeStamp >> 24)); videoHeader.add3Bytes(streamID); byte cVideoParam = 0x17; videoHeader.addByte(cVideoParam); byte cAVCPacketType = 0x00; videoHeader.addByte(cAVCPacketType); videoHeader.add3Bytes(0x00); videoHeader.addByte((byte)0x01); videoHeader.addByte(SPS.seek(5).nextByte()); videoHeader.addByte(SPS.seek(6).nextByte()); videoHeader.addByte(SPS.seek(7).nextByte()); videoHeader.addByte((byte)0xff); videoHeader.addByte((byte)0xe1); videoHeader.addShort((short)(SPSSize - 4)); videoHeader.addBytes(SPS.seek(4).nextBytes()); videoHeader.addByte((byte)0x01); videoHeader.addShort((short)(PPSSize - 4)); videoHeader.addBytes(PPS.seek(4).nextBytes()); prevTagSize = 11 + nDataSize; videoHeader.addInt(prevTagSize); } void writeH264Frame(byte[] nalu, int nTimeStamp) { int nNaluType = nalu[4] & 0x1f; if (nNaluType == 7 || nNaluType == 8) return; writeByte(0x09); int nDataSize = 1 + 1 + 3 + 4 + (nalu.length - 4); writeU3(nDataSize); writeU3(nTimeStamp); writeByte(nTimeStamp >> 24); writeU3(streamID); if (nNaluType == 5) writeByte(0x17); else writeByte(0x27); writeByte(0x01); writeU3(0x00); writeU4(nalu.length - 4); writeBytes(nalu, 4, nalu.length - 4); prevTagSize = 11 + nDataSize; writeU4(prevTagSize); } void write(byte u) { videoFrame.write(u); } void writeBytes(byte[] data) { videoFrame.write(data, 0, data.length); } void writeBytes(byte[] data, int offset, int len) { videoFrame.write(data, offset, len); } void writeU4(int i) { write((byte)((i >> 24) & 0xff)); write((byte)((i >> 16) & 0xff)); write((byte)((i >> 8) & 0xff)); write((byte)((i >> 0) & 0xff)); } void writeU3(int i) { write((byte)((i >> 16) & 0xff)); write((byte)((i >> 8) & 0xff)); write((byte)((i >> 0) & 0xff)); } void writeU2(int i) { write((byte)((i >> 8) & 0xff)); write((byte)((i >> 0) & 0xff)); } void writeByte(int i) { write((byte)(i & 0xff)); } }