开发中遇到调用sdk返回音视频es数据,需要封包成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 后查看