ffmpeg 不解码某些 h264 流
ffmpeg does not decode some h264 streams
我在本地有一些摄像头的 ip network.I 使用 live555 库接收视频流(我以 testRtspClient 为基础)并使用 ffmpeg 解码帧(avcodec_decode_video2)。一切都完美无缺。
当我尝试解码来自互联网的流时,问题就开始了。
第一个问题——部分数据包丢失,出现缺陷。但这不是问题。问题 - 在停止和启动视频流后,需要等待大约 5 分钟的流式传输,然后 ffmpeg 才能解码来自同一网络摄像机的内容。如果没有丢包就ok了
第二个问题——有摄像头发送分辨率为2048х1538的视频。这种分辨率的帧由几个数据包发送。 live555 通常将它们放在一起但是当帧传输到解码器时,解码器 returns 数据包长度,但得到的帧总是 0.
这是我的一些代码:
#define RECEIVE_BUFFER_SIZE 1000000
AVCodecContext* avCodecContext; //definition
AVFrame *frame; //definition
...
//init code
_fReceiveBuffer = new uint8_t[RECEIVE_BUFFER_SIZE+512]; //buffer to receive frame
ZeroMemory(_fReceiveBuffer, RECEIVE_BUFFER_SIZE + 512); //zeros
_bufferSize = RECEIVE_BUFFER_SIZE * sizeof(uint8_t); //buffer size
static const uint8_t startCode[4] = { 0x00, 0x00, 0x00, 0x01 }; //this is for 0 0 0 1
//before frame will transfer to decoder
memcpy(_fReceiveBuffer, (void*)startCode, sizeof(uint8_t)* 4);
_fReceiveBuffer += sizeof(sizeof(uint8_t)* 4);
_bufferSize -= sizeof(sizeof(uint8_t)* 4);
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); //find codec
avCodecContext = avcodec_alloc_context3(codec);
avCodecContext->flags |= AV_PKT_FLAG_KEY;
avcodec_open2(avCodecContext, codec, NULL);
frame = av_frame_alloc();
//frame
void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned durationInMicroseconds) {
if (strcmp(fSubsession.codecName(), "H264") == 0)
{
//code from onvif device manager
static const uint8_t startCode3[] = { 0x00, 0x00, 0x01 };
static const uint8_t startCode4[] = { 0x00, 0x00, 0x00, 0x01 };
auto correctedFrameSize = frameSize;
auto correctedBufferPtr = fPlObj->_fReceiveBuffer;
if (frameSize < sizeof(startCode4) || memcmp(startCode4, correctedBufferPtr, sizeof(startCode4)) != 0){
if (frameSize < sizeof(startCode3) || memcmp(startCode3, correctedBufferPtr, sizeof(startCode3)) != 0){
correctedFrameSize += sizeof(uint8_t)* 4;
correctedBufferPtr -= sizeof(uint8_t)* 4;
}
}
ProcessFrame(correctedBufferPtr, correctedFrameSize, presentationTime, durationInMicroseconds);
}
continuePlaying();
}
void DummySink::ProcessFrame(unsigned char* framePtr, int frameSize, struct timeval presentationTime, unsigned duration) {
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = framePtr;
avpkt.size = frameSize;
while (avpkt.size > 0) {
int got_frame = 0;
int len = avcodec_decode_video2(avCodecContext, frame, &got_frame, &avpkt);
if (len < 0) {
//TODO: log error
return;
}
else if (got_frame == 0)
{
//I tried this code, bacause "codecs which have the AV_CODEC_CAP_DELAY capability set have a delay between input and output"
//but it didn't help
/*AVPacket emptyPacket;
av_init_packet(&emptyPacket);
emptyPacket.data = NULL;
emptyPacket.size = 0;
emptyPacket.stream_index = avpkt.stream_index;
len = avcodec_decode_video2(avCodecContext, frame, &got_frame, &emptyPacket);
if ( got_frame == 1) goto next;*/
return;
}
next:
//... here code for view with DirectDraw - everithing ok with it
avpkt.size -= len;
avpkt.data += len;
}
}
我还尝试使用 sps 和 pps 信息将帧发送到解码器:
0 0 0 1 sps 0 0 0 1 pps 0 0 0 1 frame
但这并没有帮助。
有趣的是 avcodec_decode_video2 没有 return 框架与第二个问题(return 框架的所有大小),但 avCodecContext 中的宽度和高度设置正确。我不明白为什么它没有 return 框架。
任何人都可以帮助解决这些问题吗?
我通过使用 rtp over tcp 而不是 rtp over udp 解决了这些问题。
我在本地有一些摄像头的 ip network.I 使用 live555 库接收视频流(我以 testRtspClient 为基础)并使用 ffmpeg 解码帧(avcodec_decode_video2)。一切都完美无缺。 当我尝试解码来自互联网的流时,问题就开始了。
第一个问题——部分数据包丢失,出现缺陷。但这不是问题。问题 - 在停止和启动视频流后,需要等待大约 5 分钟的流式传输,然后 ffmpeg 才能解码来自同一网络摄像机的内容。如果没有丢包就ok了
第二个问题——有摄像头发送分辨率为2048х1538的视频。这种分辨率的帧由几个数据包发送。 live555 通常将它们放在一起但是当帧传输到解码器时,解码器 returns 数据包长度,但得到的帧总是 0.
这是我的一些代码:
#define RECEIVE_BUFFER_SIZE 1000000
AVCodecContext* avCodecContext; //definition
AVFrame *frame; //definition
...
//init code
_fReceiveBuffer = new uint8_t[RECEIVE_BUFFER_SIZE+512]; //buffer to receive frame
ZeroMemory(_fReceiveBuffer, RECEIVE_BUFFER_SIZE + 512); //zeros
_bufferSize = RECEIVE_BUFFER_SIZE * sizeof(uint8_t); //buffer size
static const uint8_t startCode[4] = { 0x00, 0x00, 0x00, 0x01 }; //this is for 0 0 0 1
//before frame will transfer to decoder
memcpy(_fReceiveBuffer, (void*)startCode, sizeof(uint8_t)* 4);
_fReceiveBuffer += sizeof(sizeof(uint8_t)* 4);
_bufferSize -= sizeof(sizeof(uint8_t)* 4);
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); //find codec
avCodecContext = avcodec_alloc_context3(codec);
avCodecContext->flags |= AV_PKT_FLAG_KEY;
avcodec_open2(avCodecContext, codec, NULL);
frame = av_frame_alloc();
//frame
void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned durationInMicroseconds) {
if (strcmp(fSubsession.codecName(), "H264") == 0)
{
//code from onvif device manager
static const uint8_t startCode3[] = { 0x00, 0x00, 0x01 };
static const uint8_t startCode4[] = { 0x00, 0x00, 0x00, 0x01 };
auto correctedFrameSize = frameSize;
auto correctedBufferPtr = fPlObj->_fReceiveBuffer;
if (frameSize < sizeof(startCode4) || memcmp(startCode4, correctedBufferPtr, sizeof(startCode4)) != 0){
if (frameSize < sizeof(startCode3) || memcmp(startCode3, correctedBufferPtr, sizeof(startCode3)) != 0){
correctedFrameSize += sizeof(uint8_t)* 4;
correctedBufferPtr -= sizeof(uint8_t)* 4;
}
}
ProcessFrame(correctedBufferPtr, correctedFrameSize, presentationTime, durationInMicroseconds);
}
continuePlaying();
}
void DummySink::ProcessFrame(unsigned char* framePtr, int frameSize, struct timeval presentationTime, unsigned duration) {
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = framePtr;
avpkt.size = frameSize;
while (avpkt.size > 0) {
int got_frame = 0;
int len = avcodec_decode_video2(avCodecContext, frame, &got_frame, &avpkt);
if (len < 0) {
//TODO: log error
return;
}
else if (got_frame == 0)
{
//I tried this code, bacause "codecs which have the AV_CODEC_CAP_DELAY capability set have a delay between input and output"
//but it didn't help
/*AVPacket emptyPacket;
av_init_packet(&emptyPacket);
emptyPacket.data = NULL;
emptyPacket.size = 0;
emptyPacket.stream_index = avpkt.stream_index;
len = avcodec_decode_video2(avCodecContext, frame, &got_frame, &emptyPacket);
if ( got_frame == 1) goto next;*/
return;
}
next:
//... here code for view with DirectDraw - everithing ok with it
avpkt.size -= len;
avpkt.data += len;
}
}
我还尝试使用 sps 和 pps 信息将帧发送到解码器:
0 0 0 1 sps 0 0 0 1 pps 0 0 0 1 frame
但这并没有帮助。
有趣的是 avcodec_decode_video2 没有 return 框架与第二个问题(return 框架的所有大小),但 avCodecContext 中的宽度和高度设置正确。我不明白为什么它没有 return 框架。
任何人都可以帮助解决这些问题吗?
我通过使用 rtp over tcp 而不是 rtp over udp 解决了这些问题。