package com.laifeng.sopcastsdk.stream.packer.flv;
import com.laifeng.sopcastsdk.stream.amf.AmfMap;
import com.laifeng.sopcastsdk.stream.amf.AmfString;
import java.nio.ByteBuffer;
/**
* @Title: FlvPackerHelper
* @Package com.laifeng.sopcastsdk.stream.packer.flv
* @Description:
* @Author Jim
* @Date 16/9/23
* @Time 下午6:34
* @Version
*/
public class FlvPackerHelper {
public static final int FLV_HEAD_SIZE = 9;
public static final int VIDEO_HEADER_SIZE = 5;
public static final int AUDIO_HEADER_SIZE = 2;
public static final int FLV_TAG_HEADER_SIZE = 11;
public static final int PRE_SIZE = 4;
public static final int AUDIO_SPECIFIC_CONFIG_SIZE = 2;
public static final int VIDEO_SPECIFIC_CONFIG_EXTEND_SIZE = 11;
/**
* 生成flv 头信息
* @param buffer 需要写入数据的byte buffer
* @param hasVideo 是否有视频
* @param hasAudio 是否有音频
* @return byte数组
*/
public static void writeFlvHeader(ByteBuffer buffer, boolean hasVideo, boolean hasAudio) {
/**
* Flv Header在当前版本中总是由9个字节组成。
* 第1-3字节为文件标识(Signature),总为“FLV”(0x46 0x4C 0x56),如图中紫色区域。
* 第4字节为版本,目前为1(0x01)。
* 第5个字节的前5位保留,必须为0。
* 第5个字节的第6位表示是否存在音频Tag。
* 第5个字节的第7位保留,必须为0。
* 第5个字节的第8位表示是否存在视频Tag。
* 第6-9个字节为UI32类型的值,表示从File Header开始到File Body开始的字节数,版本1中总为9。
*/
byte[] signature = new byte[] {'F', 'L', 'V'}; /* always "FLV" */
byte version = (byte) 0x01; /* should be 1 */
byte videoFlag = hasVideo ? (byte) 0x01 : 0x00;
byte audioFlag = hasAudio ? (byte) 0x04 : 0x00;
byte flags = (byte) (videoFlag | audioFlag); /* 4, audio; 1, video; 5 audio+video.*/
byte[] offset = new byte[] {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x09}; /* always 9 */
buffer.put(signature);
buffer.put(version);
buffer.put(flags);
buffer.put(offset);
}
/**
* 写flv tag头信息
* @param buffer 需要写入数据的byte buffer
* @param type 类型:音频(0x8),视频(0x9),脚本(0x12)
* @param dataSize 数据大小
* @param timestamp 时间戳
* @return byte数组
*/
public static void writeFlvTagHeader(ByteBuffer buffer, int type, int dataSize, int timestamp) {
/**
* 第1个byte为记录着tag的类型,音频(0x8),视频(0x9),脚本(0x12);
* 第2-4bytes是数据区的长度,UI24类型的值,也就是tag data的长度;注:这个长度等于最后的Tag Size-11
* 第5-7个bytes是时间戳,UI24类型的值,单位是毫秒,类型为0x12脚本类型数据,则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧率类设置;
* 第8个byte是扩展时间戳,当24位数值不够时,该字节作为最高位将时间戳扩展为32位值;
* 第9-11个bytes是streamID,UI24类型的值,但是总为0;
* tag header 长度为1+3+3+1+3=11。
*/
int sizeAndType = (dataSize & 0x00FFFFFF) | ((type & 0x1F) << 24);
buffer.putInt(sizeAndType);
int time = ((timestamp << 8) & 0xFFFFFF00) | ((timestamp >> 24) & 0x000000FF);
buffer.putInt(time);
buffer.put((byte) 0);
buffer.put((byte) 0);
buffer.put((byte) 0);
}
/**
* 生成flv medadata 数据
* @param width 视频宽度
* @param height 视频高度
* @param fps 视频帧率
* @param audioRate 音频采样率
* @param audioSize 音频大小
* @param isStereo 音频是否为立体声
* @return byte数组
*/
public static byte[] writeFlvMetaData(int width, int height, int fps, int audioRate, int audioSize, boolean isStereo) {
AmfString metaDataHeader = new AmfString("onMetaData", false);
AmfMap amfMap = new AmfMap();
amfMap.setProperty("width", width);
amfMap.setProperty("height", height);
amfMap.setProperty("framerate", fps);
amfMap.setProperty("videocodecid", FlvVideoCodecID.AVC);
amfMap.setProperty("audiosamplerate", audioRate);
amfMap.setProperty("audiosamplesize", audioSize);
if(isStereo) {
amfMap.setProperty("stereo", true);
} else {
amfMap.setProperty("stereo", false);
}
amfMap.setProperty("audiocodecid", FlvAudio.AAC);
int size = amfMap.getSize() + metaDataHeader.getSize();
ByteBuffer amfBuffer = ByteBuffer.allocate(size);
amfBuffer.put(metaDataHeader.getBytes());
amfBuffer.put(amfMap.getBytes());
return amfBuffer.array();
}
/**
* 第一个视频Tag,需要写入AVC视频流的configuretion信息,这个信息根据pps、sps生成
* 8 bit configuration version ------ 版本号
* 8 bit AVC Profile Indication ------- sps[1]
* 8 bit Profile Compatibility ------- sps[2]
* 8 bit AVC Level Compatibility ------- sps[3]
* 6 bit Reserved ------- 111111
* 2 bit Length Size Minus One ------- NAL Unit Length长度为-1,一般为3
* 3 bit Reserved ------- 111
* 5 bit Num of Sequence Parameter Sets ------- sps个数,一般为1
* ? bit Sequence Parameter Set NAL Units ------- (sps_size + sps)的数组
* 8 bit Num of Picture Parameter Sets ------- pps个数,一般为1
* ? bit Picture Parameter Set NAL Units ------- (pps_size + pps)的数组
* @param sps
* @param pps
* @return
*/
public static void writeFirstVideoTag(ByteBuffer buffer, byte[] sps, byte[] pps) {
//写入Flv Video Header
writeVideoHeader(buffer, FlvVideoFrameType.KeyFrame, FlvVideoCodecID.AVC, FlvVideoAVCPacketType.SequenceHeader);
buffer.put((byte)0x01);
buffer.put(sps[1]);
buffer.put(sps[2]);
buffer.put(sps[3]);
buffer.put((byte)0xff);
buffer.put((byte)0xe1);
buffer.putShort((short)sps.length);
buffer.put(sps);
buffer.put((byte)0x01);
buffer.putShort((short)pps.length);
buffer.put(pps);
}
/**
* 封装flv 视频头信息
* 4 bit Frame Type ------ 帧类型
* 4 bit CodecID ------ 视频类型
* 8 bit AVCPacketType ------ 是NALU 还是 sequence header
* 24 bit CompositionTime ------ 如果为NALU 则为时间间隔,否则为0
* @param flvVideoFrameType 参见 class FlvVideoFrameType
* @param codecID 参见 class FlvVideo
* @param AVCPacketType 参见 class FlvVideoAVCPacketType
* @return
*/
public static void writeVideoHeader(ByteBuffer buffer, int flvVideoFrameType, int codecID, int AVCPacketType) {
byte first = (byte) (((flvVideoFrameType & 0x0F) << 4)| (codecID & 0x0F));
buffer.put(first);
buffer.put((byte) AVCPacketType);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
}
/**
* 写视频tag
* @param data 视频数据
* @param isKeyFrame 是否为关键帧
* @return byte数组
*/
public static void writeH264Packet(ByteBuffer buffer, byte[] data, boolean isKeyFrame) {
//生成Flv Video Header
int flvVideoFrameType = FlvVideoFrameType.InterFrame;
if(isKeyFrame) {
flvVideoFrameType = FlvVideoFrameType.KeyFrame;
}
writeVideoHeader(buffer, flvVideoFrameType, FlvVideoCodecID.AVC, FlvVideoAVCPacketType.NALU);
//写入视频信息
buffer.put(data);
}
/**
* 写第一个音频tag
* @param audioRate 音频采样率
* @param isStereo 是否为立体声
* @return byte数组
*/
public static void writeFirstAudioTag(ByteBuffer buffer, int audioRate, boolean isStereo, int audioSize) {
byte[] audioInfo = new byte[2];
int soundRateIndex = getAudioSimpleRateIndex(audioRate);
int channelCount = 1;
if(isStereo) {
channelCount = 2;
}
audioInfo[0] = (byte) (0x10 | ((soundRateIndex>>1) & 0x7));
audioInfo[1] = (byte) (((soundRateIndex & 0x1)<<7) | ((channelCount & 0xF) << 3));
writeAudioTag(buffer, audioInfo, true, audioSize);
}
public static void writeAudioTag(ByteBuffer buffer, byte[] audioInfo, boolean isFirst, int audioSize) {
//写入音频头信息
writeAudioHeader(buffer, isFirst, audioSize);
//写入音频信息
buffer.put(audioInfo);
}
/**
* 写Audio Header信息
* soundFormat 声音类型 参见 FlvAudio
* soundRate 声音采样频率 参加 FlvAudioSampleRate
* soundSize 声音采样大小 参加 FlvAudioSampleSize
* soundType 声音的类别 参加 FlvAudioSampleType
* AACPacketType 0 = AAC sequence header 1 = AAC raw
* @return
*/
public static void writeAudioHeader(ByteBuffer buffer, boolean isFirst, int audioSize) {
int soundFormat = FlvAudio.AAC;
// AAC always 3
int soundRateIndex = 3;
int soundSize = FlvAudioSampleSize.PCM_16;
if(audioSize == 8) {
soundSize = FlvAudioSampleSize.PCM_8;
}
// aac always stereo
int soundType = FlvAudioSampleType.STEREO;
int AACPacketType = FlvAudioAACPacketType.Raw;
if(isFirst) {
AACPacketType = FlvAudioAACPacketType.SequenceHeader;
}
byte[] header = new byte[2];
header[0] = (byte)(((byte) (soundFormat & 0x0F) << 4) | ((byte) (soundRateIndex & 0x03) << 2) | ((byte) (soundSize & 0x01) << 1) | ((byte) (soundType & 0x01)));
header[1] = (byte) AACPacketType;
buffer.put(header);
}
/**
* 根据传入的采样频率获取规定的采样频率的index
* @param audioSampleRate
* @return
*/
public static int getAudioSimpleRateIndex(int audioSampleRate) {
int simpleRateIndex;
switch (audioSampleRate) {
case 96000:
simpleRateIndex = 0;
break;
case 88200:
simpleRateIndex = 1;
break;
case 64000:
simpleRateIndex = 2;
break;
case 48000:
simpleRateIndex = 3;
break;
case 44100:
simpleRateIndex = 4;
break;
case 32000:
simpleRateIndex = 5;
break;
case 24000:
simpleRateIndex = 6;
break;
case 22050:
simpleRateIndex = 7;
break;
case 16000:
simpleRateIndex = 8;
break;
case 12000:
simpleRateIndex = 9;
break;
case 11025:
simpleRateIndex = 10;
break;
case 8000:
simpleRateIndex = 11;
break;
case 7350:
simpleRateIndex = 12;
break;
default:
simpleRateIndex = 15;
}
return simpleRateIndex;
}
/**
* E.4.3.1 VIDEODATA
* Frame Type UB [4]
* Type of video frame. The following values are defined:
* 1 = key frame (for AVC, a seekable frame)
* 2 = inter frame (for AVC, a non-seekable frame)
* 3 = disposable inter frame (H.263 only)
* 4 = generated key frame (reserved for server use only)
* 5 = video info/command frame
*/
public class FlvVideoFrameType
{
// set to the zero to reserved, for array map.
public final static int Reserved = 0;
public final static int Reserved1 = 6;
public final static int KeyFrame = 1;
public final static int InterFrame = 2;
public final static int DisposableInterFrame = 3;
public final static int GeneratedKeyFrame = 4;
public final static int VideoInfoFrame = 5;
}
/**
* AVCPacketType IF CodecID == 7 UI8
* The following values are defined:
* 0 = AVC sequence header
* 1 = AVC NALU
* 2 = AVC end of sequence (lower level NALU sequence ender is not required or supported)
*/
public class FlvVideoAVCPacketType
{
// set to the max value to reserved, for array map.
public final static int Reserved = 3;
public final static int SequenceHeader = 0;
public final static int NALU = 1;
public final static int SequenceHeaderEOF = 2;
}
/**
* AACPacketType
* The following values are defined:
* 0 = AAC sequence header
* 1 = AAC Raw
*/
public class FlvAudioAACPacketType
{
public final static int SequenceHeader = 0;
public final static int Raw = 1;
}
/**
* E.4.1 FLV Tag, page 75
*/
public class FlvTag
{
// set to the zero to reserved, for array map.
public final static int Reserved = 0;
// 8 = audio
public final static int Audio = 8;
// 9 = video
public final static int Video = 9;
// 18 = script data
public final static int Script = 18;
}
/**
* E.4.3.1 VIDEODATA
* CodecID UB [4]
* Codec Identifier. The following values are defined:
* 2 = Sorenson H.263
* 3 = Screen video
* 4 = On2 VP6
* 5 = On2 VP6 with alpha channel
* 6 = Screen video version 2
* 7 = AVC
*/
public class FlvVideoCodecID
{
// set to the zero to reserved, for array map.
public final static int Reserved = 0;
public final static int Reserved1 = 1;
public final static int Reserved2 = 9;
// for user to disable video, for example, use pure audio hls.
public final static int Disabled = 8;
public final static int SorensonH263 = 2;
public final static int ScreenVideo = 3;
public final static int On2VP6 = 4;
public final static int On2VP6WithAlphaChannel = 5;
public final static int ScreenVideoVersion2 = 6;
public final static int AVC = 7;
}
public class FlvAudio {
public final static int LINEAR_PCM = 0;
public final static int AD_PCM = 1;
public final static int MP3 = 2;
public final static int LINEAR_PCM_LE = 3;
public final static int NELLYMOSER_16_MONO = 4;
public final static int NELLYMOSER_8_MONO = 5;
public final static int NELLYMOSER = 6;
public final static int G711_A = 7;
public final static int G711_MU = 8;
public final static int RESERVED = 9;
public final static int AAC = 10;
public final static int SPEEX = 11;
public final static int MP3_8 = 14;
public final static int DEVICE_SPECIFIC = 15;
}
/**
* the aac object type, for RTMP sequence header
* for AudioSpecificConfig, @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33
* for audioObjectType, @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 23
*/
public class FlvAacObjectType
{
public final static int Reserved = 0;
// Table 1.1 – Audio Object Type definition
// @see @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 23
public final static int AacMain = 1;
public final static int AacLC = 2;
public final static int AacSSR = 3;
// AAC HE = LC+SBR
public final static int AacHE = 5;
// AAC HEv2 = LC+SBR+PS
public final static int AacHEV2 = 29;
}
/**
* the aac profile, for ADTS(HLS/TS)
* @see "https://github.com/simple-rtmp-server/srs/issues/310"
*/
public class FlvAacProfile
{
public final static int Reserved = 3;
// @see 7.1 Profiles, aac-iso-13818-7.pdf, page 40
public final static int Main = 0;
public final static int LC = 1;
public final static int SSR = 2;
}
/**
* the FLV/RTMP supported audio sample rate.
* Sampling rate. The following values are defined:
*/
public class FlvAudioSampleRate
{
// set to the max value to reserved, for array map.
public final static int Reserved = 15;
public final static int R96000 = 0;
public final static int R88200 = 1;
public final static int R64000 = 2;
public final static int R48000 = 3;
public final static int R44100 = 4;
public final static int R32000 = 5;
public final static int R24000 = 6;
public final static int R22050 = 7;
public final static int R16000 = 8;
public final static int R12000 = 9;
public final static int R11025 = 10;
public final static int R8000 = 11;
public final static int R7350 = 12;
}
/**
* the FLV/RTMP supported audio sample size.
* Sampling size. The following values are defined:
* 0 = 8-bit samples
* 1 = 16-bit samples
*/
public class FlvAudioSampleSize
{
public final static int PCM_8 = 0;
public final static int PCM_16 = 1;
}
/**
* the FLV/RTMP supported audio sample type.
* Sampling type. The following values are defined:
* 0 = Mono sound
* 1 = Stereo sound
*/
public class FlvAudioSampleType
{
public final static int MONO = 0;
public final static int STEREO = 1;
}
/**
* the type of message to process.
*/
public class FlvMessageType {
public final static int FLV = 0x100;
}
/**
* Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes
* H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83.
*/
public class FlvAvcNaluType
{
// Unspecified
public final static int Reserved = 0;
// Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( )
public final static int NonIDR = 1;
// Coded slice data partition A slice_data_partition_a_layer_rbsp( )
public final static int DataPartitionA = 2;
// Coded slice data partition B slice_data_partition_b_layer_rbsp( )
public final static int DataPartitionB = 3;
// Coded slice data partition C slice_data_partition_c_layer_rbsp( )
public final static int DataPartitionC = 4;
// Coded slice of an IDR picture slice_layer_without_partitioning_rbsp( )
public final static int IDR = 5;
// Supplemental enhancement information (SEI) sei_rbsp( )
public final static int SEI = 6;
// Sequence parameter set seq_parameter_set_rbsp( )
public final static int SPS = 7;
// Picture parameter set pic_parameter_set_rbsp( )
public final static int PPS = 8;
// Access unit delimiter access_unit_delimiter_rbsp( )
public final static int AccessUnitDelimiter = 9;
// End of sequence end_of_seq_rbsp( )
public final static int EOSequence = 10;
// End of stream end_of_stream_rbsp( )
public final static int EOStream = 11;
// Filler data filler_data_rbsp( )
public final static int FilterData = 12;
// Sequence parameter set extension seq_parameter_set_extension_rbsp( )
public final static int SPSExt = 13;
// Prefix NAL unit prefix_nal_unit_rbsp( )
public final static int PrefixNALU = 14;
// Subset sequence parameter set subset_seq_parameter_set_rbsp( )
public final static int SubsetSPS = 15;
// Coded slice of an auxiliary coded picture without partitioning slice_layer_without_partitioning_rbsp( )
public final static int LayerWithoutPartition = 19;
// Coded slice extension slice_layer_extension_rbsp( )
public final static int CodedSliceExt = 20;
}
/**
* 0 = Number type //DOUBLE(8个字节的double数据)
* 1 = Boolean type //UI8(1个字节)
* 2 = String type //SCRIPTDATASTRING
* 3 = Object type //SCRIPTDATAOBJECT[n]
* 4 = MovieClip type //SCRIPTDATASTRING
* 5 = Null type
* 6 = Undefined type
* 7 = Reference type //UI16(2个字节)
* 8 = ECMA array type //SCRIPTDATAVARIABLE[ECMAArrayLength]
* 10 = Strict array type //SCRIPTDATAVARIABLE[n]
* 11 = Date type //SCRIPTDATADATE
* 12 = Long string type //SCRIPTDATALONGSTRING
*/
public class FlvMetaValueType {
public final static int NumberType = 0;
public final static int BooleanType = 1;
public final static int StringType = 2;
public final static int ObjectType = 3;
public final static int MovieClipType = 4;
public final static int NullType = 5;
public final static int UndefinedType = 6;
public final static int ReferenceType = 7;
public final static int ECMAArrayType = 8;
public final static int StrictArrayType = 10;
public final static int DateType = 11;
public final static int LongStringType = 12;
}
}