Compare commits

...

16 Commits

Author SHA1 Message Date
maxdunbar e84551daea
Merge 6dba1b01aa into 99f1b2b7b4 2024-04-27 01:25:10 +02:00
rcombs 99f1b2b7b4 player/command: add sub-text/ass-full sub-property
This is like sub-text/ass, but it returns a full ASS line, making it suitable for some more advanced scripting use-cases.
2024-04-27 01:19:56 +02:00
rcombs 437fff9f21 player/command: move sub-text-ass to a sub-property 2024-04-27 01:19:56 +02:00
rcombs aa0a9ce2ec sd_ass: allow get_text to return more than 500 bytes 2024-04-27 01:19:56 +02:00
Kacper Michajłow e3fd24496a stats.lua: show osd-dimensions property
This change displays the scaled position and size of the image before
cropping to the target rectangle. In simple terms, it shows how much
margin has been added to the image or how much of the image has been
cropped.

Note that target resolution is displayed after crop as in fact all other
pixels are discarded anyway.
2024-04-27 01:15:25 +02:00
Kacper Michajłow f55d19e846 sub/lavc_conv: don't override style of converted teletext pages
This fixes teletext pages rendering, while keeping the same default
style for subtitles and other converted formats.
2024-04-27 01:14:23 +02:00
Kacper Michajłow d8378dc226 sub/lavc_conv: don't strip ASS style header
This fixes converted subtitles that are styled.

This reverts commit 5e2c211a4e.

Most of the subtitle decoders in libavcodec sets meaningful style
values. For the rest we can conditionally strip style.
2024-04-27 01:14:23 +02:00
Shreesh Adiga 4aa7588e44 DOCS/vf: update vf_gpu options 2024-04-27 01:08:22 +02:00
Shreesh Adiga d9c5aef98d vf_gpu: vulkan and egl implementations
Abstract out EGL, and allow choosing between EGL and vulkan at runtime.
vf_gpu_egl.c contains GL specific context and creation/destroy code,
vf_gpu_vulkan.c contains Vulkan specific. This allows vf_gpu being
built in systems where EGL is not available and where Vulkan is
available.
2024-04-27 01:08:22 +02:00
ferreum 773c5e2ae0 af_scaletempo2: migrate to internals to talloc
Fixes corrupted audio after resize_input_buffer; realloc_2d did not move
data to new location. Rather than reimplementing more allocator logic,
migrate internals to use talloc and grow buffer with realloc.
2024-04-27 01:05:07 +02:00
ferreum 190b15c827 af_scaletempo2: remove redundant buffer zeroing
First iteration does not overlap with initial buffer contents any more,
so this zeroing was redundant.
2024-04-27 01:05:07 +02:00
nanahi 51e01e9772 ao_wasapi: fix player core lockup when avoiding premature buffer fills
6863eefc3d handled this situation by using
an atomic variable to express the state for which the wakeup is caused
by AO control, and the dispatch queue is only processed at this state.
However, this can cause permanent lockup of the player core when the
following happens:

- AO control sets the thread state to WASAPI_THREAD_DISPATCH, and
  sets the wakeup handle.
- WASAPI thread reads the WASAPI_THREAD_DISPATCH state and processes
  the dispatch queue.
- Another AO control happens. A dispatch item is enqueued, and the
  state stays at WASAPI_THREAD_DISPATCH.
- WASAPI thread resets the thread state to WASAPI_THREAD_FEED since
  the state has not changed.
- WaitForSingleObject() returns in the WASAPI thread, sees this state,
  and does not process the dispatch queue.
- The player core locks permanently because it is waiting for the dispatch
  to be processed.

This has been experimentally verified on a system under high contention:
The easiest way to trigger this lockup is to continuously hold down "i",
which rapidly issues AO get volume/mute controls.

To properly handle this, use separate handles for system and user wakeup
requests. Only feed audio when woke up by system and only process the
dispatch queue when woke up by user.

Fixes: 6863eefc3d
2024-04-27 00:59:09 +02:00
nanahi 7f0961479a Revert "ao_wasapi: address premature buffer fills in exclusive mode"
This reverts commit 6863eefc3d.
2024-04-27 00:59:09 +02:00
Max 6dba1b01aa osxbundle: reorder nodes and collections/arrays 2024-04-07 19:01:27 -07:00
Max e330a2dbf6 osxbundle: partial cleanup of LSItemContentTypes 2024-03-27 15:05:07 -07:00
maxdunbar cd0e2d41c3
osxbundle: replace deprecated keys
replaces deprecated CFBundleTypeExtensions with LSItemContentTypes.
LSHandlerRank ranks apps that declare as editors or viewers of a specific file type. Default value was chosen since mpv is a viewer of file types.
2024-03-18 14:54:41 -07:00
26 changed files with 867 additions and 433 deletions

View File

@ -0,0 +1 @@
add `sub-text/ass-full` sub-property

View File

@ -0,0 +1 @@
deprecate `sub-text-ass` property; add `sub-text/ass` sub-property

View File

@ -2823,19 +2823,27 @@ Property list
stripped. If the subtitle is not text-based (i.e. DVD/BD subtitles), an
empty string is returned.
``sub-text-ass``
Like ``sub-text``, but return the text in ASS format. Text subtitles in
other formats are converted. For native ASS subtitles, events that do
not contain any text (but vector drawings etc.) are not filtered out. If
multiple events match with the current playback time, they are concatenated
with line breaks. Contains only the "Text" part of the events.
This has sub-properties for different formats:
This property is not enough to render ASS subtitles correctly, because ASS
header and per-event metadata are not returned. You likely need to do
further filtering on the returned string to make it useful.
``sub-text/ass``
Like ``sub-text``, but return the text in ASS format. Text subtitles in
other formats are converted. For native ASS subtitles, events that do
not contain any text (but vector drawings etc.) are not filtered out. If
multiple events match with the current playback time, they are concatenated
with line breaks. Contains only the "Text" part of the events.
This property is not enough to render ASS subtitles correctly, because ASS
header and per-event metadata are not returned. Use ``/ass-full`` for that.
``sub-text/ass-full``
Like ``sub-text-ass``, but return the full event with all fields, formatted as
lines in a .ass text file. Use with ``sub-ass-extradata`` for style information.
``sub-text-ass`` (deprecated)
Deprecated alias for ``sub-text/ass``.
``secondary-sub-text``
Same as ``sub-text``, but for the secondary subtitles.
Same as ``sub-text`` (with the same sub-properties), but for the secondary subtitles.
``sub-start``
The current subtitle start time (in seconds). If there's multiple current

View File

@ -765,12 +765,22 @@ Available mpv-only filters are:
read information from this filter instead.
``gpu=...``
Convert video to RGB using the OpenGL renderer normally used with
``--vo=gpu``. This requires that the EGL implementation supports off-screen
rendering on the default display. (This is the case with Mesa.)
Convert video to RGB using the Vulkan or OpenGL renderer normally used with
``--vo=gpu``. In case of OpenGL, this requires that the EGL implementation
supports off-screen rendering on the default display. (This is the case with
Mesa.)
Sub-options:
``api=<type>``
The value ``type`` selects the rendering API. You can also pass
``help`` to get a complete list of compiled in backends.
egl
EGL (default if available)
vulkan
Vulkan
``w=<pixels>``, ``h=<pixels>``
Size of the output in pixels (default: 0). If not positive, this will
use the size of the first filtered input frame.

View File

@ -7,169 +7,112 @@
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>AAC</string>
<string>AC3</string>
<string>AIFF</string>
<string>M4A</string>
<string>MKA</string>
<string>MP3</string>
<string>OGG</string>
<string>PCM</string>
<string>VAW</string>
<string>WAV</string>
<string>WAW</string>
<string>WMA</string>
<string>aac</string>
<string>ac3</string>
<string>aiff</string>
<string>m4a</string>
<string>mka</string>
<string>mp3</string>
<string>ogg</string>
<string>pcm</string>
<string>vaw</string>
<string>wav</string>
<string>waw</string>
<string>wma</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Audio file</string>
<string>Audio File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>XML</string>
<key>LSItemContentTypes</key>
<array>
<string>public.aac-audio</string>
<string>public.ac3-audio</string>
<string>public.aiff-audio</string>
<string>public.mpeg-4-audio</string>
<string>org.matroska.mka</string>
<string>public.mp3</string>
<string>org.xiph.ogg-audio</string>
<string>io.mpv.pcm</string>
<string>com.microsoft.waveform-audio</string>
<string>com.microsoft.windows-media-wma</string>
</array>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Movie File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>XML</string>
<key>LSItemContentTypes</key>
<array>
<string>*</string>
<string>*</string>
<string>3GP</string>
<string>3IV</string>
<string>3gp</string>
<string>3iv</string>
<string>ASF</string>
<string>AVI</string>
<string>public.avi</string>
<string>CPK</string>
<string>DAT</string>
<string>DIVX</string>
<string>DV</string>
<string>FLAC</string>
<string>io.mpv.divx</string>
<string>io.mpv.dts</string>
<string>public.dv-movie</string>
<string>org.xiph.flac</string>
<string>FLI</string>
<string>FLV</string>
<string>H264</string>
<string>com.adobe.flash.video</string>
<string>io.mpv.h264</string>
<string>io.mpv.hevc</string>
<string>I263</string>
<string>M2TS</string>
<string>M4V</string>
<string>MKV</string>
<string>MOV</string>
<string>MP2</string>
<string>MP4</string>
<string>MPEG</string>
<string>MPG</string>
<string>MPG2</string>
<string>MPG4</string>
<string>NSV</string>
<string>io.mpv.mts</string>
<string>com.apple.m4v-video</string>
<string>org.matroska.mkv</string>
<string>com.apple.quicktime-movie</string>
<string>public.mp2</string>
<string>public.mpeg-4</string>
<string>public.mpeg</string>
<string>public.mpeg-2-video</string>
<string>io.mpv.nsv</string>
<string>NUT</string>
<string>NUV</string>
<string>OGG</string>
<string>OGM</string>
<string>QT</string>
<string>RM</string>
<string>RMVB</string>
<string>io.mpv.nuv</string>
<string>org.xiph.ogg-video</string>
<string>com.real.realmedia</string>
<string>VCD</string>
<string>VFW</string>
<string>VOB</string>
<string>WEBM</string>
<string>WMV</string>
<string>MK3D</string>
<string>asf</string>
<string>avi</string>
<string>cpk</string>
<string>dat</string>
<string>divx</string>
<string>dv</string>
<string>flac</string>
<string>fli</string>
<string>flv</string>
<string>h264</string>
<string>i263</string>
<string>m2ts</string>
<string>m4v</string>
<string>mkv</string>
<string>mov</string>
<string>mp2</string>
<string>mp4</string>
<string>mpeg</string>
<string>mpg</string>
<string>mpg2</string>
<string>mpg4</string>
<string>nsv</string>
<string>nut</string>
<string>nuv</string>
<string>ogg</string>
<string>ogm</string>
<string>qt</string>
<string>rm</string>
<string>rmvb</string>
<string>vcd</string>
<string>vfw</string>
<string>vob</string>
<string>webm</string>
<string>wmv</string>
<string>mk3d</string>
<string>io.mpv.vob</string>
<string>io.mpv.webm</string>
<string>io.mpv.wmv</string>
<string>io.mpv.mk3d</string>
<string>io.mpv.xvid</string>
<string>io.mpv.y4m</string>
<string>io.mpv.yuv</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Movie file</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>XML</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>AQT</string>
<string>ASS</string>
<string>JSS</string>
<string>RT</string>
<string>SMI</string>
<string>SRT</string>
<string>SSA</string>
<string>SUB</string>
<string>TXT</string>
<string>UTF</string>
<string>aqt</string>
<string>ass</string>
<string>jss</string>
<string>rt</string>
<string>smi</string>
<string>srt</string>
<string>ssa</string>
<string>sub</string>
<string>txt</string>
<string>utf</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeName</key>
<string>Subtitles file</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>XML</string>
<key>LSItemContentTypes</key>
<array>
<string>AQT</string>
<string>io.mpv.ass</string>
<string>JSS</string>
<string>RT</string>
<string>io.mpv.smi</string>
<string>io.mpv.subrip</string>
<string>io.mpv.sub</string>
<string>io.mpv.vobsub</string>
<string>public.plain-text</string>
<string>UTF</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
@ -202,6 +145,8 @@
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>CFBundleURLName</key>
<string>mpv Custom Protocol</string>
<key>CFBundleURLSchemes</key>
@ -212,6 +157,8 @@
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>CFBundleURLName</key>
<string>Streaming Protocol</string>
<key>CFBundleURLSchemes</key>
@ -233,6 +180,8 @@
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>CFBundleURLName</key>
<string>CD/DVD/Bluray Media</string>
<key>CFBundleURLSchemes</key>
@ -256,7 +205,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ac3</string>
<string>public.ac3-audio</string>
<key>UTTypeReferenceURL</key>
<string>http://wiki.multimedia.cx/index.php?title=AC3</string>
<key>UTTypeTagSpecification</key>
@ -267,6 +216,11 @@
<string>a52</string>
<string>eac3</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/ac3</string>
<string>audio/eac3</string>
</array>
</dict>
</dict>
<dict>
@ -288,6 +242,10 @@
<array>
<string>dts</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/vnd.dts</string>
</array>
</dict>
</dict>
<dict>
@ -300,7 +258,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.flac</string>
<string>org.xiph.flac</string>
<key>UTTypeReferenceURL</key>
<string>http://flac.sourceforge.net/format.html</string>
<key>UTTypeTagSpecification</key>
@ -309,6 +267,10 @@
<array>
<string>flac</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/flac</string>
</array>
</dict>
</dict>
<dict>
@ -321,7 +283,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.mka</string>
<string>org.matroska.mka</string>
<key>UTTypeReferenceURL</key>
<string>http://www.matroska.org</string>
<key>UTTypeTagSpecification</key>
@ -330,6 +292,10 @@
<array>
<string>mka</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/matroska</string>
</array>
</dict>
</dict>
<dict>
@ -342,7 +308,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ogg-audio</string>
<string>org.xiph.ogg-audio</string>
<key>UTTypeReferenceURL</key>
<string>http://xiph.org/ogg</string>
<key>UTTypeTagSpecification</key>
@ -351,6 +317,10 @@
<array>
<string>ogg</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/ogg</string>
</array>
</dict>
</dict>
<dict>
@ -372,6 +342,35 @@
<array>
<string>pcm</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.audio</string>
</array>
<key>UTTypeDescription</key>
<string>Waveform Audio</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>com.microsoft.waveform-audio</string>
<key>UTTypeReferenceURL</key>
<string>https://en.wikipedia.org/wiki/WAV</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>wav</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/wav</string>
</array>
</dict>
</dict>
<dict>
@ -384,7 +383,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.wma</string>
<string>com.microsoft.windows-media-wma</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/Windows_Media_Audio</string>
<key>UTTypeTagSpecification</key>
@ -393,6 +392,10 @@
<array>
<string>wma</string>
</array>
<key>public.mime-type</key>
<array>
<string>audio/x-ms-wma</string>
</array>
</dict>
</dict>
<dict>
@ -405,7 +408,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.avi</string>
<string>public.avi</string>
<key>UTTypeReferenceURL</key>
<string>http://www.the-labs.com/Video/odmlff2-avidef.pdf</string>
<key>UTTypeTagSpecification</key>
@ -414,6 +417,10 @@
<array>
<string>avi</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/x-msvideo</string>
</array>
</dict>
</dict>
<dict>
@ -435,6 +442,10 @@
<array>
<string>divx</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/divx</string>
</array>
</dict>
</dict>
<dict>
@ -447,7 +458,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.dv</string>
<string>public.dv-movie</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/DV</string>
<key>UTTypeTagSpecification</key>
@ -457,6 +468,10 @@
<string>dv</string>
<string>hdv</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/dv</string>
</array>
</dict>
</dict>
<dict>
@ -469,7 +484,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.flv</string>
<string>com.adobe.flash.video</string>
<key>UTTypeReferenceURL</key>
<string>http://en.wikipedia.org/wiki/Flash_Video</string>
<key>UTTypeTagSpecification</key>
@ -477,10 +492,17 @@
<key>public.filename-extension</key>
<array>
<string>flv</string>
<string>fla</string>
<string>f4a</string>
<string>f4v</string>
<string>f4b</string>
<string>f4p</string>
<string>swf</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/vnd.adobe.flash.movie</string>
</array>
</dict>
</dict>
<dict>
@ -507,6 +529,35 @@
<string>mtv</string>
<string>ts</string>
</array>
<key>public.mime-type</key>
<array>
<string>model/vnd.mts</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>MPEG-4 File</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>com.apple.m4v-video</string>
<key>UTTypeReferenceURL</key>
<string>https://en.wikipedia.org/wiki/M4V</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>m4v</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/m4v</string>
</array>
</dict>
</dict>
<dict>
@ -519,7 +570,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.mkv</string>
<string>org.matroska.mkv</string>
<key>UTTypeReferenceURL</key>
<string>http://www.matroska.org</string>
<key>UTTypeTagSpecification</key>
@ -528,6 +579,10 @@
<array>
<string>mkv</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/matroska</string>
</array>
</dict>
</dict>
<dict>
@ -549,6 +604,10 @@
<array>
<string>mk3d</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/x-matroska</string>
</array>
</dict>
</dict>
<dict>
@ -570,6 +629,10 @@
<array>
<string>webm</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/webm</string>
</array>
</dict>
</dict>
<dict>
@ -582,7 +645,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.ogv</string>
<string>org.xiph.ogg-video</string>
<key>UTTypeReferenceURL</key>
<string>http://xiph.org/ogg</string>
<key>UTTypeTagSpecification</key>
@ -592,6 +655,10 @@
<string>ogm</string>
<string>ogv</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/ogg</string>
</array>
</dict>
</dict>
<dict>
@ -604,7 +671,7 @@
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.rmvb</string>
<string>com.real.realmedia</string>
<key>UTTypeReferenceURL</key>
<string>http://www.real.com</string>
<key>UTTypeTagSpecification</key>
@ -614,6 +681,60 @@
<string>rmvb</string>
<string>rm</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/vnd.rn-realmedia-vbr</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>Nullsoft Streaming Video</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.nsv</string>
<key>UTTypeReferenceURL</key>
<string>https://en.wikipedia.org/wiki/Nullsoft</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nsv</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/x-winamp</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.movie</string>
</array>
<key>UTTypeDescription</key>
<string>NuppleVideo File</string>
<key>UTTypeIconFile</key>
<string>document.icns</string>
<key>UTTypeIdentifier</key>
<string>io.mpv.nuv</string>
<key>UTTypeReferenceURL</key>
<string>https://en.wikipedia.org/wiki/Nullsoft</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nuv</string>
</array>
<key>public.mime-type</key>
<array>
<string></string>
</array>
</dict>
</dict>
<dict>
@ -635,6 +756,10 @@
<array>
<string>vob</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/x-ms-vob</string>
</array>
</dict>
</dict>
<dict>
@ -656,6 +781,10 @@
<array>
<string>wmv</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/x-ms-wmv</string>
</array>
</dict>
</dict>
<dict>
@ -677,6 +806,10 @@
<array>
<string>xvid</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/x-xvid</string>
</array>
</dict>
</dict>
<dict>
@ -698,6 +831,10 @@
<array>
<string>264</string>
</array>
<key>public.mime-type</key>
<array>
<string>video/H264</string>
</array>
</dict>
</dict>
<dict>
@ -719,6 +856,10 @@
<array>
<string>hevc</string>
</array>
<key>public.mime-type</key>
<array>
<string></string>
</array>
</dict>
</dict>
<dict>
@ -740,6 +881,10 @@
<array>
<string>yuv</string>
</array>
<key>public.mime-type</key>
<array>
<string></string>
</array>
</dict>
</dict>
<dict>
@ -782,6 +927,10 @@
<array>
<string>srt</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/x-subrip</string>
</array>
</dict>
</dict>
<dict>
@ -803,6 +952,10 @@
<array>
<string>sub</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
<dict>
@ -825,6 +978,10 @@
<string>ass</string>
<string>ssa</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
<dict>
@ -847,6 +1004,10 @@
<string>idx</string>
<string>sub</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
<dict>
@ -869,6 +1030,10 @@
<string>smi</string>
<string>smil</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/smil</string>
</array>
</dict>
</dict>
</array>

View File

@ -8,7 +8,7 @@
#include "options/m_option.h"
struct priv {
struct mp_scaletempo2 data;
struct mp_scaletempo2 *data;
struct mp_pin *in_pin;
struct mp_aframe *cur_format;
struct mp_aframe_pool *out_pool;
@ -29,7 +29,7 @@ static void af_scaletempo2_process(struct mp_filter *f)
return;
while (!p->initialized || !p->pending ||
!mp_scaletempo2_frames_available(&p->data, p->speed))
!mp_scaletempo2_frames_available(p->data, p->speed))
{
bool eof = false;
if (!p->pending || !mp_aframe_get_size(p->pending)) {
@ -64,16 +64,16 @@ static void af_scaletempo2_process(struct mp_filter *f)
if (p->pending && !format_change && !p->sent_final) {
int frame_size = mp_aframe_get_size(p->pending);
uint8_t **planes = mp_aframe_get_data_ro(p->pending);
int read = mp_scaletempo2_fill_input_buffer(&p->data,
int read = mp_scaletempo2_fill_input_buffer(p->data,
planes, frame_size, p->speed);
mp_aframe_skip_samples(p->pending, read);
}
if (final && p->pending && !p->sent_final) {
mp_scaletempo2_set_final(&p->data);
mp_scaletempo2_set_final(p->data);
p->sent_final = true;
}
if (mp_scaletempo2_frames_available(&p->data, p->speed)) {
if (mp_scaletempo2_frames_available(p->data, p->speed)) {
if (eof) {
mp_pin_out_repeat_eof(p->in_pin); // drain more next time
}
@ -89,9 +89,9 @@ static void af_scaletempo2_process(struct mp_filter *f)
}
assert(p->pending);
if (mp_scaletempo2_frames_available(&p->data, p->speed)) {
if (mp_scaletempo2_frames_available(p->data, p->speed)) {
struct mp_aframe *out = mp_aframe_new_ref(p->cur_format);
int out_samples = p->data.ola_hop_size;
int out_samples = p->data->ola_hop_size;
if (mp_aframe_pool_allocate(p->out_pool, out, out_samples) < 0) {
talloc_free(out);
goto error;
@ -101,14 +101,14 @@ static void af_scaletempo2_process(struct mp_filter *f)
uint8_t **planes = mp_aframe_get_data_rw(out);
assert(planes);
assert(mp_aframe_get_planes(out) == p->data.channels);
assert(mp_aframe_get_planes(out) == p->data->channels);
out_samples = mp_scaletempo2_fill_buffer(&p->data,
out_samples = mp_scaletempo2_fill_buffer(p->data,
(float**)planes, out_samples, p->speed);
double pts = mp_aframe_get_pts(p->pending);
if (pts != MP_NOPTS_VALUE) {
double frame_delay = mp_scaletempo2_get_latency(&p->data, p->speed)
double frame_delay = mp_scaletempo2_get_latency(p->data, p->speed)
+ out_samples * p->speed;
mp_aframe_set_pts(out, pts - frame_delay / mp_aframe_get_effective_rate(out));
@ -122,7 +122,7 @@ static void af_scaletempo2_process(struct mp_filter *f)
// reset the filter to ensure it stops generating audio
// and mp_scaletempo2_frames_available returns false
mp_scaletempo2_reset(&p->data);
mp_scaletempo2_reset(p->data);
}
}
}
@ -150,7 +150,7 @@ static bool init_scaletempo2(struct mp_filter *f)
p->sent_final = false;
mp_aframe_config_copy(p->cur_format, p->pending);
mp_scaletempo2_init(&p->data, mp_aframe_get_channels(p->pending),
mp_scaletempo2_init(p->data, mp_aframe_get_channels(p->pending),
mp_aframe_get_rate(p->pending));
return true;
@ -172,7 +172,7 @@ static bool af_scaletempo2_command(struct mp_filter *f, struct mp_filter_command
static void af_scaletempo2_reset(struct mp_filter *f)
{
struct priv *p = f->priv;
mp_scaletempo2_reset(&p->data);
mp_scaletempo2_reset(p->data);
p->initialized = false;
TA_FREEP(&p->pending);
}
@ -180,8 +180,8 @@ static void af_scaletempo2_reset(struct mp_filter *f)
static void af_scaletempo2_destroy(struct mp_filter *f)
{
struct priv *p = f->priv;
mp_scaletempo2_destroy(&p->data);
talloc_free(p->pending);
TA_FREEP(&p->data);
TA_FREEP(&p->pending);
}
static const struct mp_filter_info af_scaletempo2_filter = {
@ -206,7 +206,8 @@ static struct mp_filter *af_scaletempo2_create(
mp_filter_add_pin(f, MP_PIN_OUT, "out");
struct priv *p = f->priv;
p->data.opts = talloc_steal(p, options);
p->data = talloc_zero(p, struct mp_scaletempo2);
p->data->opts = talloc_steal(p, options);
p->speed = 1.0;
p->cur_format = talloc_steal(p, mp_aframe_create());
p->out_pool = mp_aframe_pool_create(p);

View File

@ -41,19 +41,15 @@ static bool in_interval(int n, struct interval q)
return n >= q.lo && n <= q.hi;
}
static float **realloc_2d(float **p, int x, int y)
static void alloc_sample_buffer(struct mp_scaletempo2 *p, float ***ptr, size_t size)
{
float **array = realloc(p, sizeof(float*) * x + sizeof(float) * x * y);
float* data = (float*) (array + x);
for (int i = 0; i < x; ++i) {
array[i] = data + i * y;
}
return array;
}
talloc_free(*ptr);
static void zero_2d(float **a, int x, int y)
{
memset(a + x, 0, sizeof(float) * x * y);
float **buff = talloc_array(p, float*, p->channels);
for (int i = 0; i < p->channels; ++i) {
buff[i] = talloc_array(buff, float, size);
}
*ptr = buff;
}
static void zero_2d_partial(float **a, int x, int y)
@ -480,12 +476,6 @@ static bool can_perform_wsola(struct mp_scaletempo2 *p, double playback_rate)
return frames_needed(p, playback_rate) <= 0;
}
static void resize_input_buffer(struct mp_scaletempo2 *p, int size)
{
p->input_buffer_size = size;
p->input_buffer = realloc_2d(p->input_buffer, p->channels, size);
}
// pad end with silence until a wsola iteration can be performed
static void add_input_buffer_final_silence(struct mp_scaletempo2 *p, double playback_rate)
{
@ -493,11 +483,9 @@ static void add_input_buffer_final_silence(struct mp_scaletempo2 *p, double play
if (needed <= 0)
return; // no silence needed for iteration
int required_size = needed + p->input_buffer_frames;
if (required_size > p->input_buffer_size)
resize_input_buffer(p, required_size);
int last_index = needed + p->input_buffer_frames - 1;
for (int i = 0; i < p->channels; ++i) {
MP_TARRAY_GROW(p, p->input_buffer[i], last_index);
float *ch_input = p->input_buffer[i];
for (int j = 0; j < needed; ++j) {
ch_input[p->input_buffer_frames + j] = 0.0f;
@ -523,11 +511,9 @@ int mp_scaletempo2_fill_input_buffer(struct mp_scaletempo2 *p,
if (read == 0)
return 0;
int required_size = read + p->input_buffer_frames;
if (required_size > p->input_buffer_size)
resize_input_buffer(p, required_size);
int last_index = read + p->input_buffer_frames - 1;
for (int i = 0; i < p->channels; ++i) {
MP_TARRAY_GROW(p, p->input_buffer[i], last_index);
memcpy(p->input_buffer[i] + p->input_buffer_frames,
planes[i], read * sizeof(float));
}
@ -771,18 +757,6 @@ bool mp_scaletempo2_frames_available(struct mp_scaletempo2 *p, double playback_r
|| p->num_complete_frames > 0;
}
void mp_scaletempo2_destroy(struct mp_scaletempo2 *p)
{
free(p->ola_window);
free(p->transition_window);
free(p->wsola_output);
free(p->optimal_block);
free(p->search_block);
free(p->target_block);
free(p->input_buffer);
free(p->energy_candidate_blocks);
}
void mp_scaletempo2_reset(struct mp_scaletempo2 *p)
{
p->input_buffer_frames = 0;
@ -791,8 +765,6 @@ void mp_scaletempo2_reset(struct mp_scaletempo2 *p)
p->output_time = 0.0;
p->search_block_index = 0;
p->target_block_index = 0;
// Clear the queue of decoded packets.
zero_2d(p->wsola_output, p->channels, p->wsola_output_size);
p->num_complete_frames = 0;
p->wsola_output_started = false;
}
@ -847,28 +819,26 @@ void mp_scaletempo2_init(struct mp_scaletempo2 *p, int channels, int rate)
// 1, ... |num_candidate_blocks|
p->search_block_center_offset = p->num_candidate_blocks / 2
+ (p->ola_window_size / 2 - 1);
p->ola_window = realloc(p->ola_window, sizeof(float) * p->ola_window_size);
MP_RESIZE_ARRAY(p, p->ola_window, p->ola_window_size);
get_symmetric_hanning_window(p->ola_window_size, p->ola_window);
p->transition_window = realloc(p->transition_window,
sizeof(float) * p->ola_window_size * 2);
MP_RESIZE_ARRAY(p, p->transition_window, p->ola_window_size * 2);
get_symmetric_hanning_window(2 * p->ola_window_size, p->transition_window);
p->wsola_output_size = p->ola_window_size + p->ola_hop_size;
p->wsola_output = realloc_2d(p->wsola_output, p->channels, p->wsola_output_size);
// Initialize for overlap-and-add of the first block.
zero_2d(p->wsola_output, p->channels, p->wsola_output_size);
alloc_sample_buffer(p, &p->wsola_output, p->wsola_output_size);
// Auxiliary containers.
p->optimal_block = realloc_2d(p->optimal_block, p->channels, p->ola_window_size);
alloc_sample_buffer(p, &p->optimal_block, p->ola_window_size);
p->search_block_size = p->num_candidate_blocks + (p->ola_window_size - 1);
p->search_block = realloc_2d(p->search_block, p->channels, p->search_block_size);
p->target_block = realloc_2d(p->target_block, p->channels, p->ola_window_size);
alloc_sample_buffer(p, &p->search_block, p->search_block_size);
alloc_sample_buffer(p, &p->target_block, p->ola_window_size);
resize_input_buffer(p, 4 * MPMAX(p->ola_window_size, p->search_block_size));
p->input_buffer_frames = 0;
p->input_buffer_final_frames = 0;
p->input_buffer_added_silence = 0;
size_t initial_size = 4 * MPMAX(p->ola_window_size, p->search_block_size);
alloc_sample_buffer(p, &p->input_buffer, initial_size);
p->energy_candidate_blocks = realloc(p->energy_candidate_blocks,
sizeof(float) * p->channels * p->num_candidate_blocks);
MP_RESIZE_ARRAY(p, p->energy_candidate_blocks,
p->channels * p->num_candidate_blocks);
}

View File

@ -110,7 +110,6 @@ struct mp_scaletempo2 {
float **target_block;
// Buffered audio data.
float **input_buffer;
int input_buffer_size;
int input_buffer_frames;
// How many frames in |input_buffer| need to be flushed by padding with
// silence to process the final packet. While this is nonzero, the filter

View File

@ -193,17 +193,19 @@ static void thread_resume(struct ao *ao)
thread_unpause(ao);
}
static void set_state_and_wakeup_thread(struct ao *ao,
enum wasapi_thread_state thread_state)
static void thread_wakeup(void *ptr)
{
struct ao *ao = ptr;
struct wasapi_state *state = ao->priv;
SetEvent(state->hUserWake);
}
static void set_thread_state(struct ao *ao,
enum wasapi_thread_state thread_state)
{
struct wasapi_state *state = ao->priv;
atomic_store(&state->thread_state, thread_state);
SetEvent(state->hWake);
}
static void thread_process_dispatch(void *ptr)
{
set_state_and_wakeup_thread(ptr, WASAPI_THREAD_DISPATCH);
thread_wakeup(ao);
}
static DWORD __stdcall AudioThread(void *lpParameter)
@ -220,18 +222,25 @@ static DWORD __stdcall AudioThread(void *lpParameter)
MP_DBG(ao, "Entering dispatch loop\n");
while (true) {
if (WaitForSingleObject(state->hWake, INFINITE) != WAIT_OBJECT_0)
MP_ERR(ao, "Unexpected return value from WaitForSingleObject\n");
HANDLE handles[] = {state->hWake, state->hUserWake};
switch (WaitForMultipleObjects(MP_ARRAY_SIZE(handles), handles, FALSE, INFINITE)) {
case WAIT_OBJECT_0:
// fill twice on under-full buffer (see comment in thread_feed)
if (thread_feed(ao) && thread_feed(ao))
MP_ERR(ao, "Unable to fill buffer fast enough\n");
continue;
case WAIT_OBJECT_0 + 1:
break;
default:
MP_ERR(ao, "Unexpected return value from WaitForMultipleObjects\n");
break;
}
mp_dispatch_queue_process(state->dispatch, 0);
int thread_state = atomic_load(&state->thread_state);
switch (thread_state) {
case WASAPI_THREAD_FEED:
// fill twice on under-full buffer (see comment in thread_feed)
if (thread_feed(ao) && thread_feed(ao))
MP_ERR(ao, "Unable to fill buffer fast enough\n");
break;
case WASAPI_THREAD_DISPATCH:
mp_dispatch_queue_process(state->dispatch, 0);
break;
case WASAPI_THREAD_RESET:
thread_reset(ao);
@ -267,8 +276,8 @@ static void uninit(struct ao *ao)
{
MP_DBG(ao, "Uninit wasapi\n");
struct wasapi_state *state = ao->priv;
if (state->hWake)
set_state_and_wakeup_thread(ao, WASAPI_THREAD_SHUTDOWN);
if (state->hWake && state->hUserWake)
set_thread_state(ao, WASAPI_THREAD_SHUTDOWN);
if (state->hAudioThread &&
WaitForSingleObject(state->hAudioThread, INFINITE) != WAIT_OBJECT_0)
@ -279,6 +288,7 @@ static void uninit(struct ao *ao)
SAFE_DESTROY(state->hInitDone, CloseHandle(state->hInitDone));
SAFE_DESTROY(state->hWake, CloseHandle(state->hWake));
SAFE_DESTROY(state->hUserWake, CloseHandle(state->hUserWake));
SAFE_DESTROY(state->hAudioThread,CloseHandle(state->hAudioThread));
wasapi_change_uninit(ao);
@ -312,14 +322,15 @@ static int init(struct ao *ao)
state->hInitDone = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hWake = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!state->hInitDone || !state->hWake) {
state->hUserWake = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!state->hInitDone || !state->hWake || !state->hUserWake) {
MP_FATAL(ao, "Error creating events\n");
uninit(ao);
return -1;
}
state->dispatch = mp_dispatch_create(state);
mp_dispatch_set_wakeup_fn(state->dispatch, thread_process_dispatch, ao);
mp_dispatch_set_wakeup_fn(state->dispatch, thread_wakeup, ao);
state->init_ok = false;
state->hAudioThread = CreateThread(NULL, 0, &AudioThread, ao, 0, NULL);
@ -474,17 +485,17 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
static void audio_reset(struct ao *ao)
{
set_state_and_wakeup_thread(ao, WASAPI_THREAD_RESET);
set_thread_state(ao, WASAPI_THREAD_RESET);
}
static void audio_resume(struct ao *ao)
{
set_state_and_wakeup_thread(ao, WASAPI_THREAD_RESUME);
set_thread_state(ao, WASAPI_THREAD_RESUME);
}
static bool audio_set_pause(struct ao *ao, bool paused)
{
set_state_and_wakeup_thread(ao, paused ? WASAPI_THREAD_PAUSE : WASAPI_THREAD_UNPAUSE);
set_thread_state(ao, paused ? WASAPI_THREAD_PAUSE : WASAPI_THREAD_UNPAUSE);
return true;
}

View File

@ -48,7 +48,6 @@ void wasapi_change_uninit(struct ao* ao);
enum wasapi_thread_state {
WASAPI_THREAD_FEED = 0,
WASAPI_THREAD_DISPATCH,
WASAPI_THREAD_RESUME,
WASAPI_THREAD_RESET,
WASAPI_THREAD_SHUTDOWN,
@ -66,6 +65,7 @@ typedef struct wasapi_state {
HANDLE hWake; // thread wakeup event
atomic_int thread_state; // enum wasapi_thread_state (what to do on wakeup)
struct mp_dispatch_queue *dispatch; // for volume/mute/session display
HANDLE hUserWake; // mpv-requested wakeup event
// for setting the audio thread priority
HANDLE hTask;

View File

@ -94,7 +94,7 @@ const struct mp_user_filter_entry *vf_list[] = {
#if HAVE_D3D_HWACCEL
&vf_d3d11vpp,
#endif
#if HAVE_GL && HAVE_EGL
#if (HAVE_GL && HAVE_EGL) || HAVE_VULKAN
&vf_gpu,
#endif
};

View File

@ -1249,7 +1249,7 @@ if features['egl'] or features['egl-android'] or features['egl-angle-win32']
endif
if features['gl'] and features['egl']
sources += files('video/filter/vf_gpu.c')
sources += files('video/filter/vf_gpu_egl.c')
endif
if features['gl']
@ -1274,7 +1274,8 @@ features += {'vulkan': vulkan.found()}
if features['vulkan']
dependencies += vulkan
sources += files('video/out/vulkan/context.c',
'video/out/vulkan/utils.c')
'video/out/vulkan/utils.c',
'video/filter/vf_gpu_vulkan.c')
endif
if features['vulkan'] and features['android']
@ -1299,6 +1300,10 @@ if features['vk-khr-display']
sources += files('video/out/vulkan/context_display.c')
endif
if features['vulkan'] or (features['gl'] and features['egl'])
sources += files('video/filter/vf_gpu.c')
endif
# hwaccel
ffnvcodec = dependency('ffnvcodec', version: '>= 11.1.5.1', required: false)

View File

@ -3021,6 +3021,20 @@ static int mp_property_sub_text(void *ctx, struct m_property *prop,
int sub_index = def[0];
int type = def[1];
if (action == M_PROPERTY_KEY_ACTION) {
struct m_property_action_arg *ka = arg;
if (!strcmp(ka->key, "ass"))
type = SD_TEXT_TYPE_ASS;
else if (!strcmp(ka->key, "ass-full"))
type = SD_TEXT_TYPE_ASS_FULL;
else
return M_PROPERTY_UNKNOWN;
action = ka->action;
arg = ka->arg;
}
struct track *track = mpctx->current_track[sub_index][STREAM_SUB];
struct dec_sub *sub = track ? track->d_sub : NULL;
double pts = mpctx->playback_pts;

View File

@ -895,18 +895,23 @@ local function add_video_out(s)
scale = mp.get_property_native("current-window-scale")
end
local r = mp.get_property_native("video-target-params")
if not r then
local osd_dims = mp.get_property_native("osd-dimensions")
local scaled_width = osd_dims["w"] - osd_dims["ml"] - osd_dims["mr"]
local scaled_height = osd_dims["h"] - osd_dims["mt"] - osd_dims["mb"]
append_resolution(s, {w=scaled_width, h=scaled_height, s=scale},
"Resolution:")
return
end
local od = mp.get_property_native("osd-dimensions")
local rt = mp.get_property_native("video-target-params")
r = rt or {}
-- Add window scale
r["s"] = scale
r["crop-x"] = od["ml"]
r["crop-y"] = od["mt"]
r["crop-w"] = od["w"] - od["ml"] - od["mr"]
r["crop-h"] = od["h"] - od["mt"] - od["mb"]
if not rt then
r["w"] = r["crop-w"]
r["h"] = r["crop-h"]
append_resolution(s, r, "Resolution:", "w", "h", true)
return
end
append_img_params(s, r)
append_hdr(s, r, true)

View File

@ -24,6 +24,7 @@ enum sd_ctrl {
enum sd_text_type {
SD_TEXT_TYPE_PLAIN,
SD_TEXT_TYPE_ASS,
SD_TEXT_TYPE_ASS_FULL,
};
struct sd_times {

View File

@ -115,7 +115,7 @@ static struct demux_packet *jsre_filter(struct sd_filter *ft,
bool drop = false;
if (ft->opts->rf_plain)
sd_ass_to_plaintext(text, strlen(text), text);
sd_ass_to_plaintext(&text, text);
for (int n = 0; n < p->num_regexes; n++) {
int found, err = p_regexec(p->J, n, text, &found);

View File

@ -64,7 +64,7 @@ static struct demux_packet *rf_filter(struct sd_filter *ft,
bool drop = false;
if (ft->opts->rf_plain)
sd_ass_to_plaintext(text, strlen(text), text);
sd_ass_to_plaintext(&text, text);
for (int n = 0; n < p->num_regexes; n++) {
int err = regexec(&p->regexes[n], text, 0, NULL, 0);

View File

@ -33,6 +33,7 @@
struct lavc_conv {
struct mp_log *log;
struct mp_subtitle_opts *opts;
bool styled;
AVCodecContext *avctx;
AVPacket *avpkt;
AVPacket *avpkt_vtt;
@ -53,20 +54,6 @@ static const char *get_lavc_format(const char *format)
return format;
}
// Disable style definitions generated by the libavcodec converter.
// We always want the user defined style instead.
static void disable_styles(bstr header)
{
bstr style = bstr0("\nStyle: ");
while (header.len) {
int n = bstr_find(header, style);
if (n < 0)
break;
header.start[n + 1] = '#'; // turn into a comment
header = bstr_cut(header, n + style.len);
}
}
struct lavc_conv *lavc_conv_create(struct sd *sd)
{
struct lavc_conv *priv = talloc_zero(NULL, struct lavc_conv);
@ -116,7 +103,6 @@ struct lavc_conv *lavc_conv_create(struct sd *sd)
priv->avctx = avctx;
priv->extradata = talloc_strndup(priv, avctx->subtitle_header,
avctx->subtitle_header_size);
disable_styles(bstr0(priv->extradata));
return priv;
error:
@ -260,9 +246,12 @@ char **lavc_conv_decode(struct lavc_conv *priv, struct demux_packet *packet,
curr_pkt = priv->avpkt_vtt;
}
priv->styled = avctx->codec_id == AV_CODEC_ID_DVB_TELETEXT;
if (avctx->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
if (!priv->opts->teletext_page) {
av_opt_set(avctx, "txt_page", "subtitle", AV_OPT_SEARCH_CHILDREN);
priv->styled = false;
} else if (priv->opts->teletext_page == -1) {
av_opt_set(avctx, "txt_page", "*", AV_OPT_SEARCH_CHILDREN);
} else {
@ -300,6 +289,11 @@ done:
return priv->cur_list;
}
bool lavc_conv_is_styled(struct lavc_conv *priv)
{
return priv->styled;
}
void lavc_conv_reset(struct lavc_conv *priv)
{
avcodec_flush_buffers(priv->avctx);

View File

@ -55,6 +55,7 @@ struct lavc_conv *lavc_conv_create(struct sd *sd);
char *lavc_conv_get_extradata(struct lavc_conv *priv);
char **lavc_conv_decode(struct lavc_conv *priv, struct demux_packet *packet,
double *sub_pts, double *sub_duration);
bool lavc_conv_is_styled(struct lavc_conv *priv);
void lavc_conv_reset(struct lavc_conv *priv);
void lavc_conv_uninit(struct lavc_conv *priv);
@ -106,8 +107,10 @@ int sd_ass_fmt_offset(const char *event_format);
bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset);
// convert \0-terminated "Text" (ass) content to plaintext, possibly in-place.
// result.start is out, result.len is MIN(out_siz, strlen(in)) or smaller.
// if there's room: out[result.len] is set to \0. out == in is allowed.
bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in);
// result.start is *out, result.len is strlen(in) or smaller.
// (*out)[result.len] is always set to \0. *out == in is allowed.
// *out must be a talloc-allocated buffer or NULL, and will be reallocated if needed.
// *out will not be reallocated if *out == in.
bstr sd_ass_to_plaintext(char **out, const char *in);
#endif

View File

@ -51,7 +51,7 @@ struct sd_ass_priv {
bool clear_once;
struct mp_ass_packer *packer;
struct sub_bitmap_copy_cache *copy_cache;
char last_text[500];
bstr last_text;
struct mp_image_params video_params;
struct mp_image_params last_params;
struct mp_osd_res osd;
@ -651,7 +651,7 @@ static struct sub_bitmaps *get_bitmaps(struct sd *sd, struct mp_osd_res dim,
struct mp_subtitle_opts *opts = sd->opts;
struct mp_subtitle_shared_opts *shared_opts = sd->shared_opts;
bool no_ass = !opts->ass_enabled || shared_opts->ass_style_override[sd->order] == 5;
bool converted = ctx->is_converted || no_ass;
bool converted = (ctx->is_converted && !lavc_conv_is_styled(ctx->converter)) || no_ass;
ASS_Track *track = no_ass ? ctx->shadow_track : ctx->ass_track;
ASS_Renderer *renderer = ctx->ass_renderer;
struct sub_bitmaps *res = &(struct sub_bitmaps){0};
@ -709,30 +709,23 @@ done:
return res;
}
struct buf {
char *start;
int size;
int len;
};
#define MAX_BUF_SIZE 1024 * 1024
#define MIN_EXPAND_SIZE 4096
static void append(struct buf *b, char c)
static void append(bstr *b, char c)
{
if (b->len < b->size) {
b->start[b->len] = c;
b->len++;
}
bstr_xappend(NULL, b, (bstr){&c, 1});
}
static void ass_to_plaintext(struct buf *b, const char *in)
static void ass_to_plaintext(bstr *b, const char *in)
{
bool in_tag = false;
const char *open_tag_pos = NULL;
bool in_drawing = false;
while (*in) {
if (in_tag) {
if (open_tag_pos) {
if (in[0] == '}') {
in += 1;
in_tag = false;
open_tag_pos = NULL;
} else if (in[0] == '\\' && in[1] == 'p' && in[2] != 'o') {
in += 2;
// Skip text between \pN and \p0 tags. A \p without a number
@ -756,7 +749,6 @@ static void ass_to_plaintext(struct buf *b, const char *in)
} else if (in[0] == '{') {
open_tag_pos = in;
in += 1;
in_tag = true;
} else {
if (!in_drawing)
append(b, in[0]);
@ -765,65 +757,86 @@ static void ass_to_plaintext(struct buf *b, const char *in)
}
}
// A '{' without a closing '}' is always visible.
if (in_tag) {
while (*open_tag_pos)
append(b, *open_tag_pos++);
if (open_tag_pos) {
bstr_xappend(NULL, b, bstr0(open_tag_pos));
}
}
// Empty string counts as whitespace. Reads s[len-1] even if there are \0s.
static bool is_whitespace_only(char *s, int len)
// Empty string counts as whitespace.
static bool is_whitespace_only(bstr b)
{
for (int n = 0; n < len; n++) {
if (s[n] != ' ' && s[n] != '\t')
for (int n = 0; n < b.len; n++) {
if (b.start[n] != ' ' && b.start[n] != '\t')
return false;
}
return true;
}
static char *get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
static bstr get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
{
struct sd_ass_priv *ctx = sd->priv;
ASS_Track *track = ctx->ass_track;
if (pts == MP_NOPTS_VALUE)
return NULL;
return (bstr){0};
long long ipts = find_timestamp(sd, pts);
struct buf b = {ctx->last_text, sizeof(ctx->last_text) - 1};
bstr *b = &ctx->last_text;
if (!b->start)
b->start = talloc_size(ctx, 4096);
b->len = 0;
for (int i = 0; i < track->n_events; ++i) {
ASS_Event *event = track->events + i;
if (ipts >= event->Start && ipts < event->Start + event->Duration) {
if (event->Text) {
int start = b.len;
int start = b->len;
if (type == SD_TEXT_TYPE_PLAIN) {
ass_to_plaintext(&b, event->Text);
ass_to_plaintext(b, event->Text);
} else if (type == SD_TEXT_TYPE_ASS_FULL) {
long long s = event->Start;
long long e = s + event->Duration;
ASS_Style *style = (event->Style < 0 || event->Style >= track->n_styles) ? NULL : &track->styles[event->Style];
int sh = (s / 60 / 60 / 1000);
int sm = (s / 60 / 1000) % 60;
int ss = (s / 1000) % 60;
int sc = (s / 10) % 100;
int eh = (e / 60 / 60 / 1000);
int em = (e / 60 / 1000) % 60;
int es = (e / 1000) % 60;
int ec = (e / 10) % 100;
bstr_xappend_asprintf(NULL, b, "Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s",
event->Layer,
sh, sm, ss, sc,
eh, em, es, ec,
(style && style->Name) ? style->Name : "", event->Name,
event->MarginL, event->MarginR, event->MarginV,
event->Effect, event->Text);
} else {
char *t = event->Text;
while (*t)
append(&b, *t++);
bstr_xappend(NULL, b, bstr0(event->Text));
}
if (is_whitespace_only(&b.start[start], b.len - start)) {
b.len = start;
if (is_whitespace_only(bstr_cut(*b, start))) {
b->len = start;
} else {
append(&b, '\n');
append(b, '\n');
}
}
}
}
b.start[b.len] = '\0';
bstr_eatend(b, (bstr)bstr0_lit("\n"));
if (b.len > 0 && b.start[b.len - 1] == '\n')
b.start[b.len - 1] = '\0';
return ctx->last_text;
return *b;
}
static char *get_text(struct sd *sd, double pts, enum sd_text_type type)
{
return talloc_strdup(NULL, get_text_buf(sd, pts, type));
return bstrto0(NULL, get_text_buf(sd, pts, type));
}
static struct sd_times get_times(struct sd *sd, double pts)
@ -862,20 +875,26 @@ static void fill_plaintext(struct sd *sd, double pts)
ass_flush_events(track);
char *text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
if (!text)
bstr text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
if (!text.len)
return;
bstr dst = {0};
while (*text) {
if (*text == '{')
while (text.len) {
if (*text.start == '{') {
bstr_xappend(NULL, &dst, bstr0("\\{"));
text = bstr_cut(text, 1);
} else if (*text.start == '\\') {
bstr_xappend(NULL, &dst, bstr0("\\"));
bstr_xappend(NULL, &dst, (bstr){text, 1});
// Break ASS escapes with U+2060 WORD JOINER
if (*text == '\\')
// Break ASS escapes with U+2060 WORD JOINER
mp_append_utf8_bstr(NULL, &dst, 0x2060);
text++;
text = bstr_cut(text, 1);
}
int i = bstrcspn(text, "{\\");
bstr_xappend(NULL, &dst, (bstr){text.start, i});
text = bstr_cut(text, i);
}
if (!dst.start)
@ -1103,11 +1122,10 @@ bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset)
return txt;
}
bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in)
bstr sd_ass_to_plaintext(char **out, const char *in)
{
struct buf b = {out, out_siz, 0};
bstr b = {*out};
ass_to_plaintext(&b, in);
if (b.len < out_siz)
out[b.len] = 0;
return (bstr){out, b.len};
*out = b.start;
return b;
}

View File

@ -24,95 +24,49 @@
#include "options/options.h"
#include "video/out/aspect.h"
#include "video/out/gpu/video.h"
#include "video/out/opengl/egl_helpers.h"
#include "video/out/opengl/ra_gl.h"
#include "video/filter/vf_gpu.h"
struct offscreen_ctx {
struct mp_log *log;
struct ra *ra;
void *priv;
extern const struct offscreen_context offscreen_vk;
extern const struct offscreen_context offscreen_egl;
void (*set_context)(struct offscreen_ctx *ctx, bool enable);
static const struct offscreen_context *contexts[] = {
#if HAVE_EGL
&offscreen_egl,
#endif
#if HAVE_VULKAN
&offscreen_vk,
#endif
};
struct gl_offscreen_ctx {
GL gl;
EGLDisplay egl_display;
EGLContext egl_context;
};
static void gl_ctx_destroy(void *p)
static inline OPT_STRING_VALIDATE_FUNC(offscreen_ctx_validate_api)
{
struct offscreen_ctx *ctx = p;
struct gl_offscreen_ctx *gl = ctx->priv;
ra_free(&ctx->ra);
if (gl->egl_context)
eglDestroyContext(gl->egl_display, gl->egl_context);
struct bstr param = bstr0(*value);
for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) {
if (bstr_equals0(param, contexts[i]->api))
return 1;
}
return M_OPT_INVALID;
}
static void gl_ctx_set_context(struct offscreen_ctx *ctx, bool enable)
static int offscreen_ctx_api_help(struct mp_log *log, const struct m_option *opt,
struct bstr name)
{
struct gl_offscreen_ctx *gl = ctx->priv;
EGLContext c = enable ? gl->egl_context : EGL_NO_CONTEXT;
if (!eglMakeCurrent(gl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, c))
MP_ERR(ctx, "Could not make EGL context current.\n");
mp_info(log, "GPU APIs (offscreen contexts):\n");
for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++)
mp_info(log, " %s\n", contexts[i]->api);
return M_OPT_EXIT;
}
static struct offscreen_ctx *gl_offscreen_ctx_create(struct mpv_global *global,
struct mp_log *log)
static struct offscreen_ctx *offscreen_ctx_create(struct mpv_global *global,
struct mp_log *log,
const char *api)
{
struct offscreen_ctx *ctx = talloc_zero(NULL, struct offscreen_ctx);
struct gl_offscreen_ctx *gl = talloc_zero(ctx, struct gl_offscreen_ctx);
talloc_set_destructor(ctx, gl_ctx_destroy);
*ctx = (struct offscreen_ctx){
.log = log,
.priv = gl,
.set_context = gl_ctx_set_context,
};
// This appears to work with Mesa. EGL 1.5 doesn't specify what a "default
// display" is at all.
gl->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(gl->egl_display, NULL, NULL)) {
MP_ERR(ctx, "Could not initialize EGL.\n");
goto error;
for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) {
if (api && strcmp(contexts[i]->api, api) != 0)
continue;
mp_info(log, "Creating offscreen GPU context '%s'\n", contexts[i]->api);
return contexts[i]->offscreen_ctx_create(global, log);
}
// Unfortunately, mpegl_create_context() is entangled with ra_ctx.
// Fortunately, it does not need much, and we can provide a stub.
struct ra_ctx ractx = {
.log = ctx->log,
.global = global,
};
EGLConfig config;
if (!mpegl_create_context(&ractx, gl->egl_display, &gl->egl_context, &config))
{
MP_ERR(ctx, "Could not create EGL context.\n");
goto error;
}
if (!eglMakeCurrent(gl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
gl->egl_context))
{
MP_ERR(ctx, "Could not make EGL context current.\n");
goto error;
}
mpegl_load_functions(&gl->gl, ctx->log);
ctx->ra = ra_create_gl(&gl->gl, ctx->log);
if (!ctx->ra)
goto error;
gl_ctx_set_context(ctx, false);
return ctx;
error:
talloc_free(ctx);
return NULL;
}
@ -124,6 +78,7 @@ static void offscreen_ctx_set_current(struct offscreen_ctx *ctx, bool enable)
struct gpu_opts {
int w, h;
char *api;
};
struct priv {
@ -327,7 +282,7 @@ static struct mp_filter *gpu_create(struct mp_filter *parent, void *options)
priv->vo_opts_cache = m_config_cache_alloc(f, f->global, &vo_sub_opts);
priv->vo_opts = priv->vo_opts_cache->opts;
priv->ctx = gl_offscreen_ctx_create(f->global, f->log);
priv->ctx = offscreen_ctx_create(f->global, f->log, priv->opts->api);
if (!priv->ctx) {
MP_FATAL(f, "Could not create offscreen ra context.\n");
goto error;
@ -368,6 +323,8 @@ const struct mp_user_filter_entry vf_gpu = {
.options = (const struct m_option[]){
{"w", OPT_INT(w)},
{"h", OPT_INT(h)},
{"api", OPT_STRING_VALIDATE(api, offscreen_ctx_validate_api),
.help = offscreen_ctx_api_help},
{0}
},
},

35
video/filter/vf_gpu.h Normal file
View File

@ -0,0 +1,35 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/common.h"
#include "common/global.h"
struct offscreen_ctx {
struct mp_log *log;
struct ra *ra;
void *priv;
void (*set_context)(struct offscreen_ctx *ctx, bool enable);
};
struct offscreen_context {
const char *api;
struct offscreen_ctx *(*offscreen_ctx_create)(struct mpv_global *,
struct mp_log *);
};

107
video/filter/vf_gpu_egl.c Normal file
View File

@ -0,0 +1,107 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/common.h"
#include "video/filter/vf_gpu.h"
#include "video/out/opengl/egl_helpers.h"
#include "video/out/opengl/ra_gl.h"
struct gl_offscreen_ctx {
GL gl;
EGLDisplay egl_display;
EGLContext egl_context;
};
static void gl_ctx_destroy(void *p)
{
struct offscreen_ctx *ctx = p;
struct gl_offscreen_ctx *gl = ctx->priv;
ra_free(&ctx->ra);
if (gl->egl_context)
eglDestroyContext(gl->egl_display, gl->egl_context);
}
static void gl_ctx_set_context(struct offscreen_ctx *ctx, bool enable)
{
struct gl_offscreen_ctx *gl = ctx->priv;
EGLContext c = enable ? gl->egl_context : EGL_NO_CONTEXT;
if (!eglMakeCurrent(gl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, c))
MP_ERR(ctx, "Could not make EGL context current.\n");
}
static struct offscreen_ctx *gl_offscreen_ctx_create(struct mpv_global *global,
struct mp_log *log)
{
struct offscreen_ctx *ctx = talloc(NULL, struct offscreen_ctx);
struct gl_offscreen_ctx *gl = talloc_zero(ctx, struct gl_offscreen_ctx);
talloc_set_destructor(ctx, gl_ctx_destroy);
*ctx = (struct offscreen_ctx){
.log = log,
.priv = gl,
.set_context = gl_ctx_set_context,
};
// This appears to work with Mesa. EGL 1.5 doesn't specify what a "default
// display" is at all.
gl->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(gl->egl_display, NULL, NULL)) {
MP_ERR(ctx, "Could not initialize EGL.\n");
goto error;
}
// Unfortunately, mpegl_create_context() is entangled with ra_ctx.
// Fortunately, it does not need much, and we can provide a stub.
struct ra_ctx ractx = {
.log = ctx->log,
.global = global,
};
EGLConfig config;
if (!mpegl_create_context(&ractx, gl->egl_display, &gl->egl_context, &config))
{
MP_ERR(ctx, "Could not create EGL context.\n");
goto error;
}
if (!eglMakeCurrent(gl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
gl->egl_context))
{
MP_ERR(ctx, "Could not make EGL context current.\n");
goto error;
}
mpegl_load_functions(&gl->gl, ctx->log);
ctx->ra = ra_create_gl(&gl->gl, ctx->log);
if (!ctx->ra)
goto error;
gl_ctx_set_context(ctx, false);
return ctx;
error:
talloc_free(ctx);
return NULL;
}
const struct offscreen_context offscreen_egl = {
.api = "egl",
.offscreen_ctx_create = gl_offscreen_ctx_create
};

View File

@ -0,0 +1,115 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include "options/m_config.h"
#include "video/filter/vf_gpu.h"
#include "video/out/placebo/ra_pl.h"
#include "video/out/placebo/utils.h"
#include "video/out/vulkan/context.h"
#include "video/out/vulkan/utils.h"
struct vk_offscreen_ctx {
struct ra_ctx *ractx;
struct mpvk_ctx *vk;
};
extern const struct m_sub_options vulkan_conf;
static void vk_ctx_destroy(void *p)
{
struct offscreen_ctx *ctx = p;
struct vk_offscreen_ctx *vkctx = ctx->priv;
struct ra_ctx *ractx = vkctx->ractx;
struct mpvk_ctx *vk = vkctx->vk;
if (ractx->ra) {
pl_gpu_finish(vk->gpu);
ractx->ra->fns->destroy(ctx->ra);
ractx->ra = NULL;
ctx->ra = NULL;
}
vk->gpu = NULL;
pl_vulkan_destroy(&vk->vulkan);
mpvk_uninit(vk);
talloc_free(vk);
talloc_free(ractx);
}
static struct offscreen_ctx *vk_offscreen_ctx_create(struct mpv_global *global,
struct mp_log *log)
{
struct offscreen_ctx *ctx = talloc(NULL, struct offscreen_ctx);
talloc_set_destructor(ctx, vk_ctx_destroy);
*ctx = (struct offscreen_ctx){
.log = log,
};
struct ra_ctx *ractx = talloc_zero(ctx, struct ra_ctx);
struct mpvk_ctx *vk = talloc_zero(ctx, struct mpvk_ctx);
ractx->log = ctx->log;
ractx->global = global;
vk->pllog = mppl_log_create(ctx, log);
if (!vk->pllog)
goto error;
struct pl_vk_inst_params pl_vk_params = {0};
struct ra_ctx_opts *ctx_opts = mp_get_config_group(NULL, global, &ra_ctx_conf);
pl_vk_params.debug = ctx_opts->debug;
talloc_free(ctx_opts);
mppl_log_set_probing(vk->pllog, true);
vk->vkinst = pl_vk_inst_create(vk->pllog, &pl_vk_params);
mppl_log_set_probing(vk->pllog, false);
if (!vk->vkinst)
goto error;
struct vulkan_opts *vk_opts = mp_get_config_group(NULL, global, &vulkan_conf);
vk->vulkan = mppl_create_vulkan(vk_opts, vk->vkinst, vk->pllog, NULL);
talloc_free(vk_opts);
if (!vk->vulkan)
goto error;
vk->gpu = vk->vulkan->gpu;
ractx->ra = ra_create_pl(vk->gpu, ractx->log);
if (!ractx->ra)
goto error;
struct vk_offscreen_ctx *vkctx = talloc(ctx, struct vk_offscreen_ctx);
*vkctx = (struct vk_offscreen_ctx){
.ractx = ractx,
.vk = vk
};
ctx->ra = ractx->ra;
ctx->priv = vkctx;
return ctx;
error:
pl_vulkan_destroy(&vk->vulkan);
mpvk_uninit(vk);
talloc_free(vk);
talloc_free(ractx);
talloc_free(ctx);
return NULL;
}
const struct offscreen_context offscreen_vk = {
.api = "vulkan",
.offscreen_ctx_create = vk_offscreen_ctx_create
};

View File

@ -28,7 +28,6 @@
#include "video/out/placebo/utils.h"
#include "context.h"
#include "utils.h"
struct vulkan_opts {
char *device; // force a specific GPU
@ -174,19 +173,11 @@ void ra_vk_ctx_uninit(struct ra_ctx *ctx)
TA_FREEP(&ctx->swapchain);
}
bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk,
struct ra_vk_ctx_params params,
VkPresentModeKHR preferred_mode)
pl_vulkan mppl_create_vulkan(struct vulkan_opts *opts,
pl_vk_inst vkinst,
pl_log pllog,
VkSurfaceKHR surface)
{
struct ra_swapchain *sw = ctx->swapchain = talloc_zero(NULL, struct ra_swapchain);
sw->ctx = ctx;
sw->fns = &vulkan_swapchain;
struct priv *p = sw->priv = talloc_zero(sw, struct priv);
p->vk = vk;
p->params = params;
p->opts = mp_get_config_group(p, ctx->global, &vulkan_conf);
VkPhysicalDeviceFeatures2 features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
};
@ -224,30 +215,47 @@ bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk,
#endif
AVUUID param_uuid = { 0 };
bool is_uuid = p->opts->device &&
av_uuid_parse(p->opts->device, param_uuid) == 0;
bool is_uuid = opts->device &&
av_uuid_parse(opts->device, param_uuid) == 0;
assert(vk->pllog);
assert(vk->vkinst);
assert(pllog);
assert(vkinst);
struct pl_vulkan_params device_params = {
.instance = vk->vkinst->instance,
.get_proc_addr = vk->vkinst->get_proc_addr,
.surface = vk->surface,
.async_transfer = p->opts->async_transfer,
.async_compute = p->opts->async_compute,
.queue_count = p->opts->queue_count,
.instance = vkinst->instance,
.get_proc_addr = vkinst->get_proc_addr,
.surface = surface,
.async_transfer = opts->async_transfer,
.async_compute = opts->async_compute,
.queue_count = opts->queue_count,
#if HAVE_VULKAN_INTEROP
.extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR,
.opt_extensions = opt_extensions,
.num_opt_extensions = MP_ARRAY_SIZE(opt_extensions),
#endif
.features = &features,
.device_name = is_uuid ? NULL : p->opts->device,
.device_name = is_uuid ? NULL : opts->device,
};
if (is_uuid)
av_uuid_copy(device_params.device_uuid, param_uuid);
vk->vulkan = pl_vulkan_create(vk->pllog, &device_params);
return pl_vulkan_create(pllog, &device_params);
}
bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk,
struct ra_vk_ctx_params params,
VkPresentModeKHR preferred_mode)
{
struct ra_swapchain *sw = ctx->swapchain = talloc_zero(NULL, struct ra_swapchain);
sw->ctx = ctx;
sw->fns = &vulkan_swapchain;
struct priv *p = sw->priv = talloc_zero(sw, struct priv);
p->vk = vk;
p->params = params;
p->opts = mp_get_config_group(p, ctx->global, &vulkan_conf);
vk->vulkan = mppl_create_vulkan(p->opts, vk->vkinst, vk->pllog, vk->surface);
if (!vk->vulkan)
goto error;

View File

@ -21,6 +21,12 @@ bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk,
struct ra_vk_ctx_params params,
VkPresentModeKHR preferred_mode);
// Helper for initializing mpvk_ctx->vulkan
pl_vulkan mppl_create_vulkan(struct vulkan_opts *opts,
pl_vk_inst vkinst,
pl_log pllog,
VkSurfaceKHR surface);
// Handles a resize request, and updates ctx->vo->dwidth/dheight
bool ra_vk_ctx_resize(struct ra_ctx *ctx, int width, int height);