pyglet 2.1.3__py3-none-any.whl → 2.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyglet/__init__.py +21 -9
- pyglet/__init__.pyi +3 -1
- pyglet/app/cocoa.py +6 -3
- pyglet/display/win32.py +14 -15
- pyglet/display/xlib_vidmoderestore.py +1 -1
- pyglet/extlibs/earcut.py +2 -2
- pyglet/font/__init__.py +3 -3
- pyglet/font/base.py +118 -51
- pyglet/font/dwrite/__init__.py +1381 -0
- pyglet/font/dwrite/d2d1_lib.py +637 -0
- pyglet/font/dwrite/d2d1_types_lib.py +60 -0
- pyglet/font/dwrite/dwrite_lib.py +1577 -0
- pyglet/font/fontconfig.py +79 -16
- pyglet/font/freetype.py +252 -77
- pyglet/font/freetype_lib.py +234 -125
- pyglet/font/harfbuzz/__init__.py +275 -0
- pyglet/font/harfbuzz/harfbuzz_lib.py +212 -0
- pyglet/font/quartz.py +432 -112
- pyglet/font/user.py +18 -11
- pyglet/font/win32.py +9 -1
- pyglet/gl/wgl.py +94 -87
- pyglet/gl/wglext_arb.py +472 -218
- pyglet/gl/wglext_nv.py +410 -188
- pyglet/gui/widgets.py +6 -1
- pyglet/image/codecs/bmp.py +3 -5
- pyglet/image/codecs/gdiplus.py +28 -9
- pyglet/image/codecs/wic.py +198 -489
- pyglet/image/codecs/wincodec_lib.py +413 -0
- pyglet/input/base.py +3 -2
- pyglet/input/macos/darwin_hid.py +28 -2
- pyglet/input/win32/directinput.py +2 -1
- pyglet/input/win32/xinput.py +10 -9
- pyglet/lib.py +14 -2
- pyglet/libs/darwin/cocoapy/cocoalibs.py +74 -3
- pyglet/libs/darwin/coreaudio.py +0 -2
- pyglet/libs/win32/__init__.py +4 -2
- pyglet/libs/win32/com.py +65 -12
- pyglet/libs/win32/constants.py +1 -0
- pyglet/libs/win32/dinput.py +1 -9
- pyglet/libs/win32/types.py +72 -8
- pyglet/media/codecs/coreaudio.py +1 -0
- pyglet/media/codecs/wmf.py +93 -72
- pyglet/media/devices/win32.py +5 -4
- pyglet/media/drivers/directsound/lib_dsound.py +4 -4
- pyglet/media/drivers/xaudio2/interface.py +21 -17
- pyglet/media/drivers/xaudio2/lib_xaudio2.py +42 -25
- pyglet/shapes.py +1 -1
- pyglet/text/document.py +7 -53
- pyglet/text/formats/attributed.py +3 -1
- pyglet/text/formats/plaintext.py +1 -1
- pyglet/text/formats/structured.py +1 -1
- pyglet/text/layout/base.py +76 -68
- pyglet/text/layout/incremental.py +38 -8
- pyglet/text/layout/scrolling.py +1 -1
- pyglet/text/runlist.py +2 -114
- pyglet/window/win32/__init__.py +1 -3
- {pyglet-2.1.3.dist-info → pyglet-2.1.4.dist-info}/METADATA +1 -1
- {pyglet-2.1.3.dist-info → pyglet-2.1.4.dist-info}/RECORD +60 -54
- pyglet/font/directwrite.py +0 -2798
- {pyglet-2.1.3.dist-info → pyglet-2.1.4.dist-info}/LICENSE +0 -0
- {pyglet-2.1.3.dist-info → pyglet-2.1.4.dist-info}/WHEEL +0 -0
pyglet/media/codecs/wmf.py
CHANGED
|
@@ -1,16 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import os
|
|
2
4
|
import platform
|
|
3
5
|
import warnings
|
|
6
|
+
from ctypes import (
|
|
7
|
+
HRESULT,
|
|
8
|
+
POINTER,
|
|
9
|
+
Structure,
|
|
10
|
+
byref,
|
|
11
|
+
c_int32,
|
|
12
|
+
c_longlong,
|
|
13
|
+
c_uint32,
|
|
14
|
+
c_uint64,
|
|
15
|
+
c_ulonglong,
|
|
16
|
+
c_void_p,
|
|
17
|
+
cast,
|
|
18
|
+
memmove,
|
|
19
|
+
string_at,
|
|
20
|
+
windll,
|
|
21
|
+
)
|
|
22
|
+
from ctypes.wintypes import BOOL, DWORD, LONG, LPCWSTR, UINT, ULONG, WORD
|
|
4
23
|
|
|
5
24
|
from pyglet import image
|
|
6
25
|
from pyglet.libs.win32 import _kernel32 as kernel32
|
|
7
26
|
from pyglet.libs.win32 import _ole32 as ole32
|
|
8
27
|
from pyglet.libs.win32 import com
|
|
9
|
-
from pyglet.libs.win32.constants import
|
|
10
|
-
|
|
28
|
+
from pyglet.libs.win32.constants import (
|
|
29
|
+
GMEM_MOVEABLE,
|
|
30
|
+
MF_ACCESSMODE_READWRITE,
|
|
31
|
+
MF_FILEFLAGS_NONE,
|
|
32
|
+
MF_OPENMODE_DELETE_IF_EXIST,
|
|
33
|
+
WINDOWS_7_OR_GREATER,
|
|
34
|
+
WINDOWS_10_ANNIVERSARY_UPDATE_OR_GREATER,
|
|
35
|
+
WINDOWS_VISTA_OR_GREATER,
|
|
36
|
+
)
|
|
37
|
+
from pyglet.libs.win32.types import BYTE, PROPVARIANT
|
|
11
38
|
from pyglet.media import Source
|
|
12
|
-
from pyglet.media.codecs import
|
|
13
|
-
from pyglet.util import
|
|
39
|
+
from pyglet.media.codecs import AudioData, AudioFormat, MediaDecoder, StaticSource, VideoFormat
|
|
40
|
+
from pyglet.util import DecodeException, debug_print
|
|
14
41
|
|
|
15
42
|
_debug = debug_print('debug_media')
|
|
16
43
|
|
|
@@ -21,13 +48,12 @@ try:
|
|
|
21
48
|
# System32 and SysWOW64 folders are opposite perception in Windows x64.
|
|
22
49
|
# System32 = x64 dll's | SysWOW64 = x86 dlls
|
|
23
50
|
# By default ctypes only seems to look in system32 regardless of Python architecture, which has x64 dlls.
|
|
24
|
-
if platform.architecture()[0] == '32bit':
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
mfplat = os.path.join(os.environ['WINDIR'], 'SysWOW64', 'mfplat.dll')
|
|
51
|
+
if platform.architecture()[0] == '32bit' and platform.machine().endswith('64'): # Machine is 64 bit, Python is 32 bit.
|
|
52
|
+
mfreadwrite = os.path.join(os.environ['WINDIR'], 'SysWOW64', 'mfreadwrite.dll')
|
|
53
|
+
mfplat = os.path.join(os.environ['WINDIR'], 'SysWOW64', 'mfplat.dll')
|
|
28
54
|
|
|
29
|
-
mfreadwrite_lib =
|
|
30
|
-
mfplat_lib =
|
|
55
|
+
mfreadwrite_lib = windll.LoadLibrary(mfreadwrite)
|
|
56
|
+
mfplat_lib = windll.LoadLibrary(mfplat)
|
|
31
57
|
except OSError:
|
|
32
58
|
# Doesn't exist? Should stop import of library.
|
|
33
59
|
raise ImportError('Could not load WMF library.')
|
|
@@ -204,7 +230,7 @@ class IMFMediaBuffer(com.pIUnknown):
|
|
|
204
230
|
('SetCurrentLength',
|
|
205
231
|
com.STDMETHOD(DWORD)),
|
|
206
232
|
('GetMaxLength',
|
|
207
|
-
com.STDMETHOD(POINTER(DWORD)))
|
|
233
|
+
com.STDMETHOD(POINTER(DWORD))),
|
|
208
234
|
]
|
|
209
235
|
|
|
210
236
|
|
|
@@ -316,7 +342,7 @@ class IMFSourceReader(com.pIUnknown):
|
|
|
316
342
|
]
|
|
317
343
|
|
|
318
344
|
|
|
319
|
-
class WAVEFORMATEX(
|
|
345
|
+
class WAVEFORMATEX(Structure):
|
|
320
346
|
_fields_ = [
|
|
321
347
|
('wFormatTag', WORD),
|
|
322
348
|
('nChannels', WORD),
|
|
@@ -328,11 +354,8 @@ class WAVEFORMATEX(ctypes.Structure):
|
|
|
328
354
|
]
|
|
329
355
|
|
|
330
356
|
def __repr__(self):
|
|
331
|
-
return 'WAVEFORMATEX(wFormatTag={}, nChannels={}, nSamplesPerSec={}, nAvgBytesPersec={}' \
|
|
332
|
-
', nBlockAlign={}, wBitsPerSample={}, cbSize={})'
|
|
333
|
-
self.wFormatTag, self.nChannels, self.nSamplesPerSec,
|
|
334
|
-
self.nAvgBytesPerSec, self.nBlockAlign, self.wBitsPerSample,
|
|
335
|
-
self.cbSize)
|
|
357
|
+
return f'WAVEFORMATEX(wFormatTag={self.wFormatTag}, nChannels={self.nChannels}, nSamplesPerSec={self.nSamplesPerSec}, nAvgBytesPersec={self.nAvgBytesPerSec}' \
|
|
358
|
+
f', nBlockAlign={self.nBlockAlign}, wBitsPerSample={self.wBitsPerSample}, cbSize={self.cbSize})'
|
|
336
359
|
|
|
337
360
|
|
|
338
361
|
# Stream constants
|
|
@@ -424,16 +447,16 @@ class WMFSource(Source):
|
|
|
424
447
|
# Stole code from GDIPlus for older IStream support.
|
|
425
448
|
hglob = kernel32.GlobalAlloc(GMEM_MOVEABLE, data_len)
|
|
426
449
|
ptr = kernel32.GlobalLock(hglob)
|
|
427
|
-
|
|
450
|
+
memmove(ptr, data, data_len)
|
|
428
451
|
kernel32.GlobalUnlock(hglob)
|
|
429
452
|
|
|
430
453
|
# Create IStream
|
|
431
454
|
self._stream_obj = com.pIUnknown()
|
|
432
|
-
ole32.CreateStreamOnHGlobal(hglob, True,
|
|
455
|
+
ole32.CreateStreamOnHGlobal(hglob, True, byref(self._stream_obj))
|
|
433
456
|
|
|
434
457
|
# MFCreateMFByteStreamOnStreamEx for future async operations exists, however Windows 8+ only. Requires new interface
|
|
435
|
-
# (Also unsure how/if new Windows async functions and callbacks work with
|
|
436
|
-
MFCreateMFByteStreamOnStream(self._stream_obj,
|
|
458
|
+
# (Also unsure how/if new Windows async functions and callbacks work with )
|
|
459
|
+
MFCreateMFByteStreamOnStream(self._stream_obj, byref(self._imf_bytestream))
|
|
437
460
|
else:
|
|
438
461
|
# Vista does not support MFCreateMFByteStreamOnStream.
|
|
439
462
|
# HACK: Create file in Windows temp folder to write our byte data to.
|
|
@@ -441,24 +464,24 @@ class WMFSource(Source):
|
|
|
441
464
|
MFCreateTempFile(MF_ACCESSMODE_READWRITE,
|
|
442
465
|
MF_OPENMODE_DELETE_IF_EXIST,
|
|
443
466
|
MF_FILEFLAGS_NONE,
|
|
444
|
-
|
|
467
|
+
byref(self._imf_bytestream))
|
|
445
468
|
|
|
446
469
|
wrote_length = ULONG()
|
|
447
470
|
data_ptr = cast(data, POINTER(BYTE))
|
|
448
|
-
self._imf_bytestream.Write(data_ptr, data_len,
|
|
471
|
+
self._imf_bytestream.Write(data_ptr, data_len, byref(wrote_length))
|
|
449
472
|
self._imf_bytestream.SetCurrentPosition(0)
|
|
450
473
|
|
|
451
474
|
if wrote_length.value != data_len:
|
|
452
475
|
raise DecodeException("Could not write all of the data to the bytestream file.")
|
|
453
476
|
|
|
454
477
|
try:
|
|
455
|
-
MFCreateSourceReaderFromByteStream(self._imf_bytestream, self._attributes,
|
|
478
|
+
MFCreateSourceReaderFromByteStream(self._imf_bytestream, self._attributes, byref(self._source_reader))
|
|
456
479
|
except OSError as err:
|
|
457
480
|
raise DecodeException(err) from None
|
|
458
481
|
else:
|
|
459
482
|
# We can just load from filename if no file object specified..
|
|
460
483
|
try:
|
|
461
|
-
MFCreateSourceReaderFromURL(filename, self._attributes,
|
|
484
|
+
MFCreateSourceReaderFromURL(filename, self._attributes, byref(self._source_reader))
|
|
462
485
|
except OSError as err:
|
|
463
486
|
raise DecodeException(err) from None
|
|
464
487
|
|
|
@@ -474,17 +497,17 @@ class WMFSource(Source):
|
|
|
474
497
|
try:
|
|
475
498
|
prop = PROPVARIANT()
|
|
476
499
|
self._source_reader.GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
|
|
477
|
-
|
|
478
|
-
|
|
500
|
+
byref(MF_PD_DURATION),
|
|
501
|
+
byref(prop))
|
|
479
502
|
|
|
480
503
|
self._duration = timestamp_from_wmf(prop.llVal)
|
|
481
|
-
ole32.PropVariantClear(
|
|
504
|
+
ole32.PropVariantClear(byref(prop))
|
|
482
505
|
except OSError:
|
|
483
|
-
warnings.warn("Could not determine duration of media file: '{}'."
|
|
506
|
+
warnings.warn(f"Could not determine duration of media file: '{filename}'.")
|
|
484
507
|
|
|
485
508
|
def _load_audio(self, stream=MF_SOURCE_READER_FIRST_AUDIO_STREAM):
|
|
486
|
-
"""
|
|
487
|
-
|
|
509
|
+
"""Prepares the audio stream for playback by detecting if it's compressed and attempting to decompress to PCM.
|
|
510
|
+
Default: Only get the first available audio stream.
|
|
488
511
|
"""
|
|
489
512
|
# Will be an audio file.
|
|
490
513
|
self._audio_stream_index = stream
|
|
@@ -493,7 +516,7 @@ class WMFSource(Source):
|
|
|
493
516
|
imfmedia = IMFMediaType()
|
|
494
517
|
|
|
495
518
|
try:
|
|
496
|
-
self._source_reader.GetNativeMediaType(self._audio_stream_index, 0,
|
|
519
|
+
self._source_reader.GetNativeMediaType(self._audio_stream_index, 0, byref(imfmedia))
|
|
497
520
|
except OSError as err:
|
|
498
521
|
if err.winerror == MF_E_INVALIDSTREAMNUMBER:
|
|
499
522
|
assert _debug('WMFAudioDecoder: No audio stream found.')
|
|
@@ -503,7 +526,7 @@ class WMFSource(Source):
|
|
|
503
526
|
# TODO: Make GUID take no arguments for a null version:
|
|
504
527
|
guid_audio_type = com.GUID(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
505
528
|
|
|
506
|
-
imfmedia.GetGUID(MF_MT_MAJOR_TYPE,
|
|
529
|
+
imfmedia.GetGUID(MF_MT_MAJOR_TYPE, byref(guid_audio_type))
|
|
507
530
|
|
|
508
531
|
if guid_audio_type == MFMediaType_Audio:
|
|
509
532
|
assert _debug('WMFAudioDecoder: Found Audio Stream.')
|
|
@@ -517,7 +540,7 @@ class WMFSource(Source):
|
|
|
517
540
|
|
|
518
541
|
# Check sub media type, AKA what kind of codec
|
|
519
542
|
guid_compressed = com.GUID(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
|
520
|
-
imfmedia.GetGUID(MF_MT_SUBTYPE,
|
|
543
|
+
imfmedia.GetGUID(MF_MT_SUBTYPE, byref(guid_compressed))
|
|
521
544
|
|
|
522
545
|
if guid_compressed == MFAudioFormat_PCM or guid_compressed == MFAudioFormat_Float:
|
|
523
546
|
assert _debug(f'WMFAudioDecoder: Found Uncompressed Audio: {guid_compressed}')
|
|
@@ -526,7 +549,7 @@ class WMFSource(Source):
|
|
|
526
549
|
# If audio is compressed, attempt to decompress it by forcing source reader to use PCM
|
|
527
550
|
mf_mediatype = IMFMediaType()
|
|
528
551
|
|
|
529
|
-
MFCreateMediaType(
|
|
552
|
+
MFCreateMediaType(byref(mf_mediatype))
|
|
530
553
|
mf_mediatype.SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio)
|
|
531
554
|
mf_mediatype.SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM)
|
|
532
555
|
|
|
@@ -537,14 +560,14 @@ class WMFSource(Source):
|
|
|
537
560
|
|
|
538
561
|
# Current media type should now be properly decoded at this point.
|
|
539
562
|
decoded_media_type = IMFMediaType() # Maybe reusing older IMFMediaType will work?
|
|
540
|
-
self._source_reader.GetCurrentMediaType(self._audio_stream_index,
|
|
563
|
+
self._source_reader.GetCurrentMediaType(self._audio_stream_index, byref(decoded_media_type))
|
|
541
564
|
|
|
542
|
-
wfx_length =
|
|
565
|
+
wfx_length = c_uint32()
|
|
543
566
|
wfx = POINTER(WAVEFORMATEX)()
|
|
544
567
|
|
|
545
568
|
MFCreateWaveFormatExFromMFMediaType(decoded_media_type,
|
|
546
|
-
|
|
547
|
-
|
|
569
|
+
byref(wfx),
|
|
570
|
+
byref(wfx_length),
|
|
548
571
|
0)
|
|
549
572
|
|
|
550
573
|
self._wfx = wfx.contents
|
|
@@ -565,7 +588,7 @@ class WMFSource(Source):
|
|
|
565
588
|
imfmedia = IMFMediaType()
|
|
566
589
|
|
|
567
590
|
try:
|
|
568
|
-
self._source_reader.GetCurrentMediaType(self._video_stream_index,
|
|
591
|
+
self._source_reader.GetCurrentMediaType(self._video_stream_index, byref(imfmedia))
|
|
569
592
|
except OSError as err:
|
|
570
593
|
if err.winerror == MF_E_INVALIDSTREAMNUMBER:
|
|
571
594
|
assert _debug('WMFVideoDecoder: No video stream found.')
|
|
@@ -575,7 +598,7 @@ class WMFSource(Source):
|
|
|
575
598
|
|
|
576
599
|
# All video is basically compressed, try to decompress.
|
|
577
600
|
uncompressed_mt = IMFMediaType()
|
|
578
|
-
MFCreateMediaType(
|
|
601
|
+
MFCreateMediaType(byref(uncompressed_mt))
|
|
579
602
|
|
|
580
603
|
imfmedia.CopyAllItems(uncompressed_mt)
|
|
581
604
|
|
|
@@ -593,12 +616,12 @@ class WMFSource(Source):
|
|
|
593
616
|
height, width = self._get_attribute_size(uncompressed_mt, MF_MT_FRAME_SIZE)
|
|
594
617
|
|
|
595
618
|
self.video_format = VideoFormat(width=width, height=height)
|
|
596
|
-
assert _debug('WMFVideoDecoder: Frame width: {} height: {}'
|
|
619
|
+
assert _debug(f'WMFVideoDecoder: Frame width: {width} height: {height}')
|
|
597
620
|
|
|
598
621
|
# Frame rate
|
|
599
622
|
den, num = self._get_attribute_size(uncompressed_mt, MF_MT_FRAME_RATE)
|
|
600
623
|
self.video_format.frame_rate = num / den
|
|
601
|
-
assert _debug('WMFVideoDecoder: Frame Rate: {} / {} = {
|
|
624
|
+
assert _debug(f'WMFVideoDecoder: Frame Rate: {num} / {den} = {self.video_format.frame_rate}')
|
|
602
625
|
|
|
603
626
|
# Sometimes it can return negative? Variable bit rate? Needs further tests and examples.
|
|
604
627
|
if self.video_format.frame_rate < 0:
|
|
@@ -608,18 +631,18 @@ class WMFSource(Source):
|
|
|
608
631
|
# Pixel ratio
|
|
609
632
|
den, num = self._get_attribute_size(uncompressed_mt, MF_MT_PIXEL_ASPECT_RATIO)
|
|
610
633
|
self.video_format.sample_aspect = num / den
|
|
611
|
-
assert _debug('WMFVideoDecoder: Pixel Ratio: {} / {} = {
|
|
634
|
+
assert _debug(f'WMFVideoDecoder: Pixel Ratio: {num} / {den} = {self.video_format.sample_aspect}')
|
|
612
635
|
|
|
613
636
|
def get_audio_data(self, num_bytes, compensation_time=0.0):
|
|
614
637
|
flags = DWORD()
|
|
615
|
-
timestamp =
|
|
638
|
+
timestamp = c_longlong()
|
|
616
639
|
|
|
617
640
|
imf_sample = IMFSample()
|
|
618
641
|
imf_buffer = IMFMediaBuffer()
|
|
619
642
|
|
|
620
643
|
while True:
|
|
621
|
-
self._source_reader.ReadSample(self._audio_stream_index, 0, None,
|
|
622
|
-
|
|
644
|
+
self._source_reader.ReadSample(self._audio_stream_index, 0, None, byref(flags),
|
|
645
|
+
byref(timestamp), byref(imf_sample))
|
|
623
646
|
|
|
624
647
|
if flags.value & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED:
|
|
625
648
|
assert _debug('WMFAudioDecoder: Data is no longer valid.')
|
|
@@ -634,14 +657,14 @@ class WMFSource(Source):
|
|
|
634
657
|
continue
|
|
635
658
|
|
|
636
659
|
# Convert to single buffer as a sample could potentially(rarely) have multiple buffers.
|
|
637
|
-
imf_sample.ConvertToContiguousBuffer(
|
|
660
|
+
imf_sample.ConvertToContiguousBuffer(byref(imf_buffer))
|
|
638
661
|
|
|
639
662
|
audio_data_ptr = POINTER(BYTE)()
|
|
640
663
|
audio_data_length = DWORD()
|
|
641
664
|
|
|
642
|
-
imf_buffer.Lock(
|
|
665
|
+
imf_buffer.Lock(byref(audio_data_ptr), None, byref(audio_data_length))
|
|
643
666
|
|
|
644
|
-
audio_data =
|
|
667
|
+
audio_data = string_at(audio_data_ptr, audio_data_length.value)
|
|
645
668
|
|
|
646
669
|
imf_buffer.Unlock()
|
|
647
670
|
imf_buffer.Release()
|
|
@@ -658,7 +681,7 @@ class WMFSource(Source):
|
|
|
658
681
|
def get_next_video_frame(self, skip_empty_frame=True):
|
|
659
682
|
video_data_length = DWORD()
|
|
660
683
|
flags = DWORD()
|
|
661
|
-
timestamp =
|
|
684
|
+
timestamp = c_longlong()
|
|
662
685
|
|
|
663
686
|
if self._current_video_sample:
|
|
664
687
|
self._current_video_buffer.Release()
|
|
@@ -668,20 +691,20 @@ class WMFSource(Source):
|
|
|
668
691
|
self._current_video_buffer = IMFMediaBuffer()
|
|
669
692
|
|
|
670
693
|
while True:
|
|
671
|
-
self._source_reader.ReadSample(self._video_stream_index, 0, None,
|
|
672
|
-
|
|
694
|
+
self._source_reader.ReadSample(self._video_stream_index, 0, None, byref(flags),
|
|
695
|
+
byref(timestamp), byref(self._current_video_sample))
|
|
673
696
|
|
|
674
697
|
if flags.value & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED:
|
|
675
698
|
assert _debug('WMFVideoDecoder: Data is no longer valid.')
|
|
676
699
|
|
|
677
700
|
# Get Major media type (Audio, Video, etc)
|
|
678
701
|
new = IMFMediaType()
|
|
679
|
-
self._source_reader.GetCurrentMediaType(self._video_stream_index,
|
|
702
|
+
self._source_reader.GetCurrentMediaType(self._video_stream_index, byref(new))
|
|
680
703
|
|
|
681
704
|
# Sometimes this happens once. I think this only
|
|
682
705
|
# changes if the stride is added/changed before playback?
|
|
683
|
-
stride =
|
|
684
|
-
new.GetUINT32(MF_MT_DEFAULT_STRIDE,
|
|
706
|
+
stride = c_uint32()
|
|
707
|
+
new.GetUINT32(MF_MT_DEFAULT_STRIDE, byref(stride))
|
|
685
708
|
new.Release()
|
|
686
709
|
|
|
687
710
|
self._stride = stride.value
|
|
@@ -698,16 +721,16 @@ class WMFSource(Source):
|
|
|
698
721
|
self._current_video_buffer = IMFMediaBuffer()
|
|
699
722
|
|
|
700
723
|
# Convert to single buffer as a sample could potentially have multiple buffers.
|
|
701
|
-
self._current_video_sample.ConvertToContiguousBuffer(
|
|
724
|
+
self._current_video_sample.ConvertToContiguousBuffer(byref(self._current_video_buffer))
|
|
702
725
|
|
|
703
726
|
video_data = POINTER(BYTE)()
|
|
704
727
|
|
|
705
|
-
self._current_video_buffer.Lock(
|
|
728
|
+
self._current_video_buffer.Lock(byref(video_data), None, byref(video_data_length))
|
|
706
729
|
|
|
707
730
|
width = self.video_format.width
|
|
708
731
|
height = self.video_format.height
|
|
709
732
|
|
|
710
|
-
# buffer =
|
|
733
|
+
# buffer = create_string_buffer(size)
|
|
711
734
|
self._timestamp = timestamp_from_wmf(timestamp.value)
|
|
712
735
|
|
|
713
736
|
self._current_video_buffer.Unlock()
|
|
@@ -734,36 +757,35 @@ class WMFSource(Source):
|
|
|
734
757
|
except OSError as err:
|
|
735
758
|
warnings.warn(str(err))
|
|
736
759
|
|
|
737
|
-
ole32.PropVariantClear(
|
|
760
|
+
ole32.PropVariantClear(byref(prop))
|
|
738
761
|
|
|
739
762
|
@staticmethod
|
|
740
763
|
def _get_attribute_size(attributes, guidKey):
|
|
741
|
-
"""
|
|
742
|
-
|
|
743
|
-
size = ctypes.c_uint64()
|
|
764
|
+
"""Convert int64 attributes to int32""" # HI32/LOW32
|
|
765
|
+
size = c_uint64()
|
|
744
766
|
attributes.GetUINT64(guidKey, size)
|
|
745
767
|
lParam = size.value
|
|
746
768
|
|
|
747
|
-
x =
|
|
748
|
-
y =
|
|
769
|
+
x = c_int32(lParam).value
|
|
770
|
+
y = c_int32(lParam >> 32).value
|
|
749
771
|
return x, y
|
|
750
772
|
|
|
751
773
|
def set_config_attributes(self):
|
|
752
|
-
"""
|
|
774
|
+
"""Here we set user specified attributes, by default we try to set low latency mode. (Win7+)"""
|
|
753
775
|
if self.low_latency or self.decode_video:
|
|
754
776
|
self._attributes = IMFAttributes()
|
|
755
777
|
|
|
756
|
-
MFCreateAttributes(
|
|
778
|
+
MFCreateAttributes(byref(self._attributes), 3)
|
|
757
779
|
|
|
758
780
|
if self.low_latency and WINDOWS_7_OR_GREATER:
|
|
759
|
-
self._attributes.SetUINT32(
|
|
781
|
+
self._attributes.SetUINT32(byref(MF_LOW_LATENCY), 1)
|
|
760
782
|
|
|
761
783
|
assert _debug('WMFAudioDecoder: Setting configuration attributes.')
|
|
762
784
|
|
|
763
785
|
# If it's a video we need to enable the streams to be accessed.
|
|
764
786
|
if self.decode_video:
|
|
765
|
-
self._attributes.SetUINT32(
|
|
766
|
-
self._attributes.SetUINT32(
|
|
787
|
+
self._attributes.SetUINT32(byref(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS), 1)
|
|
788
|
+
self._attributes.SetUINT32(byref(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING), 1)
|
|
767
789
|
|
|
768
790
|
assert _debug('WMFVideoDecoder: Setting configuration attributes.')
|
|
769
791
|
|
|
@@ -830,8 +852,7 @@ class WMFDecoder(MediaDecoder):
|
|
|
830
852
|
def decode(self, filename, file, streaming=True):
|
|
831
853
|
if streaming:
|
|
832
854
|
return WMFSource(filename, file)
|
|
833
|
-
|
|
834
|
-
return StaticSource(WMFSource(filename, file))
|
|
855
|
+
return StaticSource(WMFSource(filename, file))
|
|
835
856
|
|
|
836
857
|
def __del__(self):
|
|
837
858
|
if self.MFShutdown is not None:
|
pyglet/media/devices/win32.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
from ctypes import POINTER, Structure, byref, c_void_p
|
|
2
|
+
from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR, UINT
|
|
1
3
|
from typing import List, Optional, Tuple
|
|
2
4
|
|
|
3
|
-
from pyglet.libs.win32 import com
|
|
5
|
+
from pyglet.libs.win32 import PROPVARIANT, com
|
|
4
6
|
from pyglet.libs.win32 import _ole32 as ole32
|
|
5
7
|
from pyglet.libs.win32.constants import CLSCTX_INPROC_SERVER
|
|
6
|
-
from pyglet.libs.win32.types import *
|
|
7
8
|
from pyglet.media.devices import base
|
|
8
9
|
from pyglet.util import debug_print
|
|
9
10
|
|
|
@@ -41,7 +42,7 @@ STGM_READWRITE = 2
|
|
|
41
42
|
VT_LPWSTR = 0x001F
|
|
42
43
|
|
|
43
44
|
|
|
44
|
-
class PROPERTYKEY(
|
|
45
|
+
class PROPERTYKEY(Structure):
|
|
45
46
|
_fields_ = [
|
|
46
47
|
('fmtid', com.GUID),
|
|
47
48
|
('pid', DWORD),
|
|
@@ -180,7 +181,7 @@ class IMMDeviceEnumerator(com.pIUnknown):
|
|
|
180
181
|
('EnumAudioEndpoints',
|
|
181
182
|
com.STDMETHOD(EDataFlow, DWORD, c_void_p)),
|
|
182
183
|
('GetDefaultAudioEndpoint',
|
|
183
|
-
com.STDMETHOD(EDataFlow, ERole,
|
|
184
|
+
com.STDMETHOD(EDataFlow, ERole, POINTER(IMMDevice))),
|
|
184
185
|
('GetDevice',
|
|
185
186
|
com.STDMETHOD(LPCWSTR, POINTER(IMMDevice))),
|
|
186
187
|
('RegisterEndpointNotificationCallback',
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import ctypes
|
|
4
|
+
from ctypes.wintypes import DWORD, HWND, LONG, WORD
|
|
5
|
+
|
|
2
6
|
from pyglet.libs.win32 import com
|
|
3
7
|
|
|
4
8
|
lib = ctypes.oledll.dsound
|
|
5
9
|
|
|
6
|
-
DWORD = ctypes.c_uint32
|
|
7
10
|
LPDWORD = ctypes.POINTER(DWORD)
|
|
8
|
-
LONG = ctypes.c_long
|
|
9
11
|
LPLONG = ctypes.POINTER(LONG)
|
|
10
|
-
WORD = ctypes.c_uint16
|
|
11
|
-
HWND = DWORD
|
|
12
12
|
LPUNKNOWN = ctypes.c_void_p
|
|
13
13
|
|
|
14
14
|
D3DVALUE = ctypes.c_float
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
from collections import namedtuple, defaultdict
|
|
2
1
|
import threading
|
|
3
2
|
import weakref
|
|
4
|
-
|
|
5
|
-
from
|
|
3
|
+
from collections import defaultdict, namedtuple
|
|
4
|
+
from ctypes import POINTER, byref, c_char, c_float, cast, pointer
|
|
5
|
+
from ctypes.wintypes import DWORD, FLOAT
|
|
6
6
|
|
|
7
7
|
import pyglet
|
|
8
|
-
from pyglet.libs.win32
|
|
9
|
-
from pyglet.util import debug_print
|
|
8
|
+
from pyglet.libs.win32 import com
|
|
10
9
|
from pyglet.media.devices import get_audio_device_manager
|
|
10
|
+
from pyglet.media.devices.base import DeviceFlow
|
|
11
|
+
from pyglet.util import debug_print
|
|
12
|
+
|
|
11
13
|
from . import lib_xaudio2 as lib
|
|
12
14
|
|
|
13
15
|
_debug = debug_print('debug_media')
|
|
@@ -15,10 +17,12 @@ _debug = debug_print('debug_media')
|
|
|
15
17
|
|
|
16
18
|
def create_xa2_buffer(audio_data):
|
|
17
19
|
"""Creates a XAUDIO2_BUFFER to be used with a source voice.
|
|
18
|
-
|
|
20
|
+
|
|
21
|
+
Audio data cannot be purged until the source voice has played it; doing so will cause glitches.
|
|
22
|
+
"""
|
|
19
23
|
buff = lib.XAUDIO2_BUFFER()
|
|
20
24
|
buff.AudioBytes = audio_data.length
|
|
21
|
-
buff.pAudioData =
|
|
25
|
+
buff.pAudioData = cast(audio_data.pointer, POINTER(c_char))
|
|
22
26
|
return buff
|
|
23
27
|
|
|
24
28
|
|
|
@@ -202,7 +206,7 @@ class XAudio2Driver:
|
|
|
202
206
|
self._xaudio2 = lib.IXAudio2()
|
|
203
207
|
|
|
204
208
|
try:
|
|
205
|
-
lib.XAudio2Create(
|
|
209
|
+
lib.XAudio2Create(byref(self._xaudio2), 0, self.processor)
|
|
206
210
|
except OSError:
|
|
207
211
|
raise ImportError("XAudio2 driver could not be initialized.")
|
|
208
212
|
|
|
@@ -215,7 +219,7 @@ class XAudio2Driver:
|
|
|
215
219
|
debug.TraceMask = lib.XAUDIO2_LOG_ERRORS | lib.XAUDIO2_LOG_WARNINGS
|
|
216
220
|
debug.BreakMask = lib.XAUDIO2_LOG_WARNINGS
|
|
217
221
|
|
|
218
|
-
self._xaudio2.SetDebugConfiguration(
|
|
222
|
+
self._xaudio2.SetDebugConfiguration(byref(debug), None)
|
|
219
223
|
|
|
220
224
|
self._xaudio2.RegisterForCallbacks(self._engine_callback)
|
|
221
225
|
|
|
@@ -305,7 +309,7 @@ class XAudio2Driver:
|
|
|
305
309
|
@property
|
|
306
310
|
def volume(self):
|
|
307
311
|
vol = c_float()
|
|
308
|
-
self._master_voice.GetVolume(
|
|
312
|
+
self._master_voice.GetVolume(byref(vol))
|
|
309
313
|
return vol.value
|
|
310
314
|
|
|
311
315
|
@volume.setter
|
|
@@ -353,7 +357,7 @@ class XAudio2Driver:
|
|
|
353
357
|
def get_performance(self):
|
|
354
358
|
"""Retrieve some basic XAudio2 performance data such as memory usage and source counts."""
|
|
355
359
|
pf = lib.XAUDIO2_PERFORMANCE_DATA()
|
|
356
|
-
self._xaudio2.GetPerformanceData(
|
|
360
|
+
self._xaudio2.GetPerformanceData(byref(pf))
|
|
357
361
|
return pf
|
|
358
362
|
|
|
359
363
|
def create_listener(self):
|
|
@@ -415,8 +419,8 @@ class XAudio2Driver:
|
|
|
415
419
|
wfx_format = create_xa2_waveformat(audio_format)
|
|
416
420
|
|
|
417
421
|
callback = XAudio2VoiceCallback()
|
|
418
|
-
self._xaudio2.CreateSourceVoice(
|
|
419
|
-
|
|
422
|
+
self._xaudio2.CreateSourceVoice(byref(voice),
|
|
423
|
+
byref(wfx_format),
|
|
420
424
|
0,
|
|
421
425
|
self.max_frequency_ratio,
|
|
422
426
|
callback,
|
|
@@ -478,19 +482,19 @@ class XA2SourceVoice:
|
|
|
478
482
|
@property
|
|
479
483
|
def buffers_queued(self):
|
|
480
484
|
"""Get the amount of buffers in the current voice. Adding flag for no samples played is 3x faster."""
|
|
481
|
-
self._voice.GetState(
|
|
485
|
+
self._voice.GetState(byref(self._voice_state), lib.XAUDIO2_VOICE_NOSAMPLESPLAYED)
|
|
482
486
|
return self._voice_state.BuffersQueued
|
|
483
487
|
|
|
484
488
|
@property
|
|
485
489
|
def samples_played(self):
|
|
486
490
|
"""Get the amount of samples played by the voice."""
|
|
487
|
-
self._voice.GetState(
|
|
491
|
+
self._voice.GetState(byref(self._voice_state), 0)
|
|
488
492
|
return self._voice_state.SamplesPlayed
|
|
489
493
|
|
|
490
494
|
@property
|
|
491
495
|
def volume(self):
|
|
492
496
|
vol = c_float()
|
|
493
|
-
self._voice.GetVolume(
|
|
497
|
+
self._voice.GetVolume(byref(vol))
|
|
494
498
|
return vol.value
|
|
495
499
|
|
|
496
500
|
@volume.setter
|
|
@@ -615,7 +619,7 @@ class XA2SourceVoice:
|
|
|
615
619
|
self._voice.Stop(0, 0)
|
|
616
620
|
|
|
617
621
|
def submit_buffer(self, x2_buffer):
|
|
618
|
-
self._voice.SubmitSourceBuffer(
|
|
622
|
+
self._voice.SubmitSourceBuffer(byref(x2_buffer), None)
|
|
619
623
|
|
|
620
624
|
|
|
621
625
|
class XAudio2Listener:
|