/* * Copyright (C) 2014-2016 Intel Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "vaapilayerid.h" #include "common/log.h" namespace YamiMediaCodec { const uint8_t Vp8LayerID::m_vp8TempIds[VP8_MAX_TEMPORAL_LAYER_NUM][VP8_MIN_TEMPORAL_GOP] = { { 0, 0, 0, 0 }, { 0, 1, 0, 1 }, { 0, 2, 1, 2 } }; const uint8_t AvcLayerID::m_avcTempIds[H264_MAX_TEMPORAL_LAYER_NUM][H264_MIN_TEMPORAL_GOP] = { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 1, 0, 1, 0, 1 }, { 0, 2, 1, 2, 0, 2, 1, 2 }, { 0, 3, 2, 3, 1, 3, 2, 3 } }; TemporalLayerID::TemporalLayerID(const VideoFrameRate& frameRate, const VideoTemporalLayerIDs& layerIDs, const uint8_t* defaultIDs, uint8_t defaultIDsLen) { m_miniRefFrameNum = 0; if (layerIDs.numIDs) { m_idPeriod = layerIDs.numIDs; for (uint32_t i = 0; i < layerIDs.numIDs; i++) m_ids.push_back(layerIDs.ids[i]); } else { //use the default temporal IDs assert(defaultIDs && defaultIDsLen > 0); m_idPeriod = defaultIDsLen; for (uint32_t i = 0; i < m_idPeriod; i++) m_ids.push_back(defaultIDs[i]); } calculateFramerate(frameRate); } void TemporalLayerID::getLayerIds(LayerIDs& ids) const { ids = m_ids; } uint8_t TemporalLayerID::getTemporalLayer(uint32_t frameNumInGOP) const { return m_ids[frameNumInGOP % m_idPeriod]; } void TemporalLayerID::getLayerFrameRates(LayerFrameRates& frameRates) const { frameRates = m_frameRates; return; } void TemporalLayerID::calculateFramerate(const VideoFrameRate& frameRate) { uint8_t numberOfLayerIDs[TEMPORAL_LAYERIDS_LENGTH_MAX]; LayerIDs tempIDs = m_ids; uint8_t i; std::sort(tempIDs.begin(), tempIDs.end()); memset(numberOfLayerIDs, 0, sizeof(numberOfLayerIDs)); for (i = 0; i < tempIDs.size(); i++) { numberOfLayerIDs[tempIDs[i]]++; } m_layerLen = tempIDs[i - 1] + 1; assert(m_layerLen < TEMPORAL_LAYERIDS_LENGTH_MAX); VideoFrameRate frameRateTemp; uint32_t denom = m_ids.size(); uint32_t num = 0; assert(frameRate.frameRateNum && frameRate.frameRateDenom); frameRateTemp.frameRateDenom = frameRate.frameRateDenom * denom; for (i = 0; i < m_layerLen; i++) { num += numberOfLayerIDs[i]; frameRateTemp.frameRateNum = num * frameRate.frameRateNum; m_frameRates.push_back(frameRateTemp); } return; } uint8_t TemporalLayerID::getMiniRefFrameNum() const { return m_miniRefFrameNum; } void TemporalLayerID::checkLayerIDs(uint8_t maxLayerLength) const { LayerIDs tempIDs = m_ids; const uint8_t LAYERID0 = 0; assert(LAYERID0 == tempIDs[0]); if (m_idPeriod > TEMPORAL_LAYERIDS_LENGTH_MAX) { ERROR("m_idPeriod(%d) should be in (0, %d]", m_idPeriod, TEMPORAL_LAYERIDS_LENGTH_MAX); assert(false); } //check if the layerID is complete std::sort(tempIDs.begin(), tempIDs.end()); for (uint8_t i = 1; i < m_idPeriod; i++) { if (tempIDs[i] - tempIDs[i - 1] > 1) { ERROR("layer IDs illegal, no layer: %d.\n", (tempIDs[i - 1] + tempIDs[i]) / 2); assert(false); } } if ((m_layerLen > maxLayerLength) || (m_layerLen < 2)) { ERROR("m_layerLen(%d) should be in [2, %d]", m_layerLen, maxLayerLength); assert(false); } return; } Vp8LayerID::Vp8LayerID(const VideoFrameRate& frameRate, const VideoTemporalLayerIDs& layerIDs, uint8_t layerIndex) : TemporalLayerID(frameRate, layerIDs, m_vp8TempIds[layerIndex], VP8_MIN_TEMPORAL_GOP) { checkLayerIDs(VP8_MAX_TEMPORAL_LAYER_NUM); } AvcLayerID::AvcLayerID(const VideoFrameRate& frameRate, const VideoTemporalLayerIDs& layerIDs, uint8_t layerIndex) : TemporalLayerID(frameRate, layerIDs, m_avcTempIds[layerIndex], H264_MIN_TEMPORAL_GOP) { checkLayerIDs(H264_MAX_TEMPORAL_LAYER_NUM); calculateMiniRefNum(); } void AvcLayerID::calculateMiniRefNum() { uint8_t max = 0; const uint8_t LAYER0 = 0; //The current frame of layer0 should be in the refList uint8_t refFrameNum = 1; for (uint8_t i = 0; i < m_idPeriod; i++) { if (LAYER0 == m_ids[i]) { if (max < refFrameNum) max = refFrameNum; //The current frame of layer0 should be in the refList refFrameNum = 1; } else { refFrameNum++; } } m_miniRefFrameNum = max > refFrameNum ? max : refFrameNum; } }