基于FFMPEG提取音視訊資料,及PS封包,借鑒了很多資料及部落格,對于封裝PS包,很多屬性沒有弄懂,但至少目前做出了功能,發表用以記錄,供人學習。
Github: https://github.com/cdebug/Rtsp2ps
CSDN: https://download.csdn.net/download/qq_39805297/14022436
主要功能代碼如下:
RtspDecoder 解RTSP碼流
rtspdecoder.h
#ifndef RTSPDECODER_H
#define RTSPDECODER_H
#include "common.h"
#include "psencoder.h"
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
class RtspDecoder
{
public:
RtspDecoder();
~RtspDecoder();
int init();
void executeProcess();
void setStreamUrl(std::string);
void setStreamEncoder(std::shared_ptr<PsEncoder>);
void removeStreamEncoder();
private:
void sendFrameData(uint8_t*, int, FrameType);
AVFormatContext *m_pFormatCtx;
AVCodecContext *m_pVideoCodecCtx = nullptr;
AVCodecContext *m_pAudioCodecCtx = nullptr;
int m_videoindex, m_audioindex;
std::string m_streamUrl;
std::weak_ptr<PsEncoder> m_encoder;
};
#endif //RTSPDECODER_H
rtspdecoder.cpp
#include "rtspdecoder.h"
#include "common.h"
RtspDecoder::RtspDecoder()
{
}
RtspDecoder::~RtspDecoder()
{
}
int RtspDecoder::init()
{
int i;
AVCodec *pVideoCodec, *pAudioCodec;
struct SwsContext *img_convert_ctx;
m_pFormatCtx = avformat_alloc_context();
AVDictionary* opts = NULL;
av_dict_set(&opts, "rtsp_transport", "tcp", 0); //設定tcp or udp,預設一般優先tcp再嘗試udp
av_dict_set(&opts, "stimeout", "9000000", 0);//設定逾時3秒
if (avformat_open_input(&m_pFormatCtx, m_streamUrl.c_str(), NULL, &opts) != 0)
{
std::cout << "Couldn't open input stream." << m_streamUrl << std::endl;
return -1;
}
if (avformat_find_stream_info(m_pFormatCtx, NULL)<0)
{
std::cout << "Couldn't find stream information." << std::endl;
return -1;
}
m_videoindex = -1;
m_audioindex = -1;
for (i = 0; i<m_pFormatCtx->nb_streams; i++)
{
AVCodecContext* codec = m_pFormatCtx->streams[i]->codec;
if (codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
if(codec->codec_id != AV_CODEC_ID_H264)
std::cout << "video codec is not h264, CODE_ID=" << codec->codec_id << std::endl;
else
m_videoindex = i;
}
if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
if(codec->codec_id != AV_CODEC_ID_AAC)
std::cout << "audio codec is not aac, CODE_ID=" << codec->codec_id << std::endl;
else
m_audioindex = i;
}
}
if (m_videoindex == -1 && m_audioindex == -1)
{
std::cout << "Didn't find a video or audio stream." << std::endl;
return -1;
}
//Open Video Ctx
if(m_videoindex >= 0)
{
m_pVideoCodecCtx = m_pFormatCtx->streams[m_videoindex]->codec;
pVideoCodec = avcodec_find_decoder(m_pVideoCodecCtx->codec_id);
if (pVideoCodec == NULL)
{
std::cout << "Codec not found." << std::endl;
return -1;
}
if (avcodec_open2(m_pVideoCodecCtx, pVideoCodec, NULL)<0)
{
std::cout << "Could not open codec." << std::endl;
return -1;
}
}
else
std::cout << "No video stream" << std::endl;
//Open Audio Ctx
if(m_audioindex >= 0)
{
m_pAudioCodecCtx = m_pFormatCtx->streams[m_audioindex]->codec;
pAudioCodec = avcodec_find_decoder(m_pAudioCodecCtx->codec_id);
if (pAudioCodec == NULL)
{
std::cout << "Codec not found." << std::endl;
return -1;
}
if (avcodec_open2(m_pAudioCodecCtx, pAudioCodec, NULL)<0)
{
std::cout << "Could not open codec." << std::endl;
return -1;
}
}
else
std::cout << "No audio stream" << std::endl;
//Output Info---輸出一些檔案(RTSP)資訊
// av_dump_format(m_pFormatCtx, 0, m_streamUrl.c_str(), 0);
return 0;
}
void RtspDecoder::executeProcess()
{
std::cout << "RtspDecoder::executeProcess" << std::endl;
std::shared_ptr<PsEncoder> encoder = m_encoder.lock();
if(encoder)
{
encoder->setSampleRate(m_pFormatCtx->streams[m_audioindex]->codec->sample_rate);
encoder->setChannels(m_pFormatCtx->streams[m_audioindex]->codec->channels);
}
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
for (;;)
{
//------------------------------
if (av_read_frame(m_pFormatCtx, packet) >= 0)
{
if (packet->stream_index == m_videoindex)
sendFrameData(packet->data, packet->size, FRAME_VIDEO);
else if (packet->stream_index == m_audioindex)
sendFrameData(packet->data, packet->size, FRAME_AUDIO);
av_free_packet(packet);
}
}
avcodec_close(m_pVideoCodecCtx);
avcodec_close(m_pAudioCodecCtx);
avformat_close_input(&m_pFormatCtx);
}
void RtspDecoder::sendFrameData(uint8_t* data, int len, FrameType type)
{
std::shared_ptr<PsEncoder> encoder = m_encoder.lock();
if(encoder)
encoder->sendFrameData(data, len, type);
}
void RtspDecoder::setStreamUrl(std::string url)
{
m_streamUrl = url;
}
void RtspDecoder::setStreamEncoder(std::shared_ptr<PsEncoder> encoder)
{
m_encoder = encoder;
}
void RtspDecoder::removeStreamEncoder()
{
m_encoder.reset();
}
PsEncoder 封裝 PS
psencoder.h
#ifndef PSENCODER_H
#define PSENCODER_H
#include "mysocket.h"
#include "common.h"
class PsEncoder
{
public:
PsEncoder(SocketProtocol);
~PsEncoder();
int initSocket(std::string, int, int);
int sendFrameData(uint8_t*, int, FrameType);
int sendVideoData(uint8_t*, int);
int sendAudioData(uint8_t*, int);
void setSsrc(uint32_t);
int getLocalPort();
void setSampleRate(int);
void setChannels(int);
private:
void sendIdrFrame(uint8_t*, int);
void sendPFrame(uint8_t*, int);
int wrapPsHeader(uint8_t*, uint32_t);
int wrapSystemHeader(uint8_t*);
int wrapSystemMap(uint8_t*);
void wrapIDRFramePes(uint8_t*, int&, uint8_t*, int);
void wrapPFramePes(uint8_t*, int&, uint8_t*, int);
void wrapAudioFramePes(uint8_t*, int&, uint8_t*, int);
int makeAudioHeader(uint8_t*, int);
void makePes(uint8_t*, uint8_t, int, uint32_t);
void makeRtpHeader();
void sendPsData(uint8_t*, int);
void sendRtpPacket();
uint32_t m_ssrc;
uint8_t m_spsBuff[1000];
int m_spsLen;
uint8_t m_ppsBuff[1000];
int m_ppsLen;
uint8_t m_seiBuff[1000];
int m_seiLen;
uint8_t m_idrBuff[409600];
int m_idrLen;
uint8_t m_pBuff[409600];
int m_pLen;
uint8_t m_rtpBuff[1600];
int m_rtpLen;
uint32_t m_timeStamp = 0;
uint32_t m_timeStampIncrement = 3600;
uint16_t m_seq = 0;
bool m_idrBuffInited = false;
bool m_pBuffInited = false;
std::shared_ptr<MySocket> m_sendSocket;
uint8_t m_frameData[409600];
int m_frameLen;
int m_sampleRateType;
int m_channels;
};
#endif //PSENCODER_H
psencoder.cpp
#include "psencoder.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "common.h"
#include "udpsocket.h"
#include "tcpsocket.h"
#define PS_HDR_LEN 14
#define SYS_HDR_LEN 18
#define PSM_HDR_LEN 24
#define PES_HDR_LEN 14
#define RTP_HDR_LEN 12
#define MAX_RTP_PAYLOAD 1400
#define MAX_PES_LENGTH 65000
#define AAC_HEADER_LEN 7
static uint32_t crc32table[256] = {
0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517,
0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B,
0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048,
0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652,
0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D,
0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095,
0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA,
0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0,
0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3,
0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF,
0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730,
0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A,
0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05,
0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475,
0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A,
0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840,
0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB,
0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87,
0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4,
0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE,
0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1,
0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64,
0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B,
0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351,
0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832,
0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E,
0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5,
0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF,
0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0,
0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0,
0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F,
0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185,
0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A,
0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176,
0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15,
0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F,
0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620,
0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8,
0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7,
0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD,
0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E,
0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2,
0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1
};
uint32_t mpeg_crc32(uint32_t crc, const uint8_t *buffer, uint32_t size)
{
unsigned int i;
for (i = 0; i < size; i++) {
crc = crc32table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
}
return crc ;
}
bool startCode3(uint8_t* data)
{
if(data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01)
return true;
else
return false;
}
bool startCode4(uint8_t* data)
{
if(data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x01)
return true;
else
return false;
}
int getNaluSize(uint8_t* data, int len)
{
for(int i = 4; i < len - 4; ++i)
{
if(startCode3(data+i) || startCode4(data+i))
return i;
}
return len;
}
PsEncoder::PsEncoder(SocketProtocol protocol)
{
if(PROTOCOL_UDP == protocol)
m_sendSocket.reset(new UdpSocket);
else
m_sendSocket.reset(new TcpSocket);
}
PsEncoder::~PsEncoder()
{
}
void PsEncoder::setSsrc(uint32_t ssrc)
{
m_ssrc = ssrc;
}
int PsEncoder::getLocalPort()
{
if(m_sendSocket)
return m_sendSocket->localPort();
else
return -1;
}
int PsEncoder::initSocket(std::string serverIp, int serverPort, int localPort)
{
if(m_sendSocket)
return m_sendSocket->init(serverIp, serverPort, localPort);
else
return -1;
}
int PsEncoder::sendFrameData(uint8_t* data, int len, FrameType type)
{
if(FRAME_VIDEO == type)
return sendVideoData(data, len);
else if(FRAME_AUDIO == type)
return sendAudioData(data, len);
}
int PsEncoder::sendVideoData(uint8_t* data, int len)
{
if(len < 5)
return -1;
while (len > 0)
{
int naluSize = getNaluSize(data, len);
int naluType;
if(startCode3(data))
naluType = data[3] & 0x1f;
else
naluType = data[4] & 0x1f;
switch (naluType)
{
case 1:
sendPFrame(data, len);
break;
case 5:
sendIdrFrame(data, len);
break;
case 6:
memcpy(m_seiBuff, data, naluSize);
m_seiLen = naluSize;
break;
case 7:
memcpy(m_spsBuff, data, naluSize);
m_spsLen = naluSize;
break;
case 8:
memcpy(m_ppsBuff, data, naluSize);
m_ppsLen = naluSize;
break;
default:
return 0;
}
data+=naluSize;
len-=naluSize;
}
return 0;
}
void PsEncoder::sendIdrFrame(uint8_t* data, int len)
{
int pesNum = len % MAX_PES_LENGTH == 0 ? len / MAX_PES_LENGTH : len / MAX_PES_LENGTH + 1;
for(int i = 0; i < pesNum; ++i)
{
int pesSize = MAX_PES_LENGTH;
if(i + 1 == pesNum)
pesSize = len - MAX_PES_LENGTH*i;
if(i == 0)
{
m_idrLen = wrapPsHeader(m_idrBuff, m_timeStamp);
m_idrLen += wrapSystemHeader(m_idrBuff+m_idrLen);
m_idrLen += wrapSystemMap(m_idrBuff+m_idrLen);
}
wrapIDRFramePes(m_idrBuff, m_idrLen, data+MAX_PES_LENGTH*i, pesSize);
sendPsData(m_idrBuff, m_idrLen);
m_idrLen = 0;
m_spsLen = 0;
m_ppsLen = 0;
m_seiLen = 0;
m_idrBuffInited = true;
}
m_timeStamp += m_timeStampIncrement;
m_idrLen = 0;
}
void PsEncoder:: sendPFrame(uint8_t* data, int len)
{
m_pLen = wrapPsHeader(m_pBuff, m_timeStamp);
wrapPFramePes(m_pBuff, m_pLen,data, len);
sendPsData(m_pBuff, m_pLen);
m_timeStamp += m_timeStampIncrement;
m_pLen = 0;
m_pBuffInited = true;
}
int PsEncoder::wrapPsHeader(uint8_t* data, uint32_t pts)
{
uint32_t pts_ext = 0;
uint32_t mux_rate = 19460;
#if 0
#else
// pack_start_code
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x01;
data[3] = 0xba;
// 33-system_clock_reference_base + 9-system_clock_reference_extension
// '01xxx1xx xxxxxxxx xxxxx1xx xxxxxxxx xxxxx1xx xxxxxxx1'
data[4] = 0x44 | (((pts>> 30) & 0x07) << 3) | ((pts >> 28) & 0x03);
data[5] = ((pts >> 20) & 0xFF);
data[6] = 0x04 | (((pts >> 15) & 0x1F) << 3) | ((pts >> 13) & 0x03);
data[7] = ((pts >> 5) & 0xFF);
data[8] = 0x04 | ((pts & 0x1F) << 3) | ((pts_ext >> 7) & 0x03);
data[9] = 0x01 | ((pts_ext & 0x7F) << 1);
// program_mux_rate
// 'xxxxxxxx xxxxxxxx xxxxxx11'
data[10] = (uint8_t)(mux_rate >> 14);
data[11] = (uint8_t)(mux_rate >> 6);
data[12] = (uint8_t)(0x03 | ((mux_rate & 0x3F) << 2));
// stuffing length
// '00000xxx'
data[13] = 0xF8;
#endif
return 14;
}
int PsEncoder::wrapSystemHeader(uint8_t* data)
{
int rate_bound = 50000;
int audio_bound = 1;
int fixed_flag = 0;
int csps_flag = 1;
int sys_audio_lock_flag = 1;
int sys_video_lock_flag = 1;
int video_bound = 1;
int packet_rate_restriction_flag = 0;
int audio_buff_bound_scale = 0;
int video_buff_bound_scale = 1;
int audio_buff_bound_size = 512;
int video_buff_bound_size = 2048;
#if 0
#else
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x01;
data[3] = 0xbb;
data[6] = 0x80 | ((rate_bound >> 15) & 0x7F);
data[7] = (rate_bound >> 7) & 0xFF;
data[8] = 0x01 | ((rate_bound & 0x7F) << 1);
// 6-audio_bound + 1-fixed_flag + 1-CSPS_flag
data[9] = ((audio_bound & 0x3F) << 2) | ((fixed_flag & 0x01) << 1) | (csps_flag & 0x01);
// 1-system_audio_lock_flag + 1-system_video_lock_flag + 1-maker + 5-video_bound
data[10] = 0x20 | ((sys_audio_lock_flag & 0x01) << 7) | ((sys_video_lock_flag & 0x01) << 6) | (video_bound & 0x1F);
// 1-packet_rate_restriction_flag + 7-reserved
data[11] = 0x7F | ((packet_rate_restriction_flag & 0x01) << 7);
data[12] = 0xc0;
// '11' + 1-P-STD_buffer_bound_scale + 13-P-STD_buffer_size_bound
// '11xxxxxx xxxxxxxx'
data[16] = 0xC0 | ((audio_buff_bound_scale & 0x01) << 5) | ((audio_buff_bound_size >> 8) & 0x1F);
data[17] = audio_buff_bound_size & 0xFF;
data[12] = 0xe0;
// '11' + 1-P-STD_buffer_bound_scale + 13-P-STD_buffer_size_bound
// '11xxxxxx xxxxxxxx'
data[16] = 0xC0 | ((video_buff_bound_scale & 0x01) << 5) | ((video_buff_bound_size >> 8) & 0x1F);
data[17] = video_buff_bound_size & 0xFF;
// header length
bitsWrite(data + 4, 0, 16, 18 - 6);
return 18;
#endif
}
int PsEncoder::wrapSystemMap(uint8_t* data)
{
int psm_ver = 0;
#if 0
#else
data[0] = 0x00;
data[1] = 0x00;
data[2] = 0x01;
data[3] = 0xbc;
// program_stream_map_length 16-bits
bitsWrite(data+4, 0, 16,18); /*program stream map length*/
// current_next_indicator '1'
// single_extension_stream_flag '1'
// reserved '0'
// program_stream_map_version 'xxxxx'
data[6] = 0xc0 | (psm_ver & 0x1F);
// reserved '0000000'
// marker_bit '1'
data[7] = 0x01;
// program_stream_info_length 16-bits program_stream_info_length = 0
data[8] = 0;
data[9] = 0;
// elementary_stream_map_length 16-bits
bitsWrite(data+10, 0, 16, 8);
// audio
data[12] = 0x0f;//AAC
data[13] = 0xc0;
// elementary_stream_info_length:16
data[14] = 0;
data[15] = 0;
//video
data[16] = 0x1b;//H264
data[17] = 0xe0;
// elementary_stream_info_length:16
data[18] = 0;
data[19] = 0;
int j = 20;
// crc32
uint32_t crc = mpeg_crc32(0xffffffff, data, (uint32_t)j);
data[j+3] = (uint8_t)((crc >> 24) & 0xFF);
data[j+2] = (uint8_t)((crc >> 16) & 0xFF);
data[j+1] = (uint8_t)((crc >> 8) & 0xFF);
data[j+0] = (uint8_t)(crc & 0xFF);
#endif
return 24;
}
void PsEncoder::wrapIDRFramePes(uint8_t* buff, int& bufflen, uint8_t* data, int len)
{
if(m_spsLen > 0)
{
makePes(buff+bufflen, 0xe0, m_spsLen, m_timeStamp);
bufflen += PES_HDR_LEN;
memcpy(buff+bufflen, m_spsBuff, m_spsLen);
bufflen+=m_spsLen;
m_spsLen = 0;
}
if(m_ppsLen > 0)
{
makePes(buff+bufflen, 0xe0, m_ppsLen, m_timeStamp);
bufflen += PES_HDR_LEN;
memcpy(buff + bufflen, m_ppsBuff, m_ppsLen);
bufflen+=m_ppsLen;
m_ppsLen = 0;
}
if(m_seiLen > 0)
{
makePes(buff+bufflen, 0xe0, m_seiLen, m_timeStamp);
bufflen += PES_HDR_LEN;
memcpy(buff + bufflen, m_seiBuff, m_seiLen);
bufflen+=m_seiLen;
m_seiLen = 0;
}
makePes(buff+bufflen, 0xe0, len, m_timeStamp);
bufflen += PES_HDR_LEN;
memcpy(buff + bufflen, data, len);
bufflen += len;
}
void PsEncoder::wrapPFramePes(uint8_t* buff, int& bufflen, uint8_t* data, int len)
{
makePes(buff+bufflen, 0xe0, len, m_timeStamp);
bufflen += PES_HDR_LEN;
memcpy(buff + bufflen, data, len);
bufflen += len;
}
void PsEncoder::wrapAudioFramePes(uint8_t* buff, int& bufflen, uint8_t* data, int len)
{
makePes(buff+bufflen, 0xc0, len, m_timeStamp);
bufflen = PES_HDR_LEN;
memcpy(buff + bufflen, data, len);
bufflen += len;
}
void PsEncoder::makePes(uint8_t* buff, uint8_t streamId, int len, uint32_t pts)
{
bitsWrite(buff, 0, 24, 0x000001 ); // header
bitsWrite(buff, 24, 8, streamId);
bitsWrite(buff, 32, 16, len+8); //pes_packet_length : es len and the following pes len
bitsWrite(buff, 48, 8, 0x8c ); //
bitsWrite(buff, 56, 2, 0x02 ); //第七位元組的高兩位是PTS和DTS訓示位,00表示無PTS無DTS,01禁止使用,10表示PES頭部字段會附加PTS結構,11表示PTS和DTS都包括
bitsWrite(buff, 58, 6, 0x00 ); //
bitsWrite(buff, 64, 8, 0x05 ); //8
//UINT64 i_scr = I_SCR(_iFrameIndextemp);
bitsWrite(buff, 72, 4, 2 ); /*'0010'*/
bitsWrite(buff, 76, 3, ((pts)>>30)&0x07 ); /*PTS[32..30]*/
bitsWrite(buff, 79, 1, 1 );
bitsWrite(buff, 80, 15,((pts)>>15)&0x7FFF); /*PTS[29..15]*/
bitsWrite(buff, 95, 1, 1 );
bitsWrite(buff, 96, 15,(pts)&0x7FFF); /*PTS[14..0]*/
bitsWrite(buff, 111, 1, 1 );
}
void PsEncoder::makeRtpHeader()
{
bitsWrite(m_rtpBuff, 0, 16, 0x8060);
bitsWrite(m_rtpBuff, 16, 16, m_seq);
bitsWrite(m_rtpBuff, 32, 32, m_timeStamp);
bitsWrite(m_rtpBuff, 64, 32, m_ssrc);
m_rtpLen = RTP_HDR_LEN;
m_seq += 1;
}
void PsEncoder::sendPsData(uint8_t* buff, int len)
{
int rtpNum = len%MAX_RTP_PAYLOAD==0 ? len/MAX_RTP_PAYLOAD : len/MAX_RTP_PAYLOAD+1;
for(int i = 0; i < rtpNum; ++i)
{
int payloadLen = MAX_RTP_PAYLOAD;
if(i + 1 >= rtpNum)
payloadLen = len - MAX_RTP_PAYLOAD * i;
makeRtpHeader();
memcpy(m_rtpBuff+m_rtpLen, buff+MAX_RTP_PAYLOAD*i, payloadLen);
m_rtpLen+=payloadLen;
sendRtpPacket();
}
std::this_thread::sleep_for(std::chrono::microseconds(1));
}
void PsEncoder::sendRtpPacket()
{
if(m_sendSocket)
m_sendSocket->sendData(m_rtpBuff, m_rtpLen);
}
int PsEncoder::sendAudioData(uint8_t* data, int len)
{
uint8_t buff[40960];
int bufflen = 0;
makePes(buff, 0xc0, len+AAC_HEADER_LEN, m_timeStamp);
bufflen+=PES_HDR_LEN;
bufflen += makeAudioHeader(buff+bufflen, len);
memcpy(buff+bufflen, data, len);
bufflen+= len;
sendPsData(buff, bufflen);
return 0;
}
int PsEncoder::makeAudioHeader(uint8_t* buff, int audioLen)
{
bitsWrite(buff, 0, 12, 0xfff); /* syncword */
bitsWrite(buff, 12, 1, 1); /* ID */
bitsWrite(buff, 13, 2, 0); /* layer */
bitsWrite(buff, 15, 1, 1); /* protection_absent */
bitsWrite(buff, 16, 2, 01); /* profile_objecttype */
bitsWrite(buff, 18, 4, m_sampleRateType);
bitsWrite(buff, 22, 1, 0); /* private_bit */
bitsWrite(buff, 23, 3, m_channels); /* channel_configuration */
bitsWrite(buff, 26, 1, 0); /* original_copy */
bitsWrite(buff, 27, 1, 0); /* home */
/* adts_variable_header */
bitsWrite(buff, 28, 1, 0); /* copyright_identification_bit */
bitsWrite(buff, 29, 1, 0); /* copyright_identification_start */
bitsWrite(buff, 30, 13, audioLen+AAC_HEADER_LEN); /* aac_frame_length */
bitsWrite(buff, 43, 11, 0x7ff); /* adts_buffer_fullness */
bitsWrite(buff, 54, 2, 0); /* number_of_raw_data_blocks_in_frame */
return AAC_HEADER_LEN;
}
void PsEncoder::setSampleRate(int rate)
{
m_sampleRateType = 0;
for(int i = 0; i < 16; ++i)
{
if(rate == samplingFrequencyTable[i])
m_sampleRateType = i;
}
}
void PsEncoder::setChannels(int channels)
{
m_channels = channels;
}