为了方便演示,顺带研究了一下截获窗口标题的FPS值,搞了一些基于RGD和RGSS300/301.dll的内核修改,大概过些日子也会发布【当然这个是后话了
[Ruby] 纯文本查看 复制代码
#encoding: utf-8
#
# ■ [SIN]Video Hacker
# Extension Plugin for SINVideo
#
# SINVideo(视频功能增强)拓展插件
#
# [更新记录]
# - 2022.07.27 By 岚风 雷(gqxastg)
# * 初版
#
# [使用方法]
# - 首先请确保安装了SINVideo脚本(原版或RGD兼容版皆可),并将此脚本置于其下
#
# - SIN::PLAYER.convert_time(1, :SECOND, :MEDIA) #=>
# 转换播放时间单位(:SECOND为秒,:MEDIA为默认单位)
#
# - SIN::PLAYER.getDuration #=> 获取视频的完整长度(不受结束位置影响)
# - SIN::PLAYER.getCurrentPosition #=> 获取播放的当前位置
# - SIN::PLAYER.getStopPosition #=> 获取播放的结束位置
# - SIN::PLAYER.getPositions #=> 获取播放的当前位置和结束位置
# - SIN::PLAYER.setPositions(0) #=> 设置播放的当前位置和结束位置
# 可使用 :AbsolutePositioning 和 :NoPositioning 标志来分别指定是否要设置
# 如:(0, :NoPositioning, 100, :AbsolutePositioning) 则只设置结束位置
#
# - SIN::PLAYER.getCurFile #=> 获取当前播放视频的文件名
# - SIN::PLAYER.getState #=> 获取当前播放状态(0结束、1暂停、2播放)
# - SIN::PLAYER.pausing? #=> 获取视频是否暂停中
# - SIN::PLAYER.pause #=> 暂停播放
# - SIN::PLAYER.run #=> 继续播放(暂停时)
# - SIN::PLAYER.getRate #=> 获取播放倍速(正常速度为1.0)
# - SIN::PLAYER.setRate(2.0) #=> 设置播放倍速
#
# - SIN::PLAYER.get_Balance #=> 获取播放声道平衡(-100~100)
# - SIN::PLAYER.put_Balance(-5.0) #=> 设置播放声道平衡
# - SIN::PLAYER.get_Volume #=> 获取播放音量(0~100)
# - SIN::PLAYER.put_Volume(50.0) #=> 设置播放音量
#
# - SIN::PLAYER.playing? 判断播放中包括暂停状态
# - SIN::PLAYER.getPositions 等方法涉及时间的数值请用convert_time进行转换
#
# - 其余使用方法请参考下面的代码以及范例工程中的 SINVideoDemo
#
#
module SIN
raise '未检测到SINVideo,请将此脚本置于其下' unless defined?(SIN::Video)
# 兼容XP/VX
class ::String
def bytesize; size; end unless method_defined?(:bytesize)
def start_with?(*args)
args.any? {|s| self[0, s.size] == s.to_s }
end unless method_defined?(:start_with?)
end
class ::Symbol
def upcase; self.to_s.upcase.to_sym; end unless method_defined?(:upcase)
def to_proc; proc {|a| a.send(self) }; end unless method_defined?(:to_proc)
end
class ::Array
alias videohacker_flatten flatten unless ([].flatten(0) rescue false)
def flatten(level = nil)
return self.videohacker_flatten if !level || (level < 0)
return self if level == 0
from, to = nil, self
level.times do
from, to = to, []
from.each {|a| a.is_a?(Array) ? to.push(*a) : to.push(a) }
end
to
end if method_defined?(:videohacker_flatten)
end
#----------------------------------------------------------------------------
module VideoHacker
MultiByteToWideChar =
Win32API.new('kernel32', 'MultiByteToWideChar', 'iipipi', 'i')
WideCharToMultiByte =
Win32API.new('kernel32', 'WideCharToMultiByte', 'iipipipp', 'i')
#--------------------------------------------------------------------------
def self.u2w(str)
buf = "\0" * 2 *
MultiByteToWideChar.call(65001, 0, str, -1, nil, 0)
MultiByteToWideChar.call(65001, 0, str, -1, buf, buf.bytesize / 2)
buf
end
#--------------------------------------------------------------------------
def self.w2u(str, zero = true)
buf = "\0" *
WideCharToMultiByte.call(65001, 0, str, -1, nil, 0, nil, nil)
WideCharToMultiByte.call(65001, 0, str, -1, buf, buf.bytesize, nil, nil)
buf.sub!(/\0+$/, '') if zero
buf
end
#--------------------------------------------------------------------------
RtlMoveMemory_pl = Win32API.new('kernel32', 'RtlMoveMemory', 'pll', 'l')
RtlMoveMemory_lp = Win32API.new('kernel32', 'RtlMoveMemory', 'lpl', 'l')
RtlMoveMemory_ll = Win32API.new('kernel32', 'RtlMoveMemory', 'lll', 'l')
#RtlMoveMemory_pp = Win32API.new('kernel32', 'RtlMoveMemory', 'ppl', 'l')
GetModuleHandle = Win32API.new('kernel32', 'GetModuleHandle', 'p', 'l')
CallWindowProc_lplll =
Win32API.new('user32', 'CallWindowProc', 'lpLLL', 'i')
CallWindowProc_lllll =
Win32API.new('user32', 'CallWindowProc', 'llLLL', 'i')
CallWindowProc_lpppp =
Win32API.new('user32', 'CallWindowProc', 'lpppp', 'i')
#CallWindowProc_lplpl =
#Win32API.new('user32', 'CallWindowProc', 'lpLpL', 'i')
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
MEM_RELEASE = 0x00008000
PAGE_EXECUTE_READWRITE = 0x40
VirtualAlloc = Win32API.new('kernel32', 'VirtualAlloc', 'llll', 'l')
VirtualFree = Win32API.new('kernel32', 'VirtualFree', 'lll', 'l')
#VirtualProtect = Win32API.new('kernel32', 'VirtualProtect', 'llll', 'l')
#--------------------------------------------------------------------------
S_OK = 0x00000000
S_FALSE = 0x00000001
E_INVALIDARG = 0x80070057
E_OUTOFMEMORY = 0x8007000E
E_UNEXPECTED = 0x8000FFFF
E_NOTIMPL = 0x80004001
E_FAIL = 0x80004005
E_POINTER = 0x80004003
E_HANDLE = 0x80070006
E_ABORT = 0x80004004
E_ACCESSDENIED = 0x80070005
E_NOINTERFACE = 0x80004002
VFW_S_STATE_INTERMEDIATE = 0x00040237
VFW_S_CANT_CUE = 0x00040268
VFW_E_NOT_CONNECTED = 0x80040209
VFW_E_WRONG_STATE = 0x80040227
VFW_E_UNSUPPORTED_AUDIO = 0x8004025C
VFW_E_UNSUPPORTED_VIDEO = 0x8004025D
ReturnValueList = constants.select {|sym|
sym.to_s.start_with?('S_', 'E_', 'VFW_S_', 'VFW_E_') }.collect(&:to_sym)
AM_SEEKING_NoPositioning = 0x00
AM_SEEKING_AbsolutePositioning = 0x01
AM_SEEKING_RelativePositioning = 0x02
AM_SEEKING_IncrementalPositioning = 0x03
AM_SEEKING_PositioningBitsMask = 0x03
AM_SEEKING_SeekToKeyFrame = 0x04
AM_SEEKING_ReturnTime = 0x08
AM_SEEKING_Segment = 0x10
AM_SEEKING_NoFlush = 0x20
ALL_TIME_FORMAT = %w{TIME_FORMAT_NONE TIME_FORMAT_FRAME TIME_FORMAT_SAMPLE
TIME_FORMAT_FIELD TIME_FORMAT_BYTE TIME_FORMAT_MEDIA_TIME}.collect(&:to_sym)
ConvertTimeList = %w{SECOND FRAME MEDIA}.collect(&:to_sym)
TIME_FORMAT_NONE = "\0" * 16
TIME_FORMAT_FRAME = [0x7b785570, 0x8c82, 0x11cf,
0xbc, 0x0c, 0x00, 0xaa, 0x00, 0xac, 0x74, 0xf6].pack('LSSC8')
TIME_FORMAT_SAMPLE = [0x7b785572, 0x8c82, 0x11cf,
0xbc, 0x0c, 0x00, 0xaa, 0x00, 0xac, 0x74, 0xf6].pack('LSSC8')
TIME_FORMAT_FIELD = [0x7b785573, 0x8c82, 0x11cf,
0xbc, 0x0c, 0x00, 0xaa, 0x00, 0xac, 0x74, 0xf6].pack('LSSC8')
TIME_FORMAT_BYTE = [0x7b785571, 0x8c82, 0x11cf,
0xbc, 0x0c, 0x00, 0xaa, 0x00, 0xac, 0x74, 0xf6].pack('LSSC8')
TIME_FORMAT_MEDIA_TIME = [0x7b785574, 0x8c82, 0x11cf,
0xbc, 0x0c, 0x00, 0xaa, 0x00, 0xac, 0x74, 0xf6].pack('LSSC8')
#--------------------------------------------------------------------------
DSHOWprocList = {
:m_pBasicAudio => [
[:put_Volume, 0x1C, 'put_Volume'],
[:get_Volume, 0x20, 'get_Volume'],
[:put_Balance, 0x24, 'put_Balance'],
[:get_Balance, 0x28, 'get_Balance'],
],
:m_pSampleGrabber => [
[:GetCurrentBuffer, 0x1C, 'getCurrentBuffer'],
],
:m_pMediaSeeking => [
[:SetTimeFormat, 0x18, 'setTimeFormat'],
[:GetTimeFormat, 0x1C, 'getTimeFormat'],
[:IsUsingTimeFormat, 0x20, 'isUsingTimeFormat'],
[:IsFormatSupported, 0x24, 'isFormatSupported'],
[:GetDuration, 0x28, 'getDuration'],
[:GetStopPosition, 0x2C, 'getStopPosition'],
[:GetCurrentPosition, 0x30, 'getCurrentPosition'],
[:ConvertTimeFormat, 0x34, 'convertTimeFormat'],
[:SetPositions, 0x38, 'setPositions'],
[:GetPositions, 0x3C, 'getPositions'],
[:GetAvailable, 0x40, 'getAvailable'],
[:SetRate, 0x44, 'setRate'],
[:GetRate, 0x48, 'getRate'],
],
:m_pMediaControl => [
[:Run, 0x1C, 'run'],
[:Pause, 0x20, 'pause'],
[:Stop, 0x24, nil],
[:GetState, 0x28, 'getState'],
],
:m_pMediaEvent => [
],
:pFileSourceFilter => [
[:Load, 0x0C, nil],
[:GetCurFile, 0x10, 'getCurFile'],
],
}
#--------------------------------------------------------------------------
arr = DSHOWprocList.values.flatten(1)
ProcSym = arr.collect {|a| a[0] }
MethodSym = arr.collect {|a| a[2] }.compact
DLLmodule = GetModuleHandle.call(File.basename(::SIN::Video::DLLPATH))
DLLproc = {}
DSHOWproc = {}
ProcSym.each {|key| DSHOWproc[key] = 0 }
#DSHOWproc_p = DSHOWproc.clone
#DSHOWproc_p.each {|key, value| DSHOWproc_p[key] = [value].pack('L') }
#--------------------------------------------------------------------------
if const_defined?(:MACHproc) && (ptr = MACHproc.values[0]) && ptr != 0
VirtualFree.call(ptr, 0, MEM_RELEASE)
end
MACHcode = {
:BASE =>
[0x8B, 0x44, 0x24, 0x04, 0x8B, 0x4C, 0x24, 0x08, 0xFF, 0x34, 0x88, 0xE2,
0xFB, 0xFF, 0x10, 0xC3].pack('C*'),
:GetCurrentBuffer =>
[0x8B, 0x44, 0x24, 0x04, 0x8B, 0x4C, 0x24, 0x08, 0xB2, 0xFF, 0x83, 0xC0,
0x03, 0x88, 0x10, 0x83, 0xC0, 0x04, 0xE2, 0xF9, 0xC2, 0x10, 0x00].
pack('C*'),
}
#~ [0x8B, 0x44, 0x24, 0x04, 0xFF, 0x70, 0x14, 0xFF, 0x70, 0x10, 0xFF, 0x70,
#~ 0x0C, 0xFF, 0x70, 0x08, 0xFF, 0x70, 0x04, 0xFF, 0x10, 0xC3].pack('C*'),
#~ [0x89, 0xE0, 0xFF, 0x70, 0x10, 0xFF, 0x70, 0x0C, 0xFF, 0x70, 0x08, 0xFF,
#~ 0x70, 0x04, 0x68].pack('C*') +
#~ [DLLproc[1]].pack('L') +
#~ [0xFF, 0x15].pack('C*') +
#~ [DSHOWproc_p[:SetPositions]].pack('p') +
#~ [0xC3].pack('C*')
MACHproc = {}
hash = MACHcode#.clone
#hash.each {|key, value| hash[key] = value.call }
all = hash.values.join
ptr = VirtualAlloc.call(0, all.bytesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
raise '无法申请内存' if ptr == 0
RtlMoveMemory_lp.call(ptr, all, all.bytesize)
hash.each do |key, value|
MACHproc[key] = ptr
ptr += value.bytesize
end
#--------------------------------------------------------------------------
buf = "\0" * 4
RtlMoveMemory_pl.call(buf, DLLmodule + 0xD8AC, 4)
DLLproc[:BASE] = buf.unpack('L').first
#--------------------------------------------------------------------------
def self.recalc_DSHOWproc#(resetMACH = true)
buf = "\0" * 4
# mov esi,[SINVideo.dll+D8AC]
# m_pBasicAudio
# mov eax,[esi+14]
RtlMoveMemory_pl.call(buf, DLLproc[:BASE] + 0x14, 4)
DLLproc[:m_pBasicAudio] = buf.unpack('L').first
# m_pSampleGrabber
# mov eax,[esi+10]
RtlMoveMemory_pl.call(buf, DLLproc[:BASE] + 0x10, 4)
DLLproc[:m_pSampleGrabber] = buf.unpack('L').first
# m_pMediaSeeking->SetPositions
# mov eax,[esi+0C]
RtlMoveMemory_pl.call(buf, DLLproc[:BASE] + 0x0C, 4)
DLLproc[:m_pMediaSeeking] = buf.unpack('L').first
# m_pMediaControl->Stop
# mov eax,[esi+04]
RtlMoveMemory_pl.call(buf, DLLproc[:BASE] + 0x04, 4)
DLLproc[:m_pMediaControl] = buf.unpack('L').first
# m_pMediaEvent
# mov eax,[esi+08]
RtlMoveMemory_pl.call(buf, DLLproc[:BASE] + 0x08, 4)
DLLproc[:m_pMediaEvent] = buf.unpack('L').first
# m_pGraphBuilder
# mov eax,[esi]
RtlMoveMemory_pl.call(buf, DLLproc[:BASE], 4)
DLLproc[:m_pGraphBuilder] = buf.unpack('L').first
# pFileSourceFilter
# [[[[[SINVideo.dll+D8AC]]+BC]+8]]+44
adr = DLLproc[:BASE]
[0, 0xBC, 8, 0].each do |off|
buf = "\0" * 4
RtlMoveMemory_pl.call(buf, adr + off, 4)
adr = buf.unpack('L').first
break if adr == 0
end
adr += 0x44 unless adr == 0
DLLproc[:pFileSourceFilter] = adr
#------------------------------------------------------------------------
DSHOWprocList.each do |key, value|
value.each do |arr|
sym, off = arr
# mov eax,[SINVideo.dll+D8AC]
# mov eax,[eax+**]
adr = DLLproc[key]
break value.each {|a| DSHOWproc[a[0]] = 0 } if adr == 0
buf = "\0" * 4
# mov eax,[eax]
RtlMoveMemory_pl.call(buf, adr, 4)
adr = buf.unpack('L').first
next DSHOWproc[sym] = 0 if adr == 0
# mov eax,[eax+**]
RtlMoveMemory_pl.call(buf, adr + off, 4)
DSHOWproc[sym] = buf.unpack('L').first
end
end
#DSHOWproc_p.each {|key, value|
#RtlMoveMemory_pp.call(value, [DSHOWproc[key]].pack('L'), 4) }
#reset_MACHcode if resetMACH
end
#--------------------------------------------------------------------------
def self.clear_DSHOWproc
DSHOWproc.each_key {|key| DSHOWproc[key] = 0 }
end
#--------------------------------------------------------------------------
#~ def self.reset_MACHcode
#~ return if MACHproc.values[0] == 0
#~ all = MACHcode.values.collect(&:call).join
#~ RtlMoveMemory_lp.call(MACHproc.values[0], all, all.bytesize)
#~ end
#--------------------------------------------------------------------------
def self.convert_ret(ret)
ret = ret + 0x100000000 if ret < 0
sym = ReturnValueList.find {|s| const_get(s) == ret }
sym ? sym : ret
end
#--------------------------------------------------------------------------
def self.convert_time(time, from = :SECOND, to = :MEDIA)
2.times do |i|
format = (i == 0) ? from : to
format = (format.is_a?(Symbol) || format.is_a?(String)) ?
format.to_sym.upcase : ConvertTimeList[format.to_i]
(i == 0) ? from = format : to = format
end
case from
when :SECOND
when :FRAME then time = time / Graphics.frame_rate.to_f
when :MEDIA then time = time / 10000000.0
end
case to
when :SECOND
when :FRAME then time = (time * Graphics.frame_rate).to_i
when :MEDIA then time = (time * 10000000).to_i
end
time
end
#--------------------------------------------------------------------------
# m_pBasicAudio
#--------------------------------------------------------------------------
def self.put_Volume(lVolume = 100)
key, sym = :m_pBasicAudio, :put_Volume
return false if DSHOWproc[sym] == 0
lVolume = (lVolume * 100 - 10000).to_i
params = [DSHOWproc[sym], DLLproc[key], lVolume].pack('LLl')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
convert_ret(ret)
end
#--------------------------------------------------------------------------
def self.get_Volume
key, sym = :m_pBasicAudio, :get_Volume
return false if DSHOWproc[sym] == 0
plVolume = "\0" * 4 #[0].pack('L')
params = [DSHOWproc[sym], DLLproc[key], plVolume].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
(plVolume.unpack('l').first + 10000) / 100.0
end
#--------------------------------------------------------------------------
def self.put_Balance(lBalance = 0)
key, sym = :m_pBasicAudio, :put_Balance
return false if DSHOWproc[sym] == 0
lBalance = (lBalance * 100).to_i
params = [DSHOWproc[sym], DLLproc[key], lBalance].pack('LLl')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
convert_ret(ret)
end
#--------------------------------------------------------------------------
def self.get_Balance
key, sym = :m_pBasicAudio, :get_Balance
return false if DSHOWproc[sym] == 0
plBalance = "\0" * 4 #[0].pack('L')
params = [DSHOWproc[sym], DLLproc[key], plBalance].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
plBalance.unpack('l').first / 100.0
end
#--------------------------------------------------------------------------
# m_pSampleGrabber
#--------------------------------------------------------------------------
def self.getCurrentBuffer(dst = nil)
key, sym = :m_pSampleGrabber, :GetCurrentBuffer
return false if DSHOWproc[sym] == 0
pBufferSize = "\0" * 4 #[0].pack('L')
pBuffer = nil
params = [DSHOWproc[sym], DLLproc[key], pBufferSize, pBuffer].pack('LLpp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
size = pBufferSize.unpack('L').first
return false if size == 0
if dst.is_a?(Integer)
pBuffer = true
params = [DSHOWproc[sym], DLLproc[key], pBufferSize, dst].pack('LLpL')
else
pBuffer = dst ? dst : ("\0" * size)
params =
[DSHOWproc[sym], DLLproc[key], pBufferSize, pBuffer].pack('LLpp')
end
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
return false if ret != 0
pBuffer
end
#--------------------------------------------------------------------------
# m_pMediaSeeking
#--------------------------------------------------------------------------
def self.setTimeFormat(pFormat = :TIME_FORMAT_MEDIA_TIME)
key, sym = :m_pMediaSeeking, :SetTimeFormat
return false if DSHOWproc[sym] == 0
pFormat = const_get(pFormat)
params = [DSHOWproc[sym], DLLproc[key], pFormat].pack('LLp')
CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
end
#--------------------------------------------------------------------------
def self.getTimeFormat
key, sym = :m_pMediaSeeking, :GetTimeFormat
return false if DSHOWproc[sym] == 0
pFormat = "\0" * 16
params = [DSHOWproc[sym], DLLproc[key], pFormat].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
ALL_TIME_FORMAT.find {|key| const_get(key) == pFormat }
end
#--------------------------------------------------------------------------
def self.isUsingTimeFormat(pFormat)
key, sym = :m_pMediaSeeking, :IsUsingTimeFormat
return false if DSHOWproc[sym] == 0
pFormat = const_get(pFormat)
params = [DSHOWproc[sym], DLLproc[key], pFormat].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
ret == 0
end
#--------------------------------------------------------------------------
def self.isFormatSupported(pFormat)
key, sym = :m_pMediaSeeking, :IsFormatSupported
return false if DSHOWproc[sym] == 0
pFormat = const_get(pFormat)
params = [DSHOWproc[sym], DLLproc[key], pFormat].pack('LLp')
CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
end
#--------------------------------------------------------------------------
def self.getDuration
key, sym = :m_pMediaSeeking, :GetDuration
return false if DSHOWproc[sym] == 0
pDuration = "\0" * 8 #[0].pack('q')
params = [DSHOWproc[sym], DLLproc[key], pDuration].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
pDuration.unpack('q').first
end
#--------------------------------------------------------------------------
def self.getStopPosition
key, sym = :m_pMediaSeeking, :GetStopPosition
return false if DSHOWproc[sym] == 0
pStop = "\0" * 8 #[0].pack('q')
params = [DSHOWproc[sym], DLLproc[key], pStop].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
pStop.unpack('q').first
end
#--------------------------------------------------------------------------
def self.getCurrentPosition
key, sym = :m_pMediaSeeking, :GetCurrentPosition
return false if DSHOWproc[sym] == 0
pCurrent = "\0" * 8 #[0].pack('q')
params = [DSHOWproc[sym], DLLproc[key], pCurrent].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
pCurrent.unpack('q').first
end
#--------------------------------------------------------------------------
def self.convertTimeFormat(pTargetFormat, source, pSourceFormat = nil)
key, sym = :m_pMediaSeeking, :ConvertTimeFormat
return false if DSHOWproc[sym] == 0
pTarget = "\0" * 8 #[0].pack('q')
pTargetFormat = const_get(pTargetFormat) if pTargetFormat
pSourceFormat = const_get(pSourceFormat) if pSourceFormat
params = [DSHOWproc[sym], DLLproc[key],
pTarget, pTargetFormat, source, pSourceFormat].pack('LLppqp')
# 因为传的是longlong(8字节)所以多占一个参数
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 6, 0, 0)
pTarget.unpack('q').first
end
#--------------------------------------------------------------------------
def self.setPositions(pCurrent = 0, dwCurrentFlags = 1, pStop = 0,
dwStopFlags = 0)
key, sym = :m_pMediaSeeking, :SetPositions
return false if DSHOWproc[sym] == 0
pCurrent = [pCurrent].pack('q')
pStop = [pStop].pack('q')
2.times do |i|
flags = (i == 0) ? dwCurrentFlags : dwStopFlags
flags = flags.is_a?(Array) ?
flags.inject(0) {|r, m| r | const_get("AM_SEEKING_#{m}") } :
(flags.is_a?(Symbol) || flags.is_a?(String)) ?
const_get("AM_SEEKING_#{flags}") : flags.to_i
(i == 0) ? dwCurrentFlags = flags : dwStopFlags = flags
end
params = [DSHOWproc[sym], DLLproc[key],
pCurrent, dwCurrentFlags, pStop, dwStopFlags].pack('LLpLpL')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 5, 0, 0)
#CallWindowProc_lplpl.call(MACHproc[:SetPositions],
#pCurrent, dwCurrentFlags, pStop, dwStopFlags)
ret = convert_ret(ret)
ret = [ret, pCurrent.unpack('q').first, pStop.unpack('q').first] if
(dwCurrentFlags & AM_SEEKING_ReturnTime != 0) ||
(dwStopFlags & AM_SEEKING_ReturnTime != 0)
ret
end
#--------------------------------------------------------------------------
def self.getPositions
key, sym = :m_pMediaSeeking, :GetPositions
return false if DSHOWproc[sym] == 0
pCurrent = "\0" * 8 #[0].pack('q')
pStop = "\0" * 8 #[0].pack('q')
params = [DSHOWproc[sym], DLLproc[key], pCurrent, pStop].pack('LLpp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
[pCurrent.unpack('q').first, pStop.unpack('q').first]
end
#--------------------------------------------------------------------------
def self.getAvailable
key, sym = :m_pMediaSeeking, :GetAvailable
return false if DSHOWproc[sym] == 0
pEarliest = "\0" * 8 #[0].pack('q')
pLatest = "\0" * 8 #[0].pack('q')
params = [DSHOWproc[sym], DLLproc[key], pEarliest, pLatest].pack('LLpp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
[pEarliest.unpack('q').first, pLatest.unpack('q').first]
end
#--------------------------------------------------------------------------
def self.setRate(dRate = 1)
key, sym = :m_pMediaSeeking, :SetRate
return false if DSHOWproc[sym] == 0
params = [DSHOWproc[sym], DLLproc[key], dRate].pack('LLD')
# 因为传的是double(8字节)所以多占一个参数
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
convert_ret(ret)
end
#--------------------------------------------------------------------------
def self.getRate
key, sym = :m_pMediaSeeking, :GetRate
return false if DSHOWproc[sym] == 0
pdRate = "\0" * 8 #[0].pack('D')
params = [DSHOWproc[sym], DLLproc[key], pdRate].pack('LLp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 2, 0, 0)
pdRate.unpack('D').first
end
#--------------------------------------------------------------------------
# m_pMediaControl
#--------------------------------------------------------------------------
def self.run
key, sym = :m_pMediaControl, :Run
return false if DSHOWproc[sym] == 0
params = [DSHOWproc[sym], DLLproc[key]].pack('LL')
CallWindowProc_lplll.call(MACHproc[:BASE], params, 1, 0, 0)
end
#--------------------------------------------------------------------------
def self.pause
key, sym = :m_pMediaControl, :Pause
return false if DSHOWproc[sym] == 0
params = [DSHOWproc[sym], DLLproc[key]].pack('LL')
CallWindowProc_lplll.call(MACHproc[:BASE], params, 1, 0, 0)
end
#--------------------------------------------------------------------------
def self.getState(msTimeout = 0)
key, sym = :m_pMediaControl, :GetState
return false if DSHOWproc[sym] == 0
params = [DSHOWproc[sym], DLLproc[key],
msTimeout, state = "\0" * 4].pack('LLlp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
# State_Stopped = 0, State_Paused = 1, State_Running = 2
state.unpack('L').first
end
#--------------------------------------------------------------------------
# pFileSourceFilter
#--------------------------------------------------------------------------
def self.getCurFile
key, sym = :pFileSourceFilter, :GetCurFile
return false if DSHOWproc[sym] == 0
ppszFileName = "\0" * 4 #[0].pack('L')
pmt = nil #"\0" * (32 + 2 + 4 + 16 + 4 + 4 + 1)
params = [DSHOWproc[sym], DLLproc[key], ppszFileName, pmt].pack('LLpp')
ret = CallWindowProc_lplll.call(MACHproc[:BASE], params, 3, 0, 0)
adr = ppszFileName.unpack('L').first
if adr == 0
name = nil
else
name, buf = '', "\0" * 2
begin
RtlMoveMemory_pl.call(buf, adr, 2)
name << buf
adr += 2
end until buf == "\0\0"
name = w2u(name)
end
#[name, pmt.unpack('a16a16C2La16LLC')]
name
end
end
class Video < Sprite
class VideoUpdate_caller
CallWindowProc_lplll = ::SIN::VideoHacker::CallWindowProc_lplll
attr_accessor :mode, :default
#------------------------------------------------------------------------
def initialize(default)
@default, @mode = default, false
end
#------------------------------------------------------------------------
def call
return @default.call unless @mode
::SIN::PLAYER.instance_eval do
return 1 unless @bmpbuf
getCurrentBuffer(@bmpbuf)
return 1 unless @bmpbuf
CallWindowProc_lplll.call(
::SIN::VideoHacker::MACHproc[:GetCurrentBuffer],
@bmpbuf, width * height, 0, 0)
end
0
end
end
#~ VideoUpdate = VideoUpdate_caller.new(VideoUpdate) unless
#~ VideoUpdate.is_a?(VideoUpdate_caller)
#~ VideoUpdate.mode = true
#--------------------------------------------------------------------------
alias hackerold_play play
def play(*args)
return hackerold_play(*args) if disposed?
hackerold_play(*args)
::SIN::VideoHacker.recalc_DSHOWproc if @__playing
end
#--------------------------------------------------------------------------
alias hackerold_stop stop
def stop
hackerold_stop
::SIN::VideoHacker.clear_DSHOWproc if
::SIN::VideoHacker::DSHOWproc.values[0] != 0
end
#--------------------------------------------------------------------------
alias hackerold_playing? playing?
def playing?
return false unless @__playing
return true if getState == 1 # 避免暂停状态被误判
hackerold_playing?
end
#--------------------------------------------------------------------------
alias hackerold_replay_at_finish replay_at_finish
def replay_at_finish
return unless @__playing
return unless (s = getState) && s != 1 # 避免暂停状态被误判
hackerold_replay_at_finish
end
#--------------------------------------------------------------------------
def pausing?
return false unless @__playing
return true if getState == 1
false
end
#--------------------------------------------------------------------------
def convert_time(*args)
::SIN::VideoHacker.convert_time(*args)
end
#--------------------------------------------------------------------------
::SIN::VideoHacker::MethodSym.each do |name|
define_method(name) do |*args|
return unless @__playing
::SIN::VideoHacker.send(name, *args)
end
end
end
end
本帖来自P1论坛作者gqxastg,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg. blue/forum.php?mod=viewthread&tid=490464 若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。