2025-11-28 00:35:46 +09:00

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;
}