Jump to content

Recommended Posts

Posted

Replacing :

Func _WinAPI_SysAllocString($sString)
    Local $aCall = DllCall("mfplat.dll", "handle", "OleAut32.dll", "wchar", $sString)
    If @error Then Return SetError(__COM_GetDllError(), 0, 0)
    Return $aCall[0]
EndFunc

with

Func _WinAPI_SysAllocString($sString)
  Local $aCall = DllCall("OleAut32.dll", "handle", "SysAllocString", "wstr", $sString)
  If @error Then Return SetError(__COM_GetDllError(), 0, 0)
  Return $aCall[0]
EndFunc   ;==>_WinAPI_SysAllocString

And removing the , $oIMFEngine.CanPlay() in event handler proc.

Now starts correctly.  But after a few events the script crashes.  However from time to time, the event handler stops receiving messages and the video runs normally.  In this particular case, you cannot stop the script with the close button.  You need to interrupt it with task manager.

Posted (edited)

OK thanks! -That's amazing,, I've added those changes in Post #1.

yeah the event proc issue's likely going to be a painful one, if its the normal issue we see with callbacks in AutoIt. 

I remember once solving this by having the script pause its own thread. I found it stopped executing at that point, but the event proc continued to work as per normal.
So the "paused" script handled notifications in the background then passed anything it received to a second script via some IPC. 

As a test, you can pop this after GuiSetState().

Local $aCall = DllCall("kernel32.dll", "dword", "GetCurrentThreadId")
Local $iThreadID = $aCall[0]
$aCall = DllCall("kernel32.dll", "ptr", "OpenThread", "dword", 0x001F03FF, "int", 0, "dword", $iThreadID)
Local $hThread = $aCall[0]
DllCall("kernel32.dll", "dword", "SuspendThread", "ptr", $hThread)

You should see the notifications happily running. Just be prepared - the window will stop responding and you'll manually need to kill the process.  But you should hopefully be able to run the video through.

Edited by MattyD
Posted

Yep, it does work, the same way you could do :

SleepEx(300000, True)

Func SleepEx($nMilliseconds, $bAlertable = 0)
  Local $aRet = DllCall('kernel32.dll', 'dword', 'SleepEx', 'dword', $nMilliseconds, 'bool', $bAlertable)
  If @error Then Return SetError(@error, @extended, 0)
  Return $aRet[0]
EndFunc   ;==>_SleepEx

Video is playing normally for the duration of the sleepex

Posted

hmm you can use mediaEngine as a frameserver. So it might be worth seeing if we can get another process to do the rendering.

Its convoluted, but might be worth a look if there's no better ideas?

Posted (edited)

I came to the same conclusion.  It is quite clear that the rendering is performed into another thread.  Since AutoIt is not built to manage multiple threads, it just crashes or gets completely lost.  Try this a few times and you will receive all very weird messages :

Local $hEvent = _WinAPI_CreateEvent(0, True, False), $iRet
While True
  $iRet = _WinAPI_WaitForSingleObjectEx($hEvent, 1000, True)
  ConsoleWrite($iRet & @CRLF)
WEnd

Func _WinAPI_WaitForSingleObjectEx($hEvent, $nMilliseconds, $bAlertable = 0)
  Local $aRet = DllCall('kernel32.dll', 'dword', 'WaitForSingleObjectEx', 'handle', $hEvent, 'dword', $nMilliseconds, 'bool', $bAlertable)
  If @error Then Return SetError(@error, @extended, 0)
  Return $aRet[0]
EndFunc   ;==>_WinAPI_WaitForSingleObjectEx

 

Edited by Nine
Posted (edited)

I first ran your script in your first post with lines 674 through 679 commented. The playback started fine, but the video frames did not seem to move forward and the script stopped after about 5 seconds. I then ran your script with those lines uncommented. Aside from having to use Task Manager to exit the program, the 4k video file played smoothly without any stuttering. Congratulations!

Edited by CYCho
Posted

Nice work.

It crashes for x64 just after displaying GUI :

(609,0) IsObj($oIMFMediaEngineNotify) = 1

(648,0) Fact.CreateInstance(), hr = 0x00000000
(650,0) IMFEngine Created = True
Test a few notifications....
Event: 22   >, Volume Change, Vol: 1.000000, Muted: True
Event: 22   >, Volume Change, Vol: 1.000000, Muted: False
Event: 1001 > Purge Queued Events
Event: 1    > P1: 0, P2 0
(663,0) $oIMFEngine.SetSource hresult = 0x00000000
Event: 1001 > Purge Queued Events
Event: 4    > P1: 0, P2 0
Event: 6    > Emptied
Event: 1    > P1: 0, P2 0
(665,0) $oIMFEngine.Load hresult = 0x00000000
Event: 8    > Play
Event: 12   > Waiting
(667,0) $oIMFEngine.Play hresult = 0x00000000
Event: 21   > P1: 0, P2 0
Event: 10   > P1: 0, P2 0
Event: 11   > P1: 0, P2 0
Event: 14   > CanPlay
Event: 15   > P1: 0, P2 0
Event: 18   > Time Update
Event: 1000 > P1: 0, P2 0
Event: 1009 > P1: 0, P2 0
Event: 18   > Time Update
Event: 18   > Time Update
Event: 13   > Playing
Event: 18   > Time Update
!>09:52:06 AutoIt3.exe ended.rc:-1073741819

-1073741819 / 0xC0000005: An Access Violation is a type of Exception caused when an application Reads, Writes or Executes an invalid Memory Address.

x86:

it starts but get frozen after 1 sec and crashes with same error as for x64.

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted (edited)

Thanks guys.

I've found if you spin up a MsgBox() and just keep it open, the whole window doesn't lock up.  I don't suppose we can block execution in the same way, but without the dialog? 

If we can achieve this, we might be able to embed the video into a window owned by a child process using $WS_CHILD. Sleeping/Suspending the thread locks up both windows.

Edited by MattyD
Posted

Good find.  I was trying to use one of my IPC to connect both running processes.  Even with the MsgBox I am having a hard time to send messages to rendering process.  However the Main process can receive quite nicely messages from the rendering process.  Along the way I made a small UDF to create interface object, based on our discussion and from a post I saw from trancexx.  I also included it in the script.

I'll let you decide what you want to do with this version 2 of the engine.

 

MediaEngine.zip

Posted

Awesome - that's great @Nine

Just trying to do a bit of a tidy up before moving forward, so I've added a header to post #1 which is basically everything in defined "mfmediaengine.h".  None of the other headers included in that file are wrapped - we probably don't need them all anyway to be fair! Any constants in there outside of mfmediaengine.h have only been defined so the include works!

I've been at one project or another for last few weeks - so I'll take a few days off, and will be back after a bit of a refresh!

Posted

Ok we're back with a new stuff in post #1. 

You'll first need to compile "playerDemo_engine.au3", then run "playerDemo.au3".

We're still using a modal to block execution in the engine script - wish we could do something nicer, but I guess it'll have to do for now.  

For comms between processes we're using windows messages (thanks nine for the inspiration!). Look for the $WM_ME* values in the constants file. The WM codes are the same values as those generated by the mediaengine, combined with WM_APP. There's one totally "made up" code - its for MediaEngine to send through its window handle to the UI process ($WM_ME_PLAYBACKWINDOW).

Also with the WMs, there's a bit of jiggery pokey in order to pass floating point values over wparam and lparam. I found if you send values as a float or double, they pop out as an integer on the other end - so you lose everything after the decimal point.  But sending the values as binary solves this. We just need to ensure we convert our "doubles" to "floats" for x86 so the values fit within wparam/lparam.

One last thing...  you can still crash the engine by flooding it with messages from the UI, but that's where we're at for now.

We could probably fix this by only check incoming messages from within the event handler...  Then the problem is the engine won't be contactable when its paused, so you'd need to flick between two modes of checking for messages. And it would also require a total rethink of how to pass comms from the UI back to the engine!

Posted
On 4/18/2025 at 9:37 AM, MattyD said:

We're still using a modal to block execution in the engine script - wish we could do something nicer, but I guess it'll have to do for now.  

You have all my roots for your success! In the meantime, if it is not so much complicated, could you please move the $sSource definition and $oIMFEngine.Load() function to PlayerDemo.au3, the same way as you did for Play/Pause functions?

Posted
2 minutes ago, MattyD said:

I'm bound to have missed a bunch of formats.

$sSource = FileOpenDialog("Open Media", @ScriptDir & "\", "Video Files (*.mp4;*.m4v;*.mpg;*.wmv;*.mov;*.mkv)" & _
    "|Audio Files (*.mp3;*.aac;*.m4a;*.wma)|Good luck (*.*)",  $FD_FILEMUSTEXIST)
If Not FileExists($sSource) Then ContinueLoop

:)

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

The first pass of Load and Play works fine. But I cannot seem to be able to  load and play the next file. I tried to load another file after the end of playback of the first file, or after "Stop" of the first file, and failed in both cases with an error message saying "Variable used without being declared."  I could load and play the second file while the first file was playing, but I couldn't load the third file while the second was playing. I don't think you need to spend time to fix this becuase I believe this will be fixed when you solve the need for a modal block.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...