第一步:使用ffmpeg取流,不解码
// TEST_RTMP.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "TranserStream.h"
#ifdef _WIN32
#include
#include
#pragma warning(disable:4996)
#else
#endif
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/mathematics.h"
#include "libavutil/time.h"
#include "SDL2/include/SDL.h"
};
uint64_t TimeMilliSecond()
{
timeb now;
ftime(&now);
return now.time * 1000 + now.millitm;
}
int _tmain(int argc, _TCHAR* argv[])
{
TranserStream m_Transfer;
m_Transfer.EnableWrite264(true);
m_Transfer.EnableWriteFlv(true);
m_Transfer.Init("rtmp://120.78.76.179:1935/hls/test");
av_register_all();
avformat_network_init();
AVFormatContext* pFormatContext = avformat_alloc_context();
if (avformat_open_input(&pFormatContext, "rtsp://192.168.0.105/live/main_stream", NULL, NULL) != 0) {
return 0;
}
if (avformat_find_stream_info(pFormatContext, NULL) < 0) {
return 0;
}
int dwVideoType = -1;
for (int i = 0; i < pFormatContext->nb_streams; i++) {
if (pFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
dwVideoType = i;
break;
}
}
AVCodecContext* pCodecContext = pFormatContext->streams[dwVideoType]->codec;
AVCodec* pCodec = avcodec_find_decoder(pCodecContext->codec_id);
if (avcodec_open2(pCodecContext, pCodec, NULL) != 0) {
avformat_close_input(&pFormatContext);
return 0;
}
int nGot = 0;
AVFrame* pFrame = av_frame_alloc();
AVFrame* pRGB = av_frame_alloc();
AVPacket* pPacket = (AVPacket*)av_malloc(sizeof(AVPacket));
int nPicSize = avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecContext->width, pCodecContext->height);
uint8_t* buf = (uint8_t*)av_malloc(nPicSize);
if (buf == NULL) {
printf("av malloc failed!\n");
exit(1);
}
avpicture_fill((AVPicture*)pRGB, buf, AV_PIX_FMT_YUV420P, pCodecContext->width, pCodecContext->height);
//SwsContext* pSws = sws_getContext(pCodecContext->width, pCodecContext->height, pCodecContext->pix_fmt, pCodecContext->width, pCodecContext->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
while (true) {
if (av_read_frame(pFormatContext, pPacket) >= 0) {
if (pPacket->stream_index == dwVideoType) {
if (avcodec_decode_video2(pCodecContext, pFrame, &nGot, pPacket) < 0) {
break;
}
if (nGot) {
//int nRet = sws_scale(pSws, pFrame->data, pFrame->linesize, 0, pCodecContext->height, pRGB->data, pRGB->linesize);
m_Transfer.PushData(pPacket->data, pPacket->size);
}
}
av_free_packet(pPacket);
}
else {
break;
}
}
//sws_freeContext(pSws);
av_free(pFrame);
av_free(pRGB);
av_free(buf);
avcodec_close(pCodecContext);
avformat_close_input(&pFormatContext);
m_Transfer.UnInit();
return 0;
}
第二步:推流
#include "stdafx.h"
#include "TranserStream.h"
#include
#include
#include
#pragma comment(lib, "ws2_32")
int GetLen(int nPos, int nTotalSize, BYTE* btData)
{
int nStart = nPos;
while (nStart < nTotalSize) {
if (btData[nStart] == 0x00 && btData[nStart + 1] == 0x00 && btData[nStart + 2] == 0x01) {
return nStart - nPos;
}
else if (btData[nStart] == 0x00 && btData[nStart + 1] == 0x00 && btData[nStart + 2] == 0x00 && btData[nStart + 3] == 0x01) {
return nStart - nPos;
}
else {
nStart++;
}
}
return nTotalSize - nPos;//最后一帧。
}
unsigned char Convert(unsigned char btData)
{
char cData[2048] = {0};
sprintf(cData, "%02x", btData);
return strtoull(cData, NULL, 16);
}
string TranserStream::GetFilePath(bool bValue)
{
#ifdef _WIN32
SYSTEMTIME stInfo;
GetLocalTime(&stInfo);
char cName[2048] = { 0 };
GetCurrentDirectoryA(2048, cName);
if (!bValue) {
sprintf(cName + strlen(cName), "\\%04d_%02d_%02d_%02d_%02d_%02d_%03d.264", stInfo.wYear, stInfo.wMonth, stInfo.wDay, stInfo.wHour, stInfo.wMinute, stInfo.wSecond, stInfo.wMilliseconds);
}
else {
sprintf(cName + strlen(cName), "\\%04d_%02d_%02d_%02d_%02d_%02d_%03d.flv", stInfo.wYear, stInfo.wMonth, stInfo.wDay, stInfo.wHour, stInfo.wMinute, stInfo.wSecond, stInfo.wMilliseconds);
}
return cName;
#else
#endif
}
void TranserStream::InitFile264()
{
string qstrFile = GetFilePath(false);
m_pFile264 = fopen(qstrFile.c_str(), "ab+");
}
void TranserStream::InitFileFlv()
{
string qstrFile = GetFilePath(true);
m_pFileFlv = fopen(qstrFile.c_str(), "ab+");
//
Save_flv_header();
}
TranserStream::TranserStream()
{
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
//
m_bWriteFile264 = false;
m_bWriteFileFlv = false;
//
m_nspsLen = 0;
m_nppsLen = 0;
memset(m_spsData, 0, 2048);
memset(m_ppsData, 0, 2048);
//
m_nIndex = 0;
m_nPreTagSize = 0;
//
m_pData = NULL;
while (!m_pData) {
try {
m_pData = new unsigned char[20 * 2048 * 2048];
}
catch (...) {}
}
//
m_pTransferData = NULL;
while (!m_pTransferData) {
try{
m_pTransferData = new unsigned char[40 * 1024 * 1024];
}
catch (...) {}
}
//
m_hCLOSE_ALL_THREAD = CreateEvent(NULL, true, false, L"");//关闭事件
m_threadOfParseData = (HANDLE)_beginthreadex(NULL, 0, ParseDataThread, this, 0, NULL);
m_threadOfTransferData = (HANDLE)_beginthreadex(NULL, 0, TransferDataThread, this, 0, NULL);
//
InitFile264();
InitFileFlv();
}
TranserStream::~TranserStream()
{
if (m_pFile264) {
fclose(m_pFile264);
}
if (m_pFileFlv) {
fclose(m_pFileFlv);
}
SetEvent(m_hCLOSE_ALL_THREAD);
WaitForSingleObject(m_threadOfParseData, INFINITE);
CloseHandle(m_threadOfParseData);
WaitForSingleObject(m_threadOfTransferData, INFINITE);
CloseHandle(m_threadOfTransferData);
CloseHandle(m_hCLOSE_ALL_THREAD);
#ifdef _WIN32
WSACleanup();
#endif
if (m_pData) {
delete[]m_pData;
m_pData = NULL;
}
if (m_pTransferData) {
delete[] m_pTransferData;
m_pTransferData = NULL;
}
}
bool TranserStream::Init(char* pUrl)
{
m_pRTMP = RTMP_Alloc();
RTMP_Init(m_pRTMP);
// 设置推流地址
m_pRTMP->Link.timeout = 10;
m_pRTMP->Link.lFlags |= RTMP_LF_LIVE;
RTMP_SetupURL(m_pRTMP, pUrl);
// 开启推流标志
RTMP_EnableWrite(m_pRTMP);
// 连接服务器
int b = RTMP_Connect(m_pRTMP, NULL);
if (!b)
{
return false;
}
// 连接流地址
b = RTMP_ConnectStream(m_pRTMP, 0);
if (!b)
{
return false;
}
return true;
}
void TranserStream::UnInit()
{
RTMP_Close(m_pRTMP);
RTMP_Free(m_pRTMP);
}
FrameData* TranserStream::MallocFrame(int nLen)
{
FrameData* pstData = NULL;
while (!pstData) {
try {
pstData = new FrameData;
}
catch (...) {}
}
pstData->pData = NULL;
pstData->nLen = nLen;
while (!pstData->pData) {
try {
pstData->pData = new unsigned char[nLen];
}
catch (...) {}
}
return pstData;
}
void TranserStream::SaveFile264(unsigned char* pData, uint32_t nLen)
{
if (m_bWriteFile264) {
if (m_pFile264) {
fwrite(pData, 1, nLen, m_pFile264);
long nSize = ftell(m_pFile264);
if (nSize >= 100 * 1024 * 1024) {
fclose(m_pFile264);
m_pFile264 = NULL;
}
}
}
}
void TranserStream::SaveFileFlv(unsigned char* pData, uint32_t nLen, bool bFlvHeader)
{
if (m_bWriteFileFlv || bFlvHeader) {
if (m_pFileFlv) {
fwrite(pData, 1, nLen, m_pFileFlv);
long nSize = ftell(m_pFileFlv);
if (nSize >= 100 * 1024 * 1024) {
fclose(m_pFileFlv);
m_pFileFlv = NULL;
}
}
}
}
void TranserStream::Save_flv_header()
{
unsigned char btData[FLV_HEADER] = { 0x46, 0x4c, 0x56, 0x01, 0x01, 0x00, 0x00, 0x00, 0x09 };
SaveFileFlv(btData, FLV_HEADER, true);
Save_flv_script(614.28, 1920.0, 1080.0, 25.0, 7.0, 77777.0);
}
void TranserStream::Save_flv_script(double dbDuration, double dbWidth, double dbHeight, double dbFrameRate, double dbCodeID, double dvFileSize)
{
unsigned char btScriptData[196] = { 0 };
//script previous Tag size
btScriptData[0] = 0x00;
btScriptData[1] = 0x00;
btScriptData[2] = 0x00;
btScriptData[3] = 0x00;
//
btScriptData[4] = 0x12;//18:脚本
//DataSize
btScriptData[5] = 0x00;//
btScriptData[6] = 0x00;//
btScriptData[7] = 0xB8;//
//TimeStamp
btScriptData[8] = 0x00;
btScriptData[9] = 0x00;
btScriptData[10] = 0x00;
//TimeStamp Extended
btScriptData[11] = 0x00;
//stram ID
btScriptData[12] = 0x00;
btScriptData[13] = 0x00;
btScriptData[14] = 0x00;
//------------------------------------------------------------------------------------
//第一个AMF包类型,总为0x02
btScriptData[15] = 0x02;
//第一个AMF包数据长度
btScriptData[16] = 0x00;
btScriptData[17] = 0x0A;
//onMetaData
btScriptData[18] = 0x6f;
btScriptData[19] = 0x6e;
btScriptData[20] = 0x4d;
btScriptData[21] = 0x65;
btScriptData[22] = 0x74;
btScriptData[23] = 0x61;
btScriptData[24] = 0x44;
btScriptData[25] = 0x61;
btScriptData[26] = 0x74;
btScriptData[27] = 0x61;
//------------------------------------------------------------------------------------
//第2个AMF包类型,总为0x08
btScriptData[28] = 0x08;
//medtaData count
btScriptData[29] = 0x00;
btScriptData[30] = 0x00;
btScriptData[31] = 0x00;
btScriptData[32] = 0x08;//metaData的数量
//------------------------------------------------------------------------------------
//时长
btScriptData[33] = 0x00;
btScriptData[34] = 0x08;//duration长度
//duration字符串
btScriptData[35] = 0x64;
btScriptData[36] = 0x75;
btScriptData[37] = 0x72;
btScriptData[38] = 0x61;
btScriptData[39] = 0x74;
btScriptData[40] = 0x69;
btScriptData[41] = 0x6f;
btScriptData[42] = 0x6e;
//.
btScriptData[43] = 0x00;
//duration数值
{
unsigned char* p = (unsigned char*)&dbDuration;
char cDuration[sizeof(double)] = { 0 };//double 占8个字节
for (int i = 0; i < sizeof(double); i++)
{
sprintf(cDuration, "%02x", p[i]);
}
int j = 0;
for (int i = sizeof(double) - 1; i >= 0; i--) {
btScriptData[44 + j] = cDuration[i];
j++;
}
}
//------------------------------------------------------------------------------------
//width
btScriptData[52] = 0x00;
btScriptData[53] = 0x05;//width这5个字符的长度
//width字符串
btScriptData[54] = 0x77;
btScriptData[55] = 0x69;
btScriptData[56] = 0x64;
btScriptData[57] = 0x74;
btScriptData[58] = 0x68;
//
btScriptData[59] = 0x00;
//
{
unsigned char* p = (unsigned char*)&dbWidth;
char cData[sizeof(double)] = { 0 };//double 占8个字节
for (int i = 0; i < sizeof(double); i++)
{
sprintf(cData, "%02x", p[i]);
}
int j = 0;
for (int i = sizeof(double) - 1; i >= 0; i--) {
btScriptData[60 + j] = cData[i];
j++;
}
}
//------------------------------------------------------------------------------------
//height
btScriptData[68] = 0x00;
btScriptData[69] = 0x06;//height这5个字符的长度
//height字符串
btScriptData[70] = 0x77;
btScriptData[71] = 0x69;
btScriptData[72] = 0x64;
btScriptData[73] = 0x74;
btScriptData[74] = 0x68;
btScriptData[75] = 0x74;
//
btScriptData[76] = 0x00;
//
{
unsigned char* p = (unsigned char*)&dbHeight;
char cData[sizeof(double)] = { 0 };//double 占8个字节
for (int i = 0; i < sizeof(double); i++)
{
sprintf(cData, "%02x", p[i]);
}
int j = 0;
for (int i = sizeof(double) - 1; i >= 0; i--) {
btScriptData[77 + j] = cData[i];
j++;
}
}
//------------------------------------------------------------------------------------
//videodatarate
btScriptData[85] = 0x00;
btScriptData[86] = 0x0D;//videodatarate这几个字符的长度
//videodatarate字符串
btScriptData[87] = 0x76;
btScriptData[88] = 0x69;//
btScriptData[88] = 0x64;
btScriptData[90] = 0x65;//
btScriptData[91] = 0x6f;
btScriptData[92] = 0x64;//
btScriptData[93] = 0x61;
btScriptData[94] = 0x74;//
btScriptData[95] = 0x61;
btScriptData[96] = 0x72;//
btScriptData[97] = 0x61;
btScriptData[98] = 0x74;//
btScriptData[99] = 0x65;//
//.
btScriptData[100] = 0x00;
//
btScriptData[101] = 0x00;//
btScriptData[102] = 0x00;//
btScriptData[103] = 0x00;
btScriptData[104] = 0x00;//
btScriptData[105] = 0x00;//
btScriptData[106] = 0x00;
btScriptData[107] = 0x00;//
btScriptData[108] = 0x00;//
//------------------------------------------------------------------------------------
//framerate
btScriptData[109] = 0x00;
btScriptData[110] = 0x09;//这几个字符的长度
//framerate字符串
btScriptData[111] = 0x66;
btScriptData[112] = 0x72;//
btScriptData[113] = 0x61;
btScriptData[114] = 0x6d;//
btScriptData[115] = 0x65;
btScriptData[116] = 0x72;//
btScriptData[117] = 0x61;
btScriptData[118] = 0x74;//
btScriptData[119] = 0x65;
//.
btScriptData[120] = 0x00;
//
{
unsigned char* p = (unsigned char*)&dbFrameRate;
char cData[sizeof(double)] = { 0 };//double 占8个字节
for (int i = 0; i < sizeof(double); i++)
{
sprintf(cData, "%02x", p[i]);
}
int j = 0;
for (int i = sizeof(double) - 1; i >= 0; i--) {
btScriptData[121 + j] = cData[i];
j++;
}
}
//------------------------------------------------------------------------------------
//videocodecid
btScriptData[129] = 0x00;
btScriptData[130] = 0x0c;//这几个字符的长度
//videocodecid字符串
btScriptData[131] = 0x76;
btScriptData[132] = 0x69;//
btScriptData[133] = 0x64;
btScriptData[134] = 0x65;//
btScriptData[135] = 0x6f;
btScriptData[136] = 0x63;//
btScriptData[137] = 0x6f;
btScriptData[138] = 0x64;//
btScriptData[139] = 0x65;
btScriptData[140] = 0x63;
btScriptData[141] = 0x69;//
btScriptData[142] = 0x64;
//
btScriptData[143] = 0x00;
//
{
unsigned char* p = (unsigned char*)&dbCodeID;
char cData[sizeof(double)] = { 0 };//double 占8个字节
for (int i = 0; i < sizeof(double); i++)
{
sprintf(cData, "%02x", p[i]);
}
int j = 0;
for (int i = sizeof(double) - 1; i >= 0; i--) {
btScriptData[144 + j] = cData[i];
j++;
}
}
//------------------------------------------------------------------------------------
//encoder
btScriptData[152] = 0x00;
btScriptData[153] = 0x07;//这几个字符的长度
btScriptData[154] = 0x65;
btScriptData[155] = 0x6e;//
btScriptData[156] = 0x63;
btScriptData[157] = 0x6f;//
btScriptData[158] = 0x64;
btScriptData[159] = 0x65;//
btScriptData[160] = 0x72;
//.
btScriptData[161] = 0x02;
btScriptData[162] = 0x00;
//
btScriptData[163] = 0x0d;
btScriptData[164] = 0x4c;
btScriptData[165] = 0x61;
btScriptData[166] = 0x76;
btScriptData[167] = 0x66;
btScriptData[168] = 0x35;
btScriptData[169] = 0x37;
btScriptData[170] = 0x2e;
btScriptData[171] = 0x35;
btScriptData[172] = 0x36;
btScriptData[173] = 0x2e;
btScriptData[174] = 0x31;
btScriptData[175] = 0x30;
btScriptData[176] = 0x31;
//------------------------------------------------------------------------------------
//encoder
btScriptData[177] = 0x00;
btScriptData[178] = 0x08;//这几个字符的长度
btScriptData[179] = 0x66;
btScriptData[180] = 0x69;
btScriptData[181] = 0x6c;
btScriptData[182] = 0x65;
btScriptData[183] = 0x73;
btScriptData[184] = 0x69;
btScriptData[185] = 0x7a;
btScriptData[186] = 0x65;
//
btScriptData[187] = 0x00;
//
{
unsigned char* p = (unsigned char*)&dvFileSize;
char cData[sizeof(double)] = { 0 };//double 占8个字节
for (int i = 0; i < sizeof(double); i++)
{
sprintf(cData, "%02x", p[i]);
}
int j = 0;
for (int i = sizeof(double) - 1; i >= 0; i--) {
btScriptData[188 + j] = cData[i];
j++;
}
}
SaveFileFlv(btScriptData, 196, true);
//List Terminator 解析见表SCRIPTDATAOBJECTEND (数组结束位,占3个字节 一定为 0x 00 00 09)
unsigned char btDataOfTerminator[3] = { 0x00, 0x00, 0x09 };
SaveFileFlv(btDataOfTerminator, 3, true);
//
//unsigned char btData[PREVIOUS_TAG_SIZE] = {0x00, 0x00, 0x00, 0xc3};
//SaveFileFlv(btData, PREVIOUS_TAG_SIZE, true);
m_nPreTagSize = 0xc3;
}
void TranserStream::Save_flv_spsData(uint8_t nType)
{
//1个字节的FrameType
//1个字节的AVC Packet Type
//3个字节的CompositionTime Offset
//1个字节的ConfigurationVersion
//1个字节的AVC Profile Indication
//1个字节的profile compatibility
//1个字节的AVC Level Indication
//1个字节的LengthSizeMinusOne
//1个字节的sps的个数
//2个字节的sps的长度
//1个字节的pps的个数
//2个字节的pps的长度
int nLen = m_nspsLen + m_nppsLen + 16;
unsigned char btTagHeader[TAG_HEADER] = { 0x00 };
//Tag类型:
//8:音频
//9:视频
//18:脚本
//其他:保留
btTagHeader[0] = nType;
//数据长度
btTagHeader[1] = (nLen >> 16) & 0xff;
btTagHeader[2] = (nLen >> 8) & 0xff;
btTagHeader[3] = nLen & 0xff;
//时间戳
btTagHeader[4] = 0;
btTagHeader[5] = 0;
btTagHeader[6] = 0;
btTagHeader[7] = 0;
//streamID
btTagHeader[8] = 0;
btTagHeader[9] = 0;
btTagHeader[10] = 0;
//------------------------------------------------------------------------------
//Tag Data
unsigned char btAVCData[2048] = { 0 };
//Tag Data的第一个字节是视频信息或音频信息
//帧类型(4 bit):
//1: keyframe(for AVC, a seekable frame)
//2 : inter frame(for AVC, a non - seekable frame)
//3 : disposable inter frame(H.263 only)
//4 : generated keyframe(reserved for server use only)
//5 : video info / command frame
//编码ID(4 bit):
//1: JPEG(currently unused)
//2 : Sorenson H.263
//3 : Screen video
//4 : On2 VP6
//5 : On2 VP6 with alpha channel
//6 : Screen video version 2
//7 : AVC
btAVCData[0] = 0x17;//看注释.关键帧且为AVC数据
//AVC Packet Type
//0: AVC sequence header
//1: AVC NALU
//2: AVC end of sequence
btAVCData[1] = 0x00;
//CompositionTime Offset
btAVCData[2] = 0x00;//默认为0
btAVCData[3] = 0x00;
btAVCData[4] = 0x00;
btAVCData[5] = 1;// 版本号
btAVCData[6] = m_spsData[1];//将sps的从第2位开始的三个数据拷贝进来
btAVCData[7] = m_spsData[2];
btAVCData[8] = m_spsData[3];
btAVCData[9] = 0xff;//需要查看其他情况下的值是多少
//二进制 1110 0000 + sps个数
btAVCData[10] = 0xe0 + 1;
//sps 数据长度
btAVCData[11] = (m_nspsLen >> 8) & 0xff;
btAVCData[12] = m_nspsLen & 0xff;
//sps 数据
memcpy(btAVCData + 13, m_spsData, m_nspsLen);
//pps个数
btAVCData[m_nspsLen + 13] = 1;
//pps 数据长度
btAVCData[m_nspsLen + 14] = (m_nppsLen >> 8) & 0xff;
btAVCData[m_nspsLen + 15] = m_nppsLen & 0xff;
//pps 数据
memcpy(btAVCData + m_nspsLen + 16, m_ppsData, m_nppsLen);
//
Transer(nType, btAVCData, nLen, 0);
//------------------------------------------------------------------------------------------------------------------
//preTag 长度
unsigned char btPreTagData[4] = { 0 };
btPreTagData[0] = (m_nPreTagSize >> 24) & 0xff;
btPreTagData[1] = (m_nPreTagSize >> 16) & 0xff;
btPreTagData[2] = (m_nPreTagSize >> 8) & 0xff;
btPreTagData[3] = m_nPreTagSize & 0xff;
SaveFileFlv( btPreTagData, 4);
//
SaveFileFlv( btTagHeader, TAG_HEADER);
SaveFileFlv( btAVCData, m_nspsLen + m_nppsLen + 16);
//------------------------------------------------------------------------------------------------------------------
//
m_nIndex++;
m_nPreTagSize = TAG_HEADER + nLen;
}
void TranserStream::Saveflv_toFile(unsigned char* pData, uint32_t nLen, uint8_t nType)
{
#define TAG_DATA_NALU_HEADER 9
unsigned char btTagHeader[TAG_HEADER] = { 0x00 };
//Tag类型:
//8:音频
//9:视频
//18:脚本
//其他:保留
btTagHeader[0] = nType;
//数据长度
btTagHeader[1] = ((nLen + TAG_DATA_NALU_HEADER) >> 16) & 0xff;
btTagHeader[2] = ((nLen + TAG_DATA_NALU_HEADER) >> 8) & 0xff;
btTagHeader[3] = (nLen + TAG_DATA_NALU_HEADER) & 0xff;
//时间戳
unsigned long long nTime = m_nIndex * 40;
btTagHeader[4] = Convert(((nTime) >> 16) & 0xff);
btTagHeader[5] = Convert(((nTime) >> 8) & 0xff);
btTagHeader[6] = Convert(nTime & 0xff);
btTagHeader[7] = 0;
//streamID
btTagHeader[8] = 0;
btTagHeader[9] = 0;
btTagHeader[10] = 0;
//
m_nIndex++;
//-------------------------------------------------------------------
//
unsigned char btAVCData[TAG_DATA_NALU_HEADER] = {0};
if ((pData[0] & 0x1f) == 0x05) {//关键帧
btAVCData[0] = 0x17;//看注释.关键帧且为AVC数据
}
else {
btAVCData[0] = 0x27;//看注释.关键帧且为AVC数据
}
if ((pData[0] & 0x1f) == 7 || (pData[0] & 0x1f) == 8) {//sps帧和pps帧
btAVCData[1] = 0x00;
}
else {
btAVCData[1] = 0x01;
}
btAVCData[2] = Convert(((nTime) >> 16) & 0xff);
btAVCData[3] = Convert(((nTime) >> 8) & 0xff);
btAVCData[4] = Convert(nTime & 0xff);
btAVCData[5] = (nLen >> 24) & 0xff;
btAVCData[6] = (nLen >> 16) & 0xff;
btAVCData[7] = (nLen >> 8) & 0xff;
btAVCData[8] = nLen & 0xff;
//
memcpy(m_pTransferData, btAVCData, TAG_DATA_NALU_HEADER);
memcpy(m_pTransferData + TAG_DATA_NALU_HEADER, pData, nLen);
Transer(nType, m_pTransferData, nLen + TAG_DATA_NALU_HEADER, nTime);
//preTag 长度
unsigned char btPreTagData[4] = { 0 };
btPreTagData[0] = (m_nPreTagSize >> 24) & 0xff;
btPreTagData[1] = (m_nPreTagSize >> 16) & 0xff;
btPreTagData[2] = (m_nPreTagSize >> 8) & 0xff;
btPreTagData[3] = m_nPreTagSize & 0xff;
SaveFileFlv( btPreTagData, 4);
//
SaveFileFlv( btTagHeader, TAG_HEADER);
SaveFileFlv( btAVCData, TAG_DATA_NALU_HEADER);
SaveFileFlv( pData, nLen);
//
m_nPreTagSize = TAG_HEADER + TAG_DATA_NALU_HEADER + nLen;
}
void TranserStream::PushData(unsigned char* pData, uint32_t nLen)
{
SaveFile264(pData, nLen);
//
FrameData* pstData = MallocFrame(nLen);
memcpy(pstData->pData, pData, nLen);
//
m_mutexOfPacket.lock();
m_vPacketData.push_back(pstData);
m_mutexOfPacket.unlock();
}
void TranserStream::ParseData(unsigned char* pData, uint32_t dwFileSize)
{
int j = 0;//多少帧
int i = 0;//偏移量
while (i < dwFileSize - H264_HEADER2) {
if (pData[i] == 0x00 && pData[i + 1] == 0x00 && pData[i + 2] == 0x01) {
int nLen = GetLen(i + H264_HEADER1, dwFileSize, (unsigned char*)pData);
FrameData* pstData = MallocFrame(nLen);
memset(pstData->pData, 0, nLen);
memcpy(pstData->pData, &pData[i + H264_HEADER1], nLen);
//
m_mutexOfFrame.lock();
m_vFrameData.push_back(pstData);
m_mutexOfFrame.unlock();
j++;
i += H264_HEADER1;
}
else if (pData[i] == 0x00 && pData[i + 1] == 0x00 && pData[i + 2] == 0x00 && pData[i + 3] == 0x01) {
int nLen = GetLen(i + H264_HEADER2, dwFileSize, (unsigned char*)pData);
FrameData* pstData = MallocFrame(nLen);
memset(pstData->pData, 0, nLen);
memcpy(pstData->pData, &pData[i + H264_HEADER2], nLen);
//
m_mutexOfFrame.lock();
m_vFrameData.push_back(pstData);
m_mutexOfFrame.unlock();
//
j++;
i += H264_HEADER2;
}
else {
i++;
}
}
}
unsigned int TranserStream::ParseDataThread(void* args)
{
TranserStream* pThis = (TranserStream*)args;
while (true) {
if (WaitForSingleObject(pThis->m_hCLOSE_ALL_THREAD, 0) == WAIT_OBJECT_0) {
break;
}
FrameData* pstData = NULL;
pThis->m_mutexOfPacket.lock();
if (pThis->m_vPacketData.size() > 0) {
pstData = pThis->m_vPacketData[0];
pThis->m_vPacketData.erase(pThis->m_vPacketData.begin());
}
pThis->m_mutexOfPacket.unlock();
if (pstData) {
pThis->ParseData(pstData->pData, pstData->nLen);
delete pstData;
pstData = NULL;
}
}
return 0;
}
unsigned int TranserStream::TransferDataThread(void* args)
{
bool b_sps_exists = false;
bool b_pps_exists = false;
TranserStream* pThis = (TranserStream*)args;
while (true) {
if (WaitForSingleObject(pThis->m_hCLOSE_ALL_THREAD, 0) == WAIT_OBJECT_0) {
break;
}
FrameData* pstData = NULL;
pThis->m_mutexOfFrame.lock();
if (pThis->m_vFrameData.size() > 0) {
pstData = pThis->m_vFrameData[0];
pThis->m_vFrameData.erase(pThis->m_vFrameData.begin());
}
pThis->m_mutexOfFrame.unlock();
if (pstData) {
if ((pstData->pData[0] & 0x1f) == 7) {//sps
pThis->m_nspsLen = pstData->nLen;
b_sps_exists = true;
memset(pThis->m_spsData, 0, 2048);
memcpy(pThis->m_spsData, pstData->pData, pstData->nLen);
}
else if ((pstData->pData[0] & 0x1f) == 8) {//pps
pThis->m_nppsLen = pstData->nLen;
b_pps_exists = true;
memset(pThis->m_ppsData, 0, 2048);
memcpy(pThis->m_ppsData, pstData->pData, pstData->nLen);
}
else {//关键帧
pThis->Saveflv_toFile(pstData->pData, pstData->nLen, TagType_Video);
}
delete pstData;
pstData = NULL;
}
if (b_sps_exists && b_pps_exists) {
b_sps_exists = false;
b_pps_exists = false;
pThis->Save_flv_spsData(TagType_Video);
}
}
return 0;
}
void TranserStream::EnableWrite264(bool bValue)
{
m_bWriteFile264 = bValue;
}
void TranserStream::EnableWriteFlv(bool bValue)
{
m_bWriteFileFlv = bValue;
}
bool TranserStream::Transer(uint8_t nType, unsigned char* pData, uint32_t nLen, uint32_t timestamp)
{
// 初使化RTMP报文
RTMPPacket* packet = (RTMPPacket*)malloc(RTMP_HEAD_SIZE + nLen);
memset(packet, 0, RTMP_HEAD_SIZE);
packet->m_body = (char*)packet + RTMP_HEAD_SIZE;
packet->m_nBodySize = nLen;
memcpy(packet->m_body, pData, nLen);
packet->m_hasAbsTimestamp = 0;
packet->m_packetType = nType;
packet->m_nInfoField2 = m_pRTMP->m_stream_id;
packet->m_nChannel = 6;
// 组织报文并发送
packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
if (RTMP_PACKET_TYPE_AUDIO == nType && nLen != 4)
{
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
}
packet->m_nTimeStamp = timestamp;
if (!RTMP_SendPacket(m_pRTMP, packet, 0))
{
free(packet);
return false;
}
free(packet);
return true;
}
Demo: