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.