514 lines
12 KiB
C++
514 lines
12 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: commands.cpp
|
|
//
|
|
// Desc: DirectShow sample code
|
|
// - Processes commands from the user.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "project.h"
|
|
|
|
|
|
// Global data
|
|
extern CMovie *pMovie;
|
|
|
|
// Prototypes
|
|
extern void RepositionMovie(HWND hwnd);
|
|
|
|
typedef LPBITMAPINFOHEADER PDIB;
|
|
|
|
// Constants
|
|
#define BFT_BITMAP 0x4d42 /* 'BM' */
|
|
|
|
// Macros
|
|
#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
|
|
? (int)(1 << (int)(lpbi)->biBitCount) \
|
|
: (int)(lpbi)->biClrUsed)
|
|
|
|
#define DibSize(lpbi) ((lpbi)->biSize + (lpbi)->biSizeImage + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
|
|
|
|
#define DibPaletteSize(lpbi) (DibNumColors(lpbi) * sizeof(RGBQUAD))
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlyerCaptureImage
|
|
*
|
|
\**************************************************************************/
|
|
BOOL VcdPlyerCaptureImage(LPCTSTR szFile)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if(pMovie)
|
|
{
|
|
BYTE* lpCurrImage = NULL;
|
|
|
|
// Read the current video frame into a byte buffer. The information
|
|
// will be returned in a packed Windows DIB and will be allocated
|
|
// by the VMR.
|
|
if(SUCCEEDED(hr = pMovie->GetCurrentImage(&lpCurrImage)))
|
|
{
|
|
BITMAPFILEHEADER hdr;
|
|
DWORD dwSize, dwWritten;
|
|
LPBITMAPINFOHEADER pdib = (LPBITMAPINFOHEADER) lpCurrImage;
|
|
|
|
// Create a new file to store the bitmap data
|
|
HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
// Initialize the bitmap header
|
|
dwSize = DibSize(pdib);
|
|
hdr.bfType = BFT_BITMAP;
|
|
hdr.bfSize = dwSize + sizeof(BITMAPFILEHEADER);
|
|
hdr.bfReserved1 = 0;
|
|
hdr.bfReserved2 = 0;
|
|
hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + pdib->biSize +
|
|
DibPaletteSize(pdib);
|
|
|
|
// Write the bitmap header and bitmap bits to the file
|
|
WriteFile(hFile, (LPCVOID) &hdr, sizeof(BITMAPFILEHEADER), &dwWritten, 0);
|
|
WriteFile(hFile, (LPCVOID) pdib, dwSize, &dwWritten, 0);
|
|
|
|
// Close the file
|
|
CloseHandle(hFile);
|
|
|
|
// The app must free the image data returned from GetCurrentImage()
|
|
CoTaskMemFree(lpCurrImage);
|
|
|
|
// Give user feedback that the write has completed
|
|
TCHAR szText[128], szDir[MAX_PATH];
|
|
GetCurrentDirectory(MAX_PATH, szDir);
|
|
|
|
// Strip off the trailing slash, if it exists
|
|
int nLength = (int) wcslen(szDir);
|
|
if (szDir[nLength-1] == TEXT('\\'))
|
|
szDir[nLength-1] = TEXT('\0');
|
|
|
|
(void)StringCchPrintf(szText, NUMELMS(szText), TEXT("Captured current image to %s\\%s.\0"), szDir, szFile);
|
|
MessageBox(hwndApp, szText, TEXT("Captured bitmap"), MB_OK);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
MessageBox(hwndApp, TEXT("Failed to capture image!"), TEXT("VMRPlayer9"), MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlyerDisplayCapturedImage
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlyerDisplayCapturedImage(
|
|
LPCTSTR szFile
|
|
)
|
|
{
|
|
// Open the bitmap with the system-default application
|
|
ShellExecute(hwndApp, TEXT("open\0"), szFile, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerOpenCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerOpenCmd(
|
|
int strmID
|
|
)
|
|
{
|
|
static BOOL fFirstTime = TRUE;
|
|
BOOL fRet;
|
|
TCHAR achFileName[MAX_PATH];
|
|
TCHAR achFilter[MAX_PATH];
|
|
LPTSTR lp;
|
|
|
|
if(fFirstTime)
|
|
{
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.hwndOwner = hwndApp;
|
|
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST |
|
|
OFN_SHAREAWARE | OFN_PATHMUSTEXIST;
|
|
}
|
|
|
|
(void)StringCchCopy(achFilter, NUMELMS(achFilter), IdStr(STR_FILE_FILTER));
|
|
ofn.lpstrFilter = achFilter;
|
|
|
|
/*
|
|
** Convert the resource string into to something suitable for
|
|
** GetOpenFileName ie. replace '#' characters with '\0' characters.
|
|
*/
|
|
for(lp = achFilter; *lp; lp++)
|
|
{
|
|
if(*lp == TEXT('#'))
|
|
{
|
|
*lp = TEXT('\0');
|
|
}
|
|
}
|
|
|
|
ofn.lpstrFile = achFileName;
|
|
ofn.nMaxFile = sizeof(achFileName) / sizeof(TCHAR);
|
|
ZeroMemory(achFileName, sizeof(achFileName));
|
|
|
|
fRet = GetOpenFileName(&ofn);
|
|
if(fRet)
|
|
{
|
|
if(strmID == 0)
|
|
{
|
|
fFirstTime = FALSE;
|
|
ProcessOpen(achFileName);
|
|
}
|
|
else
|
|
{
|
|
if(pMovie)
|
|
{
|
|
pMovie->RenderSecondFile(achFileName);
|
|
}
|
|
}
|
|
|
|
InitStreamParams(strmID);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerCloseCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerCloseCmd(
|
|
void
|
|
)
|
|
{
|
|
if(pMovie)
|
|
{
|
|
LONG cx, cy;
|
|
|
|
g_State = VCD_NO_CD;
|
|
pMovie->GetMoviePosition(&lMovieOrgX, &lMovieOrgY, &cx, &cy);
|
|
pMovie->StopMovie();
|
|
pMovie->CloseMovie();
|
|
|
|
SetDurationLength((REFTIME)0);
|
|
SetCurrentPosition((REFTIME)0);
|
|
|
|
delete pMovie;
|
|
pMovie = NULL;
|
|
}
|
|
|
|
g_bSecondFileLoaded = FALSE;
|
|
InvalidateRect(hwndApp, NULL, FALSE);
|
|
UpdateWindow(hwndApp);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerPlayCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerPlayCmd(
|
|
void
|
|
)
|
|
{
|
|
BOOL fStopped = (g_State & VCD_STOPPED);
|
|
BOOL fPaused = (g_State & VCD_PAUSED);
|
|
|
|
if((fStopped || fPaused))
|
|
{
|
|
if(pMovie)
|
|
{
|
|
pMovie->PlayMovie();
|
|
}
|
|
|
|
g_State &= ~(fStopped ? VCD_STOPPED : VCD_PAUSED);
|
|
g_State |= VCD_PLAYING;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerPlayCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerStopCmd(
|
|
void
|
|
)
|
|
{
|
|
BOOL fPlaying = (g_State & VCD_PLAYING);
|
|
BOOL fPaused = (g_State & VCD_PAUSED);
|
|
|
|
if((fPlaying || fPaused))
|
|
{
|
|
if(pMovie)
|
|
{
|
|
pMovie->StopMovie();
|
|
SetCurrentPosition(pMovie->GetCurrentPosition());
|
|
}
|
|
|
|
g_State &= ~(fPlaying ? VCD_PLAYING : VCD_PAUSED);
|
|
g_State |= VCD_STOPPED;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerStepCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerStepCmd(
|
|
void
|
|
)
|
|
{
|
|
if(pMovie)
|
|
{
|
|
// Ensure that the video is paused to update toolbar buttons
|
|
if(g_State & VCD_PLAYING)
|
|
VcdPlayerPauseCmd();
|
|
|
|
if(pMovie->FrameStepMovie())
|
|
{
|
|
g_State |= VCD_STEPPING;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerPauseCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerPauseCmd(
|
|
void
|
|
)
|
|
{
|
|
BOOL fPlaying = (g_State & VCD_PLAYING);
|
|
BOOL fPaused = (g_State & VCD_PAUSED);
|
|
|
|
if(fPlaying)
|
|
{
|
|
if(pMovie)
|
|
{
|
|
pMovie->PauseMovie();
|
|
SetCurrentPosition(pMovie->GetCurrentPosition());
|
|
}
|
|
|
|
g_State &= ~VCD_PLAYING;
|
|
g_State |= VCD_PAUSED;
|
|
}
|
|
else if(fPaused)
|
|
{
|
|
if(pMovie)
|
|
{
|
|
pMovie->PlayMovie();
|
|
}
|
|
|
|
g_State &= ~VCD_PAUSED;
|
|
g_State |= VCD_PLAYING;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerSeekCmd
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
VcdPlayerSeekCmd(
|
|
REFTIME rtSeekBy
|
|
)
|
|
{
|
|
REFTIME rt;
|
|
REFTIME rtDur;
|
|
|
|
rtDur = pMovie->GetDuration();
|
|
rt = pMovie->GetCurrentPosition() + rtSeekBy;
|
|
|
|
rt = max(0, min(rt, rtDur));
|
|
|
|
pMovie->SeekToPosition(rt,TRUE);
|
|
SetCurrentPosition(pMovie->GetCurrentPosition());
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ProcessOpen
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
ProcessOpen(
|
|
TCHAR *achFileName,
|
|
BOOL bPlay
|
|
)
|
|
{
|
|
/*
|
|
** If we currently have a video loaded we need to discard it here.
|
|
*/
|
|
if(g_State & VCD_LOADED)
|
|
{
|
|
VcdPlayerCloseCmd();
|
|
}
|
|
|
|
StringCchCopy(g_achFileName, MAX_PATH, achFileName);
|
|
|
|
pMovie = new CMovie(hwndApp);
|
|
|
|
if(pMovie)
|
|
{
|
|
HRESULT hr = pMovie->OpenMovie(g_achFileName);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TCHAR achTmp[MAX_PATH];
|
|
|
|
nRecentFiles = SetRecentFiles(achFileName, nRecentFiles, 3);
|
|
|
|
(void)StringCchPrintf(achTmp, NUMELMS(achTmp), IdStr(STR_APP_TITLE_LOADED), g_achFileName);
|
|
g_State = (VCD_LOADED | VCD_STOPPED);
|
|
|
|
// SetDurationLength(pMovie->GetDuration());
|
|
g_TimeFormat = VcdPlayerChangeTimeFormat(g_TimeFormat);
|
|
|
|
RepositionMovie(hwndApp);
|
|
pMovie->SetBorderClr(RGB(0x00, 0x80, 0x80));
|
|
|
|
// If play
|
|
if(bPlay)
|
|
{
|
|
pMovie->PlayMovie();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TCHAR Buffer[MAX_ERROR_TEXT_LEN];
|
|
|
|
if(AMGetErrorText(hr, Buffer, MAX_ERROR_TEXT_LEN))
|
|
{
|
|
MessageBox(hwndApp, Buffer, IdStr(STR_APP_TITLE), MB_OK);
|
|
}
|
|
else
|
|
{
|
|
MessageBox(hwndApp,
|
|
TEXT("Failed to open the movie. Either the file was ")
|
|
TEXT("not found or the wave device is in use."),
|
|
IdStr(STR_APP_TITLE), MB_OK);
|
|
}
|
|
|
|
pMovie->CloseMovie();
|
|
delete pMovie;
|
|
pMovie = NULL;
|
|
}
|
|
}
|
|
|
|
InitStreamParams(0);
|
|
|
|
InvalidateRect(hwndApp, NULL, FALSE);
|
|
UpdateWindow(hwndApp);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerChangeTimeFormat
|
|
*
|
|
* Tries to change the time format to id. Returns the time format that
|
|
* actually got set. This may differ from id if the graph does not support
|
|
* the requested time format.
|
|
*
|
|
\**************************************************************************/
|
|
int
|
|
VcdPlayerChangeTimeFormat(
|
|
int id
|
|
)
|
|
{
|
|
// Menu items are disabled while we are playing
|
|
BOOL bRet = FALSE;
|
|
int idActual = id;
|
|
|
|
assert(pMovie);
|
|
|
|
if (pMovie)
|
|
{
|
|
assert(pMovie->StatusMovie() != MOVIE_NOTOPENED);
|
|
|
|
// Change the time format with the filtergraph
|
|
switch(id)
|
|
{
|
|
case IDM_FRAME:
|
|
bRet = pMovie->SetTimeFormat(TIME_FORMAT_FRAME);
|
|
break;
|
|
|
|
case IDM_FIELD:
|
|
bRet = pMovie->SetTimeFormat(TIME_FORMAT_FIELD);
|
|
break;
|
|
|
|
case IDM_SAMPLE:
|
|
bRet = pMovie->SetTimeFormat(TIME_FORMAT_SAMPLE);
|
|
break;
|
|
|
|
case IDM_BYTES:
|
|
bRet = pMovie->SetTimeFormat(TIME_FORMAT_BYTE);
|
|
break;
|
|
}
|
|
|
|
if(!bRet)
|
|
{
|
|
// IDM_TIME and all other cases, everyone should support IDM_TIME
|
|
bRet = pMovie->SetTimeFormat(TIME_FORMAT_MEDIA_TIME);
|
|
assert(bRet);
|
|
idActual = IDM_TIME;
|
|
}
|
|
|
|
// Pause the movie to get a current position
|
|
|
|
SetDurationLength(pMovie->GetDuration());
|
|
SetCurrentPosition(pMovie->GetCurrentPosition());
|
|
}
|
|
|
|
return idActual;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VcdPlayerRewindCmd
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
VcdPlayerRewindCmd(
|
|
void
|
|
)
|
|
{
|
|
if(pMovie)
|
|
{
|
|
pMovie->SeekToPosition((REFTIME)0,FALSE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|