Decode Fragmented HEVC Slices using FFMPEG only 1/3 of the frame decoded

432 views Asked by At

I'm having trouble to decode hevc stream from live 555 rtsp server, for some newer cameras the frame are encoded in different slices. based on the NAL value, it sends I frame then P frame and then unknown frame. I'm trying to follow the logic from this SO thread, trying to understand the logic.

here's the way I classify the frame type

int CH265Parser::CheckH265IorP(unsigned char* pData, unsigned long dwLen)
{
    int naltype = H265GetNALType(pData, dwLen);

    int frameType = 0;
    switch (naltype)
    {
    case NAL_VPS:
    case NAL_SPS:
    case NAL_PPS:
    {
        break;
    }
        
    case NAL_BLA_W_LP:
    case NAL_BLA_W_RADL:
    case NAL_BLA_N_LP:
    case NAL_IDR_W_RADL:
    case NAL_IDR_N_LP:
    case NAL_CRA_NUT:
    {
        // I-Frame
        frameType = 1;
        break;
    }
    case NAL_TRAIL_N:
    case NAL_TRAIL_R:
    case NAL_TSA_N:
    case NAL_TSA_R:
    case NAL_STSA_N:
    case NAL_STSA_R:
    case NAL_RADL_N:
    case NAL_RADL_R:
    case NAL_RASL_N:
    case NAL_RASL_R:
    {
        // P-Frame
        frameType = 2;
        break;
    }
    case NAL_AUD:               
    case NAL_SEI_SUFFIX:
    case NAL_SEI_PREFIX:
    {
        break;
    }

    default:
        break;
    }

    return frameType;
}

and here's how I get the NAL

int CH265Parser::H265GetNALType(void* pBSBuf, long nBSLen)
{
    if (nBSLen < 5)
        return -1;

    int pos = FindNALBegin((unsigned char*)pBSBuf, nBSLen);
    unsigned char* pBS = (unsigned char*)pBSBuf;
    unsigned long nType = (pBS[pos] >> 1) & 0x3F;
    if (nType >= NAL_TRAIL_N && nType <= NAL_SEI_SUFFIX)
        return nType;
    return -1;
}


long CH265Parser::FindNALBegin(unsigned char* pszBuffer, long nLength)
{
    for (int i = 0; i < nLength - 4; i++)
    {
        if (pszBuffer[i] == 0x00 && pszBuffer[i + 1] == 0x00)
        {
            if (pszBuffer[i + 2] == 0x01)
                return i + 3;
            else if (pszBuffer[i + 2] == 0x00 && pszBuffer[i + 3] == 0x01)
                return i + 4;
        }
    }
    return -1;
}

now based on the information, here's my decoder looks like (with additional info header to the buffer):

auto headSize = sizeof(isap::media::AV_HEADER);
    auto header = reinterpret_cast<const isap::media::AV_HEADER*>(packets_.data());
     std::string frameType = "I";
    if (header->nFrameType == isap::media::frame_type::_FRAME_TYPE_P)
        frameType = "P";
    else if (header->nFrameType == isap::media::frame_type::_FRAME_TYPE_UNKNOWN)
        frameType = "B";
    printf("frame %s\n", frameType.c_str());

    if (frameType == "P" || frameType == "B") {
        packets_ = packets_ + packet;
    }
    else if (frameType == "I") {
        packets_ = packet;
    }


    auto ec = decoder_.send(reinterpret_cast<const uint8_t*>(packets_.data()), static_cast<int32_t>(packets_.size()));
   
    if (ec) {
        
        error_ = "media_client::decode_video send failed: ";
        kt::error_message_to(std::back_inserter(error_), ec);
//        throw stop_signal();
    }
    else {
        packets_ = "";
        for (;;) {
                auto frame = av_frame_alloc();
                ec = decoder_.receive(frame);
                if (ec) {
                    av_frame_free(&frame);
                    if (ec.value() == AVERROR(EAGAIN)) break;

                    error_ = "media_client::decode_video receive failed: ";
                    kt::error_message_to(std::back_inserter(error_), ec);
                    throw stop_signal();
                }

                push_frame_queue(frame);
            }
    }

end result output

please note, the code above works fine for hevc with lower resolution or non fragmented stream, and the decoder itself works fine for h264 stream. did i concatenate the slice correctly? I'm very new to this subject.

output for hevc fragmented stream

frame I
frame I
[hevc @ 0000025A9CD08400] PPS changed between slices.
[hevc @ 0000025A9CD08400] Error parsing NAL unit #3.
frame I
[hevc @ 0000025A9CD08400] PPS changed between slices.
[hevc @ 0000025A9CD08400] Error parsing NAL unit #3.
frame I
frame B
frame P
[hevc @ 0000025A9CD08400] First slice in a frame missing.
frame P
[hevc @ 0000025A9CD08400] First slice in a frame missing.
width: 1920, height: 1080, size: 8294400  // this only returns 1/3 of the frame successfully decoded

output for hevc non fragmented stream

frame I
frame I
[hevc @ 00000185A06EBA40] PPS id out of range: 0
[hevc @ 00000185A06EBA40] Error parsing NAL unit #0.
frame P
[hevc @ 00000185A06EBA40] PPS id out of range: 0
[hevc @ 00000185A06EBA40] Error parsing NAL unit #0.
width: 1920, height: 1080, size: 8294400
frame P

h264 output, no error / warning

frame I
frame I
frame P
width: 1280, height: 1280, size: 6553600
frame P
width: 1280, height: 1280, size: 6553600
frame P
width: 1280, height: 1280, size: 6553600
frame P
width: 1280, height: 1280, size: 6553600

any help would be appreciated.

0

There are 0 answers