/* use the main bitstream buffer for storing the marshalled picture */ m_pcEntropyCoder->setBitstream(NULL); startCUAddrSliceIdx = 0; startCUAddrSlice = 0; startCUAddrSliceSegmentIdx = 0; startCUAddrSliceSegment = 0; nextCUAddr = 0; pcSlice = pcPic->getSlice(startCUAddrSliceIdx); Int processingState = (pcSlice->getSPS()->getUseSAO())?(EXECUTE_INLOOPFILTER):(ENCODE_SLICE); Bool skippedSlice=false; while (nextCUAddr < uiRealEndAddress) // Iterate over all slices { switch(processingState) { case ENCODE_SLICE: { pcSlice->setNextSlice ( false ); pcSlice->setNextSliceSegment( false ); if (nextCUAddr == m_storedStartCUAddrForEncodingSlice[startCUAddrSliceIdx]) { pcSlice = pcPic->getSlice(startCUAddrSliceIdx); if(startCUAddrSliceIdx > 0 && pcSlice->getSliceType()!= I_SLICE) { pcSlice->checkColRefIdx(startCUAddrSliceIdx, pcPic); } pcPic->setCurrSliceIdx(startCUAddrSliceIdx); m_pcSliceEncoder->setSliceIdx(startCUAddrSliceIdx); assert(startCUAddrSliceIdx == pcSlice->getSliceIdx()); // Reconstruction slice pcSlice->setSliceCurStartCUAddr( nextCUAddr ); // to be used in encodeSlice() + context restriction pcSlice->setSliceCurEndCUAddr ( m_storedStartCUAddrForEncodingSlice[startCUAddrSliceIdx+1 ] ); // Dependent slice pcSlice->setSliceSegmentCurStartCUAddr( nextCUAddr ); // to be used in encodeSlice() + context restriction pcSlice->setSliceSegmentCurEndCUAddr ( m_storedStartCUAddrForEncodingSliceSegment[startCUAddrSliceSegmentIdx+1 ] ); pcSlice->setNextSlice ( true ); startCUAddrSliceIdx++; startCUAddrSliceSegmentIdx++; } else if (nextCUAddr == m_storedStartCUAddrForEncodingSliceSegment[startCUAddrSliceSegmentIdx]) { // Dependent slice pcSlice->setSliceSegmentCurStartCUAddr( nextCUAddr ); // to be used in encodeSlice() + context restriction pcSlice->setSliceSegmentCurEndCUAddr ( m_storedStartCUAddrForEncodingSliceSegment[startCUAddrSliceSegmentIdx+1 ] ); pcSlice->setNextSliceSegment( true ); startCUAddrSliceSegmentIdx++; } pcSlice->setRPS(pcPic->getSlice(0)->getRPS()); pcSlice->setRPSidx(pcPic->getSlice(0)->getRPSidx()); UInt uiDummyStartCUAddr; UInt uiDummyBoundingCUAddr; m_pcSliceEncoder->xDetermineStartAndBoundingCUAddr(uiDummyStartCUAddr,uiDummyBoundingCUAddr,pcPic,true); uiInternalAddress = pcPic->getPicSym()->getPicSCUAddr(pcSlice->getSliceSegmentCurEndCUAddr()-1) % pcPic->getNumPartInCU(); uiExternalAddress = pcPic->getPicSym()->getPicSCUAddr(pcSlice->getSliceSegmentCurEndCUAddr()-1) / pcPic->getNumPartInCU(); uiPosX = ( uiExternalAddress % pcPic->getFrameWidthInCU() ) * g_uiMaxCUWidth+ g_auiRasterToPelX[ g_auiZscanToRaster[uiInternalAddress] ]; uiPosY = ( uiExternalAddress / pcPic->getFrameWidthInCU() ) * g_uiMaxCUHeight+ g_auiRasterToPelY[ g_auiZscanToRaster[uiInternalAddress] ]; uiWidth = pcSlice->getSPS()->getPicWidthInLumaSamples(); uiHeight = pcSlice->getSPS()->getPicHeightInLumaSamples(); while(uiPosX>=uiWidth||uiPosY>=uiHeight) { uiInternalAddress--; uiPosX = ( uiExternalAddress % pcPic->getFrameWidthInCU() ) * g_uiMaxCUWidth+ g_auiRasterToPelX[ g_auiZscanToRaster[uiInternalAddress] ]; uiPosY = ( uiExternalAddress / pcPic->getFrameWidthInCU() ) * g_uiMaxCUHeight+ g_auiRasterToPelY[ g_auiZscanToRaster[uiInternalAddress] ]; } uiInternalAddress++; if(uiInternalAddress==pcPic->getNumPartInCU()) { uiInternalAddress = 0; uiExternalAddress = pcPic->getPicSym()->getCUOrderMap(pcPic->getPicSym()->getInverseCUOrderMap(uiExternalAddress)+1); } UInt endAddress = pcPic->getPicSym()->getPicSCUEncOrder(uiExternalAddress*pcPic->getNumPartInCU()+uiInternalAddress); if(endAddress<=pcSlice->getSliceSegmentCurStartCUAddr()) { UInt boundingAddrSlice, boundingAddrSliceSegment; boundingAddrSlice = m_storedStartCUAddrForEncodingSlice[startCUAddrSliceIdx]; boundingAddrSliceSegment = m_storedStartCUAddrForEncodingSliceSegment[startCUAddrSliceSegmentIdx]; nextCUAddr = min(boundingAddrSlice, boundingAddrSliceSegment); if(pcSlice->isNextSlice()) { skippedSlice=true; } continue; } if(skippedSlice) { pcSlice->setNextSlice ( true ); pcSlice->setNextSliceSegment( false ); } skippedSlice=false; pcSlice->allocSubstreamSizes( iNumSubstreams ); for ( UInt ui = 0 ; ui < iNumSubstreams; ui++ ) { pcSubstreamsOut[ui].clear(); } m_pcEntropyCoder->setEntropyCoder ( m_pcCavlcCoder, pcSlice ); m_pcEntropyCoder->resetEntropy (); /* start slice NALunit */ OutputNALUnit nalu( pcSlice->getNalUnitType(), pcSlice->getTLayer() ); Bool sliceSegment = (!pcSlice->isNextSlice()); if (!sliceSegment) { uiOneBitstreamPerSliceLength = 0; // start of a new slice } m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); #if SETTING_NO_OUT_PIC_PRIOR pcSlice->setNoRaslOutputFlag(false); if (pcSlice->isIRAP()) { if (pcSlice->getNalUnitType() >= NAL_UNIT_CODED_SLICE_BLA_W_LP && pcSlice->getNalUnitType() <= NAL_UNIT_CODED_SLICE_IDR_N_LP) { pcSlice->setNoRaslOutputFlag(true); } //the inference for NoOutputPriorPicsFlag // KJS: This cannot happen at the encoder if (!m_bFirst && pcSlice->isIRAP() && pcSlice->getNoRaslOutputFlag()) { if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA) { pcSlice->setNoOutputPriorPicsFlag(true); } } } #endif tmpBitsBeforeWriting = m_pcEntropyCoder->getNumberOfWrittenBits(); m_pcEntropyCoder->encodeSliceHeader(pcSlice); actualHeadBits += ( m_pcEntropyCoder->getNumberOfWrittenBits() - tmpBitsBeforeWriting ); // is it needed? { if (!sliceSegment) { pcBitstreamRedirect->writeAlignOne(); } else { // We've not completed our slice header info yet, do the alignment later. } m_pcSbacCoder->init( (TEncBinIf*)m_pcBinCABAC ); m_pcEntropyCoder->setEntropyCoder ( m_pcSbacCoder, pcSlice ); m_pcEntropyCoder->resetEntropy (); for ( UInt ui = 0 ; ui < pcSlice->getPPS()->getNumSubstreams() ; ui++ ) { m_pcEntropyCoder->setEntropyCoder ( &pcSbacCoders[ui], pcSlice ); m_pcEntropyCoder->resetEntropy (); } } if(pcSlice->isNextSlice()) { // set entropy coder for writing m_pcSbacCoder->init( (TEncBinIf*)m_pcBinCABAC ); { for ( UInt ui = 0 ; ui < pcSlice->getPPS()->getNumSubstreams() ; ui++ ) { m_pcEntropyCoder->setEntropyCoder ( &pcSbacCoders[ui], pcSlice ); m_pcEntropyCoder->resetEntropy (); } pcSbacCoders[0].load(m_pcSbacCoder); m_pcEntropyCoder->setEntropyCoder ( &pcSbacCoders[0], pcSlice ); //ALF is written in substream #0 with CABAC coder #0 (see ALF param encoding below) } m_pcEntropyCoder->resetEntropy (); // File writing if (!sliceSegment) { m_pcEntropyCoder->setBitstream(pcBitstreamRedirect); } else { m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); } // for now, override the TILES_DECODER setting in order to write substreams. m_pcEntropyCoder->setBitstream ( &pcSubstreamsOut[0] ); } pcSlice->setFinalized(true); m_pcSbacCoder->load( &pcSbacCoders[0] ); pcSlice->setTileOffstForMultES( uiOneBitstreamPerSliceLength ); pcSlice->setTileLocationCount ( 0 ); m_pcSliceEncoder->encodeSlice(pcPic, pcSubstreamsOut); { // Construct the final bitstream by flushing and concatenating substreams. // The final bitstream is either nalu.m_Bitstream or pcBitstreamRedirect; UInt* puiSubstreamSizes = pcSlice->getSubstreamSizes(); UInt uiTotalCodedSize = 0; // for padding calcs. UInt uiNumSubstreamsPerTile = iNumSubstreams; if (iNumSubstreams > 1) { uiNumSubstreamsPerTile /= pcPic->getPicSym()->getNumTiles(); } for ( UInt ui = 0 ; ui < iNumSubstreams; ui++ ) { // Flush all substreams -- this includes empty ones. // Terminating bit and flush. m_pcEntropyCoder->setEntropyCoder ( &pcSbacCoders[ui], pcSlice ); m_pcEntropyCoder->setBitstream ( &pcSubstreamsOut[ui] ); m_pcEntropyCoder->encodeTerminatingBit( 1 ); m_pcEntropyCoder->encodeSliceFinish(); pcSubstreamsOut[ui].writeByteAlignment(); // Byte-alignment in slice_data() at end of sub-stream // Byte alignment is necessary between tiles when tiles are independent. uiTotalCodedSize += pcSubstreamsOut[ui].getNumberOfWrittenBits(); Bool bNextSubstreamInNewTile = ((ui+1) < iNumSubstreams)&& ((ui+1)%uiNumSubstreamsPerTile == 0); if (bNextSubstreamInNewTile) { pcSlice->setTileLocation(ui/uiNumSubstreamsPerTile, pcSlice->getTileOffstForMultES()+(uiTotalCodedSize>>3)); } if (ui+1 < pcSlice->getPPS()->getNumSubstreams()) { puiSubstreamSizes[ui] = pcSubstreamsOut[ui].getNumberOfWrittenBits() + (pcSubstreamsOut[ui].countStartCodeEmulations()<<3); } } // Complete the slice header info. m_pcEntropyCoder->setEntropyCoder ( m_pcCavlcCoder, pcSlice ); m_pcEntropyCoder->setBitstream(&nalu.m_Bitstream); m_pcEntropyCoder->encodeTilesWPPEntryPoint( pcSlice ); // Substreams... TComOutputBitstream *pcOut = pcBitstreamRedirect; Int offs = 0; Int nss = pcSlice->getPPS()->getNumSubstreams(); if (pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) { // 1st line present for WPP. offs = pcSlice->getSliceSegmentCurStartCUAddr()/pcSlice->getPic()->getNumPartInCU()/pcSlice->getPic()->getFrameWidthInCU(); nss = pcSlice->getNumEntryPointOffsets()+1; } for ( UInt ui = 0 ; ui < nss; ui++ ) { pcOut->addSubstream(&pcSubstreamsOut[ui+offs]); } } UInt boundingAddrSlice, boundingAddrSliceSegment; boundingAddrSlice = m_storedStartCUAddrForEncodingSlice[startCUAddrSliceIdx]; boundingAddrSliceSegment = m_storedStartCUAddrForEncodingSliceSegment[startCUAddrSliceSegmentIdx]; nextCUAddr = min(boundingAddrSlice, boundingAddrSliceSegment); // If current NALU is the first NALU of slice (containing slice header) and more NALUs exist (due to multiple dependent slices) then buffer it. // If current NALU is the last NALU of slice and a NALU was buffered, then (a) Write current NALU (b) Update an write buffered NALU at approproate location in NALU list. Bool bNALUAlignedWrittenToList = false; // used to ensure current NALU is not written more than once to the NALU list. xAttachSliceDataToNalUnit(nalu, pcBitstreamRedirect); accessUnit.push_back(new NALUnitEBSP(nalu)); actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8; bNALUAlignedWrittenToList = true; uiOneBitstreamPerSliceLength += nalu.m_Bitstream.getNumberOfWrittenBits(); // length of bitstream after byte-alignment if (!bNALUAlignedWrittenToList) { { nalu.m_Bitstream.writeAlignZero(); } accessUnit.push_back(new NALUnitEBSP(nalu)); uiOneBitstreamPerSliceLength += nalu.m_Bitstream.getNumberOfWrittenBits() + 24; // length of bitstream after byte-alignment + 3 byte startcode 0x000001 } if( ( m_pcCfg->getPictureTimingSEIEnabled() || m_pcCfg->getDecodingUnitInfoSEIEnabled() ) && ( pcSlice->getSPS()->getVuiParametersPresentFlag() ) && ( ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getNalHrdParametersPresentFlag() ) || ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getVclHrdParametersPresentFlag() ) ) && ( pcSlice->getSPS()->getVuiParameters()->getHrdParameters()->getSubPicCpbParamsPresentFlag() ) ) { UInt numNalus = 0; UInt numRBSPBytes = 0; for (AccessUnit::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++) { UInt numRBSPBytes_nal = UInt((*it)->m_nalUnitData.str().size()); if ((*it)->m_nalUnitType != NAL_UNIT_PREFIX_SEI && (*it)->m_nalUnitType != NAL_UNIT_SUFFIX_SEI) { numRBSPBytes += numRBSPBytes_nal; numNalus ++; } } accumBitsDU[ pcSlice->getSliceIdx() ] = ( numRBSPBytes << 3 ); accumNalsDU[ pcSlice->getSliceIdx() ] = numNalus; // SEI not counted for bit count; hence shouldn't be counted for # of NALUs - only for consistency } processingState = ENCODE_SLICE; } break; case EXECUTE_INLOOPFILTER: { // set entropy coder for RD m_pcEntropyCoder->setEntropyCoder ( m_pcSbacCoder, pcSlice ); if ( pcSlice->getSPS()->getUseSAO() ) { m_pcEntropyCoder->resetEntropy(); m_pcEntropyCoder->setBitstream( m_pcBitCounter ); Bool sliceEnabled[NUM_SAO_COMPONENTS]; m_pcSAO->initRDOCabacCoder(m_pcEncTop->getRDGoOnSbacCoder(), pcSlice); m_pcSAO->SAOProcess(pcPic , sliceEnabled , pcPic->getSlice(0)->getLambdas() #if SAO_ENCODE_ALLOW_USE_PREDEBLOCK , m_pcCfg->getSaoLcuBoundary() #endif ); m_pcSAO->PCMLFDisableProcess(pcPic); //assign SAO slice header for(Int s=0; s< uiNumSlices; s++) { pcPic->getSlice(s)->setSaoEnabledFlag(sliceEnabled[SAO_Y]); assert(sliceEnabled[SAO_Cb] == sliceEnabled[SAO_Cr]); pcPic->getSlice(s)->setSaoEnabledFlagChroma(sliceEnabled[SAO_Cb]); } } processingState = ENCODE_SLICE; } break; default: { printf("Not a supported encoding state\n"); assert(0); exit(-1); } } } // end iteration over slices
pcPic->compressMotion(); //-- For time output for each slice Double dEncTime = (Double)(clock()-iBeforeTime) / CLOCKS_PER_SEC; const Char* digestStr = NULL; if (m_pcCfg->getDecodedPictureHashSEIEnabled()) { /* calculate MD5sum for entire reconstructed picture */ SEIDecodedPictureHash sei_recon_picture_digest; if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 1) { sei_recon_picture_digest.method = SEIDecodedPictureHash::MD5; calcMD5(*pcPic->getPicYuvRec(), sei_recon_picture_digest.digest); digestStr = digestToString(sei_recon_picture_digest.digest, 16); } else if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 2) { sei_recon_picture_digest.method = SEIDecodedPictureHash::CRC; calcCRC(*pcPic->getPicYuvRec(), sei_recon_picture_digest.digest); digestStr = digestToString(sei_recon_picture_digest.digest, 2); } else if(m_pcCfg->getDecodedPictureHashSEIEnabled() == 3) { sei_recon_picture_digest.method = SEIDecodedPictureHash::CHECKSUM; calcChecksum(*pcPic->getPicYuvRec(), sei_recon_picture_digest.digest); digestStr = digestToString(sei_recon_picture_digest.digest, 4); } OutputNALUnit nalu(NAL_UNIT_SUFFIX_SEI, pcSlice->getTLayer()); /* write the SEI messages */ m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); m_seiWriter.writeSEImessage(nalu.m_Bitstream, sei_recon_picture_digest, pcSlice->getSPS()); writeRBSPTrailingBits(nalu.m_Bitstream); accessUnit.insert(accessUnit.end(), new NALUnitEBSP(nalu)); } if (m_pcCfg->getTemporalLevel0IndexSEIEnabled()) { SEITemporalLevel0Index sei_temporal_level0_index; if (pcSlice->getRapPicFlag()) { m_tl0Idx = 0; m_rapIdx = (m_rapIdx + 1) & 0xFF; } else { m_tl0Idx = (m_tl0Idx + (pcSlice->getTLayer() ? 0 : 1)) & 0xFF; } sei_temporal_level0_index.tl0Idx = m_tl0Idx; sei_temporal_level0_index.rapIdx = m_rapIdx; OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI); /* write the SEI messages */ m_pcEntropyCoder->setEntropyCoder(m_pcCavlcCoder, pcSlice); m_seiWriter.writeSEImessage(nalu.m_Bitstream, sei_temporal_level0_index, pcSlice->getSPS()); writeRBSPTrailingBits(nalu.m_Bitstream); /* insert the SEI message NALUnit before any Slice NALUnits */ AccessUnit::iterator it = find_if(accessUnit.begin(), accessUnit.end(), mem_fun(&NALUnit::isSlice)); accessUnit.insert(it, new NALUnitEBSP(nalu)); } xCalculateAddPSNR( pcPic, pcPic->getPicYuvRec(), accessUnit, dEncTime );