DirectShow Media File Playback Summary
MU group documentation
Author: Inkick
This article is 99% content, reproduced please indicate the source
1. Overview
DirectShow's media file playback process is also a file to select the corresponding to the media file, build FILTER GRAPH, and maintain the state of the Filter Graph's status and control. The media files mentioned here are not only the audio, video files, but also including graphic image formats such as BMP, JPEG, GIF, and digital music sequences such as MIDI.
Therefore, playback of media files using DirectShow requires the following steps:
2. Build filter graph
Filter Graph provides a container for Filter, a complete Filter Graph is a complete Filter link, which is transparent to the program. For each media file, the Filter Graph and the media file have corresponding relationships. That is, a Filter Graph can only achieve a playback of a (species) file.
In DirectShow, Filter Graph is implemented by the interface object IGRAPHBUILDER, we can call the Win32 API function cocreateInstance () to establish an entity. After the Filter Graph entity is established, it does not have any Filter, so there is no practical use. So we need to connect the need to build FilterGraph's build.
Intelligent Connection This term covers a series of Filter Graph Manager to construct all or part of the Filter GRAPH algorithm. At any time, when Filter Graph Manager needs to add Filter to complete the graph, it is roughly the following things:
If a Filter is stored in Graph, and this filter has at least one INPUT PIN that is not connected, Filter Graph Manager tries to try this filter.
Otherwise, the Filter Graph Manager can accept the Filter of the appropriate media type when you find a connection in the registered FILTER. Every Filter registers has a MERIT value, which is used to mark which filter is easier to select by Filter Graph Manager to complete the graph. Filter Graph Manager is selected by the order of MERIT values. The larger the MERIT value, the greater the chance to be selected. For each stream type (such as audio, video, midi), the default RENDERER has a very high MERIT value, the decoder is also, the dedicated Filter has a low MERIT value.
If Filter Graph Manager selected, it will return to try another Filter combination.
We have three ways to build Graph:
1.Filter Graph Manager builds the entire graph
2. Filter Graph Manager build part of graph
3. Application builds the entire graph
2.1 Renderfile
IGraphBuilder provides a variety of intelligent methods for completing Filtergraph builds. The easiest way is to use interface methods IgraphBuilder :: Renderfile.
HRESULT RENDERFILE (LPCWSTR LPWSTRFILE, LPCWSTR LPWSTRPLAYLIST);
The first parameter is the path to the file (after the text), the second parameter is retained, must be empty.
This method requires a Unicode string argument representing the media file path or the URL. The string of the file path we obtained through the interface is often an ANSI string. We can use the following method to convert: contain header files:
#include
#include
These two headers contain functions with the ANSI string and Unicode strings to transform each other and macro
Use macro: uses_conversion;
Define an array of Wchar: wchar filename [max_path];
Max_path is defined in WINDEF.H: #define max_path 260
This is 260 complosing with the maximum character of the Windows path. This array saves the path represented by the transformed Unicode form. Then you can use the following function to convert: (assuming the string given in the form of ANSI) SZFILE)
WCSNCPY (FileName, SZFILE), NUMELMS (WFILE) -1);
Filename [max_path-1] = 0;
Prototype of WCSNCPY:
Wchar_t * wcsncpy (wchar_t * strdest, const wchar_t * strsource, size_t count);
This function is similar to STRCPY, which is a replication between strings. Just, this is a version used on Unicode.
The first parameter specifies the storage address after the transformation of the string, that is, the Unicode string we have to get, the second parameter specifies the source address of the string to be transformed, that is, the ANSI string we want to translate. In the second parameter uses the macro T2W (SZFILE), this macro can convert an ANSI string to a Wchar type string. The third parameter is the number of characters in the conversion string.
Now the problem came out, the second parameter of this function requires the address of the string, if we have such an address, what do we conversion? So this is the key to T2W. Let's take a look at the definition of T2W. This definition is in the header file ATLCONV.H (only the part we are more interested).
#ifdef _unicode
INLINE LPWSTR T2W (LPTSTR LP) {Return LP;}
Inline LPTSTR W2T (LPWSTR LP) {RETURN LP;}
#ELSE
#define T2W A2W
#ENDIF
We can see that if _unicode is defined, T2W directly returns a string that will be transformed, because in the Unicode environment, the ANSI character has the same width as the Unicode character. That is, ANSI is a subset of Unicode. However, in a non-Unicode environment, the T2W is replaced with A2W so that we return to see the definition of A2W (this definition in the same header file):
#define A2W (LPA) (/
(LPCSTR) LPA == NULL)? NULL: (/
_CONVERT = (LSTRLENA (LPA) 1), /
Atla2whelper ((LPWSTR) Alloca (_Convert * 2), LPA, _CONVERT))))))
Macro definition is more embarrassing, we convert to a better understandable function:
LPCSTR A2W (LPTSTR LPA)
{
IF (lpa == null)
{
Return NULL;
}
_CONVERT = (LSTRLEN (A) (LPA) 1);
Atla2whelper ((LPWSTR) Alloca (_COVERT * 2), LPA, _CONVERT
Return LPA;
This function is clear, first determined whether it is an empty string, if it is an empty string, return empty, because the empty string in ANSI and Unicode is NULL, if not empty, start conversion. The focus is the function atla2wwhelper (), this function is implemented in AtlConv.cpp:
LPWSTR WINAPI Atla2whelper (LPWSTR LPW, LPCSTR LPA, INT NCHARS)
{
_Asserte (lpa! = Null);
_Asserte (lpw! = Null);
LPW [0] = '/ 0';
MultibyToWideChar (CP_ACP, 0, LPA, -1, LPW, NCHARS);
Return LPW;
}
In addition to doing some necessary safety decisions and preparation preparation, the core work is called a function multibytetowideChar, so we have to continue. This time we found that we couldn't find the source code, but we can get a clear tip in MSDN:
Int multibytetowidechar (
Uint CodePage, // Code Page
DWORD dwflags, // character-type options
LPCSTR LPMULTIBYTESTER, / / Address of String To Map
Int cchmultibyte, // Number of bytes in string
LPWSTR LPWIDECHARSTR, / / Address of Wide-Character Buffer
Int cchwidechar // size of buffer
);
This API function accepts six parameters (Win32 API style - a number of parameters), the first parameter specifies the CodePage (explained appendix 5.1), here we can specify CP_ACP, to indicate that we choose ANSI Code Page to represent us The source string coding form is ANSI, the second parameter is a set of position flags, which determines how to handle control characters or invalid characters in the original string. Generally specify MB_PREComposed, the third parameter is the address (or pointer) of the source string. The fourth word parameter is how many characters have been included in the string to be converted, and the fifth parameter specifies the storage address of the conversion string, the sixth parameter specifies the size of the buffer of the converted string, that is How much is the memory space after conversion.
Now we return, (if you have forgotten our original intention to suggest you listen to F.i.r's song), according to the most core function multibytetowideChar analysis, we can get the meaning of several parameters of Atla2whelper:
Atla2whelper (LPWSTR LPW, / / address of the target string
LPCSTR LPA, / / The address of the source string
INT nchars // Source string contains the number of characters
)
Therefore, it is directly called after judging the LPW and LPAs:
LPW [0] = '/ 0';
MultibyToWideChar (CP_ACP, 0, LPA, -1, LPW, NCHARS);
We have returned to that macro, or let us see the function we have rewritten:
_CONVERT = (LSTRLEN (A) (LPA) 1); Atla2whelper ((LPWSTR) Alloca (_COVERT * 2), LPA, _CONVERT);
Return LPA;
The lstrlen function gets the length of the parameter string (for the ANSI string is byte, the number of characters is the number of characters), and the following (a) indicates the argument of the ANSI string, after this parameter The value of _Convert turns into the string length to be converted to the same. Why do you want to add one? Because the end of the string is to make up a '/ 0', we always reserve space for this '/ 0'.
The next step is to apply for a space to save the string of transformation, use (LPWSTR) Alloca (_COVERT * 2), assign the number of spaces of the number of strings (because the space occupied by the Unicode character is twice the ANSI), then The address is turned to LPWSTR, and as a parameter is passed to Atla2whelper, the conversion is started, the task is completed!
However, is it true? Where is the death _convert? Haha, remember what we said at the beginning? Recall, what is the job to do before using T2W? Use macro Uses_Conversion ;! why? We continue to see this macro definition:
#ifndef _debug
#ELSE
#define uss_conversion int _Convert = 0
#ENDIF
see it? This macro is actually defined this _Convert variable. Therefore, when you use T2W macros in different scopes, you must write this stuff before using it.
Close your eyes, organize your ideas, all the technical documents say clear renderfile, and I wrote nearly three pages that I sprinkled with me. The relevant content involved in the middle can be written into a technical white paper. If you can say it clearly these two pages, I am still very accomplishment. If you are interested in Unicode and ANSI, please check the relevant information yourself, I vowed to meet similar problems in this life.
Instance code: See Appendix 5.2, Renderfile
2.2 Render
Go back to our dear DirectShow (to a hug!).
This interface method begins with an output PIN and automatically constructs the remaining filtergram. This method automatically adds the necessary FILTER until it is added to a render filter.
HRESULT RENDER (IPIN * PPINOUT);
Using this interface method First, you should first find an unconnected output PIN. The so-called PIN refers to the port that flows into or out of the Filter. There is at least one PIN on a filter, and the PIN can be divided into input Pin according to the direction of the PIN data stream. And output PIN. We look for PINs to follow the steps below:
1. Enumerate all the PINs above the target filter.
Ipin * ppin
Ienumpins * penum = null;
Pfilter-> Enumpins (& Penum);
While (Penum-> Next (1, & PPIN, NULL) == S_OK)
{
// Todo: Your Process Here
}
The first line of code first declares an enumerator pointer, then the second line calls the interface method to generate an instance, then start an enumeration with a while loop, once, the PPIN pointer points to the next PIN, then Each PIN is processed: 2, determine the connection status of each PIN and connection directions.
Judging the connection direction of the PIN:
PIN_DIRECTION PINDIR;
PPIN-> QueryDirection (& PINDIR);
// TODO: TEST The Direction Here
The first line code defines a variable PINDIR type PIN_DIRECTION, and then calls the interface method PPIN-> querydirection (& Pindir) in the second line; after the call, the value of Pindir has become the direction on the PPIN. Then determine the determination according to actual needs.
Judging the connection status of the PIN:
IPIN * PTEMP;
IF (SUCCEEDED (& PPIN-> Connectedto)))
{
// it is not the Just Pin We Want, Because IT IS HAS BEEN CONNECTED
}
Else
{
// this pin is we want
}
To determine the connection status of the PIN, we use the interface method PPIN-> Connectedto (& PTEMP). The true purpose of this interface method is to return the pointer to another PIN connected to this PIN. If there is no other PIN and this PIN connection, E_FAIL is returned, so we can use the successite macro to capture the return value of the interface method to determine the connection status of the PIN.
After obtaining a PIN that is not connected to a FILTER and the direction is in line with the data flow, we can call this render interface to complete this Filter Graph's architecture.
In general, this interface method is best to use iGraphBuilder :: addSourceFilter, which is first added to a source filter, then starting from the output PIN of this source, complete FilterGraph architecture.
AddSourceFilter method Add a source filter that can render specific files. First, it looks for the match in the registered FILTER in the registered FILTER in accordance with the protocol name, file extension, or file header. If this method is positioned to a suitable source filter, it immediately creates an instance of this filter and add it to the graph, then call the Filter's IFilesourceFilter :: Load method.
Instance code: See Appendix 5.4
2.3 ConnectDriect
IGraphBuilder also provides a variety of local, specific and micro interface methods than RENDER FILE and RENDER, etc.. Most of these interface methods are for two FILTERs or two connections. The ConnectDirect method is one of them. This method is trying to connect two filter directly, if it is not successful, return directly. Not doing other processing. This interface approach we generally be used as a negotiation check between two PINs without direct connection between two FILTERs. The reason is that this function success rate is too low. If the connection for two FILTERs requires repeated trial different Filter, it will seriously affect efficiency. Of course, if the program can be confirmed that two FILTERs can be connected, using this interface method can use a simple method to complete the connection.
HRESULT ConnectDirect (iPin * Ppinout, IPIN * PPININ, Const AM_MEDIA_TYPE * PMT);
The first two parameters are the input output PIN to which the two filters to connect, and the last one is the structure of the media type, which can be empty. For the media structure, please refer to Appendix 5.2.2.4 Connect
This interface method is the extension and expansion of the ConnectDirect interface method. The interface method is also connected to both FILTERs, but it is different from the ConnectDirect method. This interface method first tries to connect two filters first, if it is not directly connected (most of the case due to media types do not match), try to use the middle Filter connection. Therefore, this interface method has a higher success rate.
2.5 AddFilter
This interface method adds the specified FILTER to the Filter Graph, but this newly added filter will not be connected to other Filter's other Filter. Similarly, disconnecting a filter connection in Filter Graph and other Filter, does not leave the filter graph, if Filter is detached from Filter Graph, you must call the RemoveFilter interface method after disconnecting.
2.6 Manually build FILTER GRAPH
The basis of manually constructing Filter Graph is based on the filter required by the media files. Otherwise, the FilterGraph of the manual architecture will have problems such as reliability, robustness.
Manual architecture FILTER GRAPH mainly uses several interface methods described above: AddFilter, Connect, and (very little situations) ConnectDirect. These interface methods have not been described in detail above. Because of this, it is placed here.
The main ideas are as follows:
n Select Filter based on file type or set Filter Graph
Selecting Filter mainly through the existence system, supported filter, and uses the user selected by the user based on the pre-setting or in the user participation.
n Add the selected filter into the Filter GRAPH
This step mainly uses several interface methods above, and details will be referred to with the accompanying instance code.
n If there is a problem during the connection, try to join the middle filter, or replace the filter.
n Complete the connection.
We do not recommend that the entire Filter Graph is built by manual, a targeted method that can make full use of DirectShow intelligence and reflecting Filter Graph, add the source filter using AddSourceFilter, then start manual connection (of course, this method is not applicable) Requires Filter Graph for non-standard non-default file source Filter.
Instance code (temporary vacancy):
3. Control of Filter Graph
Controls for Filter Graph include control of the state of Filter Graph, control of media file video, audio control, etc. The following is divided into three parties:
3.1 Control of Filtergraph status
Before introducing the control of the Filter Graph state, the state of the Filter Graph is first to be described. Filter Graph has only three states at any time: run, pause, stop. These three states indicate the status of the media file playback.
When a filter graph is just built for a media file, this filter graph is in the stop state. As the file is played, the Filter Graph also turned into the running state (in fact, the Filter Graph transferred to the running status caused the file to start playing). The playback of Filter Graph enters the pause status file is also suspended. When the file is played, the Filter Graph returns to the stop state. (This description is only to indicate the status of the file and the corresponding relationship of the state of the FILTER GRAPH, and the order and relationship of the two interactions cannot be correctly reflected), therefore, our control of the Filter Graph status is also concentrated in three Switch between states.
Control for Filter Graph status We need to use another interface: IMEDIACONTROL, this interface is implemented on iFiltergraph, but when the application is used, apply for this interface on IgraphBuilder.
PGRAPH-> QureyInterface (Queryinterface (IID_IMEDIACONTROL, (void **) & pControl);
After obtaining this interface, we can use the above interface method (there are nine interface methods above this interface above, but we can only use the top five, the next four is true for VB, VB is really good!):
IMEDIACONTROL :: Run ();
IMediaControl :: pause ();
IMediaControl :: stop ();
IMEDIACONTROL :: GetState (long mstimeout, oafilterstate * pfs);
IMediaControl :: stopwhenready ();
In this five interface methods, the top three are self-explanatory, and there is no parameters, the return value is the standard HRESULT, which makes people feel smooth and refreshing. But we are not doing aerobics in the forest. In fact, it has made me breathless all night.
Let us concentrate:
The fourth interface method does not seem to be so painful, returns the state of Filter Graph. It is necessary to explain the parameters. The first parameter specifies a period of time, and the conversion of the Filter Graph status in DirectShow is not necessarily synchronized. Therefore, when you call this interface method, Filter Graph may be transformed into a new state, so this interface method Waiting for the Filter Graph to stabilize to a state or wait for the time period specified by the first parameter. However, this unstable state is too small (we are using DirectShow instead of studying the transition of high energy physical electronic tracks), so this parameter is assured to write 0, Microsoft set this parameter's purpose - I guess - Is it to improve the reliability of the program, even if Microsoft still has so many bugs, who knows? The second parameter is a pointer to OAFILTERSTATE, and the value of this parameter is successful after the method is successful.
The fifth interface method is quite confused, although it is naming. This interface method is suspended Filter Graph, and the Filter Graph is stopped after waiting for the data processing. The main use of this interface method is not on the control of the Filter Graph state, but is a valid search method when Filter Graph is stopped. Specific principles We introduce with the iMediaseEKing interface.
Is it finished? Really finished? That's right, but this is just part, but the application is part of the Filter Graph, if Filter Graph needs to interact with the application? The interaction between FilterGraph and the application is mainly implemented by another interface IMEDIAEventEx. (Three interfaces on the Filter Graph are related to event processing, iMediaEventsink, used for event interactions between Filter and Filtergraph, iMediaEvent and iMediaeventex are interfaces with Filter Graphs, because the latter inherits from the former, is the former Extend, so we most selected the latter.)
The iMediaEventEx interface is similar to the iMediaControl interface, implemented on iFilterGraph, but the application should apply on IgrahpBuilder.
IMediaEventEx * pevent;
PGRAPH-> QureyInterface (IID_IMEDIAEVENTEX, (Void **) & pevent;
Filter Graph has two ways to interact with the application's event, and the difference between the two ways is different from the active person of the event interaction. One is the Filter Graph actively notifies the application (form), one is the Filter Graph to maintain a message pump, and the application is constantly removed from the message. In actual development, we are typically selected, and the second method is generally used in applications that are not suitable for messaging and no forms.
First we customize a message:
#define WM_DS_EVENT 19850415
The integer behind it is that I will add it (it is not casual, you will tell you the gift), as long as it is not conflict with the internal message inside the Windows.
Then set the event notification code of the Graph Filter, after the settings, the Filter GRAPH will send the event notification to the program form in the way the event notification will be sent, and the form captures this message, it can be called. The corresponding interface method is to know the specific event.
PEVENT-> SetNotifyWindow (OAHWND) HWND, WM_DS_EVENT, 0);
This interface method registers a window that is a recipient that is a message when Filter Graph has an event, and the second parameter is a long type, that is, the message that occurs. The last parameter is accepted as LPARAM, and it is directly given here. Because we only need to know that Filter Graph has events, but not need to know more information.
Now start processing, in the WinProc function (I like Win32's important reason is that I don't have to write a message mapping macro, I am a lazy!) Capture the WM_DS_EVENT message:
Case WM_DS_EVEVT:
{
IF (PEVENT)
{
Long evenetcode = 0, wparam = 0, lparam = 0;
While (successded (PEVENT-> GetEvent (& Eventcode, & Wparam. & lparam, 0))))))))
{
PEVENT-> FreeEventParams (Eventcode, WParam.lparam);
SWTICH (Eventcode)
{
// Process Events Here
}
}
}
}
This code calls the IMEDIAEVENTEX interface method: getEvent and FreeEventParams, the description of these two interface methods is as follows: HRESULT GETEVENT (long * Leventcode, long * lparam1, long * lparam2, long mstimeout);
GetEvent Removes a message from the DirectShow Filter Graph's message pump. After the interface method is successful, the first parameter indicates that the event message is, that is, what happened. The second third parameter indicates some auxiliary information, which is also different depending on the meaning of the event. The meaning of the last parameter is similar to the event parameters of the IMEDIACONTROL: :: GetStates interface method, and the 0 representation is returned immediately.
HRESULT FreeEventParams (Long LPARAM1, Long LPARAM2);
This interface method releases the space assigned when the getEvent call is assigned. Note that the value of the parameter is not changed, so we recommend calling this interface method immediately after calling getEvent, so as not to cause waste, even memory leakage.
After these, EventCode represents the type of event. Then just how to deal with it. Exemplary events in DirectShow is:
n EC_COMPLETE means that the media file has been played back. But at this time, Filter Graph does not transfer directly to the stop state, and we need to call iMediaControl :: stop () method. And Filter Graph does not provide us to loop the way to play a file, so we need to process this event. Participate in Appendix 5.3
n EC_ERRORABOR said Filter Graph run error
n EC_USERABORT indicates that the user has stopped playback
n ec_repaint means that video window iVideoWindows needs to turn redraw the current frame.
In addition, there are other interface methods on the ImeidaeventEx interface.
Interface method on iMediaEventex:
n hResult setNotifyFlags (long lnotifyflags); set event notification code.
n hResult getnotifyflags (long * lplnonotifyflags); get an event notification code.
Interface method on iMediaEvent:
n HRESULT CANCELDEFAULTHANDLING (long levcode); unfold the default message processing for the specified message. After cancellation, this message will be passed to the application and must be manually handled by the application.
n restrictionefaultHandling (long levcode) Restore the default message processing for the specified message
n WaitForCompletion (long * pevcode); Filter Graph hangs until the file is played back.
So far, for Filter Graph Control and Interaction of File Playback involves iMediaControl and iMediaeventEx, these two interfaces work together to complete the application and Filter Graph's coordination.
Now the problem is placed on the search of the media file. I can't carefully think that this part should be controlled to the state of the Filter Graph, not the control of the media file video or audio. Let us use the programmer's language, this always makes people feel very wonderful.
For the search for media files, DirectShow provides another interface IMEDIASEEKING, (number, how many interfaces we have encountered?) This interface is numerous, but we seem to have need to use it. Several, but who can guarantee that the rest will not be used? Interface method related to time:
n HRESULT GETCAPABILITIES (DWORD * PCAPABILITIES); this interface method returns whether the current media file type supports search. The parameter is called a logging of the current Filter GRAPH after the interface method. This pointer points to a flag of an am_seeking_seeking_capabilities type. This logo is a set of enumeration values, meaning self-explanation.
n HRESULT Checkcapabilities; this interface method will check whether the search represented by the parameter is supported. When the interface method returns, the parameter pointer content will be supported by the search.
n HRESULT ISFORMATSUPPORTED (Const Guid * PFormat); if the time format represented by the parameter is supported if it supports returns S_O. Time format See Appendix 5.6
n HRESULT QueryPreferredFormat; returns the preferred time format.
n HRESULT GETTIMEFORMAT (GUID * PFormat); Returns the current time format
n HRESULT ISUSINGTIMEFORMAT (Const Guid * PFormat); Returns whether to use the time format indicated by the parameter. If it returns S_OK.
n HRESULT SETTIMEFORMAT (Const Guid * PFormat); Sets the currently used time format.
n HResult ConvertTimeFormat (longlong * ptarget, const guid * ptargetformat, longlong source, const guid * psourceFormat); transfer time value under a time format to another time value under the time format. The first parameter saves the address of the stored time value. The second parameter and the fourth parameter specify the target format and source format, respectively. The third parameter specifies the source time value.
Interface method for search scope:
n HRESULT GETDURATION (Longlong * PDuration); Returns the length of the file, in the current time format
n hResult getStopPosition (longlong * pstop); returned to the location. In units of current time format.
n hResult getCurrentPosition (longlong * pcurrent) Returns the current location, the current time format.
n HRESULT getPositions (longlong * pcurrent, longlong * pstop); Returns the current location and stop position, in units of current time.
n hResult setPositions (longlong * pcurrent, dword dwcurrentflags, longlong * pstop, dWord dwstopflags); Setting the stop position, the current location. In units of current time format.
n HRESULT GETAVAILABLE (Longlong * Pearliest); Set a valid search range, the first parameter begins with the beginning of the range, the second parameter ends. In the current time format.
Interface method for playback rate:
n HRESULT SETRATE (Double Drate); get the play rate, normal rate is 1N hResult getrate (double * DRATE); set the play rate
These interfaces can basically implement search for media files, and should be flexible according to actual conditions in the development, do not absolutely use a certain time format or interface method.
Now returning to let us see a historical legacy problem, I almost forgot. If you have forgotten, skip here.嘿嘿.
IMediaControl :: stopwhenready (); this interface method is mainly used to search for media files when Filter Graph is stopped. Once the Filter Graph is stopped, the changedowindow for the current location will not be redrawn automatically, so the call to the iMediaseEKing :: setPositions interface method will not update the Video Window. So if you want to display a new frame after completing the search of the media file, you need to call this interface method. This method first transfer Filter Graph to the paused state, then waits for the operation to refill the Filter Graph to the stop state. The data is still transmitted in the graph when paused, so the Video Render will continue to play new frames.
3.2 Control of media file video
I finally started a new topic, and this topic is much easier than the previous topic involving three interfaces. Although two interfaces and many interface methods are also involved, there are many specifications. Let me bake your hand with a light and start.
Video control includes two contents: one is the control of the video stream, one is the control of the video window. For the control of the video stream, we are more concerned about the format, walking, effective information on the data, and for the video window, we are more concerned about the size, location and other appearance factors playing with video files.
For the control of the video stream We use the ibasicVideo interface, the ibasicVideo interface inherits from IdisPatch, the implementation of this interface on Video Render, but the application is to apply for this interface on the Filter Graph. As before, this application is applied for an interface:
PGRAPH-> QueryInterface (IID_IBASICAUDIO, (Void **) & PBasicaudio);
Before we explain the interface method on this interface, we first clarify several necessary concepts:
Source rectangle: The source rectangle is part of the original image to be displayed.
Target Rectangle: Target Rectangle refers to a portion of the VIDEO Windows Acceptance
Video rectangle: The video rectangle refers to the original video image.
That is, the Video Render captures the original image to form a source rectangle, and then the source rectangle is stretched or compressed to meet the size of the target rectangle. All rectangular units are pixels.
In these three rectangles, the video rectangle is determined by the media file, while the other two can be set by us according to actual needs, and IBasicVideo provides the following method to control the source rectangles and target rectangles, which are self-explanatory.
n get_ / put_destinationheight
n get_ / put_destinationleft
n get_ / put_destinationtop
n get_ / put_destinationwidth
N get_ / put_sourceheight
n get_ / put_sourceleft
n get_ / put_sourcetop
n get_ / put_sourcewidth
n get_videoheight
n get_videoWidthn setsourcePosition
n setDestinationPosition
In addition, the iBasicVideo interface provides interface methods related to media file video properties:
N GET_AVGTIMEPERFRAME gets average time for each frame
n get_bitrrorrate gets the bit error rate. An error here refers to the error of the encoding check.
N get_bitrate gets a bit rate, unit BPS
Another important method is to get the current frame:
GetCurrentImage (long * pBuffersize, long * pdibimage); the first parameter is the size of the picture, can calculate the size of the BMP file header information according to the size of the video rectangle, the second parameter points to one when the method returns Information of bitmaps.
IbasicVideo provides us with a relatively underlying and in-depth control of the video stream. Despite this, there is not much opportunity to use ibasicvideo in the actual development. IvideoWindow, which is related to the window of the video stream, is the focus of our concern.
IvideoWindow is implemented on Graph and Video Render, but the application should apply for this interface on the Filter Graph.
PGRAPH-> QueryInterface (IID_IVideoWindow, (void **) & pvideoWindow);
See the SDK documentation in the specific part.
3.3 Control of audio of media files
This is our last topic, for the control of sound. You can't make your companions close your mouth, but you can settle the size of your media file volume, the balance of the channel. A excellent programmer can get the same rights as God in the program.
Control of relative video streams, the control of the audio stream is simple and clear. The first is the interface we use: ibasicaudio. This interface is implemented on Audio Render as usual, but the application needs to apply for this interface on the Filter Graph.
The interface method and function are as follows:
n HRESULT GET_BALANCE (long * plbalance); get the balance of the current audio stream channel. After the interface method is called successfully, the reference to the parameter pointer is a long integer range from -10000 to 10000. The meaning of this value is: -10000 indicates silence of the right channel, 10000 indicates no sound of the left channel, and 0 represents the channel balance.
n HRESULT PUT_BALANCE (long lbalance); Set the channel balance of the current audio stream. The meaning of the parameters and the description of the previous interface method reference.
n HRESULT GET_VOLUME (long * plvolume) Gets the volume of the audio stream, after the interface method is successfully called, the value of the reference to the parameter pointer is removed from 100 to the sound tone, the unit DB.
n HRESULT PUT_VOLUME (Long Lvolume); Set the volume of the audio stream. The meaning of the parameters and the description of the previous interface method.
Ok, as the voice is beautiful and smooth, our playback is also completed, is it simple? hope so.
4. Release Filter Graph
For Filter Graph's release, it is not listed as a topic. However, considering this is a roll-off of a program and is a crucial guarantee for a secure and reliable program, and in order to ensure that the structure of this file is in line with the steps of DIRETSHOW media file playback, it will be listed as a topic.
Release Filter Graph To follow these steps:
Clear Filter Graph (not necessarily, suggestion) Release the interface applied by Filter Graph, place the interface pointer as empty
Release Filter Graph, also place the interface pointer as empty.
Call CounInitialize ();
5. DirectShow file back interface relationship diagram
According to the above analysis, we can get the interface relationship of DirectShow Filter Graph for media file playback:
Description:
On the Audio Render implementation, IBASCIDIO interface is implemented, and IBASICVIDEO and IVIDEOWINDOW are implemented on Video Render, but these interfaces should be applied from Filter Graph. The labeling method in the figure is just to use the relationship, does not represent the actual interface.
6. appendix
Some relevant information is collected in this appendix, some comes from the Internet, some is my own code, some is the translation of the SDK document.
6.1 About CODEPAGE
The so-called CodePage is a character set that can be used for processing. When developing MS-DOS and WINDOWS 3.1, Microsoft will further depend on the character sets of the various varieties of IBM-HOST, MACINTSH, MS-DOS, and Windows, and The specific code page is assigned as a code called "code page ID". such as:
Chinese GB internal code page ID = 936
GBK is also a code page, its ID is also 936
Bi5 code page ID = 950
Shift-jis code page ID = 932
And also Japanese, code page ID on Macintash, = 10001
Generally speaking, UCS / Unicode is also a code page, which is code page ID = 1200. But in strict sense, UCS / Unicode is a very special code page. First, it is encoded by the Script, not by language, national or regional code; second, it contains the word exchange of each code page; third, it is "core code" in the product platform Or "axis heart code" exists, regardless of how the product is localized, it does not change; it will not be "cut over" like other code pages. "
The commonly used Code Page and the corresponding marker are listed for reference.
Value
Meaning
CP_ACP
ANSI Code Page
CP_MACCP
Macintosh Code Page
CP_OEMCP
Oem Code Page
CP_SYMBOL
Symbol Code Page (42)
Cp_thread_acp
The Current Thread's ANSI Code Page
CP_UTF7
Translate UTF-7
CP_UTF8
Translate UTF-8
6.2 Renderfile Sample Code:
IGraphbuilder * pgraph;
Coinitialize (NULL);
CoCreateInstance (CLSID_FILTERGRAPH, NULL, CLSCTX_INPROC_SERVER,
IID_IGRAPHBUILDER, (void **) & pgraph);
IMediaControl * PControl;
IMediaEvent * pevent;
PGRAPH-> QueryInterface (IID_IMEDIACONTROL, (void **) & pControl);
PGRAPH-> QueryInterface (IID_IMEDIAEVENT, (VOID **) & pevent; char * szfilename;
CIN >> SZFILENAME;
Uses_Conversion
PGRAPH-> Renderfile (T2W (SZFileName), NULL;
PCONTROL-> Run ();
// do the control here
PCONTROL-> Release ();
PEVENT-> Release ();
PGRAPH-> Release ();
Couninitialize ();
6.3 Media Type
6.4 Render Sample Code
#include
Void main (void)
{
Igraphbuilder * pgraph = null;
IMediaControl * pControl = null;
IMediaEvent * pevent = NULL;
// Initialize the COM LIBRARY.
HRESULT HR = Coinitialize (NULL);
IF (Failed (HR))
{
Printf ("Error - Could Not Initialize COM LIBRARY);
Return;
}
// Create The Filter Graph Manager and query for interface.
HR = COCREATEINSTANCE (CLSID_FILTERGRAPH, NULL, CLSCTX_INPROC_SERVER,
IID_IGRAPHBUILDER, (void **) & pgraph);
IF (Failed (HR))
{
Printf ("Error - Could Not Create The Filter Graph Manager.");
Return;
}
HR = pgraph-> queryinterface (IID_IMEDIACONTROL, (void **) & pControl);
HR = pgraph-> queryInterface (IID_IMEDIAEVENT, (VOID **) & PEVENT);
Ibasefilter * pfilter;
PGRAPH-> AddSourceFilter (l "c: //1.avi", l "test", & pfilter;
Ipin * ppin;
Ienumpins * penum = null;
Pfilter-> Enumpins (& Penum);
While (Penum-> Next (1, & PPIN, NULL) == S_OK)
{
PIN_DIRECTION PINDIR;
PPIN-> QueryDirection (& PINDIR);
IF (pindir == pindir_output)
{
IPIN * PTEMP;
IF (SUCCEEDED (& PPIN-> Connectedto)))
{
PTEMP-> Release ();
}
Else
{
PGRAPH-> Render (PPIN);
}
}
}
En (ac))
{
// Run the graph.
HR = pControl-> Run ();
En (ac))
{
// Wait for completion.
Long Evcode;
PEVENT-> WaitForcompletion (Infinite, & Evcode);
}
}
PCONTROL-> Release ();
PEVENT-> Release ();
PGRAPH-> Release ();
Couninitialize ();
}
6.5 About file loop playback
DirectShow does not provide interface methods that directly support media file loop play, so we need to capture event EC_COMPLETE, stop Filter Graph after this event, and then reposition to the beginning of the media file, start playing from the beginning. Reference Code:
Long Eventcode = 0, EVENTPARAM1 = 0, EVENTPARAM2 = 0;
Static bool bdone = false;
While (succeeded)
&&! bdone)
{
Pevents-> FreeEventParams (Eventcode, EventParam1, EventParam2);
Switch (Eventcode)
{
Case EC_COMPLETE:
Case EC_END_OF_SEGMENT:
{
PCONTROL-> STOP ();
IF (succeeded (pseeping-> settimeformat))))
{
Longlong Lframe, LStart = 0;
PSeeking-> Getduration (& lframe);
Pseeking-> setPositions (& lstart, am_seeking_absolutepositioning |
Am_seeking_segment, & lframe,
Am_seeking_absolutepositioning;
}
IF (isloop)
{
PCONTROL-> Run ();
BDONE = false;
}
Break;
}
}
}
6.6 Time Format
The so-called time format, specifically refers to the scale of the IMEDIaseEKing interface for the time of search. The time format indicates that the N frame should be searched after searching for the location of the media file or skips n seconds. The same numbers are also different in different time formats. GUID in the specific time format and description reference table below:
GUID
description
Time_Format_none
Unformatted
Time_Format_Frame
Unit with video files (common)
Time_format_sample
Sample as SAMPLE
Time_Format_field
Interlaced
Time_Format_byte
For the byte offset for the file stream.
Time_FORMAT_MEDIA_TIME
Benchmark time (common)
7. references:
Windows program design
DirectShow Development Guide
My development notes
QQ group chat record (~!)
Science fiction world (~ !!)
http://www.unihan.com.cn/cjk/conception.htm
http://eyes4.mblogger.cn/
8. Thank you
During the writing process of this article, I got support and help from all directions and thank you again.
Thanks to my idol Jonh Carmark, let me have a slow-striking, and courage. This world needs genius to encourage those quasi-genius, 嘿嘿
Thank Lamothe, let me know the COM client from one way.
Thank Maxwell's Maxwell Instant Coffee made by these poor people. I would like to thank the Science Fiction World to make my idea not zombie.
Thanks to Tencent's grade system, let me rise to QQ stars when I get all night.
Thanks to the Chongqing University Network Center to open a network in a timely manner.
Thank God, thank you, thank you for letting us meet ...................... 嘿嘿
Welcome everyone to my wife's blog:
http://www.blogcn.com/user20/ifdream/index.html
http://www.blogcn.com/User21/ink/index.html
my contact information:
QQ: 78482557
E-mail: inkick@yahoo.com.cn
9CBS ID: Inkick (star point)