void MovieTexture_FFMpeg::DecoderThread()
{
#if defined(_WINDOWS)
	/* Windows likes to boost priority when processes come out of a wait state.  We don't
	 * want that, since it'll result in us having a small priority boost after each movie
	 * frame, resulting in skips in the gameplay thread. */
	if( !SetThreadPriorityBoost(GetCurrentThread(), TRUE) && GetLastError() != ERROR_CALL_NOT_IMPLEMENTED )
		LOG->Warn( werr_ssprintf(GetLastError(), "SetThreadPriorityBoost failed") );
#endif

	CHECKPOINT;

	while( m_State != DECODER_QUIT )
	{
		if( m_ImageWaiting == FRAME_NONE )
			DecodeFrame();

		/* If we still have no frame, we're at EOF and we didn't loop. */
		if( m_ImageWaiting != FRAME_DECODED )
		{
			usleep( 10000 );
			continue;
		}

		const float fTime = CheckFrameTime();
		if( fTime == -1 )	// skip frame
		{
			DiscardFrame();
		}
		else if( fTime > 0 )		// not time to decode a new frame yet
		{
			/* This needs to be relatively short so that we wake up quickly 
			 * from being paused or for changes in m_Rate. */
			usleep( 10000 );
		}
		else // fTime == 0
		{
			{
				/* The only reason m_BufferFinished might be non-zero right now (before
				 * ConvertFrame()) is if we're quitting. */
				int n = m_BufferFinished.GetValue();
				ASSERT_M( n == 0 || m_State == DECODER_QUIT, ssprintf("%i, %i", n, m_State) );
			}
			ConvertFrame();

			/* We just went into FRAME_WAITING.  Don't actually check; the main thread
			 * will change us back to FRAME_NONE without locking, and poke m_BufferFinished.
			 * Don't time out on this; if a new screen has started loading, this might not
			 * return for a while. */
			m_BufferFinished.Wait( false );

			/* If the frame wasn't used, then we must be shutting down. */
			ASSERT_M( m_ImageWaiting == FRAME_NONE || m_State == DECODER_QUIT, ssprintf("%i, %i", m_ImageWaiting, m_State) );
		}
	}
	CHECKPOINT;
}
void MovieTexture_FFMpeg::Update(float fDeltaTime)
{
	/* We might need to decode more than one frame per update.  However, there
	 * have been bugs in ffmpeg that cause it to not handle EOF properly, which
	 * could make this never return, so let's play it safe. */
	int iMax = 4;
	while( --iMax )
	{
		if( !m_bThreaded )
		{
			/* If we don't have a frame decoded, decode one. */
			if( m_ImageWaiting == FRAME_NONE )
				DecodeFrame();

			/* If we have a frame decoded, see if it's time to display it. */
			if( m_ImageWaiting == FRAME_DECODED )
			{
				float fTime = CheckFrameTime();
				if( fTime > 0 )
					return;
				else if( fTime == -1 )
					DiscardFrame();
				else
					ConvertFrame();
			}
		}

		/* Note that if there's an image waiting, we *must* signal m_BufferFinished, or
		* the decoder thread may sit around waiting for it, even though Pause and Play
		* calls, causing the clock to keep running. */
		if( m_ImageWaiting != FRAME_WAITING )
			return;
		CHECKPOINT;

		UpdateFrame();
		
		if( m_bThreaded )
			m_BufferFinished.Post();
	}

	LOG->MapLog( "ffmpeg_looping", "MovieTexture_FFMpeg::Update looping" );
}
CString MovieTexture_FFMpeg::Init()
{
	CString sError = CreateDecoder();
	if( sError != "" )
		return sError;

	LOG->Trace("Bitrate: %i", decoder->m_stream->codec.bit_rate );
	LOG->Trace("Codec pixel format: %s", avcodec::avcodec_get_pix_fmt_name(decoder->m_stream->codec.pix_fmt) );

	/* Decode one frame, to guarantee that the texture is drawn when this function returns. */
	int ret = decoder->GetFrame();
	if( ret == -1 )
		return ssprintf( "%s: error getting first frame", GetID().filename.c_str() );
	if( ret == 0 )
	{
		/* There's nothing there. */
		return ssprintf( "%s: EOF getting first frame", GetID().filename.c_str() );
	}

	m_ImageWaiting = FRAME_DECODED;

	CreateTexture();
	LOG->Trace( "Resolution: %ix%i (%ix%i, %ix%i)",
			m_iSourceWidth, m_iSourceHeight,
			m_iImageWidth, m_iImageHeight, m_iTextureWidth, m_iTextureHeight );
	LOG->Trace( "Texture pixel format: %i", m_AVTexfmt );

	CreateFrameRects();

	ConvertFrame();
	UpdateFrame();

	CHECKPOINT;

	StartThread();

	return "";
}
Exemple #4
0
BOOL ConvertImage(LPIMAGE lpImage, LPCONVERT_PARMS lpParms)
/***********************************************************************/
{
BOOL fRet = FALSE;
LPFRAME lpDstFrame, lpBaseFrame;
LPOBJECT lpBase, lpObject;
BOOL fError, fOptimize, fProgressSet;
INTERNAL_DATA data;
int	inDepth, iMaxWidth, nColors, i;
LPCOLORMAP lpColorMap;
LPRGB lpRGB;
FRMTYPEINFO InTypeInfo, OutTypeInfo;
CFrameTypeConvert TypeConvert;
DITHER_TYPE DitherType = DT_DEFAULT;

if (ImgInMaskEditMode(lpImage))
	return(TRUE);

lpColorMap = NULL;

lpBase = ImgGetBase(lpImage);
lpBaseFrame = ObjGetEditFrame(lpBase);
inDepth = FrameDepth(lpBaseFrame);

OutTypeInfo = lpParms->cmsInfo.dst;
FrameGetTypeInfo(lpBaseFrame, &InTypeInfo);

// are we try to convert to a color managed image?
if (Control.CMSEnabled && IsDstPTSelected(&OutTypeInfo.ptInfo))
	{
	// see if our image already has a color managed source
	if (!IsSrcPTSelected(&InTypeInfo.ptInfo))
		{
		// nope, see if the source passed in is valid for this image
		if (IsSrcPTSelected(&lpParms->cmsInfo.src.ptInfo) &&
			(lpParms->cmsInfo.src.DataType == InTypeInfo.DataType))
			{	
			InTypeInfo = lpParms->cmsInfo.src;
			}
		// go get a source from the user
		else
			{
			CMSINFO CmsInfo2;
			if( CmsGetSrcPTType( &InTypeInfo, &CmsInfo2) )
				InTypeInfo = CmsInfo2.src;
			}
		}
	}
else
 	FrameSetTypeInfo(&InTypeInfo, InTypeInfo.DataType, InTypeInfo.ColorMap);

// no conversion necessary
if (FrameTypeInfoEqual(InTypeInfo, OutTypeInfo))
	return(TRUE);

DitherType = lpParms->DitherType;
fOptimize = lpParms->ConvertType == CT_OPTIMIZED;
fProgressSet = FALSE;


if ( OutTypeInfo.DataType == FDT_PALETTECOLOR/* && inDepth >= 3 */)
	{
	if (lpParms->ConvertType == CT_CUSTOM)
		{
		FNAME szFileName;

		if ( !LookupExtFileN( lpParms->szPalette, szFileName, IDN_PALETTE, NO ) )
			return(FALSE);
		if (!(lpColorMap = Palette_ReadColorMap(szFileName)))
			return(FALSE);
		}
	else
		{
		// allocate a map to carry around with image
		lpColorMap = FrameCreateColorMap();
		if (!lpColorMap)
			{
			Message(IDS_EMEMALLOC);
			goto MemError;
			}

		lpColorMap->NumEntries = lpParms->iLevels;

		if (InTypeInfo.DataType == FDT_GRAYSCALE && lpColorMap->NumEntries == 256 &&
			fOptimize)
			{
			DitherType = DT_NONE;
			lpRGB = lpColorMap->RGBData;
			for (i = 0; i < lpColorMap->NumEntries; ++i)
				{
				lpRGB->red = lpRGB->green = lpRGB->blue = i;
				++lpRGB;
				}
			}
		else
			{
			// 1. CreateOptimizedPalette phase - only if fOptimize
			// 2. Mapping phase
			ProgressBegin(fOptimize ? 2 : 1,
					lpParms->Common.idDirty-IDS_UNDOFIRST+IDS_PROGFIRST);
			fProgressSet = TRUE;
			if (fOptimize)
				ProgressBegin(1, 0);
			if (!CreateOptimizedPalette(lpBase, ObjGetEditFrame(lpBase),
									lpColorMap->RGBData, &lpColorMap->NumEntries,
									fOptimize,
									fOptimize ? AstralClockCursor : NULL))
				{
				if (fOptimize)
					ProgressEnd();
				Message(IDS_EMEMALLOC);
				goto ExitFalse;
				}
			if (fOptimize)
				ProgressEnd();
			}
		}
	if (lpColorMap->NumEntries <= 16)
		lpColorMap->NumEntries = 16;
	else
		lpColorMap->NumEntries = 256;
	FrameSetTypeInfo(&OutTypeInfo, FDT_PALETTECOLOR, lpColorMap);
	}

if (!fProgressSet)
	ProgressBegin(1, lpParms->Common.idDirty-IDS_UNDOFIRST+IDS_PROGFIRST);
fProgressSet = TRUE;
	
iMaxWidth = 0;
lpObject = NULL;
while (lpObject = ImgGetNextObject(lpImage, lpObject, YES, NO))
	{
	if (RectWidth(&lpObject->rObject) > iMaxWidth)
		iMaxWidth = RectWidth(&lpObject->rObject);
	}
if (!TypeConvert.Init(InTypeInfo, OutTypeInfo, iMaxWidth, DitherType))
	{
	Message(IDS_EMEMALLOC);
	goto ExitFalse;
	}

if (ImgMultipleObjects(lpImage))
	{
	ProgressBegin(ImgCountObjects(lpImage), 0);
	
	if ( !ImgEditInit(lpImage, ET_ALLOBJECTS, UT_NEWDATA|UT_COLORMAP, lpBase) )
		goto ExitFalse;

	fError = NO;
	lpObject = NULL;
	while (lpObject = ImgGetNextObject(lpImage, lpObject, YES, NO))
		{
		lpDstFrame = ConvertFrame(ObjGetEditFrame(lpObject), OutTypeInfo, &TypeConvert);
		if (!lpDstFrame)
			{
			fError = YES;
			break;
			}
 		ImgEditedObjectFrame( lpImage, lpObject, lpParms->Common.idDirty, NULL,
						lpDstFrame, NULL);
		}

	if (fError)
		{
		lpObject = NULL;
		while (lpObject = ImgGetNextObject(lpImage, lpObject, YES, NO))
			{
			if (lpObject->Pixmap.UndoFrame)
				{
		 		lpDstFrame = lpObject->Pixmap.EditFrame;
		 		lpObject->Pixmap.EditFrame = lpObject->Pixmap.UndoFrame;
		 		lpObject->Pixmap.UndoFrame = NULL;
		 		FrameClose(lpDstFrame);
		 		}
			}
		}
	ProgressEnd();
	}
else
	{
	if ( !ImgEditInit(lpImage, ET_OBJECT, UT_NEWDATA|UT_COLORMAP, lpBase) )
		goto ExitFalse;

	ProgressBegin(1, 0);
	lpDstFrame = ConvertFrame(lpBaseFrame, OutTypeInfo, &TypeConvert);
	ProgressEnd();

	if (!lpDstFrame)
		goto ExitFalse;
	/* Setup the new image and bring up the new image window */
	ImgEditedObjectFrame( lpImage, lpBase, lpParms->Common.idDirty, NULL,
						lpDstFrame, NULL);
	}

switch (lpParms->cmsInfo.dst.DataType)
	{
	case FDT_LINEART:
		lpImage->DataType = IDC_SAVELA;
		break;
	case FDT_GRAYSCALE:
		lpImage->DataType = IDC_SAVECT;
		break;
	case FDT_PALETTECOLOR:
		lpImage->DataType = IDC_SAVE8BITCOLOR;
		break;
	case FDT_RGBCOLOR:
		lpImage->DataType = IDC_SAVE24BITCOLOR;
		break;
	case FDT_CMYKCOLOR:
		lpImage->DataType = IDC_SAVE32BITCOLOR;
		break;
	}
ImgColorMapChanged(lpImage);
lpParms->Common.UpdateType = UT_DATATYPE;

fRet = TRUE;

ExitFalse:
if (fProgressSet)
	ProgressEnd();
MemError:
if (lpColorMap)
	FrameDestroyColorMap(lpColorMap);
return(fRet);
}