Obtaining Media File Information in Visual C++ Using FFPROBE

A short demonstration on how to utilize the ffprobe command to extract information about media files such as wav / MP4 files.

The ffprobe executable comes with the complete ffmpeg package and can be obtained from here:

https://www.ffmpeg.org/

Once downloaded and installed, the ffprobe executable resides alongside the ffmpeg and ffplay executables as shown:

ffmpeg1

Once installed, it is a good idea to add this to you environment variables, so that you can run the ffprobe executable within a command prompt. From the start button, right-click on ‘My Computer’ and select Properties. Select the Advanced tab and select the Environment Variables button. Add the path to the ffprobe executable in the edit control that opens, as shown:

ffmpeg2

Once this is set, close and re-open any command prompt you currently have open and then re-open them. Try the ffprobe command on an example media file, in this example a wmv file for example in the ‘MyStuff’ directory:

ffmpeg3

Here I open a command prompt, navigate (‘cd’) to the location of my example media file and run the ffprobe command on that file, ffprobe Beethoven.wmv

ffprobe4

In the next step I utilize more of the common line options available to me such as:

  • sexagesimal – display time values in sexagesimal format HH:MM:SS.MICROSECONDS
  • quiet – stay silent, no logging
  • print_format – set the output printing format, such as xml, json etc
  • show_format – show information about the container format of the input multimedia stream
  • show_streams – show information about each media stream contained in the input multimedia stream

So that in the next output see see the duration displayed in the HH:MM:SS.MICROSECONDS format and the “format_name” portion of the XML giving us the “asf” value. And so on.

To demonstrate this in Visual C++, we can use the MFC CreateProcess command to execute the ffprobe command, wait for it to finish and obtain the exit code. In addition there is another MFC command available to use, ReadFile, which we can use to read the output from the input/output device, such as the console input buffer. Full code listing as follows:

#include <iostream>
#include <direct.h>
#include <afx.h>

int main()
{
	// Create security attributes needed to create pipe 
	HANDLE hChildStdoutRd;
	HANDLE hChildStdoutWr;
	SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) } ;
	saAttr.bInheritHandle  = TRUE; 
	saAttr.lpSecurityDescriptor = NULL;
	
	// Create pipe to get results from child's stdout.	
	if ( !CreatePipe( &hChildStdoutRd, &hChildStdoutWr, &saAttr, 0 ) )
	{
		return 1;
	}
	
	CString l_strFileName = "Beethoven.wma";
	CString l_strPathName = "C:\\MyStuff";
	CString l_strFfprobePath = "ffprobe.exe";	
	CString l_strParameters = " -sexagesimal -v quiet -print_format xml -show_format -i " + l_strFileName;	

	PROCESS_INFORMATION pif  = { 0 };
	STARTUPINFO si = { sizeof(STARTUPINFO) }; 

	ZeroMemory( &si,sizeof( si ) );   
	si.cb = sizeof( si );  
	si.dwFlags	   = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.hStdOutput  = hChildStdoutWr;
	si.hStdError   = hChildStdoutWr;
	si.wShowWindow = SW_HIDE;

	BOOL bRet = CreateProcess(
						l_strFfprobePath.GetBuffer(0),			// Path to ffprobe executable
						l_strParameters.GetBuffer(0),			// Command parameters string
						NULL,									// Process handle not inherited
						NULL,									// Thread handle not inherited
						TRUE,									// Inheritance of handles
						CREATE_NO_WINDOW,						// Suppress console window
						NULL,									// Same environment block as this prog
						l_strPathName,							// Current directory
						&si,									// Pointer to STARTUPINFO
						&pif );									// Pointer to PROCESS_INFORMATION

	if( bRet == FALSE )
	{		
		return false;
	}

	// Wait until child processes exit, but not forever.  Terminate if still running.
	WaitForSingleObject( pif.hProcess, 4000 );
	TerminateProcess( pif.hProcess, 0 );

	// Close the write end of the pipe before reading from the read end of the pipe.
	if ( !CloseHandle( hChildStdoutWr ) )
	{
		return false;
	}

	// Read output from the child process.
	CString l_strResult;
	for ( ;; )
	{
		DWORD l_dwRead;
		CHAR l_chBuffer[ 4096 ];
				
		bool l_fIsDone = !ReadFile( hChildStdoutRd, l_chBuffer, 4096, &l_dwRead, NULL) || l_dwRead == 0;
		
		if( l_fIsDone ) break;
				
		l_strResult += CString( l_chBuffer, l_dwRead) ;
	}

	CloseHandle( hChildStdoutRd );
	CloseHandle( pif.hProcess );  
	CloseHandle( pif.hThread );    

	// Parse the resulting XML and extract its media type
	const CString l_strDelimiter = "</ffprobe>";
	const int l_nLength = l_strDelimiter.GetLength();
	int pos = l_strResult.Find( "</ffprobe>" );
	CString l_strSubstr = l_strResult.Left( pos + l_nLength );

	std::cout << l_strSubstr << std::endl;

	std::getchar();
	return 0;
}

Giving the following output:

ffprobe6

Here is another example, this time using a media file in MP4 format:

ffprobe7

Visual Studio 2010 project (includes ffprobe.exe) downloadable from here:

http://www.technical-recipes.com/Downloads/ffprobe.zip

Leave a Reply