/* 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 );