在 Windows 上获取当前正在播放的媒体缩略图的方法仅适用于每个 Python 实例

Posted

技术标签:

【中文标题】在 Windows 上获取当前正在播放的媒体缩略图的方法仅适用于每个 Python 实例【英文标题】:Approach to get currently playing media's thumbnail on Windows only works once per Python instance 【发布时间】:2021-03-27 13:42:12 【问题描述】:

我正在尝试在 Windows 上获取当前正在播放的媒体的缩略图,感谢这个答案 (https://***.com/a/66037406/15491505) 我已经走了很远,但是我遇到了一个奇怪的问题,在 get_thumbnail() 变量 @第一次运行后,987654323@ 的长度总是以 0 结尾......就像我第一次调用它时一样,我完美地取回了缩略图,但所有进一步的调用最终都失败了......

这是我目前所拥有的:

from winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager
from winrt.windows.storage.streams import DataReader, Buffer, InputStreamOptions
from io import BytesIO
from PIL import Image
import asyncio


async def get_thumbnail():
    sessions = await MediaManager.request_async()
    current_session = sessions.get_current_session()

    if current_session:
        properties = await current_session.try_get_media_properties_async()
        media_info = song_attr: properties.__getattribute__(song_attr) for song_attr in dir(properties) if song_attr[0] != '_'

        if media_info.get('thumbnail'):
            thumb_stream_ref = media_info['thumbnail']
            thumb_read_buffer = Buffer(5000000)

            readable_stream = await thumb_stream_ref.open_read_async()
            readable_stream.read_async(thumb_read_buffer, thumb_read_buffer.capacity, InputStreamOptions.READ_AHEAD)

            buffer_reader = DataReader.from_buffer(thumb_read_buffer)
            byte_buffer = buffer_reader.read_bytes(thumb_read_buffer.length)

            binary = BytesIO()
            binary.write(bytearray(byte_buffer))
            binary.seek(0)
            print(len(bytearray(byte_buffer)))

            img = Image.open(binary)
            return img


thumbnail = asyncio.run(get_thumbnail())
thumbnail.show()
# This will work

thumbnail2 = asyncio.run(get_thumbnail())
thumbnail2.show()
# This will not

示例输出:

C:\Users\willy\Desktop>test.py
117672
0
Traceback (most recent call last):
  File "C:\Users\willy\Desktop\test.py", line 39, in <module>
    thumbnail2 = asyncio.run(get_thumbnail())
  File "C:\Python38\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "C:\Users\willy\Desktop\test.py", line 31, in get_thumbnail
    img = Image.open(binary)
  File "C:\Python38\lib\site-packages\PIL\Image.py", line 2930, in open
    raise UnidentifiedImageError(
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x00000278D2FB3B30>

【问题讨论】:

【参考方案1】:

解决方案

只需等待readable_stream.read_async(...) 调用的结果:

...
readable_stream = await thumb_stream_ref.open_read_async()
await readable_stream.read_async(thumb_read_buffer, thumb_read_buffer.capacity, InputStreamOptions.READ_AHEAD)

buffer_reader = DataReader.from_buffer(thumb_read_buffer)
...

现在应该每次都能成功显示缩略图。

调试过程

(对于任何感兴趣的人以及未来的类似错误)

在您的代码断点后,似乎在第二次调用get_thumbnail() 时,byte_buffer 被留空。这表明 thumb_read_buffer 没有从流中正确填充。

有趣的是,当单步执行代码时,图像会显示两次。这向我表明,可能没有等待异步函数调用。

原来.read_async()(正如函数名称所暗示的那样)是winrt 中的异步操作(参见IInputStream.ReadAsync on docs.microsoft.com)。因此,等待其执行解决了空thumb_read_buffer 的问题。

【讨论】:

尝试解释 我不保证这个解释是正确的,这只是我最好的猜测.......read_async()是在没有await 的情况下调用,没有时间将数据实际读入thumb_read_buffer;该程序直接执行read_bytes() 调用,该调用没有任何可读取的内容。至于为什么在get_thumbnail() 的第一次通话中没有发生这种情况,我真的不知道。 (如果我发现了,我会尝试编辑它)。

以上是关于在 Windows 上获取当前正在播放的媒体缩略图的方法仅适用于每个 Python 实例的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS Safari 中播放音频时如何设置缩略图?

如何在 chrome 媒体控制菜单和 Windows 媒体控制对话框中设置 HTML 音频或视频缩略图和标题

从资产创建缩略图 - Azure 媒体服务

在 Windows 上可靠地暂停所有正在播放的媒体

如何在嵌入视频的末尾添加缩略图?

如何从 PHAsset 获取视频的缩略图?