0

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.

ios dev
  • 1
  • 2

0 Answers0