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;
}
Example #2
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;
}