h264 / aac es流转ts流 代码

发布于:2024-03-01 ⋅ 阅读:(55) ⋅ 点赞:(0)

开发中遇到调用sdk返回音视频es数据,需要封包成ts流转发到组播,再拉流回放,其中es到ts之间经历了两次封包,其中细节可参考如下文章:

打包TS

es pes ts 分析

关于es ts

几代人的努力,智慧的结晶,人类的文明之光,黑暗中的那道光,出现吧,源码!!!

头文件 es2ts.h

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <time.h>

#define DATA_TYPE_UNKNOWN 0
#define DATA_TYPE_VIDEO	96
#define DATA_TYPE_AUDIO	98

#define DATA_TYPE_USER	3

#define MAX_SIZE_SAVE_TS 6000*188

#define TS_PKT_LEN	188
#define DEF_TS_PKT_LEN	1316
#define LPCMPACKTLEN	4
#define PCMAUDIOPETPACKETLEN	14
#define PMTLEN	44
#define DATELEN	22
#define DATELEN1	12
#define VIDEOTIMEINTERVAL 3000
#define AUDIOTIMEINTERVAL 1920//1875
#define CACHEVIDEOFREMCNT	15 //视频缓存个数
#define VIDEOFREAMLEN	150



typedef struct
{
	unsigned int 		m_iDatalen;
	int				m_frametype;
	unsigned int		m_uiPartTimeTamp;//音频分帧时间戳
	unsigned char		m_c48KTwoChnPcmBufPart[8192];
}TAudio48KTwoChnPart;

typedef struct
{
	int 				m_iDatalen;
	int 				m_frametype;
	unsigned int		m_uTimeTamp;
	unsigned char		m_cVideoBuf[VIDEOFREAMLEN * 1024];
}TVideoFream;

typedef struct _es2tsParam
{
	unsigned short pc48KTwoChnPcmBigEndianBuf[4096 * 3];//存放转化后的大端音频格式
	TAudio48KTwoChnPart Audio48KTwoChnPcmPart[6];//存放音频分解的数据
	TVideoFream VideoFreamCach[CACHEVIDEOFREMCNT];//存放缓存的视频数据,缓存5帧视频,累计大于5帧开始丢弃
	unsigned int videoLastTime ;
	unsigned int audioLastTime ;
	int videoAddTime ;//VIDEOTIMEINTERVAL;
	int audioAddTime ;//AUDIOTIMEINTERVAL;
	double videoFPS ;
	int fpsFlag ;
	int audioFlag ;
	int audioTmp ;
	int nFindPFream ;
	int iNeedAudioFream ;
	int iNeedVideoFream ;
	unsigned int uiVideoCnt ;
	unsigned int uiAudioCnt ;
	unsigned int uiWritVideoCnt ;//写入 Ts中的视频帧个数
	int iCachVideoCnt ;//缓存的视频帧个数
	unsigned int iWritAudioCnt ;
	unsigned int iExistAudioFream ;//存在 音频帧
	unsigned int uiCurWtsTime ; //记录当前音视频写入 Ts 的时间戳
	int need_i_frame ;
	int g_iWriteTsPCMFileFd ;
}es2tsParam;
typedef struct
{
    int maxPacketSize;
    int encid;
    int encrypt;
    int ts_id;
    int prog_num;
    int pmt_pid;
    int pcr_pid;
    int vid_pid;
    int aud_pid;
    int cbr;
    int cbr_pkt_rate;
    int pcr_interval;
    int cbr_bit;
    int vbitrate;
    int fps;
} TSWRITER_CONFIG;

typedef struct
{
    TSWRITER_CONFIG cfg;

    int video_audio;
    int pat_present;
    int pat_cnt;
    int pmt_cnt;
    int pcr_cnt;
    int *pcr_cnt_ptr;
    int vid_cnt;
    int aud_cnt;
    int spsFound;
    int samplingFrequencyIndex;
    int channelConfiguration;

    int first_pcr;
    int avg_count;
    int pkt_count;
    unsigned int pcr;
    unsigned int pcr_high;
    int accum_pkt;	// number of packets accum
    int frame_pkt;

} TSWRITER_HANDLE;

unsigned int sync_timestamp_a_to_v(unsigned timestamp, int samplingFrequencyIndex);
int store_ts_from_es(unsigned char *outPut,unsigned int outPtrLen, unsigned char *esbuf, int boxSize, unsigned int sample_type, unsigned int timestamp, int samplingFrequencyIndex = 0, int channelConfiguration = 0);
int sampling_frequeny_change(long fre);
int init_e2t_param(es2tsParam * e2tPtr);
int m_es2ts(es2tsParam * e2tPtr ,unsigned char *data,unsigned int dataLen,unsigned int frameType, unsigned int timestamp,unsigned char *outPut,unsigned int outPutLen);
void InitSocket(int *UdpSocket, int iPort,char * ethName,char * MulticIp);
int send_ts_stream(int socket,unsigned char * sendPtr,int sendLen);

cpp文件

#include "es2ts.h"
#include "g711.h"
#include <net/if.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>

typedef unsigned int DWORD32, *PDWORD32;
typedef unsigned long       DWORD;
typedef unsigned char       BYTE;

typedef enum 
{
    STREAM_FRAME_RAW_AUDIO = 3,
    STREAM_FRAME_H264_IDR,
    STREAM_FRAME_H264_I,
    STREAM_FRAME_H264_P,
    STREAM_FRAME_H264_B,
    STREAM_FRAME_H264_SPS,
    STREAM_FRAME_H264_PPS,
    STREAM_FRAME_JPEG,
    STREAM_FRAME_G711,
    STREAM_FRAME_AAC,
    STREAM_FRAME_MPEG4_I,
    STREAM_FRAME_MPEG4_P,
    STREAM_FRAME_MPEG4_B,
    STREAM_FRAME_MPEG4_VOL,
    STREAM_FRAME_MOTION_VALUES = 18,
    STREAM_FRAME_RAW_VIDEO,
    STREAM_FRAME_H264_SVC_SEI,
    STREAM_FRAME_H264_SVC_PREFIX,
    STREAM_FRAME_H264_SVC_SUBSET_SPS,
    STREAM_FRAME_H264_SVC_SLICE_SCALABLE,
    STREAM_FRAME_MPEG2_I,
    STREAM_FRAME_MPEG2_P,
    STREAM_FRAME_MPEG2_B,
    STREAM_FRAME_CMD_RESPONSE,
    STREAM_FRAME_JPEG_SNAPSHOT,
    STREAM_FRAME_APP_ANALYTIC = 90,
    STREAM_FRAME_VIDEO_ENCODED_PRIMARY = 100,
    STREAM_FRAME_VIDEO_ENCODED_SECONDARY,
    STREAM_FRAME_AUDIO_ENCODED,
    STREAM_FRAME_ANALYTIC,
    STREAM_FRAME_RAW_VIDEO_SECONDARY,
    STREAM_FRAME_VIDEO_ENCODED,
    STREAM_FRAME_RTP_PACKAGE_H264 = 150,
    STREAM_FRAME_RTP_PACKAGE_MPEG4V,
    STREAM_FRAME_RTP_PACKAGE_MJPEG,
    STREAM_FRAME_RTP_PACKAGE_MP2T,
    STREAM_FRAME_RTP_PACKAGE_G711A = 180,
    STREAM_FRAME_RTP_PACKAGE_G711U,
    STREAM_FRAME_RTP_PACKAGE_L16,
    STREAM_FRAME_RTP_PACKAGE_AAC,
    STREAM_FRAME_RTP_PACKAGE_G726,
    STREAM_FRAME_RTP_PACKAGE_MPA,
    STREAM_FRAME_TS_PACKAGE,
    STREAM_FRAME_DOWNLOAD_PROGRESS_INDICATOR = 254,       // 下载进度提示
    STREAM_FRAME_INVALID = 255
}Stream_Frame_type;
#define DBG_MSG_ON 0



static unsigned char pat_pkt[] = {
  0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xB0, 0x0D, 0x59, 0x81, 0xEB, 0x00, 0x00, 0x00, 0x01, 0xE0,
  0x42, 0x5E, 0x44, 0x05, 0x9A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

static unsigned char pmt_pkt_va[] = {
  0x47, 0x40, 0x42, 0x10, 0x00, 0x02, 0xb0, 0x2d, 0x00, 0x01, 0xd5, 0x00, 0x00, 0xe0, 0x44, 0xf0,
  0x0c, 0x05, 0x04, 0x48, 0x44, 0x4d, 0x56, 0x88, 0x04, 0x0f, 0xff, 0xfc, 0xfc, 0x1b, 0xe0, 0x44,
  0xf0, 0x00, 0x80, 0xe0, 0x45, 0xf0, 0x0a, 0x05, 0x08, 0x48, 0x44, 0x4d, 0x56, 0x00, 0x80, 0x61,
  0x40, 0x8c, 0xd6, 0x37, 0xbe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  

static unsigned char pmt_pkt_v[] = {
  0x47, 0x40, 0x42, 0x10, 0x00, 0x02, 0xB0, 0x12, 0x00, 0x01, 0xD5, 0x00, 0x00, 0xE0, 0x44, 0xF0,
  0x00, 0x1B, 0xE0, 0x44, 0xF0, 0x00, 0xFE, 0x8A, 0x98, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

static int sampling_frequeny[] = {96000, 88200, 64000, 48000, 
								44100, 32000, 24000, 22050,
								16000,  2000, 11025,  8000};

static DWORD32 crc32_table[256];
static unsigned char * ptsbuf = NULL;

unsigned int sync_timestamp_a_to_v(unsigned timestamp, int samplingFrequencyIndex){
	double tmp = 0;

	if(samplingFrequencyIndex <= 0xb)
		samplingFrequencyIndex = sampling_frequeny[samplingFrequencyIndex];
	tmp = 90 * ( ((double)timestamp) / (((double)samplingFrequencyIndex) / 1000));

	return (unsigned int)tmp;
}

int isIFrame(unsigned char frametype)
{
	if(frametype == 4 || frametype == 5)
		return 1;
	return 0;
}

int DateType(int frametype)
{
	switch(frametype)
	{
		case 4:
		case 5:
		case 6:
		case 7:	
			return DATA_TYPE_VIDEO;
		case 11:
			return DATA_TYPE_AUDIO;
		default:
			printf("frame_type unknown:%d\n", frametype);
			return DATA_TYPE_UNKNOWN;
	}
}

static void init_crc32_table()
{
        DWORD32 i, j, k;

        for( i = 0; i < 256; i++ )
        {
            k = 0;
            for( j = (i << 24) | 0x800000; j != 0x80000000; j <<= 1 )
                k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);

            crc32_table[i] = k;
        }
}

DWORD32 crc32(DWORD32 _crc, const BYTE *buf, DWORD32 len)
{
	DWORD32 i_crc = _crc ^ 0xffffffff;
	unsigned int i;
	static int init=0;
	if (!init) {
		init_crc32_table();
		init = 1;
	}
	for (i = 0; i < len; i++)
		i_crc = (i_crc << 8) ^ crc32_table[((i_crc >> 24) ^ buf[i]) & 0xff];

	return i_crc;
}


TSWRITER_HANDLE *tsWriterCreate()
{
		TSWRITER_HANDLE *h;
	    if(!(h = (TSWRITER_HANDLE *)malloc(sizeof(TSWRITER_HANDLE))))
	        return NULL;

	    h->video_audio = 1;
	    h->pat_present = 0;
	    h->pat_cnt = 0;
	    h->pmt_cnt = 0;
	    h->pcr_cnt = 0;
	    h->vid_cnt = 0x0F;
	    h->aud_cnt = 0;

    // mark sps not found yet
	    h->spsFound = 0;

    // mark header as not found
	    h->samplingFrequencyIndex = -1;
	    h->channelConfiguration = -1;

    // bitrate count
	    h->first_pcr = 1;
	    h->avg_count = 0;
	    h->pkt_count = 0;
	    h->accum_pkt = 0;
	    h->frame_pkt = 0;

		ptsbuf = (ptsbuf) ? ptsbuf : (unsigned char*)malloc(MAX_SIZE_SAVE_TS);	

		h->cfg.maxPacketSize = DEF_TS_PKT_LEN;
		h->cfg.encid = 0;
		h->cfg.encrypt = 0;
		h->cfg.ts_id = 0x5981;
		h->cfg.prog_num = 1;
		h->cfg.pmt_pid = 0x42;
		h->cfg.pcr_pid = 0;
		h->cfg.vid_pid = 0x44;
		h->cfg.aud_pid = 0x45;
		h->cfg.cbr = 0;
		h->cfg.cbr_pkt_rate = 99;//0
		h->cfg.pcr_interval = 3003;//0
		h->cfg.cbr_bit = 0; 
		h->cfg.vbitrate = 3000000;//0
		h->cfg.fps = 30;//0

		if (h->cfg.pcr_pid == 0 || !h->cfg.cbr) {
    		h->cfg.pcr_pid = h->cfg.vid_pid;
	    		h->pcr_cnt_ptr = &h->vid_cnt;
	    } else {
	        h->pcr_cnt_ptr = &h->pcr_cnt;
	    }
	    if (h->cfg.cbr) {
	        h->avg_count = h->cfg.cbr_pkt_rate;
		    h->pkt_count = h->avg_count - 2;
		}
		return h;
}
int sampling_frequeny_change(long fre){
	switch(fre){
		case 96000:
			return 0x0;
		case 88200:
			return 0x1;
		case 64000:
			return 0x2;
		case 48000:
			return 0x3;
		case 44100:
			return 0x4;
		case 32000:
			return 0x5;
		case 24000:
			return 0x6;
		case 22050:
			return 0x7;
		case 16000:
			return 0x8;
		case 2000:
			return 0x9;
		case 11025:
			return 0xa;
		case 8000:
			return 0xb;
		default:
			return 0xc;
	}
}


int store_ts_from_es(unsigned char *outPut,unsigned int outPtrLen, unsigned char *esbuf, int boxSize, unsigned int frametype, unsigned int timestamp, int samplingFrequencyIndex, int channelConfiguration)
{
	if(!outPut)
		return -1; //ERR:no file...

	unsigned int sampleSize;
	unsigned int cts;
	unsigned int sample_type,sample_flags = 0;
	unsigned char *cur, *tsptr, *tspkt;
	int first;	// first piece of frame
	int payload_size, adaptsize;
	
	static unsigned cts_high = 0x0;
	static unsigned last_timestamp = 0;

	sampleSize = boxSize;//视频大小

	sample_type = DateType(frametype);
	sample_flags |= isIFrame(frametype);
	cts = timestamp;
	//if(cts == last_timestamp)
	//	cts++;

	//samplingFrequencyIndex = (samplingFrequencyIndex>=0x10)?sampling_frequeny_change(samplingFrequencyIndex):samplingFrequencyIndex;
	if(timestamp < last_timestamp && timestamp - last_timestamp <= 100)
		cts_high ^=  0x1;
	last_timestamp = timestamp;

	cur = esbuf;
	
    // malloc a handle
	static TSWRITER_HANDLE *h = NULL;
	if(h == NULL){
		if((h = tsWriterCreate()) == NULL)
			return -2;
	}
	h->video_audio = 1;
	tsptr = ptsbuf;

	if (sample_type == DATA_TYPE_VIDEO) {
        
		if (h->cfg.cbr == 1 || (sample_flags & 1)) 
		{
			unsigned int c;

			//开始组装 PAT 标号
			memcpy(tsptr, pat_pkt, 188);

			tsptr[3] = (tsptr[3] & 0xF0) | h->pat_cnt;
            h->pat_cnt = (h->pat_cnt + 1) & 0x0F;
			tsptr[8] = h->cfg.ts_id >> 8;
			tsptr[9] = h->cfg.ts_id & 0xFF;

			//填充节目号
			tsptr[13] = h->cfg.prog_num >> 8;
			tsptr[14] = h->cfg.prog_num & 0xFF;

			//PMT ID
			tsptr[15] = 0xE0 | (h->cfg.pmt_pid >> 8);
			tsptr[16] = h->cfg.pmt_pid & 0xFF; 

			//填充校验位
			c = crc32(0, tsptr+5, 12);
			tsptr[17] = c >> 24;
			tsptr[18] = (c >> 16) & 0xFF;
			tsptr[19] = (c >> 8) & 0xFF;
			tsptr[20] = c & 0xFF; //四个字节的校验位
			tsptr += 188; //PAT 包组装完成
			h->accum_pkt ++;
			h->pkt_count ++;

			if (h->cfg.cbr == 1 && h->pkt_count >= h->avg_count) 
			{
				unsigned int new_pcr;

				*tsptr++ = 0x47;
				*tsptr++ = h->cfg.pcr_pid>>8;
				*tsptr++ = h->cfg.pcr_pid&0xFF;
				*tsptr++ = 0x20|*h->pcr_cnt_ptr;
				*tsptr++ = 0xB7;
				*tsptr++ = 0x10;	// PCR
				*tsptr++ = (h->pcr_high<<7)|(h->pcr>>25);
				*tsptr++ = (h->pcr>>17)&0xFF;
				*tsptr++ = (h->pcr>>9)&0xFF;
				*tsptr++ = (h->
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到