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; }
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; }