void VaapiDecoderH264::initPicturePOC2(VaapiPictureH264 * picture,
                                       H264SliceHdr * sliceHdr)
{
    H264PPS *const pps = sliceHdr->pps;
    H264SPS *const sps = pps->sequence;
    const int32_t maxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
    int32_t prevFrameNumOffset, tempPOC;

    if (m_prevPicHasMMCO5)
        prevFrameNumOffset = 0;
    else
        prevFrameNumOffset = m_frameNumOffset;

    // (8-11)
    if (VAAPI_H264_PICTURE_IS_IDR(picture))
        m_frameNumOffset = 0;
    else if (m_prevFrameNum > m_frameNum)
        m_frameNumOffset = prevFrameNumOffset + maxFrameNum;
    else
        m_frameNumOffset = prevFrameNumOffset;

    // (8-12)
    if (VAAPI_H264_PICTURE_IS_IDR(picture))
        tempPOC = 0;
    else if (!VAAPI_PICTURE_IS_REFERENCE(picture))
        tempPOC = 2 * (m_frameNumOffset + m_frameNum) - 1;
    else
        tempPOC = 2 * (m_frameNumOffset + m_frameNum);

    // (8-13)
    if (picture->m_structure != VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD)
        m_fieldPoc[TOP_FIELD] = tempPOC;
    if (picture->m_structure != VAAPI_PICTURE_STRUCTURE_TOP_FIELD)
        m_fieldPoc[BOTTOM_FIELD] = tempPOC;
}
bool VaapiDPBManager::execRefPicMarking(const PicturePtr& pic,
                                        bool * hasMMCO5)
{
    *hasMMCO5 = false;

    if (!VAAPI_PICTURE_IS_REFERENCE(pic)) {
        return true;
    }

    if (!VAAPI_H264_PICTURE_IS_IDR(pic)) {
        H264SliceHdr* header = pic->getLastSliceHeader();
        H264DecRefPicMarking *const decRefPicMarking =
            &header->dec_ref_pic_marking;
        if (decRefPicMarking->adaptive_ref_pic_marking_mode_flag) {
            if (!execRefPicMarkingAdaptive(pic, decRefPicMarking, hasMMCO5))
                return false;
        } else {
            if (!execRefPicMarkingSlidingWindow(pic))
                return false;
        }

    }

    return true;
}
void VaapiDecoderH264::initPicturePOC0(VaapiPictureH264 * picture,
                                       H264SliceHdr * sliceHdr)
{
    H264PPS *const pps = sliceHdr->pps;
    H264SPS *const sps = pps->sequence;
    const int32_t MaxPicOrderCntLsb =
        1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
    int32_t tempPOC;

    if (VAAPI_H264_PICTURE_IS_IDR(picture)) {
        m_prevPOCMsb = 0;
        m_prevPOCLsb = 0;
    } else if (m_prevPicHasMMCO5) {
        m_prevPOCMsb = 0;
        m_prevPOCLsb =
            (m_prevPicStructure == VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD ?
             0 : m_fieldPoc[TOP_FIELD]);
    } else {
        m_prevPOCMsb = m_POCMsb;
        m_prevPOCLsb = m_POCLsb;
    }

    // (8-3)
    m_POCLsb = sliceHdr->pic_order_cnt_lsb;
    if (m_POCLsb < m_prevPOCLsb &&
        (m_prevPOCLsb - m_POCLsb) >= (MaxPicOrderCntLsb / 2))
        m_POCMsb = m_prevPOCMsb + MaxPicOrderCntLsb;
    else if (m_POCLsb > m_prevPOCLsb &&
             (m_POCLsb - m_prevPOCLsb) > (MaxPicOrderCntLsb / 2))
        m_POCMsb = m_prevPOCMsb - MaxPicOrderCntLsb;
    else
        m_POCMsb = m_prevPOCMsb;

    tempPOC = m_POCMsb + m_POCLsb;
    switch (picture->m_structure) {
    case VAAPI_PICTURE_STRUCTURE_FRAME:
        // (8-4, 8-5)
        m_fieldPoc[TOP_FIELD] = tempPOC;
        m_fieldPoc[BOTTOM_FIELD] = tempPOC +
            sliceHdr->delta_pic_order_cnt_bottom;
        break;
    case VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
        // (8-4)
        m_fieldPoc[TOP_FIELD] = tempPOC;
        break;
    case VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
        // (8-5)
        m_fieldPoc[BOTTOM_FIELD] = tempPOC;
        break;
    }
}
bool VaapiDPBManager::addDPB(const VaapiFrameStore::Ptr& newFrameStore,
                             const PicturePtr& pic)
{
    uint32_t i, j;
    VaapiFrameStore::Ptr frameStore;

#ifdef __ENABLE_DEBUG__
    debugDPBStatus();
#endif
    outputImmediateBFrame();

    // Remove all unused pictures
    if (!VAAPI_H264_PICTURE_IS_IDR(pic)) {
        i = 0;
        while (i < DPBLayer->DPBCount) {
            frameStore = DPBLayer->DPB[i];
            if (!frameStore->m_outputNeeded && !frameStore->hasReference()) {
                removeDPBIndex(i);
            } else
                i++;
        }
    }
    // C.4.5.1 - Storage and marking of a reference decoded picture into the DPB
    if (VAAPI_PICTURE_IS_REFERENCE(pic)) {
        while (DPBLayer->DPBCount == DPBLayer->DPBSize) {
            if (!bumpDPB())
                return false;
        }

        DPBLayer->DPB[DPBLayer->DPBCount++] = newFrameStore;
        if (pic->m_outputFlag) {
            pic->m_outputNeeded = true;
            newFrameStore->m_outputNeeded++;
        }
    }
    // C.4.5.2 - Storage and marking of a non-reference decoded picture into the DPB
    else {
        if (!pic->m_outputFlag)
            return true;
        while (DPBLayer->DPBCount == DPBLayer->DPBSize) {
            bool foundPicture = false;
            for (i = 0; !foundPicture && i < DPBLayer->DPBCount; i++) {
                frameStore = DPBLayer->DPB[i];
                if (!frameStore->m_outputNeeded)
                    continue;
                for (j = 0; !foundPicture && j < frameStore->m_numBuffers;
                     j++)
                    foundPicture = frameStore->m_buffers[j]->m_outputNeeded
                        && frameStore->m_buffers[j]->m_POC < pic->m_POC;
            }
            if (!foundPicture) {
                bool ret = true;
                if (newFrameStore->hasFrame()) {
                    ret = outputDPB(newFrameStore, pic);
                } else {
                    m_prevFrameStore = newFrameStore;   // wait for a complete frame to render
                }
                return ret;
            }
            if (!bumpDPB())
                return false;
        }

        DPBLayer->DPB[DPBLayer->DPBCount++] = newFrameStore;
        pic->m_outputNeeded = true;
        newFrameStore->m_outputNeeded++;
    }

    return true;
}
bool VaapiDecoderH264::initPicture(VaapiPictureH264 * picture,
                                   H264SliceHdr * sliceHdr,
                                   H264NalUnit * nalu)
{
    H264SPS *const sps = sliceHdr->pps->sequence;

    m_prevFrameNum = m_frameNum;
    m_frameNum = sliceHdr->frame_num;
    picture->m_frameNum = m_frameNum;
    picture->m_frameNumWrap = m_frameNum;
    picture->m_outputFlag = true;   /* XXX: conformant to Annex A only */
    picture->m_timeStamp = m_currentPTS;

    /* Reset decoder state for IDR pictures */
    if (nalu->idr_pic_flag) {
        DEBUG("H264: IDR frame detected");
        VAAPI_PICTURE_FLAG_SET(picture, VAAPI_PICTURE_FLAG_IDR);
        m_DPBManager->flushDPB();
        m_prevFrame = NULL;
    }

    /* Initialize slice type */
    switch (sliceHdr->type % 5) {
    case H264_P_SLICE:
        picture->m_type = VAAPI_PICTURE_TYPE_P;
        break;
    case H264_B_SLICE:
        picture->m_type = VAAPI_PICTURE_TYPE_B;
        break;
    case H264_I_SLICE:
        picture->m_type = VAAPI_PICTURE_TYPE_I;
        break;
    case H264_SP_SLICE:
        picture->m_type = VAAPI_PICTURE_TYPE_SP;
        break;
    case H264_SI_SLICE:
        picture->m_type = VAAPI_PICTURE_TYPE_SI;
        break;
    }

    /* Initialize picture structure */
    if (!sliceHdr->field_pic_flag)
        picture->m_picStructure = VAAPI_PICTURE_STRUCTURE_FRAME;
    else {
        VAAPI_PICTURE_FLAG_SET(picture, VAAPI_PICTURE_FLAG_INTERLACED);
        if (!sliceHdr->bottom_field_flag)
            picture->m_picStructure = VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
        else
            picture->m_picStructure = VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
    }
    picture->m_structure = picture->m_picStructure;

    /* Initialize reference flags */
    if (nalu->ref_idc) {
        H264DecRefPicMarking *const decRefPicMarking =
            &sliceHdr->dec_ref_pic_marking;

        if (VAAPI_H264_PICTURE_IS_IDR(picture) &&
            decRefPicMarking->long_term_reference_flag) {
            VAAPI_PICTURE_FLAG_SET(picture,
                                   VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE);

        } else {
            VAAPI_PICTURE_FLAG_SET(picture,
                                   VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE);
        }
    }

    initPicturePOC(picture, sliceHdr);

    m_DPBManager->initPictureRefs(picture, sliceHdr, m_frameNum);
    return true;
}
void VaapiDecoderH264::initPicturePOC1(VaapiPictureH264 * picture,
                                       H264SliceHdr * sliceHdr)
{
    H264PPS *const pps = sliceHdr->pps;
    H264SPS *const sps = pps->sequence;
    const int32_t maxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
    int32_t prevFrameNumOffset, absFrameNum, expectedPOC;
    uint32_t i;

    if (m_prevPicHasMMCO5)
        prevFrameNumOffset = 0;
    else
        prevFrameNumOffset = m_frameNumOffset;

    // (8-6)
    if (VAAPI_H264_PICTURE_IS_IDR(picture))
        m_frameNumOffset = 0;
    else if (m_prevFrameNum > m_frameNum)
        m_frameNumOffset = prevFrameNumOffset + maxFrameNum;
    else
        m_frameNumOffset = prevFrameNumOffset;

    // (8-7)
    if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0)
        absFrameNum = m_frameNumOffset + m_frameNum;
    else
        absFrameNum = 0;
    if (!VAAPI_PICTURE_IS_REFERENCE(picture) && absFrameNum > 0)
        absFrameNum = absFrameNum - 1;

    if (absFrameNum > 0) {
        int32_t expectedDeltaPerPocCycle;
        int32_t pocCycleCnt, frameNumInPocCycle;

        expectedDeltaPerPocCycle = 0;
        for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
            expectedDeltaPerPocCycle += sps->offset_for_ref_frame[i];

        // (8-8)
        pocCycleCnt = (absFrameNum - 1) /
            sps->num_ref_frames_in_pic_order_cnt_cycle;
        frameNumInPocCycle = (absFrameNum - 1) %
            sps->num_ref_frames_in_pic_order_cnt_cycle;

        // (8-9)
        expectedPOC = pocCycleCnt * expectedDeltaPerPocCycle;
        for (i = 0; (int32_t) i <= frameNumInPocCycle; i++)
            expectedPOC += sps->offset_for_ref_frame[i];
    } else
        expectedPOC = 0;
    if (!VAAPI_PICTURE_IS_REFERENCE(picture))
        expectedPOC += sps->offset_for_non_ref_pic;

    // (8-10)
    switch (picture->m_structure) {
    case VAAPI_PICTURE_STRUCTURE_FRAME:
        m_fieldPoc[TOP_FIELD] = expectedPOC +
            sliceHdr->delta_pic_order_cnt[0];
        m_fieldPoc[BOTTOM_FIELD] = m_fieldPoc[TOP_FIELD] +
            sps->offset_for_top_to_bottom_field +
            sliceHdr->delta_pic_order_cnt[1];
        break;
    case VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
        m_fieldPoc[TOP_FIELD] = expectedPOC +
            sliceHdr->delta_pic_order_cnt[0];
        break;
    case VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
        m_fieldPoc[BOTTOM_FIELD] = expectedPOC +
            sps->offset_for_top_to_bottom_field +
            sliceHdr->delta_pic_order_cnt[0];
        break;
    }
}
bool VaapiDecoderH264::isNewPicture(H264NalUnit * nalu,
                                    H264SliceHdr * sliceHdr)
{
    H264PPS *const pps = sliceHdr->pps;
    H264SPS *const sps = pps->sequence;
    VaapiSliceH264 *slice;
    H264SliceHdr *prevSliceHdr;

    if (!m_currentPicture)
        return true;

    slice = (VaapiSliceH264 *) (m_currentPicture->getLastSlice());
    if (!slice)
        return false;
    prevSliceHdr = &slice->m_sliceHdr;

#define CHECK_EXPR(expr, field_name) do {              \
        if (!(expr)) {                                 \
            DEBUG(field_name " differs in value"); \
            return true;                               \
        }                                              \
    } while (0)

#define CHECK_VALUE(newSliceHdr, oldSliceHdr, field) \
    CHECK_EXPR(((newSliceHdr)->field == (oldSliceHdr)->field), #field)

    /* frame_num differs in value, regardless of inferred values to 0 */
    CHECK_VALUE(sliceHdr, prevSliceHdr, frame_num);

    /* picParameter_set_id differs in value */
    CHECK_VALUE(sliceHdr, prevSliceHdr, pps);

    /* field_pic_flag differs in value */
    CHECK_VALUE(sliceHdr, prevSliceHdr, field_pic_flag);

    /* bottom_field_flag is present in both and differs in value */
    if (sliceHdr->field_pic_flag && prevSliceHdr->field_pic_flag)
        CHECK_VALUE(sliceHdr, prevSliceHdr, bottom_field_flag);

    /* nal_ref_idc differs in value with one of the nal_ref_idc values is 0 */
    CHECK_EXPR(((VAAPI_PICTURE_IS_REFERENCE(m_currentPicture) ^
                 (nalu->ref_idc != 0)) == 0), "nal_ref_idc");

    /* POC type is 0 for both and either pic_order_cnt_lsb differs in
       value or delta_pic_order_cnt_bottom differs in value */
    if (sps->pic_order_cnt_type == 0) {
        CHECK_VALUE(sliceHdr, prevSliceHdr, pic_order_cnt_lsb);
        if (pps->pic_order_present_flag && !sliceHdr->field_pic_flag)
            CHECK_VALUE(sliceHdr, prevSliceHdr,
                        delta_pic_order_cnt_bottom);
    }

    /* POC type is 1 for both and either delta_pic_order_cnt[0]
       differs in value or delta_pic_order_cnt[1] differs in value */
    else if (sps->pic_order_cnt_type == 1) {
        CHECK_VALUE(sliceHdr, prevSliceHdr, delta_pic_order_cnt[0]);
        CHECK_VALUE(sliceHdr, prevSliceHdr, delta_pic_order_cnt[1]);
    }

    /* IdrPicFlag differs in value */
    CHECK_EXPR(((VAAPI_H264_PICTURE_IS_IDR(m_currentPicture) ^
                 (nalu->type == H264_NAL_SLICE_IDR)) == 0), "IdrPicFlag");

    /* IdrPicFlag is equal to 1 for both and idr_pic_id differs in value */
    if (VAAPI_H264_PICTURE_IS_IDR(m_currentPicture))
        CHECK_VALUE(sliceHdr, prevSliceHdr, idr_pic_id);

#undef CHECK_EXPR
#undef CHECK_VALUE
    return false;
}