以下情况时使用了GB28181 中 udp发送视频流的情况,有的相机udp丢包比较严重,有的可以,对有问题的相机着重进行分析
read ps
RTP测试工具进一步升级
今天写了一段程序,为了解决花屏的问题,需要知道问题到底在哪里,保存了几百个ps文件,然后读出按照流程保存成h264文件,使用vlc 工具读,有简单跳帧。
int main_ps()
{
int meetkeyframe = 0;
const char* buffer = "j:/ps/h264save%d.264";
char filename[128];
uint8_t* h264buffer = new uint8_t[1024 * 500];
int h264length = 0;
int skip = 0;
FILE* fpw = fopen("j:/out1.264", "wb");
for (int i = 0; i < 2855; i++)
{
sprintf(filename, buffer, i);
FILE* fp = fopen(filename, "rb");
if (fp != NULL)
{
fseek(fp, 0, SEEK_END);
long len = ftell(fp);
fseek(fp, 0, SEEK_SET);
//fread(pp, sizeof(char) * 4, 1, fp);
uint8_t* data = new uint8_t[len];
fread(data, len, 1, fp);
if (*data == 0x00 && *(data + 1) == 0x00 && *(data + 2) == 0x01 && *(data + 3) == 0xba)
{
GetH264FromPs((char*)data, len, (char*)h264buffer, &h264length);
if (h264length > 0)
{
if (meetkeyframe == 0)
{
uint8_t* pos = h264buffer + 4;
if ((*pos & 0x1f) == 0x07)
meetkeyframe = 1;
}
if (meetkeyframe == 1)
{
std::cout << "the length "<<len<< "--" << h264length << std::endl;
fwrite(h264buffer, h264length, 1, fpw);
}
else
{
std::cout << "skip num" << skip++ << std::endl;
}
}
}
std::cout << "the file of" << i << std::endl;
fclose(fp);
}
}
fclose(fpw);
return 0;
}
read rtp
为了进一步确定问题,读了1万6000个RTP包存储成文件,在存储成h264看情况如何
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "../libRtpReceive/analysevideo.h"
#include "../libRtpReceive/c_rtp.h"
s_rtp_context g_ctx;
//解ps流,qianbo 请按照这条路走下去
int live_rtp_unpack_ps(s_rtp_context* ctx, uint8_t* payload, int payloadlen, uint32_t ssrc)
{
uint8_t* buffer = ctx->v_buffer;
int& buflen = ctx->v_len;
//analyse_struct &as = ctx->v_as;
#define D(x) *(payload+x)
if (D(0) == 0x00 && D(1) == 0x00 && D(2) == 0x01 && D(3) == 0xc0)
{
//(音频数据包)
//std::cout << "audio packet" << std::endl;
return 0;
}
if (D(0) == 0x00 && D(1) == 0x00 && D(2) == 0x01 && D(3) == 0xba)
{
if (buflen > 0)//数据已经凑齐,可以发送或者显示
{
#define B(x) *(buffer+x)
if (B(0) == 0x00 && B(1) == 0x00 && B(2) == 0x01 && B(3) == 0xba)
{
int h264length = 0;
uint8_t* h26xbuffer = new uint8_t[buflen];
GetH264FromPs((char*)buffer, buflen, (char*)h26xbuffer, &h264length);
if (h264length > 0)
{
if (g_ctx.v_meet_keyframe == 0)
{
uint8_t* pos = h26xbuffer + 4;
if ((*pos & 0x1f) == 0x07)
g_ctx.v_meet_keyframe = 1;
}
if (g_ctx.v_meet_keyframe == 1)
{
if (g_ctx.fwp == NULL)
g_ctx.fwp = fopen("j:/out2.264","wb");
//std::cout << "the length " << len << "--" << h264length << std::endl;
fwrite(h26xbuffer, h264length, 1, g_ctx.fwp);
}
else
{
//std::cout << "skip num" << skip++ << std::endl;
}
}
if (ctx->v_meet_keyframe == 0)
{
//写入文件
}
delete[]h26xbuffer;
}
buflen = 0;
}
}
//合帧
std::memcpy(buffer + buflen, payload, payloadlen);
buflen += payloadlen;
return 0;
}
int ReadRTPPacket(uint8_t* data, int dlen)
{
RTPFrame_ frame(data, (int)dlen);
uint8_t* payload = frame.GetPayloadPtr();
int payloadlen = frame.GetPayloadSize();
uint32_t timestamp = frame.GetTimestamp();
rtp_header* rtp = (rtp_header*)data;
//big(net) to little(home)
uint32_t ssrc = b2l(rtp->ssrc);
#define D(x) *(payload+x)
//if (ctx->v_is_ps == -1)//未曾确定是否ps流
if (D(0) == 0x00 && D(1) == 0x00 && D(2) == 0x01 && D(3) == 0xba)
{
//std::cout << " the stream is " << stream << std::endl;
g_ctx.v_ssrc = ssrc;
g_ctx.v_is_ps = 1;
}
if (g_ctx.v_is_ps == 1)
{
uint16_t nowseq = frame.GetSequenceNumber();
std::cout << "seq:" << nowseq << " ";
if (nowseq - g_ctx.v_last_sequenceNum != 1)
{
std::cout << "not continue seq "<< nowseq - g_ctx.v_last_sequenceNum <<std::endl;
}
g_ctx.v_last_sequenceNum = frame.GetSequenceNumber();
g_ctx.v_payloadtype = frame.GetPayloadType();
live_rtp_unpack_ps(&g_ctx, payload, payloadlen, ssrc);
}
return 0;
}
int main()
{
const char* buffer = "j:/rtp/h264saveRTP%d.264";
char filename[128];
uint8_t* h264buffer = new uint8_t[1024 * 500];
int h264length = 0;
int skip = 0;
//FILE* fpw = fopen("j:/out2.264", "wb");
for (int i = 0; i < 16445; i++)
{
sprintf(filename, buffer, i);
FILE* fp = fopen(filename, "rb");
if (fp != NULL)
{
fseek(fp, 0, SEEK_END);
long len = ftell(fp);
fseek(fp, 0, SEEK_SET);
//fread(pp, sizeof(char) * 4, 1, fp);
uint8_t* data = new uint8_t[len];
fread(data, len, 1, fp);
ReadRTPPacket(data, len);
//std::cout <<i <<" ";
fclose(fp);
}
}
if(g_ctx.fwp!=NULL)
fclose(g_ctx.fwp);
}
通过打印RTP包的sequence number,相减后发现,丢包较多,平均每隔一定的时间会丢3-4个RTP包,有时会丢掉几十个,上几百个包,乱序的情况比较少,有一次,通过seq number相减后会得到负数。
RTP工具以后会同时增加分析RTP协议的可视化。