int cParserH264::Parse_H264(uint32_t startcode, int buf_ptr, bool &complete) { int len = m_PesBufferPtr - buf_ptr; uint8_t *buf = m_PesBuffer + buf_ptr; switch(startcode & 0x9f) { case 1 ... 5: { if (m_NeedSPS || m_NeedPPS) { m_FoundFrame = true; return 0; } // need at least 32 bytes for parsing nal if (len < 32) return -1; h264_private::VCL_NAL vcl; memset(&vcl, 0, sizeof(h264_private::VCL_NAL)); vcl.nal_ref_idc = startcode & 0x60; vcl.nal_unit_type = startcode & 0x1F; if (!Parse_SLH(buf, len, vcl)) return 0; // check for the beginning of a new access unit if (m_FoundFrame && IsFirstVclNal(vcl)) { complete = true; m_PesNextFramePtr = buf_ptr - 4; return -1; } if (!m_FoundFrame) { if (buf_ptr - 4 >= m_PesTimePos) { m_DTS = m_curDTS; m_PTS = m_curPTS; } else { m_DTS = m_prevDTS; m_PTS = m_prevPTS; } } m_streamData.vcl_nal = vcl; m_FoundFrame = true; break; } case NAL_SEI: if (m_FoundFrame) { complete = true; m_PesNextFramePtr = buf_ptr - 4; return -1; } break; case NAL_SPS: { if (m_FoundFrame) { complete = true; m_PesNextFramePtr = buf_ptr - 4; return -1; } // TODO: how big is SPS? if (len < 256) return -1; if (!Parse_SPS(buf, len)) return 0; m_NeedSPS = false; break; } case NAL_PPS: { if (m_FoundFrame) { complete = true; m_PesNextFramePtr = buf_ptr - 4; return -1; } // TODO: how big is PPS if (len < 64) return -1; if (!Parse_PPS(buf, len)) return 0; m_NeedPPS = false; break; } case NAL_AUD: if (m_FoundFrame && (m_prevPTS != DVD_NOPTS_VALUE)) { complete = true; m_PesNextFramePtr = buf_ptr - 4; return -1; } break; case NAL_END_SEQ: if (m_FoundFrame) { complete = true; m_PesNextFramePtr = buf_ptr; return -1; } break; case 13 ... 18: if (m_FoundFrame) { complete = true; m_PesNextFramePtr = buf_ptr - 4; return -1; } break; default: break; } return 0; }
bool cParserH264::Parse_H264(size_t len, uint32_t next_startcode, int sc_offset) { uint8_t nal_data[len]; int pkttype; uint8_t *buf = m_pictureBuffer + sc_offset; uint32_t startcode = m_StartCode; if (startcode == 0x10c) { /* RBSP padding, we don't want this */ int length = len - sc_offset; memcpy(buf, buf + length, 4); /* Move down new start code */ m_pictureBufferPtr -= length; /* Drop buffer */ } if (startcode >= 0x000001e0 && startcode <= 0x000001ef) { /* System start codes for video */ if (len >= 9) ParsePESHeader(buf, len); if (m_PrevDTS != DVD_NOPTS_VALUE) { int64_t duration = (m_curDTS - m_PrevDTS) & 0x1ffffffffLL; if (duration < 90000) m_FrameDuration = duration; } m_PrevDTS = m_curDTS; return true; } switch(startcode & 0x1f) { case NAL_SPS: { int nal_len = nalUnescape(nal_data, buf + 4, len - 4); if (!Parse_SPS(nal_data, nal_len)) return true; m_demuxer->SetVideoInformation(0,0, m_Height, m_Width, m_PixelAspect.num/m_PixelAspect.den); break; } case NAL_PPS: { int nal_len = nalUnescape(nal_data, buf + 4, len - 4); if (!Parse_PPS(nal_data, nal_len)) return true; break; } case 5: /* IDR+SLICE */ case NAL_SLH: { if (m_FoundFrame || m_FrameDuration == 0 || m_curDTS == DVD_NOPTS_VALUE) break; int nal_len = nalUnescape(nal_data, buf + 4, len - 4 > 64 ? 64 : len - 3); if (!Parse_SLH(nal_data, nal_len, &pkttype)) return true; m_StreamPacket.id = m_streamID; m_StreamPacket.pts = m_curPTS; m_StreamPacket.dts = m_curDTS; m_StreamPacket.frametype = pkttype; m_StreamPacket.duration = m_FrameDuration; m_FoundFrame = true; break; } default: break; } if (next_startcode >= 0x000001e0 && next_startcode <= 0x000001ef) { /* Complete frame */ if (!m_FoundFrame) return true; /* Discard Packets until we have the picture size (XBMC can't enable VDPAU without it) */ if (!m_Width) return true; else m_Streamer->SetReady(); m_FoundFrame = false; m_StreamPacket.data = m_pictureBuffer; m_StreamPacket.size = m_pictureBufferPtr; SendPacket(&m_StreamPacket); m_firstPUSIseen = true; return true; } return false; }