当前位置:网站首页>A troubleshooting record of DirectShow playback problems

A troubleshooting record of DirectShow playback problems

2022-07-25 11:14:00 Fighting Horse

Playback scheme

stay Windows platform , be based on ActiveMovie  Play . ActiveMovie yes Windows Media Player A component of , The bottom layer uses  DirectShow frame .

Problem phenomenon

What is the problem : Once you click the play button , After loading for a while ( Loading complete ), The whole program is stuck ,UI The does not respond to any input , The playback did not start , No image comes out .( Here's the picture )

But most users , This function is normal . But the number of individuals with problems also exceeds 3%. And the more real users , The higher the proportion , So I have to be tough to solve this difficult and miscellaneous disease .

After various attempts to analyze , A variety of methods have been used , Although because of lack of experience , Many methods have come to a dead end , But it took a whole 3 Days later , Finally caught his tail .

The process and method , It is worth recording and sharing with you . So-called “ Nothing is difficult in the world , I'm just afraid that those who have a mind ”, The most important lesson is not to give up , Do what you know is difficult .

Now I have sorted out the methods used to eliminate this problem , But in fact 3 Days of troubleshooting and analysis , I also try everywhere , Try your luck , There are not many rules . Here is the analysis and summary later , Only then have some relatively clear logic . I hope it can be helpful to solve the difficult problems encountered later .

Preliminary analysis

Since there is no response , Let's see where the stuck code is . Debugging is not started when problems are found , So it needs to be in the task manager , Export process dump file (xxx.DMP). stay Visual Studio Open it inside , function . The stack of the main thread is as follows :

The main route is stuck in d3d9.dll Of CLockD3D in , And prompt to wait for a lock , This lock is locked by another thread 6612 hold . that 6612 What is the thread doing ? Here is 6612 The call stack for threads :

Actually, I'm not doing anything ,Nt..Wait..Ex This function is relatively low-level , Generally, I just wait for news here , There won't be any tasks to deal with .

stay Visual Studio Thread stack of “[ External code ]” It can be expanded , The expanded call stack of locked threads is as follows :( Stuck state of another operation )

     [ Waiting for thread   lock   With the  17368, Double click or press  Enter  Can switch to thread ]         Annotated frames 
     ntdll.dll!NtWaitForAlertByThreadId()     Unknown      Non-user code . Symbols loaded .
     ntdll.dll!RtlpWaitOnAddressWithTimeout()     Unknown      Non-user code . Symbols loaded .
     ntdll.dll!RtlpWaitOnAddress()     Unknown      Non-user code . Symbols loaded .
     ntdll.dll!RtlpWaitOnCriticalSection()     Unknown      Non-user code . Symbols loaded .
     ntdll.dll!RtlpEnterCriticalSectionContended()     Unknown      Non-user code . Symbols loaded .
     ntdll.dll!RtlEnterCriticalSection()     Unknown      Non-user code . Symbols loaded .
     d3d9.dll!CLockD3D::CLockD3D(class CLockOwner *,int)     Unknown      Non-user code . Symbols loaded .
     d3d9.dll!CDxva2Container::GetVideoProcessorDeviceGuidCount(struct _DXVA2_VideoDesc const *,unsigned int *)     Unknown      Non-user code . Symbols loaded .
     dxva2.dll!CVideoAccelerationService::GetVideoProcessorDeviceGuids()     Unknown      Non-user code . Symbols loaded .
     evr.dll!CMFVideoMixer9::AllocateResources()     Unknown      Non-user code . Symbols loaded .
     evr.dll!CMFVideoMixer::MFTProcessMessage()     Unknown      Non-user code . Symbols loaded .
     evr.dll!CMFVideoMixer9::MFTProcessMessage(enum _MFT_MESSAGE_TYPE,unsigned __int64)     Unknown      Non-user code . Symbols loaded .
     evr.dll!CEVRFilter::ProcessMessageMixer(enum _MFT_MESSAGE_TYPE,unsigned __int64)     Unknown      Non-user code . Symbols loaded .
     evr.dll!CEVRFilter::StartStreaming(void)     Unknown      Non-user code . Symbols loaded .
     evr.dll!CEVRFilter::Pause(void)     Unknown      Non-user code . Symbols loaded .
     quartz.dll!CFilterGraph::Pause(void)     Unknown      Non-user code . Symbols loaded .
     quartz.dll!CFGControl::Cue(void)     Unknown      Non-user code . Symbols loaded .
     quartz.dll!CFGControl::CueThenRun(void)     Unknown      Non-user code . Symbols loaded .
     quartz.dll!CFGControl::CImplMediaControl::StepRun(void)     Unknown      Non-user code . Symbols loaded .
     quartz.dll!CFGControl::CImplMediaControl::Run(void)     Unknown      Non-user code . Symbols loaded .
     wmp.dll!00007ff8f390c3b3()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f390d9d0()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37a32a3()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37a2834()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37a27ae()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37a2568()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f372e327()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f372e70f()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f372e83c()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37c6d3f()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37c6bb8()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f37c6c9f()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f3908388()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f390861c()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f390d3c2()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f390d74e()     Unknown      Non-user code . Cannot find or open  PDB  file .
     wmp.dll!00007ff8f390d0c4()     Unknown      Non-user code . Cannot find or open  PDB  file .
     user32.dll!UserCallWinProcCheckWow()     Unknown      Non-user code . Symbols loaded .

Debug analysis

Only through DMP analysis , Basically, I can't see why it's stuck . Fortunately, we also have one PC There is the same phenomenon . So you can use real-time debugging to further explore what happened .

In use Visual Studio During real-time debugging , You will encounter an exception , Continue operation 3 Next time , It's stuck . The exception stack is like this :

>   d3d9.dll!CSwapChain::CreateWindowed(unsigned int,unsigned int,enum _D3DFORMAT,unsigned int,enum _D3DMULTISAMPLE_TYPE,unsigned long,int,int,int,int,int,int)  Unknown 
    d3d9.dll!CSwapChain::Reset(struct D3DPRESENT_PARAMETERS *,struct D3DDISPLAYMODEEX const *,int,int)     Unknown 
    d3d9.dll!CSwapChain::Init(struct D3DPRESENT_PARAMETERS *,struct D3DDISPLAYMODEEX const *,long *,int,int)   Unknown 
    d3d9.dll!CBaseDevice::CreateAdditionalSwapChain(struct D3DPRESENT_PARAMETERS *,struct IDirect3DSwapChain9 * *)     Unknown 
    evr.dll!CMFVideoPresenter9FlipMode::CreateFlipModeSwapChain()    Unknown 
    evr.dll!CMFVideoPresenter9FlipMode::ProcessOutput()  Unknown 
    evr.dll!CMFVideoPresenter::RepaintVideo()    Unknown 
    rpcrt4.dll!Invoke()     Unknown 
    rpcrt4.dll!Ndr64StubWorker(void *,void *,struct RPC_MESSAGE *,struct _MIDL_SERVER_INFO *,long (*const *)(void),struct _MIDL_SYNTAX_INFO *,unsigned long *)     Unknown 
    rpcrt4.dll!NdrStubCall3()    Unknown 
    combase.dll!CStdStubBuffer_Invoke(IRpcStubBuffer * This, tagRPCOLEMESSAGE * prpcmsg, IRpcChannelBuffer * pRpcChannelBuffer)  That's ok  1458  C++
    rpcrt4.dll!CStdStubBuffer_Invoke()   Unknown 
    [ Inline framework ] combase.dll!InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_c9f3956a20c9da92a64affc24fdd69ec>::operator()()  That's ok  1279    C++

The exception information indicates that the memory access is abnormal , Memory pointer is a small value , Should be null Caused by pointer . stay d3d9 In such an important library , Didn't handle null The pointer , I really shouldn't have . But for our troubleshooting , Instead, we can observe more details , It's a good thing . You can see such a detailed call stack , I have to admire Microsoft's debugging framework , as well as pdb Completeness of symbols .

according to D3D Information ,CreateAdditionalSwapChain It seems to be creating D3D Exchange of equipment Buffer, Use on image display . But even if you know the principle , But there's no source code , It's impossible to know which line of code has the problem , It is not clear how to avoid this problem .

comparative analysis

Comparison of different devices

The first thought is to compare normal equipment 、 Different abnormal devices . I suspect that normal devices use different methods , So the program didn't run to d3d9 On the code with problems in the block .

I'm in logical order , stay “ rendering pipeline ”、“ The call stack ”、“ Call parameters ” They are compared respectively , In the end, I found no difference . Casualness is useless for solving problems , But in terms of methods, it is still worth recording and learning .

rendering pipeline

Rendering pipeline is the connection of various components used in video playback ( It is generally a pipe chain structure , stay DirectShow called Filter Graph, Filter It's the components ,Graph Is the connection diagram ). In general , The pipe contains at least three components : Source , decoder 、 Renderers ). Need to know DirectShow What components are used , Need to traverse IFilterGraph Everything in it Filter, Output its information ,Filter There are more Pin, Also output Pin Information about ,Filter adopt Pin Connect with each other .

Because the source component of the three components is implemented by ourselves , So insert some code into the source component , You get the following information :

The call stack

We know the exception stack , Can the same call stack be reproduced on normal devices ?

How to reproduce , That is, of course, to add breakpoints in the same place , Just see if it can be disconnected . But we have no source code , however Visual Studio It provides the function of directly entering the function name to set the breakpoint .

But in the CSwapChain::CreateWindowed(...) Breakpoints cannot be set , One level on the call stack  CSwapChain::Rest(...) Yes. . The reason is not clear , It may be the only method visible outside the module , To set breakpoints . It should be noted that , No parameter information is required when entering the method name .

stay Reset After the breakpoint pauses , After many single steps , Can enter the  CreateWindowed Method , At this point, you can add  CreateWindowed The breakpoint of . Then run... Again , Directly in  CreateWindowed Break point pause .

So it can be proved , Normal call stack , It is no different from the abnormal situation .

Call parameters

Since the call stack is normal , I can only suspect that the different input parameters lead to abnormal problems .

Through the analysis of stack memory , It can be inferred that it is passed to  CreateAdditionalSwapChain Parameters of . although Visial Studio Call parameter analysis without source code is not supported , But we also have a stupid and clever way . stay x86_64 Systematically , Stack pointer register rsp Indicates the position of the call stack frame , On the same call stack and instruction location , Parameter memory is equivalent to rsp The offset of is fixed .

What is the offset ? We can deduce from the known parameter values . First construct a same way to call ( Call parameters are known ), Breakpoint pause at the same instruction location , And then in rsp Find the known parameter value in the backward memory , You will know the offset .

Finally, it is inferred that it is passed to  CreateAdditionalSwapChain The parameter is :

Comparison of different procedures

Deal with the comparison of different equipment environments , On the problem device , You can also check problems by comparing the performance of different programs .

GraphStudioNext

To check 、 verification DirectShow Playback problem of ,GraphStudioNext Is the most commonly used tool ( Not one of them. ).

adopt  GraphStudioNext Play our source , It can be played on the problem device .

Although you can play , But in the image rendering scheme , Somewhat different . GraphStudioNext It uses VMR (Video Mixing Renderer), And our program ( That is to say Windwos Media Player) It uses EVR (Enhanced Video Renderer),EVR It's better than VMR Updated technical solutions .

stay GraphStudioNext in , That's not a problem . For comparative verification EVR, Just delete  VMR, add to EVR That's it . Can verify , Even using EVR , On the problem device ,GraphStudioNext It can also be played .

Simple program

however  GraphStudioNext After all, with  Windwos Media Player (WMP) There's a difference , Do not rule out the problem is caused by WMP Caused by the .

Instead of checking step by step , Simply separate the code of the playback part of our program , Build a simple program , Look at the different performances .

Although there are some repetitions , Can't play at first , Even gave up this idea for a time . But later, it was confirmed that the simple program playback is normal , This also contributed to the later exclusion analysis .

Exclusion analysis

Since simple programs can be played , Naturally, we suspect that other functions of our program have affected the playback function , So the exclusion method just popped out .

Elimination is the ultimate weapon to solve many difficult problems , The premise is to have a normal control . But the elimination method is very tiring , Remove some functions step by step , And let the whole program run . And with failure again and again , Less and less confidence , It's a test of endurance .

I have gradually eliminated the following functional effects , I didn't expect that the problem could still recur .

  1. OpenGL function ( Just skip OpenGL The initialization )
  2. WebView function ( Use fake implementations instead )
  3. Bottom network module
  4. Irrelevant interface ( each Tab page )
  5. main interface ( It has been completely replaced with a simple program interface )
  6. The function library related to the underlying algorithm
  7. Most of the code of program entry initialization

The next suspect is loading through runtime DLL The way of the . Our main function is DLL To realize , The launcher is just a shell .

I move the functions of simple programs to the startup program and directly realize , Added some link configurations , Run up . But there is still the same exception .

Can't , Since we have embarked on a road of no return , I can only go on with it . Next, you can only doubt the compilation configuration , Compare the compiled configuration . The different ones are link libraries and precompiled macros . Make it the same , It's really normal , Real shit , This is the first time to encounter problems caused by precompiled macros .

Add back the suspected precompiled macros one by one , Locate the SLIC3R_GUI This macro is the culprit . After further confirmation , Let's see what code it affects .

One of the pieces of code is very suspicious :

#ifdef SLIC3R_GUI
extern "C"
{
     // Let the NVIDIA and AMD know we want to use their graphics card
     // on a dual graphics card system.
     __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;     
     __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
#endif /* SLIC3R_GUI */

Get rid of this code, and sure enough OK.

ha-ha , Finally, the root of the problem has been found . See what the hell these two things are .

Sure enough, I'm still inexperienced , These two export symbols are often used in game development , It can be used on devices with independent graphics cards , Speed up game operations , Lifting performance .

Check the hardware configuration of the faulty device , Sure enough, there is a graphics adapter ( The graphics card ), An integrated , An independent . And we have no faulty equipment , There is only one integrated graphics card . Users of our program , His equipment , Most people also use better configurations , Therefore, it also explains the reason why the proportion of real users with problems is higher .

About the above two configurations , If you are interested, you can see the relevant information :

NVIDIA Optimus
Selecting the Best Graphics Device to Run a 3D Intensive Application

原网站

版权声明
本文为[Fighting Horse]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/206/202207250942000914.html