The simplest example based on DirectShow: Video Player custom edition

Source: Internet
Author: User

The simplest example based on DirectShow: Video Player custom edition
This document records a simple DirectShow-based custom video player. The "Custom player" mentioned here actually refers to the player that manually adds filters one by one in the Filter Graph and connects these filters to run. This method is much more complicated than the "smart" method of creating Filter Graph using RenderFile (), but it gives us a better understanding of the DirectShow system.

Flowchart

Shows the simplest DirectShow-based custom Video Player process.

The flowchart contains the following variables:
IGraphBuilder * pGraph: inherits from IFilterGraph and is used to build a Filter Graph.
IMediaControl * pControl: provides APIs related to playback control.
IMediaEvent * pEvent: used to process events sent by the Filter Graph.
IBaseFilter * pF_source: Source Filter.
IFileSourceFilter * pFileSource: exposed interface of the source Filter, used to set the path of the input file.
IBaseFilter * pF_demuxer: demultiplexing Filter.
IBaseFilter * pF_decoder: decode the Filter.
IBaseFilter * pF_render: renders the Filter.
IPin * pOut: Output Pin.
IPin * pIn: Enter the Pin.
IPin ** pPin: Internal Variable Pin.
The flowchart can be roughly divided into the following steps:
(1) initialize DirectShow
You can perform the following steps:
A) CoInitialize (): initializes the COM runtime environment.
B) CoCreateInstance (..., PGraph): Creates a Com object with the specified class identifier. Create IGraphBuilder here.
C) pGraph-> QueryInterface (..., PControl): query whether a component supports a specific interface through QueryInterface. Query the IMediaControl interface here.
D) pGraph-> QueryInterface (..., PEvent): Same as above. Query the IMediaEvent interface here.
(2) Add Source Filter
You can perform the following steps:
A) CoCreateInstance (..., PF_source): creates a Source Filter.
B) pGraph-> AddFilter (pF_source ,...) : Add Source Filter to Filter Graph.
C) pF_source-> QueryInterface (..., PFileSource): Find the IFileSourceFilter interface of the Source Filter.
D) pFileSource-> Load (Lxxx. mpg, pF_source): Call the Load () method of IFileSourceFilter to Load the video file.
(3) add Demuxer Filter
You can perform the following steps:
A) CoCreateInstance (..., PF_demuxer): Creates a Demuxer Filter.
B) pGraph-> AddFilter (pF_demuxer ,...) : Add the Demuxer Filter to the Filter Graph.
(4) Add a Decoder Filter
You can perform the following steps:
A) CoCreateInstance (..., PF_decoder): Creates a Decoder Filter.
B) pGraph-> AddFilter (pF_decoder ,...) : Add the Decoder Filter to the Filter Graph.
(5) Add a Render Filter
You can perform the following steps:
A) CoCreateInstance (..., PF_render): Creates a Render Filter.
B) pGraph-> AddFilter (pF_render ,...) : Add the Render Filter to the Filter Graph.
(6) connect Source Filter and Demuxer Filter
A function connect_filters () is called to connect two filters.
The steps for connect_filters () are as follows:
A) Call get_unconnected_pin () to select an output Pin without link from the source Filter.
B) Call get_unconnected_pin () to select an unlinked input Pin from the destination Filter.
C) connect the two pins.
The procedure for get_unconnected_pin () is as follows:
A) enumerate the Pin on the Filter.
B) traverse these pins to find the output direction (using the QueryDirection () method of IPin) and the Pin that is not in use (using the ConnectedTo () method of IPin ).
(7) connect Demuxer Filter and Decoder Filter
The process is the same as above.
(8) connect Decoder Filter and Render Filter
The process is the same as above.
(9) start playing
Perform the following steps:
PControl-> Run (): start to Run all filters in the Filter Graph.
PEvent-> WaitForCompletion (): Wait until the Filter Graph finishes processing all data.

The preceding steps can be understood as adding the following controls in GraphEdit. Among them, (1), (2), (3), (4) are the four filters first added, (5), (6), and (7) are the connection lines between filters.

 

Source code
/*** The Simplest Video Player Based on DirectShow (Custom) * Simplest DirectShow Player (Custom) ** leixiao Lei Xiaohua * leixiaohua1020@126.com * China Media University/Digital TV Technology * Communication University of China/Digital TV Technology * http://blog.csdn.net/leixiaohua1020 ** this program is a simple DirectShow-based video player. The player adds * filters one by one and connects these filters to play the video. Suitable for beginners to learn DirectShow. ** This software is a simple video player based on DirectShow. * It Add DirectShow Filter Manually and Link the Pins of these filters * to play videos. suitable for the beginner of DirectShow. */# include stdafx. h # include
 
  
// '1': Add filters manually // '0': Add filters automatically # define ADD_MANUAL 1 // Find unconnect pinsHRESULT get_unconnected_pin (IBaseFilter * pFilter, // Pointer to the filter. PIN_DIRECTION PinDir, // Direction of the pin to find. IPin ** ppPin) // es a pointer to the pin. {* ppPin = 0; IEnumPins * pEnum = 0; IPin * pPin = 0; HRESULT hr = pFilter-> EnumPins (& pEnum); if (FAILED (hr )) {return hr;} while (pEnum-> Next (1, & pPin, NULL) = S_ OK) {PIN_DIRECTION ThisPinDir; pPin-> QueryDirection (& ThisPinDir ); if (ThisPinDir = PinDir) {IPin * pTmp = 0; hr = pPin-> ConnectedTo (& pTmp); if (SUCCEEDED (hr) // Already connected, not the pin we want. {pTmp-> Release ();} else // Unconnected, the pin we want. {pEnum-> Release (); * ppPin = pPin; return S_ OK;} pPin-> Release ();} pEnum-> Release (); // Did not find a matching pin. return E_FAIL;} // Connect 2 filtersHRESULT connect_filters (IGraphBuilder * pGraph, IBaseFilter * pSrc, IBaseFilter * pDest) {if (pGraph = NULL) | (pSrc = NULL) | (pDest = NULL) {return E_POINTER;} // Find Output pin in source filterIPin * pOut = 0; HRESULT hr = NULL; hr = get_unconnected_pin (pSrc, PINDIR_OUTPUT, & pOut); if (FAILED (hr) {return hr;} // Find Input pin in destination filterIPin * pIn = 0; hr = get_unconnected_pin (pDest, PINDIR_INPUT, & pIn); if (FAILED (hr) {return hr;} // Connnect themhr = pGraph-> Connect (pOut, pIn); pIn-> Release (); pOut-> Release (); return hr;} int _ tmain (int argc, _ TCHAR * argv []) {IGraphBuilder * pGraph = NULL; IMediaControl * pControl = NULL; IMediaEvent * pEvent = NULL; // Init com hresult hr = CoInitialize (NULL); if (FAILED (hr) {printf (Error-Can't init COM .); return-1;} // Create FilterGraph hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) & pGraph); if (FAILED (hr )) {printf (Error-Can't create Filter Graph .); return-1;} // Query Interface hr = pGraph-> QueryInterface (IID_IMediaControl, (void **) & pControl); hr = pGraph-> QueryInterface (IID_IMediaEvent, (void **) & pEvent); // 1. add Filters ==================================/// SourceIBaseFilter * pF_source = 0; hr = CoCreateInstance (CLSID_AsyncReader, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) (& pF_source); if (FAILED (hr) {printf (Failed to create File Source .); return-1;} hr = pGraph-> AddFilter (pF_source, LLei's Source); if (FAILED (hr )) {printf (Failed to add File Source to Filter Graph .); return-1;} IFileSourceFilter * pFileSource; pF_source-> QueryInterface (IID_IFileSourceFilter, (void **) & pFileSource); pFileSource-> Load (Lcuc_ieschool.mpg, NULL ); pFileSource-> Release (); # if ADD_MANUAL // DemuxerIBaseFilter * pF_demuxer = 0; hr = CoCreateInstance (CLSID_MPEG1Splitter, 0, iterator, IID_IBaseFilter, (void **) (& pF_demuxer); if (FAILED (hr) {printf (Failed to create Demuxer .); return-1;} hr = pGraph-> AddFilter (pF_demuxer, LLei's Demuxer); if (FAILED (hr) {printf (Failed to add Demuxer to Filter Graph .); return-1;} // DecoderIBaseFilter * pF_decoder = 0; hr = CoCreateInstance (latency, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) (& pF_decoder )); if (FAILED (hr) {printf (Failed to create Decoder .); return-1 ;}hr = pGraph-> AddFilter (pF_decoder, LLei's Decoder); if (FAILED (hr) {printf (Failed to add Decoder to Filter Graph .); return-1;} // RenderIBaseFilter * pF_render = 0; hr = CoCreateInstance (CLSID_VideoRenderer, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) (& pF_render )); if (FAILED (hr) {printf (Failed to create Video Render .); return-1;} hr = pGraph-> AddFilter (pF_render, LLei's Render); if (FAILED (hr )) {printf (Failed to add Video Render to Filter Graph .); return-1;} // 2. connect Filters ================================== hr = connect_filters (pGraph, pF_source, pF_demuxer ); if (FAILED (hr) {printf (Failed to link Source and Demuxer .); return-1;} hr = connect_filters (pGraph, pF_demuxer, pF_decoder); if (FAILED (hr) {printf (Failed to link Demuxer and Decoder .); return-1;} hr = connect_filters (pGraph, pF_decoder, pF_render); if (FAILED (hr) {printf (Failed to link Decoder and Render .); return-1;} pF_source-> Release (); pF_demuxer-> Release (); pF_decoder-> Release (); pF_render-> Release (); # elseIPin * Pin; ULONG fetched; // get output pinIEnumPins * pEnumPins; hr = pF_source-> EnumPins (& pEnumPins); hr = pEnumPins-> Reset (); hr = pEnumPins-> Next (1, & Pin, & fetched); pEnumPins-> Release (); // render pin, graph builder automatically complete rest workshr = pGraph-> Render (Pin ); # endif if (SUCCEEDED (hr) {// Run hr = pControl-> Run (); if (SUCCEEDED (hr) {long evCode = 0; pEvent-> WaitForCompletion (INFINITE, & evCode) ;}// Release pControl-> Release (); pEvent-> Release (); pGraph-> Release (); coUninitialize (); return 0 ;}
 

Running result

Shows the running result of the program. The "cuc_ieschool.mpg" file is played. It should be noted that this program does not include audio decoding and playback filters, so there is no sound during video playback.

In addition to manually adding a Filter, you can also directly call the Render () method of IFilterGraph to automatically create a Filter Graph after obtaining the Pin of the source Filter. Note that the Render () method and RenderFile () method are different. RenderFile () is to automatically build the entire Filter Graph after specifying a file path, which is relatively easier. The Render () method is to create a Source Filter first, to automatically build the entire Filter Graph.
You can modify the macro definition ADD_MANUAL in the source file header to determine whether to manually add a Filter, as shown below.
//'1':Add filters manually//'0':Add filters automatically#define ADD_MANUAL 1

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.