【问题标题】:ffmpeg does not decode some h264 streamsffmpeg 不解码某些 h264 流
【发布时间】:2016-04-09 17:37:20
【问题描述】:

我在本地网络上有一些摄像机 IP。我使用 live555 库接收视频流(我以 testRtspClient 为基础)并使用 ffmpeg (avcodec_decode_video2) 解码帧。一切都完美无缺。 当我尝试解码来自互联网的流时,问题就开始了。

第一个问题 - 一些数据包丢失,因此出现缺陷。但这不是问题。问题 - 在停止和启动视频流之后,需要等待大约 5 分钟的流式传输,然后 ffmpeg 才能从同一个 ip 摄像头解码某些内容。如果数据包没有丢失,那么一切正常。

第二个问题 - 有一个摄像头可以发送分辨率为 2048х1538 的视频。这种分辨率的帧是由几个数据包发送的。 live555通常将它们组合在一起,但是当帧传输到解码器时,解码器返回数据包长度,但帧总是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 没有返回第二个问题的帧(返回所有帧大小),但 avCodecContext 中的宽度和高度设置正确。我无法理解为什么它不返回帧。

谁能帮助解决这些问题?

【问题讨论】:

  • 你观察到有多少帧在第二个问题中没有返回帧?根据H264,解码后不一定要立即给出显示的帧。 H264 中的解码和显示顺序不同。所以,我建议你一般检查超过 16 帧以找到任何显示的帧
  • 感谢您的信息。在测试期间,第二个问题是第一个问题的结果。如果我第一次启动程序 - 好的,第二次 - 收到超过 16 帧并且没有解码。但是后来我决定使用 rtp 而不是 tcp 而不是 rtp 而不是 udp - 问题消失了。如果 rtp 使用 udp,则 50-100 中大约有 1 个数据包丢失,但我不明白为什么当我运行程序第二次或更多次时它如此重要。
  • 可能您的编码器会创建 IPPPPPP ..... 5 分钟,第二个 I Frame 出现。

标签: c++ ffmpeg h.264 decoder


【解决方案1】:

我通过使用 rtp over tcp 而不是 rtp over udp 解决了这些问题。

【讨论】:

    猜你喜欢
    • 2011-08-26
    • 2020-10-06
    • 2011-11-24
    • 2012-07-05
    • 2011-08-21
    • 2015-02-23
    • 2015-06-07
    • 2020-06-13
    • 2017-05-07
    相关资源
    最近更新 更多