; 我也在 Win10 上尝试过 DirectX9:视频正常,音频不正常
; 使用Win10后,再运行这个Win7就能录到外置麦克风【直接在Win10下运行这个脚本会无法录制到外置麦克风声音】
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=71533
#NoEnv
SetBatchLines -1
SetWorkingDir %A_ScriptDir%

file := "test.mp4"
video_bitrate := 2000000   ; 视频比特率
video_fps := 25   ; 视频FPS
duration := 5   ; 录制时长(秒)
capture_cursor := true   ; 录制时包含光标
; audiodevice := "CABLE Output (VB-Audio Virtual Cable)"  ; 虚拟内录声卡:https://vb-audio.com/Cable/
audiodevice := "麦克风 (Realtek High Definition Audio)"  ; 不想录制声音可以删除此行
audioDelay := 80   ; 音频延迟
; x1 := 100, x2 := 1000, y1 := 100, y2 := 500   ; 设置录像屏幕坐标
; ShowAllAudioDevicesNames := true    ; 显示当前电脑的音频设备名
; CaptureCoordinatesWithCPU := true   ; 使用 CPU 捕获坐标
; Rotate := true   ; 旋转
; UseSoftwareEncoding := true   ; 使用软件编码


Global pSinkWriter, SourceReader, audioStreamIndex, Flush, IMFSourceReaderCallback, IMFTransform, pTransform, MFT_OUTPUT_DATA_BUFFER, cbOutBytes
d3d := Direct3DCreate9(D3D_SDK_VERSION := 32) 
if !d3d {
    MsgBox, 16, 报错, Direct3DCreate9 失败。
    ExitApp
}
VarSetCapacity(D3DDISPLAYMODE, 16, 0)
, IDirect3D9_GetAdapterDisplayMode(d3d, D3DADAPTER_DEFAULT := 0, &D3DDISPLAYMODE)
, Windowed := true
, BackBufferCount := 1
, height := NumGet(D3DDISPLAYMODE, 4, "uint")
, width := NumGet(D3DDISPLAYMODE, 0, "uint")
, SwapEffect := 1   ; D3DSWAPEFFECT_DISCARD
, hDeviceWindow := 0
, VarSetCapacity(D3DPRESENT_PARAMETERS, 48+2*A_PtrSize, 0) 
, NumPut(width, D3DPRESENT_PARAMETERS, 0)
, NumPut(height, D3DPRESENT_PARAMETERS, 4)
, NumPut(BackBufferCount, D3DPRESENT_PARAMETERS, 12)
, NumPut(SwapEffect, D3DPRESENT_PARAMETERS, 24)
, NumPut(hDeviceWindow, D3DPRESENT_PARAMETERS, 24+A_PtrSize)
, NumPut(Windowed, D3DPRESENT_PARAMETERS, 24+2*A_PtrSize)
, IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT := 0, D3DDEVTYPE_HAL := 1, 0, D3DCREATE_SOFTWARE_VERTEXPROCESSING := 0x00000020, &D3DPRESENT_PARAMETERS, device)
, IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, D3DFMT_A8R8G8B8 := 21, D3DPOOL_SYSTEMMEM := 2, surface, 0)
, Release(d3d)
, d3d := ""

, LOAD_DLL_Mf_Mfplat_Mfreadwrite()
, MFStartup(version := 2, MFSTARTUP_FULL := 0)

if (ShowAllAudioDevicesNames != 1) {
   if (UseSoftwareEncoding != 1)
      VarSetCapacity(MFT_REGISTER_TYPE_INFO, 32, 0)
      , DllCall("RtlMoveMemory", "ptr", &MFT_REGISTER_TYPE_INFO, "ptr", MF_GUID(GUID, "MFMediaType_Video"), "ptr", 16)
      , DllCall("RtlMoveMemory", "ptr", &MFT_REGISTER_TYPE_INFO + 16, "ptr", MF_GUID(GUID, "MFVideoFormat_H264"), "ptr", 16)
      , hardware_encoder := MFTEnumEx(MF_GUID(GUID, "MFT_CATEGORY_VIDEO_ENCODER"), MFT_ENUM_FLAG_HARDWARE := 0x04|MFT_ENUM_FLAG_SORTANDFILTER := 0x40, 0, &MFT_REGISTER_TYPE_INFO)

   if (x1 != "")
      checkCoordinates(x1, x2, y1, y2, hardware_encoder)
      , width := x2-x1
      , height := y2-y1
      , VarSetCapacity(RECT, 16, 0)
      , NumPut(x1, RECT, 0, "int")
      , NumPut(y1, RECT, 4, "int")
      , NumPut(x2, RECT, 8, "int")
      , NumPut(y2, RECT, 12, "int")

   if (hardware_encoder != "")
      MFCreateAttributes(pMFAttributes, 4)
      , IMFAttributes_SetUINT32(pMFAttributes, MF_GUID(GUID, "MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS"), true)
   else
      MFCreateAttributes(pMFAttributes, 3)

   IMFAttributes_SetGUID(pMFAttributes, MF_GUID(GUID, "MF_TRANSCODE_CONTAINERTYPE"), MF_GUID(GUID1, "MFTranscodeContainerType_MPEG4"))
   , IMFAttributes_SetUINT32(pMFAttributes, MF_GUID(GUID, "MF_SINK_WRITER_DISABLE_THROTTLING"), true)
   , IMFAttributes_SetUINT32(pMFAttributes, MF_GUID(GUID, "MF_LOW_LATENCY"), true)
   , MFCreateSinkWriterFromURL(file, 0, pMFAttributes, pSinkWriter)
   , Release(pMFAttributes)
   , pMFAttributes := ""

   Loop 2 {  ; 1 - input 输入, 2 - output 输出
      MFCreateMediaType(pMediaType%A_Index%)
      , IMFAttributes_SetGUID(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_MAJOR_TYPE"), MF_GUID(GUID1, "MFMediaType_Video"))
      if (A_Index = 1) {
         if (A_OSVersion = "WIN_7") or !InStr(hardware_encoder, "NVIDIA") or ((x1 != "") and (CaptureCoordinatesWithCPU = true))
            IMFAttributes_SetGUID(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_SUBTYPE"), MF_GUID(GUID1, "MFVideoFormat_RGB32"))
         else
            IMFAttributes_SetGUID(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_SUBTYPE"), MF_GUID(GUID1, "MFVideoFormat_ARGB32"))
      } else
         IMFAttributes_SetGUID(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_SUBTYPE"), MF_GUID(GUID1, "MFVideoFormat_H264"))
         , IMFAttributes_SetUINT32(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_AVG_BITRATE"), video_bitrate)

      IMFAttributes_SetUINT32(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_INTERLACE_MODE"), MFVideoInterlace_Progressive := 2)
      , IMFAttributes_SetUINT64(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_FRAME_SIZE"), (width<<32)|height)
      , IMFAttributes_SetUINT64(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_FRAME_RATE"), (video_fps<<32)|1)
      , IMFAttributes_SetUINT64(pMediaType%A_Index%, MF_GUID(GUID, "MF_MT_PIXEL_ASPECT_RATIO"), (1<<32)|1)
   }
   IMFSinkWriter_AddStream(pSinkWriter, pMediaType2, videoStreamIndex)
   , IMFSinkWriter_SetInputMediaType(pSinkWriter, videoStreamIndex, pMediaType1, 0)
   , Release(pMediaType1)
   , Release(pMediaType2)
   , pMediaType1 := pMediaType2 := ""
}

if (audiodevice != "") or (ShowAllAudioDevicesNames = 1) {
   NUM_CHANNELSMax := BITS_PER_SAMPLEMax := SAMPLES_PER_SECONDMax := BYTES_PER_SECONDMax := StreamNumberAudio := TypeNumberAudio := AudioSources := ""
   , audiobasedevice := audiodevice
   , IMFSourceReaderCallback := IMFSourceReaderCallback_new()
   , MFCreateAttributes(pMFAttributes, 1)
   , IMFAttributes_SetGUID(pMFAttributes, MF_GUID(GUID, "MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE"), MF_GUID(GUID1, "MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID"))
   , MFEnumDeviceSources(pMFAttributes, pppSourceActivate, pcSourceActivate)
   Loop % pcSourceActivate {
      IMFActivate := NumGet(pppSourceActivate + (A_Index - 1)*A_PtrSize)
      , devicename := IMFActivate_GetAllocatedString(IMFActivate, MF_GUID(GUID, "MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME"))
      if (ShowAllAudioDevicesNames = 1) {
         basedevicename := devicename
         Loop {
            if !InStr(Audiodevicenames, """" devicename """`r`n")
               break
            devicename := basedevicename "[" A_Index+1 "]"
         }
         Audiodevicenames .= """" devicename """`r`n"
      } else {
         if RegexMatch(audiodevice, "\[(\d)]$", match) and (devicename = RegexReplace(audiodevice, "\[\d]$")) {
            match1--
            if (match1 = 0)
               audiodevice := devicename
            else
               audiodevice := devicename "[" match1 "]"
         }
         if (devicename = audiodevice) and (MediaSourceAudio = "")
            IMFActivate_ActivateObject(IMFActivate, IMFMediaSource := "{279a808d-aec7-40c8-9c6b-a6b492c78a66}", MediaSourceAudio)
      }
      Release(IMFActivate)
      , IMFActivate := ""
   }
   DllCall("ole32\CoTaskMemFree", "ptr", pppSourceActivate)
   , Release(pMFAttributes)
   , pMFAttributes := ""
   if (ShowAllAudioDevicesNames = 1) {
      if (Audiodevicenames = "")
         Audiodevicenames .= "None"
      MsgBox 0x40, 音频设备名已存入剪贴板, % "Audio:`r`n" clipboard := Audiodevicenames
      ExitApp
   }
   if (MediaSourceAudio = "") {
      MsgBox 0x10, 请匹配你电脑对应的音频设备, % "找不到音频设备 - """ audiobasedevice """"
      ExitApp
   }
   MFCreateAttributes(pMFAttributes, 1)
   , IMFAttributes_SetUnknown(pMFAttributes, MF_GUID(GUID, "MF_SOURCE_READER_ASYNC_CALLBACK"), IMFSourceReaderCallback)
   , MFCreateSourceReaderFromMediaSource(MediaSourceAudio, pMFAttributes, SourceReader)
   Loop {
      n := A_Index - 1
      if (IMFSourceReader_GetNativeMediaType(SourceReader, n, 0, ppMediaType) = "MF_E_INVALIDSTREAMNUMBER")
         break
      Release(ppMediaType)
      , ppMediaType := ""
      Loop {
         k := A_Index - 1
         if (IMFSourceReader_GetNativeMediaType(SourceReader, n, k, ppMediaType) = "MF_E_NO_MORE_TYPES")
            break
         IMFAttributes_GetGUID(ppMediaType, MF_GUID(GUID, "MF_MT_MAJOR_TYPE"), pguidValue)
         if (MemoryDifference(&pguidValue, MF_GUID(GUID, "MFMediaType_Audio"), 16) = 0) {
            IMFAttributes_GetGUID(ppMediaType, MF_GUID(GUID, "MF_MT_SUBTYPE"), pguidValueSubType)
            , AudioSources .= Format("0x{:x}", NumGet(pguidValueSubType, 0, "int")) "`n"
            if (MemoryDifference(&pguidValueSubType, MF_GUID(GUID, "MFAudioFormat_PCM"), 16) = 0) or (MemoryDifference(&pguidValueSubType, MF_GUID(GUID, "MFAudioFormat_Float"), 16) = 0) {
               if (IMFAttributes_GetUINT32(ppMediaType, MF_GUID(GUID, "MF_MT_AUDIO_AVG_BYTES_PER_SECOND"), BYTES_PER_SECOND) = "MF_E_ATTRIBUTENOTFOUND")
                  BYTES_PER_SECOND := 0
               if (IMFAttributes_GetUINT32(ppMediaType, MF_GUID(GUID, "MF_MT_AUDIO_BITS_PER_SAMPLE"), BITS_PER_SAMPLE) = "MF_E_ATTRIBUTENOTFOUND")
                  BITS_PER_SAMPLE := 0
               if (IMFAttributes_GetUINT32(ppMediaType, MF_GUID(GUID, "MF_MT_AUDIO_SAMPLES_PER_SECOND"), SAMPLES_PER_SECOND) = "MF_E_ATTRIBUTENOTFOUND")
                  SAMPLES_PER_SECOND := 0
               if (IMFAttributes_GetUINT32(ppMediaType, MF_GUID(GUID, "MF_MT_AUDIO_NUM_CHANNELS"), NUM_CHANNELS) = "MF_E_ATTRIBUTENOTFOUND")
                  NUM_CHANNELS := 0
               if (InStr(A_OSVersion, "W") and (((NUM_CHANNELSMax != 1) and (NUM_CHANNELSMax != 2) and (NUM_CHANNELS > 0)) or ((NUM_CHANNELSMax = 1) and (NUM_CHANNELS = 2)))) or (!InStr(A_OSVersion, "W") and (((NUM_CHANNELSMax < 2) and (NUM_CHANNELS > NUM_CHANNELSMax)) or ((NUM_CHANNELSMax = 2) and (NUM_CHANNELS = 6)) or ((NUM_CHANNELSMax > 2) and (NUM_CHANNELSMax != 6) and ((NUM_CHANNELS = 2) or (NUM_CHANNELS = 6))))) or ((NUM_CHANNELS = NUM_CHANNELSMax) and (BITS_PER_SAMPLEMax != 16) and ((BITS_PER_SAMPLE = 16) or (BITS_PER_SAMPLE > BITS_PER_SAMPLEMax))) or ((NUM_CHANNELS = NUM_CHANNELSMax) and (BITS_PER_SAMPLE = BITS_PER_SAMPLEMax) and (SAMPLES_PER_SECONDMax != 44100) and (SAMPLES_PER_SECONDMax != 48000) and ((SAMPLES_PER_SECOND = 44100) or (SAMPLES_PER_SECOND > SAMPLES_PER_SECONDMax))) or ((SAMPLES_PER_SECONDMax != 48000) and (SAMPLES_PER_SECOND = 48000)) or ((NUM_CHANNELS = NUM_CHANNELSMax) and (BITS_PER_SAMPLE = BITS_PER_SAMPLEMax) and (SAMPLES_PER_SECOND = SAMPLES_PER_SECONDMax) and (BYTES_PER_SECOND > BYTES_PER_SECONDMax))
               {
                  if (MemoryDifference(&pguidValueSubType, MF_GUID(GUID, "MFAudioFormat_PCM"), 16) = 0)
                     MFAudioFormat := "MFAudioFormat_PCM"
                  else
                     MFAudioFormat := "MFAudioFormat_Float" 
                  NUM_CHANNELSMax := NUM_CHANNELS
                  , BITS_PER_SAMPLEMax := BITS_PER_SAMPLE
                  , SAMPLES_PER_SECONDMax := SAMPLES_PER_SECOND
                  , BYTES_PER_SECONDMax := BYTES_PER_SECOND
                  , StreamNumberAudio := n
                  , TypeNumberAudio := k
               }
            }
         }
         Release(ppMediaType)
         , ppMediaType := ""
      }
   }
   if (StreamNumberAudio = "") {
      Sort, AudioSources, U
      MsgBox % "不支持当前的音频源:`n" AudioSources
      ExitApp
   }
   IMFSourceReader_SetStreamSelection(SourceReader, MF_SOURCE_READER_ALL_STREAMS := 0xFFFFFFFE, false)
   , IMFSourceReader_SetStreamSelection(SourceReader, StreamNumberAudio, true)
   , Release(pMFAttributes)
   , pMFAttributes := ""
   if (NUM_CHANNELSMax = 0)
      NUM_CHANNELS := 1
   else if (NUM_CHANNELSMax > 2) and (NUM_CHANNELSMax < 6)
      NUM_CHANNELS := 2
   else if (NUM_CHANNELSMax >= 6) {
      if !InStr(A_OSVersion, "W")
         NUM_CHANNELS := 6
      else
         NUM_CHANNELS := 2
   }
   if (SAMPLES_PER_SECONDMax < 44100)
      SAMPLES_PER_SECOND := 44100
   else if (SAMPLES_PER_SECONDMax > 44100)
      SAMPLES_PER_SECOND := 48000
   Loop 2 {  ; 1 - input 输入, 2 - output 输出
      MFCreateMediaType(pMediaTypeAudio%A_Index%)
      , IMFAttributes_SetGUID(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_MAJOR_TYPE"), MF_GUID(GUID1, "MFMediaType_Audio"))
      if (A_Index = 1)
         IMFAttributes_SetGUID(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_SUBTYPE"), MF_GUID(GUID1, "MFAudioFormat_PCM"))
      else
         IMFAttributes_SetGUID(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_SUBTYPE"), MF_GUID(GUID1, "MFAudioFormat_AAC"))
         , IMFAttributes_SetUINT32(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_AVG_BYTES_PER_SECOND"), 20000)

      IMFAttributes_SetUINT32(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_BITS_PER_SAMPLE"), 16)
      , IMFAttributes_SetUINT32(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_SAMPLES_PER_SECOND"), SAMPLES_PER_SECOND)
      , IMFAttributes_SetUINT32(pMediaTypeAudio%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_NUM_CHANNELS"), NUM_CHANNELS)
   }
   IMFSinkWriter_AddStream(pSinkWriter, pMediaTypeAudio2, audioStreamIndex)
   , IMFSinkWriter_SetInputMediaType(pSinkWriter, audioStreamIndex, pMediaTypeAudio1, 0)
   if (IMFSourceReader_SetCurrentMediaType(SourceReader, StreamNumberAudio, 0, pMediaTypeAudio1) = "MF_E_TOPO_CODEC_NOT_FOUND") {
      LOAD_DLL_Resampledmo_Mfaacenc()
      , IMFTransform := 1
      , cbOutBytes := 100000
      Loop 2 {   ; 1 - input 输入, 2 - output 输出
         MFCreateMediaType(pMedia%A_Index%)
         , IMFAttributes_SetGUID(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_MAJOR_TYPE"), MF_GUID(GUID1, "MFMediaType_Audio"))
         , IMFAttributes_SetGUID(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_SUBTYPE"), MF_GUID(GUID1, MFAudioFormat))
         , IMFAttributes_SetUINT32(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_BITS_PER_SAMPLE"), BITS_PER_SAMPLEMax)
         , IMFAttributes_SetUINT32(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_NUM_CHANNELS"), NUM_CHANNELSMax)
         , IMFAttributes_SetUINT32(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_SAMPLES_PER_SECOND"), SAMPLES_PER_SECONDMax)
         , IMFAttributes_SetUINT32(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_BLOCK_ALIGNMENT"), NUM_CHANNELSMax*BITS_PER_SAMPLEMax//8)
         , IMFAttributes_SetUINT32(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_AUDIO_AVG_BYTES_PER_SECOND"), SAMPLES_PER_SECONDMax*NUM_CHANNELSMax*BITS_PER_SAMPLEMax//8)
         , IMFAttributes_SetUINT32(pMedia%A_Index%, MF_GUID(GUID, "MF_MT_ALL_SAMPLES_INDEPENDENT"), true)
         if (A_Index = 1)
            MFAudioFormat := "MFAudioFormat_PCM", BITS_PER_SAMPLEMax := 16, NUM_CHANNELSMax := NUM_CHANNELS, SAMPLES_PER_SECONDMax := SAMPLES_PER_SECOND
      }
      spTransformUnk := ComObjCreate(CLSID_CResamplerMediaObject := "{f447b69e-1884-4a7e-8055-346f74d6edb3}", IID_IUnknown := "{00000000-0000-0000-C000-000000000046}")
      , pTransform := ComObjQuery(spTransformUnk, IID_IMFTransform := "{bf94c121-5b05-4e6f-8000-ba598961414d}")
      , spResamplerProps := ComObjQuery(spTransformUnk, IID_IWMResamplerProps := "{E7E9984F-F09F-4da4-903F-6E2E0EFE56B5}")
      , IWMResamplerProps_SetHalfFilterLength(spResamplerProps, 60)
      , IMFTransform_SetInputType(pTransform, 0, pMedia1, 0)
      , IMFTransform_SetOutputType(pTransform, 0, pMedia2, 0)
      , IMFTransform_GetInputStatus(pTransform, 0, mftStatus)
      if (mftStatus != 1) {   ; MFT_INPUT_STATUS_ACCEPT_DATA
         MsgBox IMFTransform_GetInputStatus 无法接收数据
         ExitApp
      }
      IMFTransform_ProcessMessage(pTransform, MFT_MESSAGE_COMMAND_FLUSH := 0, 0)
      , IMFTransform_ProcessMessage(pTransform, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING := 0x10000000, 0)
      , IMFTransform_ProcessMessage(pTransform, MFT_MESSAGE_NOTIFY_START_OF_STREAM := 0x10000003, 0)
      , Release(pMedia1)
      , Release(pMedia2)
      , pMedia1 := pMedia2 := ""
   }
   Release(pMediaTypeAudio1)
   , Release(pMediaTypeAudio2)
   , pMediaTypeAudio1 := pMediaTypeAudio2 := ""
}
IMFSinkWriter_BeginWriting(pSinkWriter)
, video_frame_duration := 10000000/video_fps
, video_frame_count := duration*video_fps
, cbWidth := 4 * width
, cbBuffer := cbWidth * height
, rtStart := 0
, fps := 1000/video_fps
, CaptureDuration := duration*1000 - 2*fps
, VarSetCapacity(TIMECAPS, 8, 0)
, DllCall("winmm\timeGetDevCaps", "ptr", &TIMECAPS, "uint", 8)
, uPeriod := NumGet(TIMECAPS, 0, "uint")
, DllCall("Winmm\timeBeginPeriod", "uint", uPeriod)

MsgBox % "硬件编码器 - " ((hardware_encoder != "") ? hardware_encoder : "none")

Loop {
   if (A_Index = 1) {
      if (audiodevice != "") {
         IMFSourceReader_ReadSample(SourceReader, MF_SOURCE_READER_ANY_STREAM := 0xFFFFFFFE, 0, 0, 0, 0, 0)
         if (audioDelay > 0)
            DllCall("Sleep", "uint", audioDelay)
      }
      DllCall("QueryPerformanceCounter", "int64*", start)
      , DllCall("QueryPerformanceFrequency", "int64*", freq)
   } else {
      DllCall("QueryPerformanceCounter", "int64*", ATickCount)
      , sleepDuration := fps*(A_Index-1) - (ATickCount - start)*1000/freq
      , SleepEnd := ATickCount + sleepDuration*freq/1000
      sleep % sleepDuration - 15
      DllCall("QueryPerformanceCounter", "int64*", ATickCount)
      if (ATickCount < SleepEnd)
         DllCall("Sleep", "uint", (SleepEnd - ATickCount)*1000/freq)
   }

   IDirect3DDevice9_GetFrontBufferData(device, 0, surface)
   if (capture_cursor = true) {
      VarSetCapacity(CURSORINFO, cbSize := 16 + A_PtrSize, 0)
      , NumPut(cbSize, CURSORINFO, 0, "uint")
      if DllCall("GetCursorInfo", "ptr", &CURSORINFO) and (NumGet(CURSORINFO, 4, "uint") = 1) {   ; CURSOR_SHOWING 光标显示
         hCursor := NumGet(CURSORINFO, 8)
         , xCursor := NumGet(CURSORINFO, 8 + A_PtrSize, "int")
         , yCursor := NumGet(CURSORINFO, 12 + A_PtrSize, "int")
         , VarSetCapacity(ICONINFO, 8 + A_PtrSize*3, 0)
         , DllCall("GetIconInfo", "ptr", hCursor, "ptr", &ICONINFO)
         , xHotspot := NumGet(ICONINFO, 4, "uint")
         , yHotspot := NumGet(ICONINFO, 8, "uint")
         , hbmMask  := NumGet(ICONINFO, 8 + A_PtrSize)
         , hbmColor := NumGet(ICONINFO, 8 + A_PtrSize*2)
         , IDirect3DSurface9_GetDC(surface, hdc)
         , DllCall("DrawIconEx", "ptr", hdc, "int", xCursor - xHotspot, "int", yCursor - yHotspot, "ptr", hCursor, "int", 0, "int", 0, "uint", 0, "ptr", 0, "uint", DI_NORMAL := 0x0003 | DI_DEFAULTSIZE := 0x0008)
         if hbmMask
            DllCall("DeleteObject", "ptr", hbmMask)
         if hbmColor
            DllCall("DeleteObject", "ptr", hbmColor)
         hbmMask := hbmColor := ""
         , IDirect3DSurface9_ReleaseDC(surface, hdc)
      }
   }
   VarSetCapacity(D3DLOCKED_RECT, A_PtrSize*2, 0)
   if (x1 = "")
      IDirect3DSurface9_LockRect(surface, &D3DLOCKED_RECT, 0, 0)
   else
      IDirect3DSurface9_LockRect(surface, &D3DLOCKED_RECT, &RECT, 0)
   pitch := NumGet(D3DLOCKED_RECT, 0, "int")
   , pBits := NumGet(D3DLOCKED_RECT, A_PtrSize, "ptr")

   , MFCreateMemoryBuffer(cbBuffer, pBuffer)
   , IMFMediaBuffer_Lock(pBuffer, pData, 0, 0)
   if (A_OSVersion = "WIN_7") or !InStr(hardware_encoder, "NVIDIA") or ((x1 != "") and (CaptureCoordinatesWithCPU = true)) or (Rotate = true)
      MFCopyImage(pData, cbWidth, pBits+(height-1)*pitch, pitch*-1, cbWidth, height)
   else
      MFCopyImage(pData, cbWidth, pBits, pitch, cbWidth, height)
   IMFMediaBuffer_Unlock(pBuffer)
   , IMFMediaBuffer_SetCurrentLength(pBuffer, cbBuffer)
   , MFCreateSample(pSample)
   , IMFSample_AddBuffer(pSample, pBuffer)
   , IMFSample_SetSampleTime(pSample, rtStart)
   , IMFSample_SetSampleDuration(pSample, video_frame_duration)
   , IMFSinkWriter_WriteSample(pSinkWriter, streamIndex, pSample)

   , IDirect3DSurface9_UnlockRect(surface)
   , Release(pSample)
   , Release(pBuffer)
   , pSample := pBuffer := ""
   if ((ATickCount - start)/freq*1000 >= CaptureDuration) {
      video_frame_countReal := A_Index
      if (audiodevice != "") {
         flush := 1
         Loop {
            if (flush = "")
               break
            sleep 50
         }
      }
      break
   }
   rtStart += video_frame_duration
}
IMFSinkWriter_Finalize(pSinkWriter)
, DllCall("Winmm\timeEndPeriod", "uint", uPeriod)
if (audiodevice != "") {
   if (IMFTransform = 1)
      Release(spResamplerProps)
      , Release(pTransform)
      , Release(spTransformUnk)
      , spResamplerProps := pTransform := spTransformUnk := IMFTransform := ""

   Release(MediaSourceAudio)
   , MediaSourceAudio := ""
}
Release(pSinkWriter)
, Release(surface)
, Release(device)
, pSinkWriter := surface := device := ""
, MFShutdown()
MsgBox % "录制完毕`n`n" video_frame_countReal " 捕获`n" video_frame_count-video_frame_countReal " 丢帧"
ExitApp


; ==================== 以下是屏幕录制类库 ====================

Direct3DCreate9(SDKVersion) {
    if !DllCall("GetModuleHandle","str","d3d9")
        DllCall("LoadLibrary","str","d3d9")
    return DllCall("d3d9\Direct3DCreate9", "uint", SDKVersion)
}

IDirect3D9_GetAdapterDisplayMode(this,Adapter,pMode) {
   hr := DllCall(NumGet(NumGet(this+0)+8*A_PtrSize),"ptr",this,"uint",Adapter,"ptr",pMode)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3D9_CreateDevice(this,Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,ByRef ppReturnedDeviceInterface) {
   hr := DllCall(NumGet(NumGet(this+0)+16*A_PtrSize),"ptr",this,"uint",Adapter,"uint",DeviceType,"ptr",hFocusWindow,"uint",BehaviorFlags,"ptr",pPresentationParameters,"ptr*",ppReturnedDeviceInterface)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3DDevice9_GetFrontBufferData(this,iSwapChain,pDestSurface) {
   hr := DllCall(NumGet(NumGet(this+0)+33*A_PtrSize),"ptr",this,"uint",iSwapChain,"ptr",pDestSurface)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3DDevice9_CreateOffscreenPlainSurface(this,Width,Height,Format,Pool,ByRef ppSurface,pSharedHandle) {
   hr := DllCall(NumGet(NumGet(this+0)+36*A_PtrSize),"ptr",this,"uint",Width,"uint",Height,"uint",Format,"uint",Pool,"ptr*",ppSurface,"ptr",pSharedHandle)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3DSurface9_LockRect(this,pLockedRect,pRect,Flags) {
   hr := DllCall(NumGet(NumGet(this+0)+13*A_PtrSize),"ptr",this,"ptr",pLockedRect,"ptr",pRect,"uint",Flags)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3DSurface9_UnlockRect(this) {
   hr := DllCall(NumGet(NumGet(this+0)+14*A_PtrSize),"ptr",this)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3DSurface9_GetDC(this, ByRef phdc) {
   hr := DllCall(NumGet(NumGet(this+0)+15*A_PtrSize),"ptr",this,"ptr*",phdc)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IDirect3DSurface9_ReleaseDC(this,phdc) {
   hr := DllCall(NumGet(NumGet(this+0)+16*A_PtrSize),"ptr",this,"ptr",phdc)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}



LOAD_DLL_Mf_Mfplat_Mfreadwrite() {
   if !DllCall("GetModuleHandle","str","Mf")
      DllCall("LoadLibrary","Str", "Mf.dll", "ptr")
   if !DllCall("GetModuleHandle","str","Mfplat")
      DllCall("LoadLibrary","Str", "Mfplat.dll", "ptr")
   if !DllCall("GetModuleHandle","str","Mfreadwrite")
      DllCall("LoadLibrary","Str", "Mfreadwrite.dll", "ptr")
}

MFStartup(version, dwFlags) {
   hr := DllCall("Mfplat.dll\MFStartup", "uint", version, "uint", dwFlags)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFShutdown() {
   hr := DllCall("Mfplat.dll\MFShutdown")
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFTEnumEx(guidCategory, Flags, pInputType, pOutputType) {
   if (A_PtrSize = 8)
      hr := DllCall("Mfplat\MFTEnumEx", "ptr", guidCategory, "uint", Flags, "ptr", pInputType, "ptr", pOutputType, "ptr*", pppMFTActivate, "uint*", pnumMFTActivate)
   else
      hr := DllCall("Mfplat\MFTEnumEx", "uint64", NumGet(guidCategory+0, 0, "uint64"), "uint64", NumGet(guidCategory+0, 8, "uint64"), "uint", Flags, "ptr", pInputType, "ptr", pOutputType, "ptr*", pppMFTActivate, "uint*", pnumMFTActivate)
   Loop % pnumMFTActivate {
      IMFActivate := NumGet(pppMFTActivate + (A_Index - 1)*A_PtrSize)
      if (A_Index = 1)
         hardware_encoder := IMFActivate_GetAllocatedString(IMFActivate, MF_GUID(GUID, "MFT_FRIENDLY_NAME_Attribute"))
      Release(IMFActivate)
   }
   DllCall("ole32\CoTaskMemFree", "ptr", pppMFTActivate)
   return hardware_encoder
}

MFCreateSinkWriterFromURL(pwszOutputURL, pByteStream, pAttributes, ByRef ppSinkWriter) {
   hr := DllCall("Mfreadwrite.dll\MFCreateSinkWriterFromURL", "str", pwszOutputURL, "ptr", pByteStream, "ptr", pAttributes, "ptr*", ppSinkWriter)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateSourceReaderFromMediaSource(pMediaSource, pAttributes, ByRef ppSourceReader) {
   hr := DllCall("Mfreadwrite.dll\MFCreateSourceReaderFromMediaSource", "ptr", pMediaSource, "ptr", pAttributes, "ptr*", ppSourceReader)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateMediaType(ByRef ppMFType) {
   hr := DllCall("Mfplat.dll\MFCreateMediaType", "ptr*", ppMFType)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateAttributes(ByRef ppMFAttributes, cInitialSize) {
   hr := DllCall("Mfplat.dll\MFCreateAttributes", "ptr*", ppMFAttributes, "uint", cInitialSize)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateSample(ByRef ppIMFSample) {
   hr := DllCall("Mfplat.dll\MFCreateSample", "ptr*", ppIMFSample)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateMemoryBuffer(cbMaxLength, ByRef ppBuffer) {
   hr := DllCall("Mfplat.dll\MFCreateMemoryBuffer", "uint", cbMaxLength, "ptr*", ppBuffer)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCopyImage(pDest, lDestStride, pSrc, lSrcStride, dwWidthInBytes, dwLines) {
   hr := DllCall("Mfplat.dll\MFCopyImage", "ptr", pDest, "int", lDestStride, "ptr", pSrc, "int", lSrcStride, "uint", dwWidthInBytes, "uint", dwLines)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFEnumDeviceSources(pAttributes, ByRef pppSourceActivate, ByRef pcSourceActivate) {
   hr := DllCall("Mf.dll\MFEnumDeviceSources", "ptr", pAttributes, "ptr*", pppSourceActivate, "uint*", pcSourceActivate)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateCollection(ByRef ppIMFCollection) {
   hr := DllCall("Mfplat.dll\MFCreateCollection", "ptr*", ppIMFCollection)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MFCreateAggregateSource(pSourceCollection, ByRef ppAggSource) {
   hr := DllCall("Mf.dll\MFCreateAggregateSource", "ptr", pSourceCollection, "ptr*", ppAggSource)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSourceReader_SetCurrentMediaType(this, dwStreamIndex, pdwReserved, pMediaType) {
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "uint", pdwReserved, "ptr", pMediaType)
   if hr or ErrorLevel
   {
      if !ErrorLevel {
         if (hr&=0xFFFFFFFF) = 0xC00D5212   ; MF_E_TOPO_CODEC_NOT_FOUND
            return "MF_E_TOPO_CODEC_NOT_FOUND"
      }
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
   }
}

IMFSourceReader_SetStreamSelection(this, dwStreamIndex, fSelected) {
   hr := DllCall(NumGet(NumGet(this+0)+4*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "int", fSelected)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSourceReader_GetNativeMediaType(this, dwStreamIndex, dwMediaTypeIndex, ByRef ppMediaType) {
   hr := DllCall(NumGet(NumGet(this+0)+5*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "uint", dwMediaTypeIndex, "ptr*", ppMediaType)
   if hr or ErrorLevel
   {
      if !ErrorLevel {
         if (hr&=0xFFFFFFFF) = 0xC00D36B3   ; MF_E_INVALIDSTREAMNUMBER
            return "MF_E_INVALIDSTREAMNUMBER"
         if (hr&=0xFFFFFFFF) = 0xC00D36B9   ; MF_E_NO_MORE_TYPES
            return "MF_E_NO_MORE_TYPES"
      }
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
   }
}

IMFSourceReader_ReadSample(this, dwStreamIndex, dwControlFlags, pdwActualStreamIndex, pdwStreamFlags, pllTimestamp, ppSample) {
   hr := DllCall(NumGet(NumGet(this+0)+9*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "uint", dwControlFlags, "uint", pdwActualStreamIndex, "uint", pdwStreamFlags, "int", pllTimestamp, "ptr", ppSample)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSourceReader_Flush(this, dwStreamIndex) {
   hr := DllCall(NumGet(NumGet(this+0)+10*A_PtrSize), "ptr", this, "uint", dwStreamIndex)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFAttributes_GetGUID(this, guidKey, ByRef pguidValue) {
   VarSetCapacity(pguidValue, 16, 0)
   , hr := DllCall(NumGet(NumGet(this+0)+10*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr", &pguidValue)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
   return &pguidValue
}

IMFAttributes_GetUINT64(this, guidKey, ByRef punValue) {
   hr := DllCall(NumGet(NumGet(this+0)+8*A_PtrSize), "ptr", this, "ptr", guidKey, "uint64*", punValue)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFAttributes_GetUINT32(this, guidKey, ByRef punValue) {
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), "ptr", this, "ptr", guidKey, "uint*", punValue)
   if hr or ErrorLevel
   {
      if !ErrorLevel {
         if (hr&=0xFFFFFFFF) = 0xC00D36E6   ; MF_E_ATTRIBUTENOTFOUND
            return "MF_E_ATTRIBUTENOTFOUND"
      }
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
   }
}

IMFAttributes_SetUINT32(this, guidKey, unValue) {
   hr := DllCall(NumGet(NumGet(this+0)+21*A_PtrSize), "ptr", this, "ptr", guidKey, "uint", unValue)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFAttributes_SetUINT64(this, guidKey, unValue) {
   hr := DllCall(NumGet(NumGet(this+0)+22*A_PtrSize), "ptr", this, "ptr", guidKey, "uint64", unValue)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFAttributes_SetGUID(this, guidKey, guidValue) {
   hr := DllCall(NumGet(NumGet(this+0)+24*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr", guidValue)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFAttributes_SetUnknown(this, guidKey, pUnknown) {
   hr := DllCall(NumGet(NumGet(this+0)+27*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr", pUnknown)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFActivate_GetAllocatedString(this, guidKey) {
   hr := DllCall(NumGet(NumGet(this+0)+13*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr*", ppwszValue, "uint*", pcchLength)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
   AllocatedString := StrGet(ppwszValue, pcchLength, "UTF-16")
   , DllCall("ole32\CoTaskMemFree", "ptr", ppwszValue)
   return AllocatedString
}

IMFActivate_ActivateObject(this, riid, ByRef ppv) {
   GUID(riid, riid)
   , hr := DllCall(NumGet(NumGet(this+0)+33*A_PtrSize), "ptr", this, "ptr", &riid, "ptr*", ppv)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSinkWriter_SendStreamTick(this, dwStreamIndex, llTimestamp) {
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "int64", llTimestamp)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSinkWriter_AddStream(this, pMediaTypeOut, ByRef pdwStreamIndex) {
   hr := DllCall(NumGet(NumGet(this+0)+3*A_PtrSize), "ptr", this, "ptr", pMediaTypeOut, "ptr*", pdwStreamIndex)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSinkWriter_SetInputMediaType(this, dwStreamIndex, pInputMediaType, pEncodingParameters) {
   hr := DllCall(NumGet(NumGet(this+0)+4*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "ptr", pInputMediaType, "ptr", pEncodingParameters)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSinkWriter_BeginWriting(this) {
   hr := DllCall(NumGet(NumGet(this+0)+5*A_PtrSize), "ptr", this)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSinkWriter_WriteSample(this, dwStreamIndex, pSample) {
   hr := DllCall(NumGet(NumGet(this+0)+6*A_PtrSize), "ptr", this, "uint", dwStreamIndex, "ptr", pSample)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSinkWriter_Finalize(this) {
   hr := DllCall(NumGet(NumGet(this+0)+11*A_PtrSize), "ptr", this)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFMediaBuffer_Lock(this, ByRef ppbBuffer, ByRef pcbMaxLength, ByRef pcbCurrentLength) {
   hr := DllCall(NumGet(NumGet(this+0)+3*A_PtrSize), "ptr", this, "ptr*", ppbBuffer, "uint*", pcbMaxLength, "uint*", pcbCurrentLength)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFMediaBuffer_Unlock(this) {
   hr := DllCall(NumGet(NumGet(this+0)+4*A_PtrSize), "ptr", this)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFMediaBuffer_SetCurrentLength(this, cbCurrentLength) {
   hr := DllCall(NumGet(NumGet(this+0)+6*A_PtrSize), "ptr", this, "uint", cbCurrentLength)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFMediaSource_Shutdown(this) {
   hr := DllCall(NumGet(NumGet(this+0)+12*A_PtrSize), "ptr", this)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSample_AddBuffer(this, pBuffer) {
   hr := DllCall(NumGet(NumGet(this+0)+42*A_PtrSize), "ptr", this, "ptr", pBuffer)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSample_SetSampleTime(this, hnsSampleTime) {
   hr := DllCall(NumGet(NumGet(this+0)+36*A_PtrSize), "ptr", this, "int64", hnsSampleTime)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSample_GetSampleDuration(this, ByRef phnsSampleDuration) {
   hr := DllCall(NumGet(NumGet(this+0)+37*A_PtrSize), "ptr", this, "int64*", phnsSampleDuration)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFSample_SetSampleDuration(this, hnsSampleDuration) {
   hr := DllCall(NumGet(NumGet(this+0)+38*A_PtrSize), "ptr", this, "int64", hnsSampleDuration)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFCollection_AddElement(this, pUnkElement) {
   hr := DllCall(NumGet(NumGet(this+0)+5*A_PtrSize), "ptr", this, "ptr", pUnkElement)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

LOAD_DLL_Resampledmo_Mfaacenc() {
   if !DllCall("GetModuleHandle","str","Resampledmo")
      DllCall("LoadLibrary","Str", "Resampledmo.dll", "ptr")
   if !DllCall("GetModuleHandle","str","Mfaacenc")
      DllCall("LoadLibrary","Str", "Mfaacenc.dll", "ptr")
}

IMFTransform_GetInputStatus(this, dwInputStreamID, ByRef pdwFlags) {
   hr := DllCall(NumGet(NumGet(this+0)+19*A_PtrSize), "ptr", this, "uint", dwInputStreamID, "uint*", pdwFlags)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFTransform_ProcessMessage(this, eMessage, ulParam) {
   hr := DllCall(NumGet(NumGet(this+0)+23*A_PtrSize), "ptr", this, "uint", eMessage, "uint", ulParam)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFTransform_ProcessOutput(this, dwFlags, cOutputBufferCount, pOutputSamples, ByRef pdwStatus) {
   hr := DllCall(NumGet(NumGet(this+0)+25*A_PtrSize), "ptr", this, "uint", dwFlags, "uint", cOutputBufferCount, "ptr", pOutputSamples, "uint*", pdwStatus)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFTransform_ProcessInput(this, dwInputStreamID, pSample, dwFlags) {
   hr := DllCall(NumGet(NumGet(this+0)+24*A_PtrSize), "ptr", this, "uint", dwInputStreamID, "ptr", pSample, "uint", dwFlags)
   if hr or ErrorLevel
   {
      if !ErrorLevel {
         if (hr&=0xFFFFFFFF) = 0xC00D36B2   ; MF_E_INVALIDREQUEST
            return "MF_E_INVALIDREQUEST"
      }
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
   }
}

IMFTransform_GetOutputStreamInfo(this, dwInputStreamID, pStreamInfo) {
   hr := DllCall(NumGet(NumGet(this+0)+7*A_PtrSize), "ptr", this, "uint", dwInputStreamID, "ptr", pStreamInfo)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFTransform_SetOutputType(this, dwInputStreamID, pType, dwFlags) {
   hr := DllCall(NumGet(NumGet(this+0)+16*A_PtrSize), "ptr", this, "uint", dwInputStreamID, "ptr", pType, "uint", dwFlags)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IMFTransform_SetInputType(this, dwInputStreamID, pType, dwFlags) {
   hr := DllCall(NumGet(NumGet(this+0)+15*A_PtrSize), "ptr", this, "uint", dwInputStreamID, "ptr", pType, "uint", dwFlags)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

IWMResamplerProps_SetHalfFilterLength(this, lhalfFilterLen) {
   hr := DllCall(NumGet(NumGet(this+0)+3*A_PtrSize), "ptr", this, "int", lhalfFilterLen)
   if hr or ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MF_GUID(ByRef GUID, name) {
   static init:=1, _:={}
   if init {
      init:=0
      _.MF_MT_MAJOR_TYPE := [0x48eba18e, 0xf8c9, 0x4687, 0xbf, 0x11, 0x0a, 0x74, 0xc9, 0xf9, 0x6a, 0x8f]
      _.MF_MT_SUBTYPE := [0xf7e34c9a, 0x42e8, 0x4714, 0xb7, 0x4b, 0xcb, 0x29, 0xd7, 0x2c, 0x35, 0xe5]
      _.MF_MT_AVG_BITRATE := [0x20332624, 0xfb0d, 0x4d9e, 0xbd, 0x0d, 0xcb, 0xf6, 0x78, 0x6c, 0x10, 0x2e]
      _.MF_MT_INTERLACE_MODE := [0xe2724bb8, 0xe676, 0x4806, 0xb4, 0xb2, 0xa8, 0xd6, 0xef, 0xb4, 0x4c, 0xcd]
      _.MF_MT_FRAME_SIZE := [0x1652c33d, 0xd6b2, 0x4012, 0xb8, 0x34, 0x72, 0x03, 0x08, 0x49, 0xa3, 0x7d]
      _.MF_MT_FRAME_RATE := [0xc459a2e8, 0x3d2c, 0x4e44, 0xb1, 0x32, 0xfe, 0xe5, 0x15, 0x6c, 0x7b, 0xb0]
      _.MF_MT_PIXEL_ASPECT_RATIO := [0xc6376a1e, 0x8d0a, 0x4027, 0xbe, 0x45, 0x6d, 0x9a, 0x0a, 0xd3, 0x9b, 0xb6]
      _.MF_MT_AUDIO_AVG_BYTES_PER_SECOND := [0x1aab75c8, 0xcfef, 0x451c, 0xab, 0x95, 0xac, 0x03, 0x4b, 0x8e, 0x17, 0x31]
      _.MF_MT_AUDIO_BLOCK_ALIGNMENT := [0x322de230, 0x9eeb, 0x43bd, 0xab, 0x7a, 0xff, 0x41, 0x22, 0x51, 0x54, 0x1d]
      _.MF_MT_AUDIO_SAMPLES_PER_SECOND := [0x5faeeae7, 0x0290, 0x4c31, 0x9e, 0x8a, 0xc5, 0x34, 0xf6, 0x8d, 0x9d, 0xba]
      _.MF_MT_AUDIO_BITS_PER_SAMPLE := [0xf2deb57f, 0x40fa, 0x4764, 0xaa, 0x33, 0xed, 0x4f, 0x2d, 0x1f, 0xf6, 0x69]
      _.MF_MT_AUDIO_NUM_CHANNELS := [0x37e48bf5, 0x645e, 0x4c5b, 0x89, 0xde, 0xad, 0xa9, 0xe2, 0x9b, 0x69, 0x6a]
      _.MFT_CATEGORY_VIDEO_ENCODER := [0xf79eac7d, 0xe545, 0x4387, 0xbd, 0xee, 0xd6, 0x47, 0xd7, 0xbd, 0xe4, 0x2a]
      _.MF_TRANSCODE_CONTAINERTYPE := [0x150ff23f, 0x4abc, 0x478b, 0xac, 0x4f, 0xe1, 0x91, 0x6f, 0xba, 0x1c, 0xca]
      _.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS := [0xa634a91c, 0x822b, 0x41b9, 0xa4, 0x94, 0x4d, 0xe4, 0x64, 0x36, 0x12, 0xb0]
      _.MFTranscodeContainerType_MPEG4 := [0xdc6cd05d, 0xb9d0, 0x40ef, 0xbd, 0x35, 0xfa, 0x62, 0x2c, 0x1a, 0xb2, 0x8a]
      _.MFT_FRIENDLY_NAME_Attribute := [0x314ffbae, 0x5b41, 0x4c95, 0x9c, 0x19, 0x4e, 0x7d, 0x58, 0x6f, 0xac, 0xe3]
      _.MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME := [0x60d0e559, 0x52f8, 0x4fa2, 0xbb, 0xce, 0xac, 0xdb, 0x34, 0xa8, 0xec, 0x1]
      _.MF_SINK_WRITER_DISABLE_THROTTLING := [0x08b845d8, 0x2b74, 0x4afe, 0x9d, 0x53, 0xbe, 0x16, 0xd2, 0xd5, 0xae, 0x4f]
      _.MF_LOW_LATENCY := [0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee]
      _.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE := [0xc60ac5fe, 0x252a, 0x478f, 0xa0, 0xef, 0xbc, 0x8f, 0xa5, 0xf7, 0xca, 0xd3]
      _.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID := [0x14dd9a1c, 0x7cff, 0x41be, 0xb1, 0xb9, 0xba, 0x1a, 0xc6, 0xec, 0xb5, 0x71]
      _.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID := [0x8ac3587a, 0x4ae7, 0x42d8, 0x99, 0xe0, 0x0a, 0x60, 0x13, 0xee, 0xf9, 0x0f]
      _.MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN := [0x56b67165, 0x219e, 0x456d, 0xa2, 0x2e, 0x2d, 0x30, 0x04, 0xc7, 0xfe, 0x56]
      _.MF_MT_ALL_SAMPLES_INDEPENDENT := [0xc9173739, 0x5e56, 0x461c, 0xb7, 0x13, 0x46, 0xfb, 0x99, 0x5c, 0xb9, 0x5f]
      _.MF_SOURCE_READER_ASYNC_CALLBACK := [0x1e3dbeac, 0xbb43, 0x4c35, 0xb5, 0x07, 0xcd, 0x64, 0x44, 0x64, 0xc9, 0x65]
      _.MFSampleExtension_Discontinuity := [0x9cdf01d9, 0xa0f0, 0x43ba, 0xb0, 0x77, 0xea, 0xa0, 0x6c, 0xbd, 0x72, 0x8a]
      _.MFMediaType_Video := [0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFMediaType_Audio := [0x73647561, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71]
      _.MFAudioFormat_AAC := [0x1610, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFAudioFormat_Float := [0x0003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFAudioFormat_PCM := [0x0001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_H264 := [0x34363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]   ; FCC("H264") = 0x34363248
      _.MFVideoFormat_RGB32 := [0x00000016, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_ARGB32 := [0x00000015, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_I420 := [0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_IYUV := [0x56555949, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_NV12 := [0x3231564E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_YUY2 := [0x32595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_YV12 := [0x32315659, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
      _.MFVideoFormat_RGB24 := [0x00000014, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71]
   }
   if _.haskey(name) {
      p := _[name]
      , VarSetCapacity(GUID,16)
      ,NumPut(p.1+(p.2<<32)+(p.3<<48),GUID,0,"int64")
      ,NumPut(p.4+(p.5<<8)+(p.6<<16)+(p.7<<24)+(p.8<<32)+(p.9<<40)+(p.10<<48)+(p.11<<56),GUID,8,"int64")
      return &GUID
   }
   else return name
}

GUID(ByRef GUID, sGUID) {
    VarSetCapacity(GUID, 16, 0)
    return DllCall("ole32\CLSIDFromString", "WStr", sGUID, "Ptr", &GUID) >= 0 ? &GUID : ""
}

FCC(var) {
   c := StrSplit(var)
   MsgBox % clipboard := Format("{:#x}",((Asc(c[1])&255)+((Asc(c[2])&255)<<8)+((Asc(c[3])&255)<<16)+((Asc(c[4])&255)<<24)))
}

Release(this) {
   DllCall(NumGet(NumGet(this+0)+2*A_PtrSize), "ptr", this)
   if ErrorLevel
      _Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}

MemoryDifference(ptr1, ptr2, num) {
   return DllCall("msvcrt\memcmp", "ptr", ptr1, "ptr", ptr2, "int", num) 
}

_Error(val) {
   MsgBox % val
   ExitApp
}

checkCoordinates(ByRef start1, ByRef end1, ByRef start2, ByRef end2, hardware_encoder:="") {
   if (A_OSVersion = "WIN_7") or !InStr(hardware_encoder, "NVIDIA") or ((x1 != "") and (CaptureCoordinatesWithCPU = true))
      min1 := min2 := 33
   else
      min1 := 33, min2 := 17
   max1 := A_ScreenWidth, max2 := A_ScreenHeight
   Loop 2 {
      if (end%A_Index% - start%A_Index% < min%A_Index%)
         end%A_Index% := start%A_Index% + min%A_Index%
      if ((A_OSVersion = "WIN_7") or !InStr(hardware_encoder, "NVIDIA") or ((x1 != "") and (CaptureCoordinatesWithCPU = true))) and (mod(end%A_Index% - start%A_Index%, 2) != 0)
         end%A_Index%++
      if (end%A_Index% > max%A_Index%)
         start%A_Index% += max%A_Index%-end%A_Index%
         , end%A_Index% := max%A_Index%
   }
}



IMFSourceReaderCallback_new() {
   static VTBL := [ "QueryInterface", "AddRef", "Release", "OnReadSample" A_PtrSize, "OnFlush", "OnEvent" ]
        heapSize := A_PtrSize*10
        , heapOffset := A_PtrSize*9

        , flags := (HEAP_GENERATE_EXCEPTIONS := 0x4) | (HEAP_NO_SERIALIZE := 0x1)
        , HEAP_ZERO_MEMORY := 0x8

   , hHeap := DllCall("HeapCreate", "UInt", flags, "Ptr", 0, "Ptr", 0, "Ptr")
   , addr := IMFSourceReaderCallback := DllCall("HeapAlloc", "Ptr", hHeap, "UInt", HEAP_ZERO_MEMORY, "Ptr", heapSize, "Ptr")
   , addr := NumPut(addr + A_PtrSize, addr + 0)
   for k, v in VTBL
      addr := NumPut( RegisterSyncCallback("IMFSourceReaderCallback_" . v), addr + 0 )
   NumPut(hHeap, IMFSourceReaderCallback + heapOffset)
   Return IMFSourceReaderCallback
}

IMFSourceReaderCallback_QueryInterface(this, riid, ppvObject) {
   static IID_IUnknown, IID_IMFSourceReaderCallback
   if (!VarSetCapacity(IID_IUnknown))
      VarSetCapacity(IID_IUnknown, 16), VarSetCapacity(IID_IMFSourceReaderCallback, 16)
      , DllCall("ole32\CLSIDFromString", "WStr", "{00000000-0000-0000-C000-000000000046}", "Ptr", &IID_IUnknown)
      , DllCall("ole32\CLSIDFromString", "WStr", "{deec8d99-fa1d-4d82-84c2-2c8969944867}", "Ptr", &IID_IMFSourceReaderCallback)

   if (DllCall("ole32\IsEqualGUID", "Ptr", riid, "Ptr", &IID_IMFSourceReaderCallback) || DllCall("ole32\IsEqualGUID", "Ptr", riid, "Ptr", &IID_IUnknown)) {
      NumPut(this, ppvObject+0, "Ptr")
      IMFSourceReaderCallback_AddRef(this)
      return 0 ; S_OK
   }
   NumPut(0, ppvObject+0, "Ptr")
   return 0x80004002 ; E_NOINTERFACE
}

IMFSourceReaderCallback_AddRef(this) {
   static refOffset := A_PtrSize*8
   NumPut(refCount := NumGet(this + refOffset, "UInt") + 1, this + refOffset, "UInt")
   Return refCount
}

IMFSourceReaderCallback_Release(this) {
   static refOffset := A_PtrSize*8
        , heapOffset := A_PtrSize*9
   NumPut(refCount := NumGet(this + refOffset, "UInt") - 1, this + refOffset, "UInt")
   if (refCount = 0) {
      hHeap := NumGet(this + heapOffset)
      DllCall("HeapDestroy", "Ptr", hHeap)
   }
   Return refCount
}

/*
    RegisterSyncCallback

    A replacement for RegisterCallback for use with APIs that will call
    the callback on the wrong thread.  Synchronizes with the script's main
    thread via a window message.

    This version tries to emulate RegisterCallback as much as possible
    without using RegisterCallback, so shares most of its limitations,
    and some enhancements that could be made are not.

    Other differences from v1 RegisterCallback:
      - Variadic mode can't be emulated exactly, so is not supported.
      - A_EventInfo can't be set in v1, so is not supported.
      - Fast mode is not supported (the option is ignored).
      - ByRef parameters are allowed (but ByRef is ignored).
      - Throws instead of returning "" on failure.
*/
RegisterSyncCallback(FunctionName, Options:="", ParamCount:="") {
    if !(fn := Func(FunctionName)) || fn.IsBuiltIn
        throw Exception("Bad function", -1, FunctionName)
    if (ParamCount == "")
        ParamCount := fn.MinParams
    if (ParamCount > fn.MaxParams && !fn.IsVariadic || ParamCount+0 < fn.MinParams)
        throw Exception("Bad param count", -1, ParamCount)

    static sHwnd := 0, sMsg, sSendMessageW
    if !sHwnd {
        Gui RegisterSyncCallback: +Parent%A_ScriptHwnd% +hwndsHwnd
        OnMessage(sMsg := 0x8000, Func("RegisterSyncCallback_Msg"))
        , sSendMessageW := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "user32.dll", "ptr"), "astr", "SendMessageW", "ptr")
    }

    if !(pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr"))
        throw
    DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0)

    p := pcb
    if (A_PtrSize = 8) {
        /*
        48 89 4c 24 08  ; mov [rsp+8], rcx
        48 89 54'24 10  ; mov [rsp+16], rdx
        4c 89 44 24 18  ; mov [rsp+24], r8
        4c'89 4c 24 20  ; mov [rsp+32], r9
        48 83 ec 28'    ; sub rsp, 40
        4c 8d 44 24 30  ; lea r8, [rsp+48]  (arg 3, &params)
        49 b9 ..        ; mov r9, .. (arg 4, operand to follow)
        */
        p := NumPut(0x54894808244c8948, p+0)
        , p := NumPut(0x4c182444894c1024, p+0)
        , p := NumPut(0x28ec834820244c89, p+0)
        , p := NumPut(  0xb9493024448d4c, p+0) - 1
        , lParamPtr := p, p += 8

        , p := NumPut(0xba, p+0, "char") ; mov edx, nmsg
        , p := NumPut(sMsg, p+0, "int")
        , p := NumPut(0xb9, p+0, "char") ; mov ecx, hwnd
        , p := NumPut(sHwnd, p+0, "int")
        , p := NumPut(0xb848, p+0, "short") ; mov rax, SendMessageW
        , p := NumPut(sSendMessageW, p+0)
        /*
        ff d0        ; call rax
        48 83 c4 28  ; add rsp, 40
        c3           ; ret
        */
        , p := NumPut(0x00c328c48348d0ff, p+0)
    } else   ; (A_PtrSize = 4)
        p := NumPut(0x68, p+0, "char")      ; push ... (lParam data)
        , lParamPtr := p, p += 4
        , p := NumPut(0x0824448d, p+0, "int") ; lea eax, [esp+8]
        , p := NumPut(0x50, p+0, "char")      ; push eax
        , p := NumPut(0x68, p+0, "char")      ; push nmsg
        , p := NumPut(sMsg, p+0, "int")
        , p := NumPut(0x68, p+0, "char")      ; push hwnd
        , p := NumPut(sHwnd, p+0, "int")
        , p := NumPut(0xb8, p+0, "char")      ; mov eax, &SendMessageW
        , p := NumPut(sSendMessageW, p+0, "int")
        , p := NumPut(0xd0ff, p+0, "short")   ; call eax
        , p := NumPut(0xc2, p+0, "char")      ; ret argsize
        , p := NumPut((InStr(Options, "C") ? 0 : ParamCount*4), p+0, "short")

    NumPut(p, lParamPtr+0) ; To be passed as lParam.
    , p := NumPut(&fn, p+0)
    , p := NumPut(ParamCount, p+0, "int")
    return pcb
}

RegisterSyncCallback_Msg(wParam, lParam) {
    if (A_Gui != "RegisterSyncCallback")
        return
    fn := Object(NumGet(lParam + 0))
    , paramCount := NumGet(lParam + A_PtrSize, "int")
    , params := []
    Loop % paramCount
        params.Push(NumGet(wParam + A_PtrSize * (A_Index-1)))
    return %fn%(params*)
}

IMFSourceReaderCallback_OnReadSample4(this_, hrStatus, dwStreamIndex, dwStreamFlags, llTimestamp, llTimestamp1, pSample) {
   Static audioStart, gapAudio
   critical
   if hrStatus
      _Error(A_ThisFunc " error: " hrStatus "`nErrorLevel: " ErrorLevel)
   llTimestamp |= (llTimestamp1 << 32)
   if (pSample != 0) {
      if (gapAudio = 1)
         IMFAttributes_SetUINT32(pSample, MF_GUID(GUID, "MFSampleExtension_Discontinuity"), true)
         , gapAudio := ""

      if (audioStart = "")
         audioStart := llTimestamp
      IMFSample_SetSampleTime(pSample, llTimestamp - audioStart)
      if (IMFTransform = 1) {
         IMFSample_GetSampleDuration(pSample, llSampleDuration)
         Loop
            if (IMFTransform_ProcessInput(pTransform, 0, pSample, 0) != "MF_E_INVALIDREQUEST")
               break

         MFCreateSample(pSample1)
         , VarSetCapacity(MFT_OUTPUT_DATA_BUFFER, 4*A_PtrSize, 0)
         , NumPut(pSample1, MFT_OUTPUT_DATA_BUFFER, A_PtrSize, "ptr")
         , MFCreateMemoryBuffer(cbOutBytes, pBuffer)
         , IMFSample_AddBuffer(pSample1, pBuffer)
         , IMFTransform_ProcessOutput(pTransform, 0, 1, &MFT_OUTPUT_DATA_BUFFER, processOutputStatus)
         , IMFSample_SetSampleTime(pSample1, llTimestamp - audioStart)
         , IMFSample_SetSampleDuration(pSample1, llSampleDuration)
         , IMFSinkWriter_WriteSample(pSinkWriter, audioStreamIndex, pSample1)
         , Release(pSample1)
         , Release(pBuffer)
         , pSample1 := pBuffer := ""
      } else
         IMFSinkWriter_WriteSample(pSinkWriter, audioStreamIndex, pSample)
   } else if (dwStreamFlags & MF_SOURCE_READERF_STREAMTICK := 256) and (audioStart != "")
      IMFSinkWriter_SendStreamTick(pSinkWriter, audioStreamIndex, llTimestamp - audioStart)
      , gapAudio := 1

   if (flush = "")
      IMFSourceReader_ReadSample(SourceReader, MF_SOURCE_READER_ANY_STREAM := 0xFFFFFFFE, 0, 0, 0, 0, 0)
   else
      Release(IMFSourceReaderCallback)
      , Release(SourceReader)
      , SourceReader := IMFSourceReaderCallback := flush := audioStart := gapAudio := ""

   return
}

IMFSourceReaderCallback_OnReadSample8(this_, hrStatus, dwStreamIndex, dwStreamFlags, llTimestamp, pSample) {
   Static audioStart, gapAudio 
   critical
   if hrStatus
      _Error(A_ThisFunc " error: " hrStatus "`nErrorLevel: " ErrorLevel)
   if (pSample != 0) {
      if (gapAudio = 1)
         IMFAttributes_SetUINT32(pSample, MF_GUID(GUID, "MFSampleExtension_Discontinuity"), true)
         , gapAudio := ""

      if (audioStart = "")
         audioStart := llTimestamp
      IMFSample_SetSampleTime(pSample, llTimestamp - audioStart)
      if (IMFTransform = 1) {
         IMFSample_GetSampleDuration(pSample, llSampleDuration)
         Loop
            if (IMFTransform_ProcessInput(pTransform, 0, pSample, 0) != "MF_E_INVALIDREQUEST")
               break

         MFCreateSample(pSample1)
         , VarSetCapacity(MFT_OUTPUT_DATA_BUFFER, 4*A_PtrSize, 0)
         , NumPut(pSample1, MFT_OUTPUT_DATA_BUFFER, A_PtrSize, "ptr")
         , MFCreateMemoryBuffer(cbOutBytes, pBuffer)
         , IMFSample_AddBuffer(pSample1, pBuffer)
         , IMFTransform_ProcessOutput(pTransform, 0, 1, &MFT_OUTPUT_DATA_BUFFER, processOutputStatus)
         , IMFSample_SetSampleTime(pSample1, llTimestamp - audioStart)
         , IMFSample_SetSampleDuration(pSample1, llSampleDuration)
         , IMFSinkWriter_WriteSample(pSinkWriter, audioStreamIndex, pSample1)
         , Release(pSample1)
         , Release(pBuffer)
         , pSample1 := pBuffer := ""
      } else
         IMFSinkWriter_WriteSample(pSinkWriter, audioStreamIndex, pSample)
   } else if (dwStreamFlags & MF_SOURCE_READERF_STREAMTICK := 256) and (audioStart != "")
      IMFSinkWriter_SendStreamTick(pSinkWriter, audioStreamIndex, llTimestamp - audioStart)
      , gapAudio := 1

   if (flush = "")
      IMFSourceReader_ReadSample(SourceReader, MF_SOURCE_READER_ANY_STREAM := 0xFFFFFFFE, 0, 0, 0, 0, 0)
   else
      Release(IMFSourceReaderCallback)
      , Release(SourceReader)
      , SourceReader := IMFSourceReaderCallback := flush := audioStart := gapAudio := ""

   return
}

IMFSourceReaderCallback_OnFlush(this_, dwStreamIndex) {
   return
}

IMFSourceReaderCallback_OnEvent(this_) {
   return
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。