853 lines
27 KiB
C++
853 lines
27 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Winmain.cpp : Defines the entry point for the application.
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
//This sample demostrates the use of the following ASF objects provided by
|
|
//Media Foundation, for reading an ASF media file:
|
|
//- ASF Splitter
|
|
//- ASF ContentInfo
|
|
//- ASF Indexer
|
|
//
|
|
//All of these objects are controlled by the ASF Manager, implemented in the
|
|
//CASFManager class.
|
|
//
|
|
//The user opens an ASF media file (*.wma or *.wmv) by using a standard Open
|
|
//dialog box. The global file attributes is shown on the Information pane.
|
|
//The ASF Manager enumerates the streams contained in the media file
|
|
//and displays only the first audio stream and the video stream to the user.
|
|
//
|
|
//The user can: then
|
|
//- Select a stream for parsing. By default, the first stream is selected by the ASF Manager.
|
|
//- Specify the offset from where to start parsing by seeking to a point in the presentation.
|
|
//- Check the Reverse check box to generate samples in reverse.
|
|
//
|
|
//The ASF Manager generates samples that passed through a decoder for decompression.
|
|
//As the samples are generated, sample attributes are shown on the Information pane.
|
|
//
|
|
//To test the samples, the user can use to Media Controller, implemented in the
|
|
//CMediaController class. For an audio stream, the Media Controller plays samples for
|
|
//5 seconds. For a video stream, it shows the first key frame as a bitmap.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//local project files
|
|
|
|
#include "MF_ASFParser.h"
|
|
#include "resource.h"
|
|
#include "ASFManager.h"
|
|
|
|
// Global Variables:
|
|
|
|
HINSTANCE g_hInst = NULL; //Global application instance.
|
|
HWND g_hWnd = NULL; //Global handle to the main Window.
|
|
|
|
CASFManager* g_pASFManager = NULL; //Pointer to the ASF Manager object.
|
|
CMediaController* g_pMediaController = NULL; //Pointer to the Media Controller object.
|
|
|
|
GUID g_guidMediaType = GUID_NULL; //Major media type GUID of the currently selected stream.
|
|
|
|
FILE_PROPERTIES_OBJECT g_fileinfo; //FILE_PROPERTIES_OBJECT variable that stores global ASF file attributes.
|
|
|
|
MFTIME g_seektime =0; //Seek time in 100 nano-seconds
|
|
BOOL g_fIsReverse = FALSE; //Reverse flag.
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: FormatTimeString
|
|
// Description: Converts MFTIME format to mm:ss format.
|
|
//
|
|
// time: MFTIME type 100 nano second unit.
|
|
// szTimeString: NULL-terminated string containing the time string.
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
void FormatTimeString(MFTIME time, WCHAR *szTimeString, DWORD cbSize, HRESULT hr)
|
|
{
|
|
//Convert nanoseconds to seconds
|
|
MFTIME TimeInSeconds = 0, Hours = 0, Minutes = 0, Seconds = 0;
|
|
|
|
TimeInSeconds = (MFTIME)time/10000000;
|
|
|
|
if (TimeInSeconds > 60)
|
|
{
|
|
Minutes = TimeInSeconds/60;
|
|
|
|
if( Minutes > 60 )
|
|
{
|
|
Hours = Minutes/60;
|
|
Minutes = Minutes % 60;
|
|
}
|
|
Seconds = (TimeInSeconds % 60);
|
|
}
|
|
else
|
|
{
|
|
Seconds = TimeInSeconds;
|
|
}
|
|
|
|
hr = StringCchPrintf (szTimeString, cbSize, L"%02d:%02d:%02d", (int) Hours, (int) Minutes, (int)Seconds);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: NotifyError
|
|
// Description: Show a message box with an error message.
|
|
//
|
|
// sErrorMessage: NULL-terminated string containing the error message.
|
|
// hrErr: HRESULT from the error.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void NotifyError(const WCHAR *szErrorMessage, HRESULT hrErr, HWND hWnd)
|
|
{
|
|
WCHAR szMessage[MAX_STRING_SIZE];
|
|
|
|
HRESULT hr = StringCchPrintf (szMessage, MAX_STRING_SIZE, L"%s (HRESULT = 0x%X)", szErrorMessage, hrErr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
MessageBox(hWnd, szMessage, NULL, MB_OK | MB_ICONERROR);
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: DisplaySampleInfo
|
|
// Description: Displays sample attributes on the Information pane.
|
|
// Parameter: Handle to the main Window.
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
void DisplaySampleInfo(SAMPLE_INFO *sampleinfo)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WCHAR szMessage [MAX_STRING_SIZE], szTemp [MAX_STRING_SIZE];
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"");
|
|
|
|
SendMessage(GetDlgItem(g_hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
if (sampleinfo->fSeekedKeyFrame == TRUE)
|
|
{
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Seeked Key Frame");
|
|
SendMessage(GetDlgItem(g_hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
}
|
|
|
|
//Stream number
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Stream number: %d", sampleinfo->wStreamNumber);
|
|
SendMessage(GetDlgItem(g_hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Total buffers in the sample
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Buffer count: %d", sampleinfo->cBufferCount);
|
|
SendMessage(GetDlgItem(g_hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Total sample size in bytes
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Total length: %d", sampleinfo->cbTotalLength);
|
|
SendMessage(GetDlgItem(g_hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Current sample time
|
|
FormatTimeString(sampleinfo->hnsSampleTime, szMessage, MAX_STRING_SIZE, hr);
|
|
StringCchPrintf(szTemp, MAX_STRING_SIZE, L"Sample time: %s (%d hns)", szMessage, sampleinfo->hnsSampleTime);
|
|
SendMessage(GetDlgItem(g_hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szTemp);
|
|
|
|
ZeroMemory((void*)sampleinfo, sizeof(SAMPLE_INFO));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: DisplayFilePropertiesObject
|
|
// Description: Displays File Properties Object Header about the currently open ASF file.
|
|
//
|
|
// Parameter: Handle to the main Window.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void DisplayFilePropertiesObject(const FILE_PROPERTIES_OBJECT& fileinfo, HWND hWnd)
|
|
{
|
|
SYSTEMTIME systemtime;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
WCHAR szMessage [MAX_STRING_SIZE], szTemp [MAX_STRING_SIZE];
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"");
|
|
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_RESETCONTENT, 0, 0);
|
|
|
|
SetDlgItemText(hWnd, IDC_STATIC_INFO, L"Global File Attributes");
|
|
|
|
//File ID
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"File ID: %08lX %04X %04X", fileinfo.guidFileID);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Creation Time
|
|
FileTimeToSystemTime(&fileinfo.ftCreationTime, &systemtime);
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Creation Time: %d-%d-%d %02d:%02d:%02d", systemtime.wYear, systemtime.wMonth, systemtime.wDay, systemtime.wHour, systemtime.wMinute, systemtime.wSecond);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Data Packet Count
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Packets: %d ", fileinfo.cbPackets);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Play Duration
|
|
FormatTimeString(fileinfo.cbPlayDuration, szMessage, MAX_STRING_SIZE, hr);
|
|
StringCchPrintf(szTemp, MAX_STRING_SIZE, L"Play duration: %s (%I64d hns)", szMessage, fileinfo.cbPlayDuration);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szTemp);
|
|
|
|
//Presenation Duration
|
|
FormatTimeString(fileinfo.cbPresentationDuration, szMessage, MAX_STRING_SIZE, hr);
|
|
StringCchPrintf(szTemp, MAX_STRING_SIZE, L"Presentation duration: %s (%I64d hns)", szMessage, fileinfo.cbPresentationDuration);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szTemp);
|
|
|
|
//Send Duration
|
|
FormatTimeString(fileinfo.cbSendDuration, szMessage, MAX_STRING_SIZE, hr);
|
|
StringCchPrintf(szTemp, MAX_STRING_SIZE, L"Send duration: %s (%I64d hns)", szMessage, fileinfo.cbSendDuration);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szTemp);
|
|
|
|
//Preroll
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Preroll: %I64d hns", fileinfo.cbPreroll);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Flags
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Flags: %d", fileinfo.cbFlags);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Minimum Data Packet Size
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Minimum packet size: %d bytes", fileinfo.cbMinPacketSize);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Maximum Data Packet Size
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Maximum packet size: %d bytes", fileinfo.cbMaxPacketSize);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
//Maximum Bit rate
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"Maximum bit rate: %d bits/sec", fileinfo.cbMaxBitRate);
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
|
|
StringCchPrintf(szMessage, MAX_STRING_SIZE, L"");
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_ADDSTRING, 0, (LPARAM)szMessage);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: ResetUI
|
|
// Description: Reset controls to original state because there is not ASF file
|
|
// that is currently open.
|
|
// Parameter: Handle to the main Window.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void ResetUI(HWND hWnd)
|
|
{
|
|
//Hide Show File Properties button
|
|
ShowWindow(GetDlgItem(hWnd, IDC_FILE_PROP), SW_HIDE);
|
|
|
|
//Hide Information pane
|
|
ShowWindow(GetDlgItem(hWnd, IDC_INFO), SW_HIDE);
|
|
|
|
//Hide Splitter configuration controls
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_PARSER_CONFIG), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_STREAM), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_STREAM2), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_STREAM1), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STREAM1), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STREAM2), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_REVERSE), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_SEEK), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_SEEK), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_TIME), SW_HIDE);
|
|
SendMessage(GetDlgItem(hWnd, IDC_STREAM1), BM_SETCHECK , BST_UNCHECKED, 0);
|
|
SendMessage(GetDlgItem(hWnd, IDC_STREAM2), BM_SETCHECK , BST_UNCHECKED, 0);
|
|
|
|
//Hide the Generate Samples button
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PARSE), SW_HIDE);
|
|
|
|
//Hide the test controls
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PLAY_AUDIO), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_SHOW_BITMAP), SW_HIDE);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: StreamSelect
|
|
// Description: Selects audio or video stream for parsing.
|
|
// Parameter:
|
|
// wStreamNumber: Stream number of the stream to select.
|
|
// hWnd: Handle to the main Window.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void StreamSelect(WORD wStreamNumber, HWND hWnd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//New stream selection so hide the test controls for audio and video.
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PLAY_AUDIO), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_SHOW_BITMAP), SW_HIDE);
|
|
|
|
//Select the specified stream for parsing
|
|
hr = g_pASFManager->SelectStream(wStreamNumber, &g_guidMediaType);
|
|
|
|
//If the media type is invalid, the stream will be parsed but generated samples cannot be tested
|
|
if (hr == MF_E_INVALIDMEDIATYPE)
|
|
{
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PARSE), SW_SHOW);
|
|
NotifyError(L"Media type is not supported by the stream decoder. \nNo test samples will be available", hr, hWnd);
|
|
return;
|
|
}
|
|
|
|
//Stream selected, show the GenerateSamples button
|
|
if (hr == S_OK)
|
|
{
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PARSE), SW_SHOW);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
NotifyError(L"Could not select stream", hr, hWnd);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: GetAvailableStreams
|
|
// Description: Enumerates available streams in the ASF file and selects the
|
|
// first stream.
|
|
// Parameter: Handle to the main Window.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void GetAvailableStreams(HWND hWnd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WORD *pwStreamNumbers = NULL;
|
|
GUID *pGUIDs = NULL;
|
|
|
|
DWORD cbTotalStreams = 0;
|
|
|
|
WCHAR szLabel[MAX_STRING_SIZE];
|
|
StringCchPrintf(szLabel, MAX_STRING_SIZE, L"");
|
|
|
|
//Get the stream numbers and the major media type GUIDs for the streams
|
|
hr = g_pASFManager->EnumerateStreams(&pwStreamNumbers, &pGUIDs, &cbTotalStreams);
|
|
|
|
if(SUCCEEDED(hr) && pwStreamNumbers)
|
|
{
|
|
|
|
for ( DWORD index = 0; index < cbTotalStreams; index++)
|
|
{
|
|
if(pGUIDs[index] == MFMediaType_Audio)
|
|
{
|
|
//For audio stream make UI adjustments:
|
|
|
|
//Show the stream number
|
|
StringCchPrintf(szLabel, MAX_STRING_SIZE, L"%d", pwStreamNumbers[index]);
|
|
SetDlgItemText(hWnd, IDC_STATIC_STREAM1, szLabel);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_STREAM1), SW_SHOW);
|
|
|
|
//Designate the radio button 1 as Audio
|
|
SetDlgItemText(hWnd, IDC_STREAM1, L"- Audio");
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STREAM1), SW_SHOW);
|
|
}
|
|
|
|
if(pGUIDs[index] == MFMediaType_Video)
|
|
{
|
|
//For video stream make UI adjustments:
|
|
|
|
//Show the stream number
|
|
StringCchPrintf(szLabel, MAX_STRING_SIZE, L"%d", pwStreamNumbers[index]);
|
|
SetDlgItemText(hWnd, IDC_STATIC_STREAM2, szLabel);
|
|
SetDlgItemText(hWnd, IDC_STREAM2, L"- Video");
|
|
|
|
//Designate the radio button 1 as Video
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_STREAM2), SW_SHOW);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STREAM2), SW_SHOW);
|
|
}
|
|
|
|
}
|
|
|
|
//By default select the first stream and based on the GUID show the corresponding
|
|
//stream radio button as checked.
|
|
StreamSelect(pwStreamNumbers[0], hWnd);
|
|
|
|
if(pGUIDs[0] == MFMediaType_Audio)
|
|
{
|
|
SendMessage(GetDlgItem(hWnd, IDC_STREAM1), BM_SETCHECK , BST_CHECKED, 0);
|
|
}
|
|
if(pGUIDs[0] == MFMediaType_Video)
|
|
{
|
|
SendMessage(GetDlgItem(hWnd, IDC_STREAM2), BM_SETCHECK , BST_CHECKED, 0);
|
|
}
|
|
|
|
//Show the related UI controls
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_STREAM), SW_SHOW);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_STATIC_PARSER_CONFIG), SW_SHOW);
|
|
|
|
}
|
|
else
|
|
{
|
|
NotifyError(L"No streams found.", hr, hWnd);
|
|
}
|
|
|
|
SAFE_ARRAY_DELETE( pwStreamNumbers);
|
|
SAFE_ARRAY_DELETE( pGUIDs);
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: SetSeekBar
|
|
// Description: Setup seek bar range.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetSeekBar(HWND hWnd)
|
|
{
|
|
WCHAR szMessage [MAX_STRING_SIZE];
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//Setup the track bar for seeking
|
|
SendMessage(GetDlgItem(hWnd, IDC_SEEK), TBM_SETRANGEMIN, TRUE, 0);
|
|
SendMessage(GetDlgItem(hWnd, IDC_SEEK), TBM_SETRANGEMAX, TRUE, (LPARAM)g_fileinfo.cbPresentationDuration/10000000);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_SEEK), SW_SHOW);
|
|
|
|
//Show play duration
|
|
FormatTimeString(g_fileinfo.cbPresentationDuration, szMessage, MAX_STRING_SIZE, hr);
|
|
SetDlgItemText(hWnd, IDC_TIME, szMessage);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_TIME), SW_SHOW);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// Name: OnOpen
|
|
// Description: Opens the standard open file dialog and allows the user to a wma or wmv file.
|
|
//
|
|
// Parameter: Handle to the main Window.
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void OnOpen(HWND hWnd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD extendedError = 0;
|
|
const size_t bufferSize = 2000;
|
|
|
|
ZeroMemory((void*)&g_fileinfo, sizeof(FILE_PROPERTIES_OBJECT));
|
|
|
|
//Reset the UI and show the controls later depending on the file opened and stream selection.
|
|
ResetUI(hWnd);
|
|
|
|
if (g_pASFManager)
|
|
{
|
|
// Show the File Open dialog.
|
|
WCHAR path[bufferSize];
|
|
path[0] = L'\0';
|
|
|
|
OPENFILENAME ofn;
|
|
ZeroMemory(&ofn, sizeof(ofn));
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.hwndOwner = hWnd;
|
|
ofn.lpstrFilter = L"Windows Media \0*.wma;*.wmv\0ASF\0*.asf\0All files\0*.*\0";
|
|
ofn.lpstrFile = path;
|
|
ofn.nMaxFile = MAX_PATH;
|
|
ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_FILEMUSTEXIST;
|
|
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
CHECK_HR (hr = g_pASFManager->OpenASFFile(path));
|
|
|
|
CHECK_HR (hr = g_pASFManager->SetFilePropertiesObject(&g_fileinfo));
|
|
|
|
//Get File Properties Header Object that stores the global file attributes
|
|
DisplayFilePropertiesObject(g_fileinfo, hWnd);
|
|
|
|
//Show the Show File Properties button that will display the global file attributes
|
|
ShowWindow(GetDlgItem(hWnd, IDC_FILE_PROP), SW_SHOW);
|
|
|
|
//Show the Information pane
|
|
ShowWindow(GetDlgItem(hWnd, IDC_INFO), SW_SHOW);
|
|
|
|
//Enumerate the streams in the file
|
|
GetAvailableStreams(hWnd);
|
|
|
|
//Setup seek bar that the user can use to set the offset
|
|
SetSeekBar(hWnd);
|
|
|
|
//If the file is reversible, show the Reverse check box
|
|
if (g_fileinfo.cbMaxPacketSize == g_fileinfo.cbMinPacketSize)
|
|
{
|
|
ShowWindow(GetDlgItem(hWnd, IDC_REVERSE), SW_SHOW);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
done:
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
NotifyError(L"Cannot open the ASF file.", hr, hWnd);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: OnParse
|
|
// Description: Generates uncompressed samples for the selected stream.
|
|
// Parameter: Handle to the main Window.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void OnParse(HWND hWnd)
|
|
{
|
|
assert ( g_pASFManager!=NULL);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwFlags = 0;
|
|
|
|
SAMPLE_INFO sampleinfo;
|
|
ZeroMemory(&sampleinfo, sizeof(SAMPLE_INFO));
|
|
|
|
g_hWnd = hWnd;
|
|
|
|
//Reset UI
|
|
//Hide the test controls
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PLAY_AUDIO), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hWnd, IDC_SHOW_BITMAP), SW_HIDE);
|
|
SetDlgItemText(hWnd, IDC_STATIC_INFO, L"Sample Attributes");
|
|
SendMessage(GetDlgItem(hWnd, IDC_INFO), LB_RESETCONTENT, 0, 0);
|
|
|
|
//Get the Media Controller that will control test data
|
|
if (!g_pMediaController)
|
|
{
|
|
hr = g_pASFManager->GetMediaController(&g_pMediaController);
|
|
}
|
|
|
|
//Clear exisiting test content from the Media Controller
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
hr = g_pMediaController->Reset();
|
|
}
|
|
if (FAILED (hr))
|
|
{
|
|
NotifyError(L"Media controller could not be found.", hr, hWnd);
|
|
}
|
|
|
|
//Check if the user requested reverse parsing
|
|
if (g_fIsReverse)
|
|
{
|
|
dwFlags |= MFASF_SPLITTER_REVERSE;
|
|
}
|
|
|
|
//Get the data offset based on seektime
|
|
hr = g_pASFManager->GenerateSamples(g_seektime, dwFlags, &sampleinfo, &DisplaySampleInfo);
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//If the Media Controller collected any test content
|
|
if (g_pMediaController && g_pMediaController->HasTestMedia())
|
|
{
|
|
//For the audio stream, show the Test Audio button
|
|
if (g_guidMediaType == MFMediaType_Audio)
|
|
{
|
|
ShowWindow(GetDlgItem(hWnd, IDC_PLAY_AUDIO), SW_SHOW);
|
|
}
|
|
|
|
//For the video stream, show the Show Bitmap button
|
|
if (g_guidMediaType == MFMediaType_Video)
|
|
{
|
|
ShowWindow(GetDlgItem(hWnd, IDC_SHOW_BITMAP), SW_SHOW);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NotifyError(L"Samples could not be generated.", hr, hWnd);
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: OnPlayTestAudio
|
|
// Description: Play the test audio clip.
|
|
// Parameter: Handle to the main Window.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void OnPlayTestAudio(HWND hWnd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//Check if the Media Controller has test content
|
|
if (g_pMediaController && g_pMediaController->HasTestMedia())
|
|
{
|
|
hr = g_pMediaController->PlayAudio();
|
|
}
|
|
else
|
|
{
|
|
NotifyError(L"Test clip not found.", E_FAIL, hWnd);
|
|
}
|
|
|
|
if (FAILED (hr))
|
|
{
|
|
NotifyError(L"Could not play test audio clip.", hr, hWnd);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: ConvertLabelToStreamNumber
|
|
// Description: Converts the control caption to a valid stream number and then
|
|
// selects the stream.
|
|
//
|
|
// lpControlID: Control ID
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
void ConvertLabelToStreamNumber( HWND hWnd, int ControlID)
|
|
{
|
|
WCHAR szLabel [3];
|
|
|
|
GetDlgItemText(hWnd, ControlID, (LPWSTR)szLabel, sizeof(szLabel));
|
|
|
|
WCHAR *szStop = (szLabel+1);
|
|
|
|
int l = wcstol(szLabel, &szStop, 10);
|
|
|
|
WORD wStreamNumber = (WORD)l;
|
|
|
|
StreamSelect(wStreamNumber, hWnd);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: SetReverse
|
|
// Description: Setup the reverse flag and the seektime when reverse is enabled.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetReverse(HWND hWnd)
|
|
{
|
|
//Check if the Reverse check box is enabled.
|
|
if (SendMessage(GetDlgItem(hWnd, IDC_REVERSE), BM_GETCHECK , 0, 0)==BST_CHECKED)
|
|
{
|
|
LRESULT nMax = SendMessage(GetDlgItem(hWnd, IDC_SEEK), TBM_GETRANGEMAX , 0, 0);
|
|
SendMessage(GetDlgItem(hWnd, IDC_SEEK), TBM_SETPOS, TRUE, nMax);
|
|
|
|
//Setup seek time
|
|
g_seektime = nMax*10000000;
|
|
|
|
g_fIsReverse = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LRESULT nMin = SendMessage(GetDlgItem(hWnd, IDC_SEEK), TBM_GETRANGEMIN , 0, 0);
|
|
SendMessage(GetDlgItem(hWnd, IDC_SEEK), TBM_SETPOS, TRUE, nMin);
|
|
|
|
g_seektime = nMin*1;
|
|
|
|
g_fIsReverse = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: UIBitmap
|
|
// Description: Dialogbox callback for the window that shows the bitmap
|
|
// for the key frame.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
INT_PTR CALLBACK UIBitmap(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG :
|
|
{
|
|
RECT rcClient = { 0, 0, 0, 0 };
|
|
|
|
g_pMediaController->GetBitmapDimensions((UINT32*)&rcClient.right, (UINT32*)&rcClient.bottom);
|
|
|
|
AdjustWindowRectEx(&rcClient, GetWindowStyle(hDlg), FALSE, GetWindowExStyle(hDlg));
|
|
|
|
SetWindowPos(
|
|
hDlg,
|
|
HWND_TOP,
|
|
0, 0,
|
|
// New window size:
|
|
(rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top),
|
|
SWP_NOMOVE
|
|
);
|
|
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_PAINT:
|
|
hr = g_pMediaController->DrawKeyFrame(hDlg);
|
|
if (FAILED(hr))
|
|
{
|
|
NotifyError(L"Could not display bitmap.", hr, hDlg);
|
|
EndDialog(hDlg, 0);
|
|
}
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
return TRUE;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
default:
|
|
return FALSE; // Dialog manager will perform the default action.
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: OnShowBitmap
|
|
// Description: Creates a Window and shows the key frame in another window.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
void OnShowBitmap(void)
|
|
{
|
|
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_BITMAP), g_hWnd, UIBitmap);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: UIMain
|
|
// Description: Dialogbox callback for the main Window.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
INT_PTR CALLBACK UIMain(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
int seekposition =0;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
ResetUI(hDlg);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch ( wParam )
|
|
{
|
|
case IDC_OPENFILE:
|
|
OnOpen(hDlg);
|
|
break;
|
|
|
|
case IDC_FILE_PROP:
|
|
DisplayFilePropertiesObject(g_fileinfo, hDlg);
|
|
break;
|
|
|
|
case IDC_PARSE:
|
|
OnParse(hDlg);
|
|
break;
|
|
|
|
case IDC_SHOW_BITMAP:
|
|
OnShowBitmap();
|
|
break;
|
|
|
|
case IDC_PLAY_AUDIO:
|
|
OnPlayTestAudio(hDlg);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_STREAM1:
|
|
ConvertLabelToStreamNumber(hDlg, IDC_STATIC_STREAM1);
|
|
break;
|
|
|
|
case IDC_STREAM2:
|
|
ConvertLabelToStreamNumber(hDlg, IDC_STATIC_STREAM2);
|
|
break;
|
|
|
|
case IDC_REVERSE:
|
|
SetReverse(hDlg);
|
|
break;
|
|
|
|
} // switch (inner)
|
|
} // if
|
|
// wm_command
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
switch ( LOWORD(wParam) )
|
|
{
|
|
case TB_ENDTRACK:
|
|
DWORD dwPos;
|
|
dwPos = (DWORD)SendMessage(GetDlgItem(hDlg, IDC_SEEK), TBM_GETPOS, 0, 0);
|
|
//Get current slider position and convert value into seconds.
|
|
g_seektime = dwPos*10000000;
|
|
|
|
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
default:
|
|
return FALSE; // Dialog manager will perform the default action.
|
|
}
|
|
return (INT_PTR)TRUE;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name: WinMain
|
|
// Description: Application entry point.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
int APIENTRY _tWinMain(HINSTANCE hInstance,
|
|
HINSTANCE /* hPrevInstance */,
|
|
LPTSTR /* lpCmdLine */,
|
|
int nCmdShow)
|
|
|
|
{
|
|
|
|
TRACE_INIT();
|
|
|
|
g_hInst = hInstance;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//Initialize CASFManager object as a global instance
|
|
CHECK_HR( hr = CASFManager::CreateInstance(&g_pASFManager));
|
|
|
|
DialogBox( hInstance, (LPCTSTR)IDD_MAIN, NULL, UIMain );
|
|
|
|
TRACE((L"Released resources. Closing application...\n"));
|
|
|
|
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
NotifyError(L"ASF manager could not be created", hr, g_hWnd);
|
|
}
|
|
|
|
SAFE_RELEASE (g_pASFManager); //This also releases the Media Controller.
|
|
|
|
TRACE_CLOSE();
|
|
|
|
return 0;
|
|
}
|