⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sesenc.cpp

📁 此源码是在VC平台下,实现MPEG4编解码的源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		UInt uiFrmWidth_SS,
		UInt uiFrmHeight_SS,
		UInt uiHor_sampling_n,
		UInt uiHor_sampling_m,
		UInt uiVer_sampling_n,
		UInt uiVer_sampling_m
) :
	m_iFirstFrame (iFirstFrm), m_iLastFrame (iLastFrm),
	m_iFirstVO (iFirstVO), m_iLastVO (iLastVO),
	m_rgbSpatialScalability (rgbSpatialScalability),
	m_rguiRateControl (rguiRateControl), 
	m_rguiBudget (rguiBudget),
	m_pchPrefix (pchPrefix), m_pchBmpFiles (pchBmpFiles),
	m_pchReconYUVDir (pchOutBmpFiles), m_rgfChrType (rgfChrType),
	m_pchOutStrFiles (pchOutStrFiles),
	m_rguiSpriteUsage (rguiSpriteUsage), m_rguiWarpingAccuracy (rguiWarpingAccuracy), 
	m_rgNumOfPnts (rgNumOfPnts), m_pchSptDir (pchSptDir), 
	m_pchSptPntDir (pchSptPntDir),
	m_rgiTemporalScalabilityType (rgiTemporalScalabilityType)
{
	// data preparation
	m_iNumFrame = m_iLastFrame - m_iFirstFrame + 1;
	assert (m_iNumFrame > 0);
	m_rctOrg = CRct (0, 0, uiFrmWidth, uiFrmHeight);
	if( uiFrmWidth_SS !=0 && uiFrmHeight_SS!=0)
		m_rctOrgSpatialEnhn = CRct(0, 0, uiFrmWidth_SS, uiFrmHeight_SS);
	assert (uiFrmWidth <= 8192 && uiFrmHeight <= 8192); //2^13 maximum size
	m_iNumVO = m_iLastVO - m_iFirstVO + 1;
	assert (m_iNumVO > 0);
	m_rgvolmd [BASE_LAYER] = new VOLMode [m_iNumVO];
	m_rgvolmd [ENHN_LAYER] = new VOLMode [m_iNumVO];
	m_rgvopmd [BASE_LAYER] = new VOPMode [m_iNumVO];
	m_rgvopmd [ENHN_LAYER] = new VOPMode [m_iNumVO];
	Int iVO;
	for (iVO = 0; iVO < m_iNumVO; iVO++) {
		// set VOL and VOP mode values
		for (Int iLayer = BASE_LAYER; iLayer <= m_rgbSpatialScalability [iVO] * ENHN_LAYER; iLayer++)	{
			// NBIT
			m_rgvolmd [iLayer][iVO].bNot8Bit 		= bNot8Bit;
			m_rgvolmd [iLayer][iVO].uiQuantPrecision 	= uiQuantPrecision;
			m_rgvolmd [iLayer][iVO].nBits 			= nBits;

			m_rgvolmd [iLayer][iVO].volType			= (VOLtype) iLayer;
			m_rgvolmd [iLayer][iVO].fAUsage			= rgfAlphaUsage [iVO];
			m_rgvolmd [iLayer][iVO].bShapeOnly		= rgbShapeOnly [iVO];
			m_rgvolmd [iLayer][iVO].iBinaryAlphaTH	= rgiBinaryAlphaTH [iVO] * 16;  //magic no. from the vm
			m_rgvolmd [iLayer][iVO].iBinaryAlphaRR	= (rgiBinaryAlphaRR [iVO]<0)?-1:(rgiBinaryAlphaRR [iVO] +1)*(rgiNumOfBbetweenPVOP [iVO] +1)*rgiTemporalRate [iVO];  // Binary shape refresh rate: Added for error resilient mode by Toshiba(1997-11-14): Modified (1998-1-16)
			m_rgvolmd [iLayer][iVO].bNoCrChange		= rgbNoCrChange [iVO];
			m_rgvolmd [iLayer][iVO].bOriginalForME	= rgbOriginalForME [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bAdvPredDisable = rgbAdvPredDisable [iLayer][iVO];
			// START: Complexity Estimation syntax support - Marc Mongenet (EPFL) - 17 Jun 1998
			m_rgvolmd [iLayer][iVO].bComplexityEstimationDisable = rgbComplexityEstimationDisable [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bOpaque = rgbOpaque [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bTransparent = rgbTransparent [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bIntraCAE = rgbIntraCAE [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bInterCAE = rgbInterCAE [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bNoUpdate = rgbNoUpdate [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bUpsampling = rgbUpsampling [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bIntraBlocks = rgbIntraBlocks [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bInterBlocks = rgbInterBlocks [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bInter4vBlocks = rgbInter4vBlocks [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bNotCodedBlocks = rgbNotCodedBlocks [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bDCTCoefs = rgbDCTCoefs [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bDCTLines = rgbDCTLines [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bVLCSymbols = rgbVLCSymbols [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bVLCBits = rgbVLCBits [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bAPM = rgbAPM [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bNPM = rgbNPM [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bInterpolateMCQ = rgbInterpolateMCQ [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bForwBackMCQ = rgbForwBackMCQ [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bHalfpel2 = rgbHalfpel2 [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bHalfpel4 = rgbHalfpel4 [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bAllowSkippedPMBs = rgbAllowSkippedPMBs [iVO];

			// END: Complexity Estimation syntax support
			// START: Vol Control Parameters
			if(rguiVolControlParameters[0]!=NULL)
			{
				m_rgvolmd [iLayer][iVO].uiVolControlParameters = rguiVolControlParameters [iLayer][iVO];
				m_rgvolmd [iLayer][iVO].uiChromaFormat = rguiChromaFormat [iLayer][iVO];
				m_rgvolmd [iLayer][iVO].uiLowDelay = rguiLowDelay [iLayer][iVO];
				m_rgvolmd [iLayer][iVO].uiVBVParams = rguiVBVParams [iLayer][iVO];
				m_rgvolmd [iLayer][iVO].uiBitRate = rguiBitRate [iLayer][iVO];
				m_rgvolmd [iLayer][iVO].uiVbvBufferSize = rguiVbvBufferSize [iLayer][iVO];
				m_rgvolmd [iLayer][iVO].uiVbvBufferOccupany = rguiVbvBufferOccupany [iLayer][iVO];
			}
			else
				m_rgvolmd [iLayer][iVO].uiVolControlParameters = 0;
			// END: Vol Control Parameters
			m_rgvolmd [iLayer][iVO].bRoundingControlDisable	= (iLayer== BASE_LAYER) ? rgbRoundingControlDisable[iVO] : 0;
			m_rgvolmd [iLayer][iVO].iInitialRoundingType = (iLayer== BASE_LAYER) ? rgiInitialRoundingType[iVO] : 0;
			m_rgvolmd [iLayer][iVO].bVPBitTh		= rgbVPBitTh[iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bDataPartitioning = rgbDataPartitioning [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bReversibleVlc  = rgbReversibleVlc [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].fQuantizer		= rgfQuant [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bNoGrayQuantUpdate 
													= rgbNoAlphaQuantUpdate [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].dFrameHz		= rgdFrameFrequency [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].iMVRadiusPerFrameAwayFromRef = rguiSearchRange [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].iSearchRangeForward	= rguiSearchRange [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].iSearchRangeBackward= rguiSearchRange [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].intStepI		= rgiStepI [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].intStep			= rgiStepP [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].intStepB		= rgiStepB [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].intStepIAlpha	= rgiStepIAlpha [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].intStepPAlpha	= rgiStepPAlpha [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].intStepBAlpha	= rgiStepBAlpha [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].iIntraDcSwitchThr 
													= rgiIntraDCSwitchingThr [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].bInterlace		= rgbInterlacedCoding [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].bTopFieldFirst	= rgbTopFieldFirst [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].bAlternateScan	= rgbAlternateScan [iLayer][iVO];
			m_rgvopmd [iLayer][iVO].iDirectModeRadius = rgiDirectModeRadius [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bLoadIntraMatrix= rgbLoadIntraMatrix [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bLoadInterMatrix= rgbLoadInterMatrix [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bLoadIntraMatrixAlpha 
													= rgbLoadIntraMatrixAlpha [iLayer][iVO];
			m_rgvolmd [iLayer][iVO].bLoadInterMatrixAlpha 
													= rgbLoadInterMatrixAlpha [iLayer][iVO];
			memcpy (m_rgvolmd [iLayer][iVO].rgiIntraQuantizerMatrix,		rgppiIntraQuantizerMatrix [iLayer][iVO], BLOCK_SQUARE_SIZE * sizeof (Int));
			memcpy (m_rgvolmd [iLayer][iVO].rgiInterQuantizerMatrix,		rgppiInterQuantizerMatrix [iLayer][iVO], BLOCK_SQUARE_SIZE * sizeof (Int));
			memcpy (m_rgvolmd [iLayer][iVO].rgiIntraQuantizerMatrixAlpha,	rgppiIntraQuantizerMatrixAlpha [iLayer][iVO], BLOCK_SQUARE_SIZE * sizeof (Int));
			memcpy (m_rgvolmd [iLayer][iVO].rgiInterQuantizerMatrixAlpha,	rgppiInterQuantizerMatrixAlpha [iLayer][iVO], BLOCK_SQUARE_SIZE * sizeof (Int));

			m_rgvolmd [iLayer][iVO].bDeblockFilterDisable 
													= rgbDeblockFilterDisable [iVO];
			m_rgvolmd [iLayer][iVO].iBbetweenP	= rgiNumOfBbetweenPVOP [iVO];
			m_rgvolmd [iLayer][iVO].iPbetweenI	= rgiNumOfPbetweenIVOP [iVO];
			m_rgvolmd [iLayer][iVO].iGOVperiod = rgiGOVperiod [iVO]; // count of o/p frames between govs
			// set up temporal sampling rate and clock rate from source frame rate.
			m_rgvolmd [iLayer][iVO].iTemporalRate	= rgiTemporalRate [iVO]; // frames to skip
			Double dFrameHz = m_rgvolmd [iLayer][iVO].dFrameHz;
			// this code copes with e.g. 12.5 fps and 29.97 fps by multiplying up the ticks per second
			// count appropriately
			Int iClockRate = (int)dFrameHz;
			if(dFrameHz != (double)iClockRate)
			{
				iClockRate = (int)(dFrameHz * 10.0);
				if(dFrameHz * 10.0 != (double)iClockRate)
					iClockRate = (int)(dFrameHz * 100.0);	 // not much point going to 1000*
			}
			m_rgvolmd [iLayer][iVO].iClockRate = iClockRate;

			m_rgvolmd [iLayer][iVO].bDumpMB			= rgbDumpMB [iVO];
			m_rgvolmd [iLayer][iVO].bTrace			= rgbTrace [iVO];
			m_rgvolmd [iLayer][iVO].bTemporalScalability = FALSE;
			if(m_rgvolmd[iLayer][iVO].volType == ENHN_LAYER && m_rgbSpatialScalability [iVO] && rgiTemporalRate[iVO] == rgiEnhnTemporalRate[iVO]){
				// modified by Sharp (98/02/09)
//#ifdef _Scalable_SONY_
				m_rgvolmd[iLayer][iVO].iHierarchyType = 0; //iHierarchyType 0 means spatial scalability
//#endif _Scalable_SONY_
				m_rgvolmd[iLayer][iVO].iEnhnType = 0; // Spatial Scalable Enhancement layer shuold be set to Rectangular shape
				m_rgvolmd[iLayer][iVO].iSpatialOption = iSpatialOption; // This Option is for Spatial Scalable
				m_rgvolmd[iLayer][iVO].iver_sampling_factor_n = uiVer_sampling_n;
				m_rgvolmd[iLayer][iVO].iver_sampling_factor_m = uiVer_sampling_m;
				m_rgvolmd[iLayer][iVO].ihor_sampling_factor_n = uiHor_sampling_n;
				m_rgvolmd[iLayer][iVO].ihor_sampling_factor_m = uiHor_sampling_m;
			} 
// begin: added by Sharp (98/2/12)
			else if (m_rgbSpatialScalability [iVO] && rgiTemporalRate[iVO] != rgiEnhnTemporalRate[iVO]){
				m_rgvolmd [iLayer][iVO].bTemporalScalability = TRUE;
//#ifdef _Scalable_SONY_
				m_rgvolmd[iLayer][iVO].iHierarchyType = 1; //iHierarchyType 1 means temporal scalability
//#endif _Scalable_SONY_
				m_rgvolmd [iLayer][iVO].iEnhnType	= rgiEnhancementType [iVO];
				if ( rgiEnhancementType[iVO] != 0 ) // modified by Sharp (98/3/24)
					m_rgvolmd [BASE_LAYER][iVO].fAUsage = RECTANGLE;
				if ( iLayer == ENHN_LAYER ) {
					m_rgvolmd [ENHN_LAYER][iVO].iTemporalRate	= rgiEnhnTemporalRate [iVO];
					Double dFrameHz = m_rgvolmd [ENHN_LAYER][iVO].dFrameHz;
					// this code copes with e.g. 12.5 fps and 29.97 fps by multiplying up the ticks per second
					// count appropriately
					Int iClockRate = (int)dFrameHz;
					if(dFrameHz != (double)iClockRate)
					{
						iClockRate = (int)(dFrameHz * 10.0);
						if(dFrameHz * 10.0 != (double)iClockRate)
							iClockRate = (int)(dFrameHz * 100.0);	 // not much point going to 1000*
					}
					m_rgvolmd [ENHN_LAYER][iVO].iClockRate = iClockRate;
				}
				m_rgvolmd[iLayer][iVO].iver_sampling_factor_n = 1;
				m_rgvolmd[iLayer][iVO].iver_sampling_factor_m = 1;
				m_rgvolmd[iLayer][iVO].ihor_sampling_factor_n = 1;
				m_rgvolmd[iLayer][iVO].ihor_sampling_factor_m = 1;
			}
// end: added by Sharp (98/2/12)
			else {
				m_rgvolmd[iLayer][iVO].iver_sampling_factor_n = 1;
				m_rgvolmd[iLayer][iVO].iver_sampling_factor_m = 1;
				m_rgvolmd[iLayer][iVO].ihor_sampling_factor_n = 1;
				m_rgvolmd[iLayer][iVO].ihor_sampling_factor_m = 1;
			}
		}
	}
	static Char pchYUV [100], pchSeg [100];
	// check whether there are data for separate layers
	sprintf (pchYUV, ROOT_YUVFILE, m_pchBmpFiles, m_pchPrefix);
	sprintf (pchSeg, ROOT_SEGFILE, m_pchBmpFiles, m_pchPrefix);
	m_bTexturePerVOP = !fileExistence (pchYUV);
	m_bAlphaPerVOP = !fileExistence (pchSeg);
	m_bPrevObjectExists = FALSE; // added by Sharp (98/2/13)

	// sprite info
	m_ppstSrc = new CSiteD* [m_iNumVO];
	m_pppstDst = new CSiteD** [m_iNumVO];
	for (iVO = 0; iVO < m_iNumVO; iVO++) {
		m_ppstSrc [iVO] = (m_rgNumOfPnts [iVO] > 0) ? new CSiteD [m_rgNumOfPnts [iVO]] : NULL;
		m_pppstDst [iVO] = new CSiteD* [m_iNumFrame];
		for (Int ifr = 0; ifr < m_iNumFrame; ifr++) {
			m_pppstDst [iVO] [ifr] = 
				(m_rgNumOfPnts [iVO] > 0) ? new CSiteD [m_rgNumOfPnts [iVO]] : 
				NULL;
		}
	}
	for (iVO = m_iFirstVO; iVO <= m_iLastVO; iVO++)
		if (m_rgNumOfPnts [iVO - m_iFirstVO] > 0)
				readPntFile (iVO);

    m_SptMode =	pSpriteMode[0];
	m_rgiMVFileUsage = rgiMVFileUsage;
	m_pchMVFileName  = pchMVFileName;
}	
Void CSessionEncoder::encode ()
{
	FILE* pfYuvSrc = NULL;
	FILE* pfYuvSrcSpatialEnhn = NULL;
	FILE* pfSegSrc = NULL;
	FILE* rgpfReconYUV [2];
	FILE* rgpfReconSeg [2];
	Int iVO;
	UInt iVOrelative = 0;

// begin: added by Sharp (98/2/12)
	Bool bTemporalScalability = m_rgvolmd[BASE_LAYER][0].bTemporalScalability;
//	Bool bTemporalScalability = TRUE;

	// for a buffer management of temporal scalability
	CEnhcBufferEncoder* pBufP1;
	CEnhcBufferEncoder* pBufP2;
	CEnhcBufferEncoder* pBufB1;
	CEnhcBufferEncoder* pBufB2;
	CEnhcBufferEncoder* pBufE;

	// for backward/forward shape
	Void set_modes(VOLMode* volmd, VOPMode* vopmd);
	VOLMode* volmd_backShape;
	VOLMode* volmd_forwShape;
	VOPMode* vopmd_backShape;
	VOPMode* vopmd_forwShape;

	if ( bTemporalScalability ){
		pBufP1 = new CEnhcBufferEncoder(m_rctOrg.width, m_rctOrg.height());
		pBufP2 = new CEnhcBufferEncoder(m_rctOrg.width, m_rctOrg.height());
		pBufB1 = new CEnhcBufferEncoder(m_rctOrg.width, m_rctOrg.height());
		pBufB2 = new CEnhcBufferEncoder(m_rctOrg.width, m_rctOrg.height());
		pBufE  = new CEnhcBufferEncoder(m_rctOrg.width, m_rctOrg.height());

		volmd_backShape = new VOLMode;
		volmd_forwShape = new VOLMode;
		vopmd_backShape = new VOPMode;
		vopmd_forwShape = new VOPMode;
		set_modes(volmd_backShape, vopmd_backShape);
		set_modes(volmd_forwShape, vopmd_forwShape);
	}
// end: added by Sharp (98/2/12)

	for (iVO = m_iFirstVO; iVO <= (Int) m_iLastVO; iVO++, iVOrelative++) {
		ofstream* rgpostrm [2];
		ofstream* rgpostrmTrace [2];
		PixelC pxlcObjColor;
		VOLMode volmd = m_rgvolmd [BASE_LAYER] [iVOrelative];
		VOLMode volmd_enhn = m_rgvolmd [ENHN_LAYER] [iVOrelative]; // added by Sharp (98/2/10)
		getInputFiles (	pfYuvSrc, pfSegSrc, pfYuvSrcSpatialEnhn,
						rgpfReconYUV, rgpfReconSeg, 
						rgpostrm, rgpostrmTrace, pxlcObjColor, iVO, volmd, volmd_enhn); // modified by Sharp(98/2/10)
		CRct rctOrg;
		CVideoObjectEncoder* rgpvoenc [2];
		if (m_rguiSpriteUsage [iVOrelative] == 1) {
			// change m_rctOrg to sprite size
			rctOrg = m_rctOrg;
			m_rctFrame = m_rctOrg;
			m_rctOrg = findSptRct (iVO);
		}

		initVOEncoder (rgpvoenc, iVO, rgpostrmTrace);
		rgpostrm [BASE_LAYER]->write (rgpvoenc [BASE_LAYER]->pOutStream ()->str (),			//VO and VOL header
									  rgpvoenc [BASE_LAYER]->pOutStream ()->pcount ());

		if(m_rgbSpatialScalability[iVOrelative]){
			rgpostrm[ENHN_LAYER]->write(rgpvoenc [ENHN_LAYER]->pOutStream () ->str(),
										rgpvoenc [ENHN_LAYER]->pOutStream () ->pcount ());
		}
	// begin: added by Sharp (98/2/12)
		// for back/forward shape
		if ( bTemporalScalability ){
		  initVObfShape (rgpvoenc[ENHN_LAYER]->rgpbfShape, iVO, *volmd_backShape, *vopmd_backShape, *volmd_forwShape, *vopmd_forwShape);
		  // copy pointers
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[0]->m_pchBitsBuffer = rgpvoenc[ENHN_LAYER]->m_pchBitsBuffer;
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[0]->m_pbitstrmOut   = rgpvoenc[ENHN_LAYER]->m_pbitstrmOut;
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[0]->m_pentrencSet   = rgpvoenc[ENHN_LAYER]->m_pentrencSet;

		  rgpvoenc[ENHN_LAYER]->rgpbfShape[0]->m_pchShapeBitsBuffer = rgpvoenc[ENHN_LAYER]->m_pchShapeBitsBuffer;	// Oct 8
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[0]->m_pbitstrmShape      = rgpvoenc[ENHN_LAYER]->m_pbitstrmShape;		//
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[0]->m_pbitstrmShapeMBOut = rgpvoenc[ENHN_LAYER]->m_pbitstrmShapeMBOut;	//

		  rgpvoenc[ENHN_LAYER]->rgpbfShape[1]->m_pchBitsBuffer = rgpvoenc[ENHN_LAYER]->m_pchBitsBuffer;
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[1]->m_pbitstrmOut   = rgpvoenc[ENHN_LAYER]->m_pbitstrmOut;
		  rgpvoenc[ENHN_LAYER]->rgpbfShape[1]->m_pentrencSet   = rgpvoenc[ENHN_LAYER]->m_pentrencSet;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -