Esempio n. 1
0
bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet)
{
  if (!m_pCodecContext)
    return true;

  if (!packet.pData)
    return true;

  if (m_eof)
  {
    Reset();
  }

  if (packet.recoveryPoint)
    m_started = true;

  m_dts = packet.dts;
  m_pCodecContext->reordered_opaque = pts_dtoi(packet.pts);

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = packet.pData;
  avpkt.size = packet.iSize;
  avpkt.dts = (packet.dts == DVD_NOPTS_VALUE) ? AV_NOPTS_VALUE : static_cast<int64_t>(packet.dts / DVD_TIME_BASE * AV_TIME_BASE);
  avpkt.pts = (packet.pts == DVD_NOPTS_VALUE) ? AV_NOPTS_VALUE : static_cast<int64_t>(packet.pts / DVD_TIME_BASE * AV_TIME_BASE);
  avpkt.side_data = static_cast<AVPacketSideData*>(packet.pSideData);
  avpkt.side_data_elems = packet.iSideDataElems;

  int ret = avcodec_send_packet(m_pCodecContext, &avpkt);

  // try again
  if (ret == AVERROR(EAGAIN))
  {
    return false;
  }
  // error
  else if (ret)
  {
    // handle VC_NOBUFFER error for hw accel
    if (m_pHardware)
    {
      int result = m_pHardware->Check(m_pCodecContext);
      if (result == VC_NOBUFFER)
      {
        return false;
      }
    }
  }

  m_iLastKeyframe++;
  // put a limit on convergence count to avoid huge mem usage on streams without keyframes
  if (m_iLastKeyframe > 300)
    m_iLastKeyframe = 300;

  return true;
}
Esempio n. 2
0
int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double pts)
{
  int iGotPicture = 0, len = 0;

  if (!m_pCodecContext)
    return VC_ERROR;

  if (pData)
    m_iLastKeyframe++;

  if (m_pHardware)
  {
    int result;
    if (pData || (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN))
    {
      result = m_pHardware->Check(m_pCodecContext);
      result &= ~VC_NOBUFFER;
    }
    else
    {
      result = m_pHardware->Decode(m_pCodecContext, nullptr);
    }

    if (result)
      return result;
  }

  if (!m_pHardware && pData)
    SetFilters();

  if (m_pFilterGraph && !m_filterEof)
  {
    int result = 0;
    if (pData == NULL)
      result = FilterProcess(nullptr);
    if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)
    {
      result &= VC_PICTURE;
    }
    if (result)
      return result;
  }

  m_dts = dts;
  m_pCodecContext->reordered_opaque = pts_dtoi(pts);

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = pData;
  avpkt.size = iSize;
  avpkt.dts = (dts == DVD_NOPTS_VALUE) ? AV_NOPTS_VALUE : dts / DVD_TIME_BASE * AV_TIME_BASE;
  avpkt.pts = (pts == DVD_NOPTS_VALUE) ? AV_NOPTS_VALUE : pts / DVD_TIME_BASE * AV_TIME_BASE;

  /* We lie, but this flag is only used by pngdec.c.
   * Setting it correctly would allow CorePNG decoding. */
  avpkt.flags = AV_PKT_FLAG_KEY;
  len = avcodec_decode_video2(m_pCodecContext, m_pDecodedFrame, &iGotPicture, &avpkt);

  if (m_decoderState == STATE_HW_FAILED && !m_pHardware)
    return VC_REOPEN;

  if(m_iLastKeyframe < m_pCodecContext->has_b_frames + 2)
    m_iLastKeyframe = m_pCodecContext->has_b_frames + 2;

  if (len < 0)
  {
    if(m_pHardware)
    {
      int result = m_pHardware->Check(m_pCodecContext);
      if (result & VC_NOBUFFER)
      {
        result = m_pHardware->Decode(m_pCodecContext, NULL);
        return result;
      }
    }
    CLog::Log(LOGERROR, "%s - avcodec_decode_video returned failure", __FUNCTION__);
    return VC_ERROR;
  }

  if (!iGotPicture)
  {
    if (pData && m_pCodecContext->skip_frame > AVDISCARD_DEFAULT)
    {
      m_droppedFrames++;
      if (m_interlaced)
        m_droppedFrames++;
    }

    if (m_pHardware && (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN))
    {
      int result;
      result = m_pHardware->Decode(m_pCodecContext, NULL);
      return result;
    }
    else
      return VC_BUFFER;
  }

  if (m_pDecodedFrame->key_frame)
  {
    m_started = true;
    m_iLastKeyframe = m_pCodecContext->has_b_frames + 2;
  }

  if (m_pDecodedFrame->interlaced_frame)
    m_interlaced = true;
  else
    m_interlaced = false;

  /* put a limit on convergence count to avoid huge mem usage on streams without keyframes */
  if (m_iLastKeyframe > 300)
    m_iLastKeyframe = 300;

  /* h264 doesn't always have keyframes + won't output before first keyframe anyway */
  if(m_pCodecContext->codec_id == AV_CODEC_ID_H264 ||
     m_pCodecContext->codec_id == AV_CODEC_ID_SVQ3)
    m_started = true;

  if (m_pHardware == nullptr)
  {
    bool need_scale = std::find( m_formats.begin()
                               , m_formats.end()
                               , m_pCodecContext->pix_fmt) == m_formats.end();

    bool need_reopen  = false;
    if (m_filters != m_filters_next)
      need_reopen = true;

    if (!m_filters_next.empty() && m_filterEof)
      need_reopen = true;

    if (m_pFilterIn)
    {
      if (m_pFilterIn->outputs[0]->format != m_pCodecContext->pix_fmt ||
          m_pFilterIn->outputs[0]->w != m_pCodecContext->width ||
          m_pFilterIn->outputs[0]->h != m_pCodecContext->height)
        need_reopen = true;
    }

    // try to setup new filters
    if (need_reopen || (need_scale && m_pFilterGraph == nullptr))
    {
      m_filters = m_filters_next;

      if (FilterOpen(m_filters, need_scale) < 0)
        FilterClose();
    }
  }

  int result;
  if (m_pHardware)
  {
    av_frame_unref(m_pFrame);
    av_frame_move_ref(m_pFrame, m_pDecodedFrame);
    result = m_pHardware->Decode(m_pCodecContext, m_pFrame);
  }
  else if (m_pFilterGraph && !m_filterEof)
  {
    result = FilterProcess(m_pDecodedFrame);
  }
  else
  {
    av_frame_unref(m_pFrame);
    av_frame_move_ref(m_pFrame, m_pDecodedFrame);
    result = VC_PICTURE | VC_BUFFER;
  }

  if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)
    result &= ~VC_BUFFER;

  if (result & VC_FLUSHED)
    Reset();

  return result;
}